using System;
using System.Drawing;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Iisu;
using MathNet.Numerics.LinearAlgebra.Single;

namespace bbiwarg.InputProviders
{
    class IisuInputProvider : IInputProvider
    {
        private IHandle handle;
        private IDevice device;
        private string moviePath;
        private bool active;
        private bool sourceIsMovie;

        //parameters
        private IParameterHandle<float> frameRate;
        private IParameterHandle<int> currentMovieFrame;
        private IParameterHandle<float> hfov;
        private IParameterHandle<float> vfov;
        private IParameterHandle<int> playStep;

        //data
        private IDataHandle<Iisu.Data.IImageData> depthImage;

        public IisuInputProvider(String moviePath = "")
        {
            if (moviePath.Length != 0)
            {
                this.moviePath = moviePath;
                sourceIsMovie = true;
            }
            else
            {
                sourceIsMovie = false;
            }
            active = false;
        }

        // control-methodes

        public void init()
        {
            handle = Iisu.Iisu.Context.CreateHandle();

            IDeviceConfiguration conf = handle.CreateDeviceConfiguration();
            if (sourceIsMovie)
                conf.MoviePath = moviePath;

            device = handle.InitializeDevice(conf);

            // parameters
            if (sourceIsMovie)
            {
                //device.RegisterParameterHandle<int>("SOURCE.MOVIE.PlayMode").Value = 0; // playMode = once
                device.RegisterParameterHandle<int>("SOURCE.MOVIE.PlayMode").Value = 1; // playMode = loop
                //device.RegisterParameterHandle<int>("SOURCE.MOVIE.PlayMode").Value = 2; // playMode = ping-pong
                playStep = device.RegisterParameterHandle<int>("SOURCE.MOVIE.PlayStep");
                currentMovieFrame = device.RegisterParameterHandle<int>("SOURCE.MOVIE.CurrentFrame");
            }
            else
            {
                device.RegisterParameterHandle<int>("SOURCE.DEPTHSENSE.AmplitudeThreshold").Value = 100; // confidence-threshhold
            }

            frameRate = device.RegisterParameterHandle<float>("SOURCE.FrameRate");
            hfov = device.RegisterParameterHandle<float>("SOURCE.CAMERA.DEPTH.HFOV");
            vfov = device.RegisterParameterHandle<float>("SOURCE.CAMERA.DEPTH.VFOV");

            // events
            device.EventManager.RegisterEventListener("DEVICE.Status", new Iisu.EventDelegates.Device.Status(onDeviceStatusChanged));

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

        private void onDeviceStatusChanged(string eventName, DeviceStatus status)
        {
            active = status.HasFlag(Iisu.DeviceStatus.Playing);
        }

        public void start()
        {
            device.Start();
        }

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

        public void updateFrame()
        {
            device.UpdateFrame(true);
        }

        public void releaseFrame()
        {
            device.ReleaseFrame();
        }

        // Parameter-methodes

        public float getFrameRate()
        {
            return frameRate.Value;
        }

        public float getHFOV()
        {
            return hfov.Value;
        }

        public float getVFOV()
        {
            return vfov.Value;
        }

        public bool isActive()
        {
            return active;
        }


        // Data-methodes
        public InputFrame getInputFrame() {
            //depthData
            Iisu.Data.IImageInfos imageInfos = depthImage.Value.ImageInfos;
            int width = (int)imageInfos.Width;
            int height = (int)imageInfos.Height;
            IntPtr rawDepthData = depthImage.Value.Raw;

            return new InputFrame(width, height, rawDepthData);
        }

        // other
        public void pauseMovie()
        {
            if (sourceIsMovie)
                playStep.Value = 0;
        }

        public void unpauseMovie()
        {
            if (sourceIsMovie)
                playStep.Value = 1;
        }

        public int getCurrentMovieFrame()
        {
            if (sourceIsMovie)
                return currentMovieFrame.Value;
            return 0;
        }

        bool IInputProvider.sourceIsMovie()
        {
            return sourceIsMovie;
        }

        public void reversePlay()
        {
            if (sourceIsMovie)
                playStep.Value = -playStep.Value;
        }
    }
}