using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using Iisu;

namespace bbiwarg.Input.InputProviding
{
    public delegate void DeviceStartedEventHandler(object sender, EventArgs e);
    public delegate void NewFrameEventHandler(object sender, NewFrameEventArgs e);

    public class NewFrameEventArgs : EventArgs
    {
        public int FrameID { get; private set; }
        public int Width { get; private set; }
        public int Height { get; private set; }
        public IntPtr RawDepthData { get; private set; }
        public IntPtr RawConfidenceData { get; private set; }

        public NewFrameEventArgs(int frameID, int width, int height, IntPtr rawDepthData, IntPtr rawConfidenceData)
        {
            FrameID = frameID;
            Width = width;
            Height = height;
            RawDepthData = rawDepthData;
            RawConfidenceData = rawConfidenceData;
        }
    }

    class InputProvider
    {
        protected IHandle handle;
        protected IDevice device;

        protected IParameterHandle<float> frameRate;
        protected IParameterHandle<int> imageWidth;
        protected IParameterHandle<int> imageHeight;
        protected IDataHandle<Iisu.Data.IImageData> depthImage;
        protected IDataHandle<Iisu.Data.IImageData> confidenceImage;

        protected int lastFrameID;

        public bool IsActive { get; private set; }
        public virtual int CurrentFrameID { get { return device.FrameId; } }

        public event DeviceStartedEventHandler DeviceStartedEvent;
        public event NewFrameEventHandler NewFrameEvent;

        public InputProvider()
        {
            IsActive = false;
            lastFrameID = -1;
        }

        public void start()
        {
            createDevice();
            registerHandles();

            device.Start();
            IsActive = true;

            if (DeviceStartedEvent != null)
                DeviceStartedEvent(this, new EventArgs());

            run();
        }

        public void stop()
        {
            IsActive = false;
            device.Stop(true);
        }

        protected void createDevice()
        {
            handle = Iisu.Iisu.Context.CreateHandle();
            IDeviceConfiguration conf = createDeviceConfiguration();
            device = handle.InitializeDevice(conf);
        }

        protected virtual IDeviceConfiguration createDeviceConfiguration()
        {
            IDeviceConfiguration conf =  handle.CreateDeviceConfiguration();
            conf.IsAsynchronous = false;
            return conf;
        }

        protected virtual void registerHandles()
        {
            imageWidth = device.RegisterParameterHandle<int>("SOURCE.CAMERA.DEPTH.Width");
            imageHeight = device.RegisterParameterHandle<int>("SOURCE.CAMERA.DEPTH.Height");
            frameRate = device.RegisterParameterHandle<float>("SOURCE.FrameRate");
            Parameters.setImageParameters(imageWidth.Value, imageHeight.Value);

            depthImage = device.RegisterDataHandle<Iisu.Data.IImageData>("SOURCE.CAMERA.DEPTH.Image");
            confidenceImage = device.RegisterDataHandle<Iisu.Data.IImageData>("SOURCE.CAMERA.CONFIDENCE.Image");
        }

        protected virtual void run()
        {
            while (IsActive)
                nextFrame();
        }

        protected void nextFrame()
        {
            device.UpdateFrame(true);
            provideNewFrame();
            device.ReleaseFrame();
        }

        protected void provideNewFrame()
        {
            if (CurrentFrameID != lastFrameID)
            {
                if (NewFrameEvent != null)
                    NewFrameEvent(this, new NewFrameEventArgs(CurrentFrameID, imageWidth.Value, imageHeight.Value, depthImage.Value.Raw, confidenceImage.Value.Raw));

                lastFrameID = CurrentFrameID;
            }
        }
    }
}
