using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using Inspectron.Devices.Raspberry;
using Inspectron.HawkEye.Protocol;
using Inspectron.HawkEye.Protocol.Interfaces;

namespace Inspectron.HawkEye.Camera
{
    public class InspectronCamera:ICameraControl,IImageSource,ILightControl
    {

        [DllImport("libVCLibProxy.so", CallingConvention = CallingConvention.Cdecl)]
        static extern IntPtr init(Int32 captBuf);
        [DllImport("libVCLibProxy.so", CallingConvention = CallingConvention.Cdecl)]
        static extern int trigger(IntPtr cpt, byte[] addr, int lines, int captBuf,ref int cancelFlag);
        [DllImport("libVCLibProxy.so", CallingConvention = CallingConvention.Cdecl)]
        static extern void set_parameters(IntPtr cpt, ref ImageSettings imageSettings);

        [DllImport("libVCLibProxy.so", CallingConvention = CallingConvention.Cdecl)]
        public static extern int test();
        byte[] _buffer = new byte[2048 * 250 * 4];
        
        public InspectronCamera()
        {
            
            _i2c = new I2CLinux(0);
            _i2c.Open();
            
        }



        private bool _isRunningContiniuos = false;
        private IntPtr _cp= IntPtr.Zero;
        private ImageSettings _imageSettings=new ImageSettings()
        {
            CaptureBuffer = 25,
            Gain = 200,
            Lines = 1000,
            Shutter = 200,
            SensorWidth = 1440
        };

        private I2CLinux _i2c;

        private int _lastBuffer = -1;
        public void SetParameters(CameraSettings cameraSettings)

        {
            _cameraSettings = cameraSettings;
            ImageSettings imageSettings = cameraSettings.ImageSettings;
            if (_lastBuffer ==-1)
            {
                _lastBuffer = imageSettings.CaptureBuffer;
                _cp = init(_lastBuffer);
            }

            
            _imageSettings = imageSettings;
            _buffer=new byte[imageSettings.SensorWidth*(imageSettings.Lines)];
            var cpImageSettings = imageSettings;
            cpImageSettings.UseExternalTrigger =imageSettings.UseExternalTrigger;
            
            if(_lastBuffer==imageSettings.CaptureBuffer)
                set_parameters(_cp, ref cpImageSettings);
            else
                Console.WriteLine("Warning! Buffer size changed. Needs restart");
            _i2c.writeBytes(4, 2, 4, BitConverter.GetBytes(imageSettings.Divider));
            Thread.Sleep(100);
            _i2c.writeBytes(4,3,1, new byte[] { (byte)imageSettings.UseExternalTrigger });
            Thread.Sleep(100);
        }


        private int _cancelFlag = 0;
        private CameraSettings _cameraSettings;

        public byte[] GetImage()
        {
            _cancelFlag = 0;
            var sw = Stopwatch.StartNew();

            _i2c.writeBytes(4, 4, 1,new byte[]{ (byte)(_cameraSettings.LaserTrigger?1:0)} );
            //Thread.Sleep(20);
            _i2c.writeBytes(4, 5, 4, BitConverter.GetBytes(_cameraSettings.LaserTriggerDelay));
            //Thread.Sleep(20);

            trigger(_cp, _buffer, _imageSettings.Lines, _imageSettings.CaptureBuffer,ref _cancelFlag);
            sw.Stop();
            Console.WriteLine("Trigger time: "+sw.ElapsedMilliseconds);
            if(_cancelFlag==1)return new byte[0];
            return _buffer;
        }

        public void CancelTrigger()
        {
            _cancelFlag = 1;
        }

        public void SetLight(int pwm1, int pwm2)
        {
            Console.WriteLine($"setting lights to {pwm1}/{pwm2}");
            pwm1 = (int)(pwm1 / 100.0 * 255);
            pwm2 = (int)(pwm2 / 100.0 * 255);
            _i2c.writeBytes(4, 1, 2, new byte[] { (byte)pwm1,(byte)pwm2 });
            
            Thread.Sleep(10);
        }
    }
}