using System;

namespace MotorSkill
{
    class EyeTrackerDataFrame
    {
        // member data
        public long timestamp { get; set; }
        public double left_gaze_x { get; set; }         // x coordinate for left eye
        public double left_gaze_y { get; set; }         // y coordinate for left eye
        public double right_gaze_x { get; set; }        // x coordinate for right eye
        public double right_gaze_y { get; set; }        // y coordinate for right eye
        public double diam_left_eye { get; set; }       // 
        public double diam_right_eye { get; set; }      //
        public double left_eyePosition_X { get; set; }  // left eye position on X
        public double left_eyePosition_Y { get; set; }  // left eye position on Y
        public double left_eyePosition_Z { get; set; }  // left eye position on Z
        public double right_eyePosition_X { get; set; } // right eye position on X
        public double right_eyePosition_Y { get; set; } // right eye position on Y
        public double right_eyePosition_Z { get; set; } // right eye position on Z

        // constructor
        public EyeTrackerDataFrame()
        {
        }

        public EyeTrackerDataFrame(long timestamp, double left_gaze_x, double left_gaze_y, double right_gaze_x, double right_gaze_y, double diam_left_eye, double diam_right_eye, double left_eyePosition_X, double left_eyePosition_Y, double left_eyePosition_Z, double right_eyePosition_X, double right_eyePosition_Y, double right_eyePosition_Z)
        {
            this.timestamp = timestamp;
            this.left_gaze_x = left_gaze_x;
            this.left_gaze_y = left_gaze_y;
            this.right_gaze_x = right_gaze_x;
            this.right_gaze_y = right_gaze_y;
            this.diam_left_eye = diam_left_eye;
            this.diam_right_eye = diam_right_eye;
            this.left_eyePosition_X = left_eyePosition_X;
            this.left_eyePosition_Y = left_eyePosition_Y;
            this.left_eyePosition_Z = left_eyePosition_Z;
            this.right_eyePosition_X = right_eyePosition_X;
            this.right_eyePosition_Y = right_eyePosition_Y;
            this.right_eyePosition_Z = right_eyePosition_Z;
        }
    }

    class EyeTrackerFixationDataFrame
    {
        // member data
        public long timestamp { get; set; }
        public char eye { get; set; }
        public Int64 time_start { get; set; }
        public Int64 time_end { get; set; }
        public Int64 duration { get; set; }
        public double Pos_X { get; set; }
        public double Pos_Y { get; set; }

        // constructor
        public EyeTrackerFixationDataFrame(long timestamp, char eye, Int64 time_start, Int64 time_end, Int64 duration, double Pos_X, double Pos_Y)
        {
            this.timestamp = timestamp;
            this.eye = eye;
            this.time_start = time_start;
            this.time_end = time_end;
            this.duration = duration;
            this.Pos_X = Pos_X;
            this.Pos_Y = Pos_Y;
        }
    }

    // This class is used for connect Demo class with Eyetracker data
    class EyeTrackerDataStream
    {

        // member data
        private Action<EyeTrackerDataFrame> callback; // the callback method
        private Action<EyeTrackerFixationDataFrame> callbackFixation; // the callback method for fixation

        EyeTrackingController.EyeTrackingController ETDevice;

        // callback routine declaration
        private delegate void GetSampleCallback(EyeTrackingController.EyeTrackingController.SampleStruct sampleData);
        private delegate void GetEventCallback(EyeTrackingController.EyeTrackingController.EventStruct eventData);

        // callback function instances
        GetSampleCallback m_SampleCallback;
        GetEventCallback m_EventCallback;

        // the object receive the callback function on instantiation
        public EyeTrackerDataStream(Action<EyeTrackerDataFrame> callback, Action<EyeTrackerFixationDataFrame> callbackFixation)
        {
            this.callback = callback;
            this.callbackFixation = callbackFixation;
            // instantiate the eye tracking controller 
            ETDevice = new EyeTrackingController.EyeTrackingController();

            // define callbacks for data stream 
            m_SampleCallback = new GetSampleCallback(GetSampleCallbackFunction);
            m_EventCallback = new GetEventCallback(GetEventCallbackFunction);
        }

        public static void testAvailability()
        {
            EyeTrackingController.EyeTrackingController tmp = new EyeTrackingController.EyeTrackingController();
            if (tmp.iV_Connect() != 1)
            {
                throw new EyeTrackerFailedToOpenException();
            }
            tmp.iV_Disconnect();
        }

        // this method initializes the data stream
        public void Open()
        {
            int ret = 0;
            // setting callback functions 
            ETDevice.iV_SetSampleCallback(m_SampleCallback);
            ETDevice.iV_SetEventCallback(m_EventCallback);

            // connecting to myGaze eye tracking server 
            ret = ETDevice.iV_Connect();
            /// if (ret == 1) Console."iV_Connect: connection established";
            if (ret != 1)
            {
                throw new EyeTrackerFailedToOpenException();
            }
        }

        void GetSampleCallbackFunction(EyeTrackingController.EyeTrackingController.SampleStruct sampleData)
        {
            double left_gaze_x = sampleData.leftEye.gazeX;
            double left_gaze_y = sampleData.leftEye.gazeY;
            double right_gaze_x = sampleData.rightEye.gazeX;
            double right_gaze_y = sampleData.rightEye.gazeY;
            double diam_left_eye = sampleData.leftEye.diam;
            double diam_right_eye = sampleData.rightEye.diam;
            double left_eyePosition_X = sampleData.leftEye.eyePositionX;
            double left_eyePosition_Y = sampleData.leftEye.eyePositionY;
            double left_eyePosition_Z = sampleData.leftEye.eyePositionZ;
            double right_eyePosition_X = sampleData.rightEye.eyePositionX;
            double right_eyePosition_Y = sampleData.rightEye.eyePositionY;
            double right_eyePosition_Z = sampleData.rightEye.eyePositionZ;

            EyeTrackerDataFrame eyeTrackerDataFrame = new EyeTrackerDataFrame(ExperimentConfig.getMsDateTime(), left_gaze_x, left_gaze_y, right_gaze_x, right_gaze_y, diam_left_eye, diam_right_eye, left_eyePosition_X, left_eyePosition_Y, left_eyePosition_Z, right_eyePosition_X, right_eyePosition_Y, right_eyePosition_Z);
            callback(eyeTrackerDataFrame);

        }

        //pentru fixare privire si clipire
        void GetEventCallbackFunction(EyeTrackingController.EyeTrackingController.EventStruct eventData)
        {
            char eye = eventData.eye;
            Int64 time_start = eventData.startTime;
            Int64 time_end = eventData.endTime;
            Int64 duration = eventData.duration;
            double Pos_X = eventData.positionX;
            double Pos_Y = eventData.positionY;

            EyeTrackerFixationDataFrame eyeTrackerFixationDataFrame = new EyeTrackerFixationDataFrame(ExperimentConfig.getMsDateTime(),eye, time_start, time_end, duration, Pos_X, Pos_Y);
            callbackFixation(eyeTrackerFixationDataFrame);

        }

        // this method closes the data stream
        public void Close()
        {
            int ret = 0;
            Console.WriteLine(ETDevice.ToString());
            ret = ETDevice.iV_Disconnect();
            ///if (ret == 1) logger.Text = "iV_Disconnect: disconnected successfully";
            if (ret != 1)
            {
                throw new EyeTrackerFailedToCloseException();
            }
        }
    }
    public class EyeTrackerFailedToOpenException : Exception
    {
    }
    public class EyeTrackerFailedToCloseException : Exception
    {
    }
}
