using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV;
using Emgu.CV.Structure;
using bbiwarg.Recognition.FingerRecognition;

using System.Diagnostics;
using bbiwarg.Utility;
using bbiwarg.Graphics;

namespace bbiwarg.Images
{
    class EdgeImage
    {
        public Image<Gray, Byte> Image { get; private set; }
        public Image<Gray, byte> RoughImage { get; private set; }
        public int Width { get; private set; }
        public int Height { get; private set; }

        public EdgeImage(DepthImage depthImage)
        {
            Width = depthImage.Width;
            Height = depthImage.Height;
            Image = (depthImage.Image * (255.0f / (float)(depthImage.MaxDepth - depthImage.MinDepth))).Canny(Constants.EdgeImageCannyStartThreshold, Constants.EdgeImageCannyLinkingThreshold, Constants.EdgeImageCannySize).ThresholdBinary(new Gray(0), new Gray(1));
            RoughImage = Image.Dilate(Constants.EdgeImageRoughNumDilationIterations);
        }

        public EdgeImage(Image<Gray, Byte> edgeImage)
        {
            Image = edgeImage;
            RoughImage = Image.Dilate(Constants.EdgeImageRoughNumDilationIterations);
        }

        public bool isEdgeAt(Point point)
        {
            return isEdgeAt(point.X, point.Y);
        }

        public bool isEdgeAt(int x, int y)
        {
            return (Image.Data[y, x, 0] > 0);
        }

        public bool isRoughEdgeAt(Point point)
        {
            return isRoughEdgeAt(point.X, point.Y);
        }

        public bool isRoughEdgeAt(int x, int y)
        {
            return (RoughImage.Data[y, x, 0] > 0);
        }

        public void removeEdgesInsidePolygon(Point[] polygon)
        {
            Image.FillConvexPoly(polygon, new Gray(0));
            RoughImage.FillConvexPoly(polygon, new Gray(0));
        }

        public Vector2D findNextEdge(Vector2D start, Vector2D direction, int maxSearchSize = 0, bool roughEdge=true, bool returnNullIfNoEdgeFound=true)
        {
            Vector2D max = new Vector2D(Image.Width-1, Image.Height-1);
            Vector2D maxGrow = (max - start) / direction;
            Vector2D maxDecline = start / direction.getAbsolute();

            int maxStepsX;
            if (direction.X > 0)
                maxStepsX = maxGrow.IntX;
            else if (direction.X < 0)
                maxStepsX = maxDecline.IntX;
            else
                maxStepsX = int.MaxValue;

            int maxStepsY;
            if (direction.Y > 0)
                maxStepsY = maxGrow.IntY;
            else if (direction.Y < 0)
                maxStepsY = maxDecline.IntY;
            else
                maxStepsY = int.MaxValue;

            int maxSteps = Math.Min(maxStepsX, maxStepsY);

            if (maxSearchSize != 0)
                maxSteps = Math.Min(maxSteps, maxSearchSize);

            Vector2D end = new Vector2D(start);
            for (int i = 0; i < maxSteps; i++)
            {
                end += direction;

                if((roughEdge && isRoughEdgeAt(end)) || (!roughEdge && isEdgeAt(end)))
                {
                    return end;
                }
            }

            if (returnNullIfNoEdgeFound)
                return null;
            else
                return end;
        }

        public EdgeImage copy()
        {
            return new EdgeImage(Image.Copy());
        }
    }
}
