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.Graphics;
using bbiwarg.Detectors.FingerDetection;
using bbiwarg.Detectors.HandDetection;
using bbiwarg.Utility;

namespace bbiwarg.Images
{
    class DepthImage
    {
        private OutputImage outputImage;
        public Image<Gray, byte> Image { get; private set; }
        public Image<Gray, byte> BackgroundMask { get; private set; }
        public int Width { get; private set; }
        public int Height { get; private set; }
        public Int16 MinDepth { get; private set; }
        public Int16 MaxDepth { get; private set; }

        public DepthImage(Image<Gray, Int16> image, OutputImage outputImage)
        {
            this.outputImage = outputImage;

            Width = image.Width;
            Height = image.Height;

            image = image.SmoothMedian(Constants.DepthImageMedianSize);

            //threshold min&maxDepth
            MinDepth = findMinDepth(image);
            MaxDepth = (Int16)(MinDepth + Constants.DepthImageDepthRange);

            //smooth+threshold (dst = (src > (MaxDepth - MinDepth)) ? MaxDepth - MinDepth : src)
            Image = (image- MinDepth).ThresholdTrunc(new Gray(MaxDepth - MinDepth)).Convert<Gray, byte>();

            Image = Image.SmoothMedian(Constants.DepthImageMedianSize);
        }

        public Int16 getDepthAt(Point point)
        {
            return getDepthAt(point.X, point.Y);
        }

        public Int16 getDepthAt(int x, int y)
        {
            return (Int16)(MinDepth + Image.Data[y, x, 0]);
        }

        public void setDepthAt(Point point, Int16 depth)
        {
            setDepthAt(point.X, point.Y, depth);
        }

        public void setDepthAt(int x, int y, Int16 depth)
        {
            Image.Data[y, x, 0] = (byte)(depth - MinDepth);
        }

        private Int16 findMinDepth(Image<Gray, Int16> image)
        {
            // min and max values
            double[] min, max;
            // min and max locations
            Point[] minLoc, maxLoc;

            image.MinMax(out min, out max, out minLoc, out maxLoc);

            return (Int16)min[0];
        }

        public void removeBackground(List<Hand> hands) {
            Image<Gray, byte> mask = Image.CopyBlank();
            foreach (Hand hand in hands) {
                mask = mask.Or(hand.Mask);
            }


            Image = Image.Or(255-mask);
        }
    }
}