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 bbiwarg.Utility;
using bbiwarg.Recognition.Tracking;
using bbiwarg.Recognition.PalmRecognition;

namespace bbiwarg.Recognition.HandRecognition
{
    public class Hand : TrackableObject
    {
        public Vector2D Centroid { get; private set; }
        public Image<Gray, byte> Mask { get; private set; }
        public List<Finger> Fingers { get; private set; }
        public Palm Palm { get; set; }

        public Hand(Image<Gray, byte> mask, List<Finger> fingers)
        {
            Mask = mask;
            Fingers = fingers;

            foreach (Finger finger in Fingers)
                finger.Hand = this;
        }

        public bool isInside(Vector2D point)
        {
            return (Mask.Data[point.IntY, point.IntX, 0] != 0);
        }

        public void mergeWith(Hand mergeHand)
        {
            extendMask(mergeHand.Mask);
            Fingers.AddRange(mergeHand.Fingers);
            foreach (Finger finger in mergeHand.Fingers)
                finger.Hand = this;
        }

        public void extendMask(Image<Gray, byte> extendMask)
        {
            Mask = Mask.Or(extendMask);
        }

        public void fillOverlappingFingers(List<Finger> otherFingers)
        {
            foreach (Finger finger in otherFingers)
            {
                FingerSliceTrail trail = null;
                foreach (FingerSlice slice in finger.SliceTrail.Slices)
                {
                    Vector2D out1 = slice.Start.moveWithinBound(slice.Direction.getInverse(), Parameters.FingerContourMargin);
                    Vector2D out2 = slice.End.moveWithinBound(slice.Direction, Parameters.FingerContourMargin);

                    if (isInside(out1) && isInside(out2))
                    {
                        if (trail == null)
                            trail = new FingerSliceTrail(slice);
                        else
                            trail.addSlice(slice);
                    }
                }

                if (trail != null)
                    Mask.FillConvexPoly(trail.getContour(Parameters.FingerOutMargin).ToArray(), new Gray(1));
            }
            Mask = Mask.Dilate(1);
        }

        public void findCentroid()
        {
            MCvPoint2D64f gravityCenter = Mask.GetMoments(true).GravityCenter;
            Centroid = new Vector2D((float)gravityCenter.x, (float)gravityCenter.y);
        }
    }
}
