using bbiwarg.Utility;
using Emgu.CV;
using Emgu.CV.Structure;
using System;
using System.Drawing;

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

        public EdgeImage(DepthImage depthImage)
        {
            Image = depthImage.Image.ConvertScale<byte>(255f / (depthImage.MaxDepth - depthImage.MinDepth), 0).Canny(Parameters.EdgeImageCannyStartThreshold, Parameters.EdgeImageCannyLinkingThreshold, Parameters.EdgeImageCannySize).ThresholdBinary(new Gray(0), new Gray(1));
            RoughImage = Image.Dilate(Parameters.EdgeImageRoughNumDilationIterations);
        }

        public EdgeImage(Image<Gray, Byte> edgeImage, Image<Gray, Byte> roughEdgeImage)
        {
            Image = edgeImage;
            RoughImage = roughEdgeImage;
        }

        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 findNextRoughEdge(Vector2D start, Vector2D direction, int maxSearchSize = 0)
        {
            Vector2D maxGrow = (Parameters.ImageMaxPixel - 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 (isRoughEdgeAt(end))
                    return end;
            }

            return null;
        }

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