using bbiwarg.Images;
using bbiwarg.Input.InputProviding;
using bbiwarg.Recognition.FingerRecognition;
using bbiwarg.Recognition.HandRecognition;
using bbiwarg.Recognition.PalmRecognition;
using bbiwarg.Recognition.TouchRecognition;
using bbiwarg.Utility;
using System;

namespace bbiwarg.Input.InputHandling
{
    public delegate void NewProcessedFrameEventHandler(InputHandler sender, EventArgs e);

    public class InputHandler
    {
        private FingerDetector fingerDetector;
        private HandDetector handDetector;
        private PalmDetector palmDetector;
        private TouchDetector touchDetector;

        private FingerTracker fingerTracker;
        private HandTracker handTracker;
        private PalmTracker palmTracker;
        private TouchTracker touchTracker;

        public FrameData FrameData { get; private set; }

        public event NewProcessedFrameEventHandler NewProcessedFrameEvent;

        public InputHandler()
        {
            initialize();
        }

        private void initialize()
        {
            fingerDetector = new FingerDetector();
            handDetector = new HandDetector();
            palmDetector = new PalmDetector();
            touchDetector = new TouchDetector();

            fingerTracker = new FingerTracker();
            handTracker = new HandTracker();
            palmTracker = new PalmTracker();
            touchTracker = new TouchTracker();
        }

        public void reset()
        {
            touchTracker.reset();
            handTracker.reset();
            palmTracker.reset();
            fingerTracker.reset();
        }

        public void handleNewFrame(object sender, NewFrameEventArgs e)
        {
            Timer.start("InputHandler.handleNewFrame");

            FrameData frameData = new FrameData();

            frameData.FrameID = e.FrameID;

            // confidence image
            Timer.start("InputHandler.handleNewFrame::createConfidenceImage");
            frameData.ConfidenceImage = new ConfidenceImage(e.RawConfidenceData, e.Width, e.Height);
            Timer.stop("InputHandler.handleNewFrame::createConfidenceImage");

            // depth image
            Timer.start("InputHandler.handleNewFrame::createDepthImage");
            frameData.DepthImage = new DepthImage(e.RawDepthData, e.Width, e.Height, frameData.ConfidenceImage);
            Timer.stop("InputHandler.handleNewFrame::createDepthImage");

            // edge image
            Timer.start("InputHandler.handleNewFrame::createEdgeImage");
            frameData.EdgeImage = new EdgeImage(frameData.DepthImage);
            Timer.stop("InputHandler.handleNewFrame::createEdgeImage");

            // detect fingers
            Timer.start("InputHandler.handleNewFrame::detectFingers");
            fingerDetector.detectFingers(frameData);
            Timer.stop("InputHandler.handleNewFrame::detectFingers");

            // track fingers
            Timer.start("InputHandler.handleNewFrame::trackFingers");
            fingerTracker.trackFingers(frameData);
            Timer.stop("InputHandler.handleNewFrame::trackFingers");

            // detect hands
            Timer.start("InputHandler.handleNewFrame::detectHands");
            handDetector.detectHands(frameData);
            Timer.stop("InputHandler.handleNewFrame::detectHands");

            // track hands
            Timer.start("InputHandler.handleNewFrame::trackHands");
            handTracker.trackHands(frameData);
            Timer.stop("InputHandler.handleNewFrame::trackHands");

            // detect palms
            Timer.start("InputHandler.handleNewFrame::detectPalms");
            palmDetector.detectPalms(frameData);
            Timer.stop("InputHandler.handleNewFrame::detectPalms");

            // track palms
            Timer.start("InputHandler.handleNewFrame::trackPalms");
            palmTracker.trackPalms(frameData);
            Timer.stop("InputHandler.handleNewFrame::trackPalms");

            // detect touches
            Timer.start("InputHandler.handleNewFrame::detectTouches");
            touchDetector.detectTouches(frameData);
            Timer.stop("InputHandler.handleNewFrame::detectTouches");

            //track touches
            Timer.start("InputHandler.handleNewFrame::trackTouches");
            touchTracker.trackTouches(frameData);
            Timer.stop("InputHandler.handleNewFrame::trackTouches");


            Timer.start("InputHandler.handleNewFrame::exportResults");
            FrameData = frameData;
            if (NewProcessedFrameEvent != null)
                NewProcessedFrameEvent(this, new EventArgs());
            Timer.stop("InputHandler.handleNewFrame::exportResults");


            Timer.stop("InputHandler.handleNewFrame");

            Timer.outputAll();
        }
    }
}