using System;
using System.Collections.Generic;
using System.Text;
using InterpreterLibrary.Models;
using Tesseract;

namespace InterpreterLibrary.Processing
{
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    public class BlobCounter : BlobCounterBase
    {
        private byte backgroundThresholdR = 0;
        private byte backgroundThresholdG = 0;
        private byte backgroundThresholdB = 0;
        private Rectangle _areaOfInterest;

        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        public System.Drawing.Color BackgroundThreshold
        {
            get
            {
                return System.Drawing.Color.FromArgb(backgroundThresholdR, backgroundThresholdG, backgroundThresholdB);
            }
            set
            {
                backgroundThresholdR = value.R;
                backgroundThresholdG = value.G;
                backgroundThresholdB = value.B;
            }
        }

        public bool FilterBlobs { get; set; }
        public int MinWidth { get; set; }
        public int MaxWidth { get; set; }
        public int MinHeight { get; set; }
        public int MaxHeight { get; set; }

        
        
        
        
        
        
        
        
        
        
        public BlobCounter()
        {
        }

        
        
        
        
        
        
        public BlobCounter(Pix image) : base(image)
        {
        }


        
        
        
        
        
        
        
        public BlobCounter(Pix image, Rectangle areaOfInterest) : base(image)
        {
            _areaOfInterest = areaOfInterest;
        }

        
        
        
        
        
        
        

        
        
        
        
        
        
        

        
        
        
        
        
        
        
        
        
        
        
        
        protected override void BuildObjectsMap(Pix image)
        {
            int stride = image.GetData().WordsPerLine * sizeof(Int32); 

            
            
            
            
            
            
            
            
            

            if (image.Depth != 1)
            {
                throw new NotSupportedException("Unsupported pixel format of the source image.");
            }

            
            if (imageWidth == 1)
            {
                throw new NotSupportedException(
                    "BlobCounter cannot process images that are one pixel wide. Rotate the image or use RecursiveBlobCounter.");
            }

            var imageWidthM1 = imageWidth - 1;

            
            objectLabels = new int[imageWidth * imageHeight];
            
            var labelsCount = 0;

            
            var maxObjects = ((imageWidth / 2) + 1) * ((imageHeight / 2) + 1) + 1;
            var map = new int[maxObjects];

            
            for (var i = 0; i < maxObjects; i++)
            {
                map[i] = i;
            }

            
            unsafe
            {
                var helper =  PixHelper.Create(image);
                
                var p = 0;

                
                {
                    if (helper.GetPixel(0, 0) > backgroundThresholdG)
                    {
                        objectLabels[p] = ++labelsCount;
                    }

                    
                    for (var x = 1; x < imageWidth; x++, p++)
                    {
                        

                        
                        if (helper.GetPixel(x, 0) > backgroundThresholdG)
                        {
                            
                            if (helper.GetPixel(x - 1, 0) > backgroundThresholdG)
                            {
                                
                                objectLabels[p] = objectLabels[p - 1];
                            }
                            else
                            {
                                
                                objectLabels[p] = ++labelsCount;
                            }
                        }
                    }

                    
                    
                    for (var y = 1; y < imageHeight; y++)
                    {
                        
                        
                        if (helper.GetPixel(0, y) > backgroundThresholdG)
                        {
                            
                            if (helper.GetPixel(0, y - 1) > backgroundThresholdG)
                            {
                                
                                objectLabels[p] = objectLabels[p - imageWidth];
                            }
                            else if (helper.GetPixel(1, y - 1) > backgroundThresholdG)
                            {
                                
                                objectLabels[p] = objectLabels[p + 1 - imageWidth];
                            }
                            else
                            {
                                
                                objectLabels[p] = ++labelsCount;
                            }
                        }
                        
                        ++p;

                        
                        for (var x = 1; x < imageWidthM1; x++, p++)
                        {
                            if (helper.GetPixel(x, y) > backgroundThresholdG)
                            {
                                
                                if (helper.GetPixel(x - 1, y) > backgroundThresholdG)
                                {
                                    
                                    objectLabels[p] = objectLabels[p - 1];
                                }
                                else if (helper.GetPixel(x - 1, y - 1) > backgroundThresholdG)
                                {
                                    
                                    objectLabels[p] = objectLabels[p - 1 - imageWidth];
                                }
                                else if (helper.GetPixel(x, y - 1) > backgroundThresholdG)
                                {
                                    
                                    objectLabels[p] = objectLabels[p - imageWidth];
                                }

                                if (helper.GetPixel(x + 1, y - 1)  > backgroundThresholdG)
                                {
                                    if (objectLabels[p] == 0)
                                    {
                                        
                                        objectLabels[p] = objectLabels[p + 1 - imageWidth];
                                    }
                                    else
                                    {
                                        int l1 = objectLabels[p];
                                        int l2 = objectLabels[p + 1 - imageWidth];

                                        if ((l1 != l2) && (map[l1] != map[l2]))
                                        {
                                            
                                            if (map[l1] == l1)
                                            {
                                                
                                                map[l1] = map[l2];
                                            }
                                            else if (map[l2] == l2)
                                            {
                                                
                                                map[l2] = map[l1];
                                            }
                                            else
                                            {
                                                
                                                map[map[l1]] = map[l2];
                                                map[l1] = map[l2];
                                            }

                                            
                                            for (var i = 1; i <= labelsCount; i++)
                                            {
                                                if (map[i] != i)
                                                {
                                                    
                                                    var j = map[i];
                                                    while (j != map[j])
                                                    {
                                                        j = map[j];
                                                    }
                                                    map[i] = j;
                                                }
                                            }
                                        }
                                    }
                                }

                                
                                if (objectLabels[p] == 0)
                                {
                                    
                                    objectLabels[p] = ++labelsCount;
                                }
                            }
                        }

                        
                        
                        if (helper.GetPixel(imageWidthM1, y)  > backgroundThresholdG)
                        {
                            
                            if (helper.GetPixel(imageWidthM1 - 1, y)  > backgroundThresholdG)
                            {
                                
                                objectLabels[p] = objectLabels[p - 1];
                            }
                            else if (helper.GetPixel(imageWidthM1 - 1, y - 1)  >
                                     backgroundThresholdG)
                            {
                                
                                objectLabels[p] = objectLabels[p - 1 - imageWidth];
                            }
                            else if (helper.GetPixel(imageWidthM1, y - 1)  > backgroundThresholdG)
                            {
                                
                                objectLabels[p] = objectLabels[p - imageWidth];
                            }
                            else
                            {
                                
                                objectLabels[p] = ++labelsCount;
                            }
                        }
                        
                        ++p;

                        


                    }

                    
                    var reMap = new int[map.Length];

                    
                    objectsCount = 0;
                    for (var i = 1; i <= labelsCount; i++)
                    {
                        if (map[i] == i)
                        {
                            
                            reMap[i] = ++objectsCount;
                        }
                    }
                    
                    for (var i = 1; i <= labelsCount; i++)
                    {
                        if (map[i] != i)
                        {
                            reMap[i] = reMap[map[i]];
                        }
                    }

                    
                    for (int i = 0, n = objectLabels.Length; i < n; i++)
                    {
                        objectLabels[i] = reMap[objectLabels[i]];
                    }
                }
            }
        }
    }
}

