using System.Diagnostics;
using OpenCvSharp;
using MvCamCtrl.NET;
using System.Runtime.InteropServices;
using System.Xml.Linq;
using DH.Commons.Enums;
using static MvCamCtrl.NET.MyCamera;
using DH.Commons.Base;



namespace DH.Devices.Camera
{
   public class HikVisionCamera : CameraBase
    {
        readonly MyCamera cameraObj = new MyCamera();
        MyCamera.MV_CC_DEVICE_INFO stDevInfo = new MyCamera.MV_CC_DEVICE_INFO();
        int nRet = MyCamera.MV_OK;
        MyCamera.cbExceptiondelegate pCallBackFunc;
        public MyCamera.cbOutputExdelegate ImageCallback;
        MyCamera.MV_FRAME_OUT _frame = new MyCamera.MV_FRAME_OUT();
        readonly ManualResetEvent _snapHandle = new ManualResetEvent(false);
        bool _snapFlag = false;

        public HikVisionCamera() 
        {


       
        }

        public override bool CameraConnect()
        {
            try
            {
                pCallBackFunc = new MyCamera.cbExceptiondelegate(cbExceptiondelegate);

                #region 根据IP连接相机
                stDevInfo.nTLayerType = MyCamera.MV_GIGE_DEVICE;
                MyCamera.MV_GIGE_DEVICE_INFO stGigEDev = new MyCamera.MV_GIGE_DEVICE_INFO();


                var parts = CameraIP.Split('.');
                int nIp1 = Convert.ToInt32(parts[0]);
                int nIp2 = Convert.ToInt32(parts[1]);
                int nIp3 = Convert.ToInt32(parts[2]);
                int nIp4 = Convert.ToInt32(parts[3]);
                stGigEDev.nCurrentIp = (uint)((nIp1 << 24) | (nIp2 << 16) | (nIp3 << 8) | nIp4);

                parts = ComputerIP.Split('.');
                nIp1 = Convert.ToInt32(parts[0]);
                nIp2 = Convert.ToInt32(parts[1]);
                nIp3 = Convert.ToInt32(parts[2]);
                nIp4 = Convert.ToInt32(parts[3]);
                stGigEDev.nNetExport = (uint)((nIp1 << 24) | (nIp2 << 16) | (nIp3 << 8) | nIp4);

                IntPtr stGigeInfoPtr = Marshal.AllocHGlobal(216);
                Marshal.StructureToPtr(stGigEDev, stGigeInfoPtr, false);
                stDevInfo.SpecialInfo.stGigEInfo = new Byte[540];
                Marshal.Copy(stGigeInfoPtr, stDevInfo.SpecialInfo.stGigEInfo, 0, 540);
                //释放内存空间
                Marshal.FreeHGlobal(stGigeInfoPtr);
                #endregion
                // ch:创建设备 | en: Create device
                nRet = cameraObj.MV_CC_CreateDevice_NET(ref stDevInfo);
                if (MyCamera.MV_OK != nRet)
                {
                    throw new Exception($"Create device failed:{nRet:x8}");
                }

                // ch:打开设备 | en:Open device
                nRet = cameraObj.MV_CC_OpenDevice_NET();
                if (MyCamera.MV_OK != nRet)
                {
                    throw new Exception($"Open device failed:{nRet:x8}");
                }


                // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
                if (stDevInfo.nTLayerType == MyCamera.MV_GIGE_DEVICE)
                {
                    int nPacketSize = cameraObj.MV_CC_GetOptimalPacketSize_NET();
                    if (nPacketSize > 0)
                    {
                        nRet = cameraObj.MV_CC_SetIntValue_NET("GevSCPSPacketSize", (uint)nPacketSize);
                        if (nRet != MyCamera.MV_OK)
                        {
                            Console.WriteLine("Warning: Set Packet Size failed {0:x8}", nRet);
                        }
                    }
                    else
                    {
                        Console.WriteLine("Warning: Get Packet Size failed {0:x8}", nPacketSize);
                    }
                }

                // ch:注册异常回调函数 | en:Register Exception Callback
                nRet = cameraObj.MV_CC_RegisterExceptionCallBack_NET(pCallBackFunc, IntPtr.Zero);
                if (MyCamera.MV_OK != nRet)
                {
                    throw new Exception($"Register expection callback failed:{nRet}");
                }
                GC.KeepAlive(pCallBackFunc);

                // ch:设置采集连续模式 | en:Set Continues Aquisition Mode
                cameraObj.MV_CC_SetEnumValue_NET("AcquisitionMode", 2);// ch:工作在连续模式 | en:Acquisition On Continuous Mode
                                                                       //if (IIConfig.IsContinueMode)
                                                                       //{
                                                                       //    cameraObj.MV_CC_SetEnumValue_NET("TriggerMode", 0);    // ch:连续模式 | en:Continuous

                //    // ch:注册回调函数 | en:Register image callback
                //    ImageCallback = new MyCamera.cbOutputExdelegate(ImageCallbackFunc);
                //    nRet = cameraObj.MV_CC_RegisterImageCallBackEx_NET(ImageCallback, IntPtr.Zero);
                //    if (MyCamera.MV_OK != nRet)
                //    {
                //        throw new Exception("Register image callback failed!");
                //    }
                //}
                //else
                //{
                // ch:设置触发模式为off || en:set trigger mode as off
                nRet = cameraObj.MV_CC_SetEnumValue_NET("TriggerMode", 1);
                if (MyCamera.MV_OK != nRet)
                {
                    throw new Exception("Set TriggerMode failed!");
                }

                //if (IIConfig.IsHardwareTrigger)
                //{
                // ch:触发源选择:0 - Line0; | en:Trigger source select:0 - Line0;
                //           1 - Line1;
                //           2 - Line2;
                //           3 - Line3;
                //           4 - Counter;
                //           7 - Software;
                nRet = cameraObj.MV_CC_SetEnumValue_NET("TriggerSource", 0);
                if (MyCamera.MV_OK != nRet)
                {
                    throw new Exception("Set Line0 Trigger failed!");
                }

                // ch:注册回调函数 | en:Register image callback
                ImageCallback = new MyCamera.cbOutputExdelegate(ImageCallbackFunc);
                nRet = cameraObj.MV_CC_RegisterImageCallBackEx_NET(ImageCallback, IntPtr.Zero);
                if (MyCamera.MV_OK != nRet)
                {
                    throw new Exception("Register image callback failed!");
                }
                //}
                //else
                //{
                //    nRet = cameraObj.MV_CC_SetEnumValue_NET("TriggerSource", 7);
                //    if (MyCamera.MV_OK != nRet)
                //    {
                //        throw new Exception("Set Software Trigger failed!");
                //    }
                //}
                //}
                // ch:开启抓图 || en: start grab image
                nRet = cameraObj.MV_CC_StartGrabbing_NET();
                if (MyCamera.MV_OK != nRet)
                {
                    throw new Exception($"Start grabbing failed:{nRet:x8}");
                }

                //if (IConfig.DefaultExposure != 0)
                //{
                //    cameraObj.MV_CC_SetEnumValue_NET("ExposureAuto", 0);
                //    nRet = cameraObj.MV_CC_SetFloatValue_NET("ExposureTime", IConfig.DefaultExposure);
                //    if (nRet != MyCamera.MV_OK)
                //    {
                //        throw new Exception($"Exposure set failed:{nRet}");
                //    }
                //}
                //if (IIConfig.Gain >= 0)
                //{
                //    nRet = cameraObj.MV_CC_SetFloatValue_NET("Gain", IIConfig.Gain);
                //    if (nRet != MyCamera.MV_OK)
                //    {
                //        throw new Exception($"Gain set failed:{nRet}");
                //    }
                //}
                // 设置 触发延迟
                //if (IIConfig.TriggerDelay > 0)
                //{
                //    nRet = cameraObj.MV_CC_SetFloatValue_NET("TriggerDelay", IIConfig.TriggerDelay);
                //    if (MyCamera.MV_OK != nRet)
                //    {
                //        throw new Exception("Set TriggerDelay failed!");
                //    }
                //}
                //if (IIConfig.LineDebouncerTime > 0)
                //{
                //    nRet = cameraObj.MV_CC_SetIntValue_NET("LineDebouncerTime", (uint)IIConfig.LineDebouncerTime);
                //    if (nRet != MyCamera.MV_OK)
                //    {
                //        throw new Exception($"LineDebouncerTime set failed:{nRet}");
                //    }
                //}
                //IIConfig.PropertyChanged -= IIConfig_PropertyChanged;
                //IIConfig.PropertyChanged += IIConfig_PropertyChanged;
                return true;
            }
            catch (Exception ex)
            { 
              return false;
            }


        }

        private void IIConfig_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            //if (e.PropertyName == "IsHardwareTrigger" && !IIConfig.IsContinueMode)
            //{
            //    // ch:停止抓图 | en:Stop grab image
            //    nRet = cameraObj.MV_CC_StopGrabbing_NET();
            //    if (MyCamera.MV_OK != nRet)
            //    {
            //        throw new Exception($"Stop grabbing failed{nRet:x8}");
            //    }

            //    if (IIConfig.IsHardwareTrigger)
            //    {
            //        // ch:触发源选择:0 - Line0; | en:Trigger source select:0 - Line0;
            //        //           1 - Line1;
            //        //           2 - Line2;
            //        //           3 - Line3;
            //        //           4 - Counter;
            //        //           7 - Software;
            //        nRet = cameraObj.MV_CC_SetEnumValue_NET("TriggerSource", 0);
            //        if (MyCamera.MV_OK != nRet)
            //        {
            //            throw new Exception("Set Line0 Trigger failed!");
            //        }

            //        // ch:注册回调函数 | en:Register image callback
            //        ImageCallback = new MyCamera.cbOutputExdelegate(ImageCallbackFunc);
            //        nRet = cameraObj.MV_CC_RegisterImageCallBackEx_NET(ImageCallback, IntPtr.Zero);
            //        if (MyCamera.MV_OK != nRet)
            //        {
            //            throw new Exception("Register image callback failed!");
            //        }
            //    }
            //    else
            //    {
            //        nRet = cameraObj.MV_CC_SetEnumValue_NET("TriggerSource", 7);
            //        if (MyCamera.MV_OK != nRet)
            //        {
            //            throw new Exception("Set Software Trigger failed!");
            //        }
            //    }

            //    // ch:开启抓图 || en: start grab image
            //    nRet = cameraObj.MV_CC_StartGrabbing_NET();
            //    if (MyCamera.MV_OK != nRet)
            //    {
            //        throw new Exception($"Start grabbing failed:{nRet:x8}");
            //    }

            //    if (IConfig.DefaultExposure != 0)
            //    {
            //        cameraObj.MV_CC_SetEnumValue_NET("ExposureAuto", 0);
            //        nRet = cameraObj.MV_CC_SetFloatValue_NET("ExposureTime", IConfig.DefaultExposure);
            //        if (nRet != MyCamera.MV_OK)
            //        {
            //            throw new Exception($"Exposure set failed:{nRet}");
            //        }
            //    }
            //    if (IIConfig.Gain >= 0)
            //    {
            //        nRet = cameraObj.MV_CC_SetFloatValue_NET("Gain", IIConfig.Gain);
            //        if (nRet != MyCamera.MV_OK)
            //        {
            //            throw new Exception($"Gain set failed:{nRet}");
            //        }
            //    }

            //    // 设置 触发延迟
            //    if (IIConfig.TriggerDelay > 0)
            //    {
            //        nRet = cameraObj.MV_CC_SetFloatValue_NET("TriggerDelay", IIConfig.TriggerDelay);
            //        if (MyCamera.MV_OK != nRet)
            //        {
            //            throw new Exception("Set TriggerDelay failed!");
            //        }
            //    }
            //    if (IIConfig.LineDebouncerTime > 0)
            //    {
            //        nRet = cameraObj.MV_CC_SetIntValue_NET("LineDebouncerTime", (uint)IIConfig.LineDebouncerTime);
            //        if (nRet != MyCamera.MV_OK)
            //        {
            //            throw new Exception($"LineDebouncerTime set failed:{nRet}");
            //        }
            //    }
            //}
        }

        public override bool CameraDisConnect()
        {
            //IIConfig.PropertyChanged -= IIConfig_PropertyChanged;

            //base.Stop();

            // ch:停止抓图 | en:Stop grab image

            try
            {
                nRet = cameraObj.MV_CC_StopGrabbing_NET();
                if (MyCamera.MV_OK != nRet)
                {
                    throw new Exception($"Stop grabbing failed{nRet:x8}");
                }

                // ch:关闭设备 | en:Close device
                nRet = cameraObj.MV_CC_CloseDevice_NET();
                if (MyCamera.MV_OK != nRet)
                {
                    throw new Exception($"Close device failed{nRet:x8}");
                }

                // ch:销毁设备 | en:Destroy device
                nRet = cameraObj.MV_CC_DestroyDevice_NET();
                if (MyCamera.MV_OK != nRet)
                {
                    throw new Exception($"Destroy device failed:{nRet:x8}");
                }
                return true;
            }
            catch (Exception ex) 
            { 
              return false ;
            }
        }




        void ImageCallbackFunc(IntPtr pData, ref MyCamera.MV_FRAME_OUT_INFO_EX pFrameInfo, IntPtr pUser)
        {
            Mat cvImage = new Mat();
            try
            {

                Interlocked.Increment(ref SnapshotCount);
                int nWidth = pFrameInfo.nWidth;
                int nHeight = pFrameInfo.nHeight;
                switch (pFrameInfo.enPixelType)
                {
                    case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR8:
                    case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG8:
                    case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB8:
                    case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG8:
                        cvImage = Mat.FromPixelData(nHeight, nWidth, MatType.CV_8UC1, pData);
                        break;
                    case MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed:
                        cvImage = Mat.FromPixelData(nHeight, nWidth, MatType.CV_8UC3, pData);
                        Cv2.CvtColor(cvImage, cvImage, ColorConversionCodes.RGB2BGR);
                        break;
                    case MyCamera.MvGvspPixelType.PixelType_Gvsp_BGR8_Packed:
                        cvImage = Mat.FromPixelData(nHeight, nWidth, MatType.CV_8UC3, pData);
                        break;
                    case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8:
                        cvImage = Mat.FromPixelData(nHeight, nWidth, MatType.CV_8UC1, pData);
                        break;

                    default:
                        throw new NotSupportedException($"Unsupported pixel type: {pFrameInfo.enPixelType}");
                }

                OnHImageOutput?.Invoke(DateTime.Now, this, cvImage);

            }
            catch (Exception ex)
            {

            }
            finally
            {
                cvImage?.Dispose();
            }
        }





        public  MvGvspPixelType GetMvGvspPixelType(StreamFormat streamFormat)
        {
            switch (streamFormat)
            {
                // 原始数据格式映射
                case StreamFormat.S_RAW8:
                    return MvGvspPixelType.PixelType_Gvsp_Mono8;
                case StreamFormat.S_RAW10:
                    return MvGvspPixelType.PixelType_Gvsp_Mono10_Packed;
                case StreamFormat.S_RAW12:
                    return MvGvspPixelType.PixelType_Gvsp_Mono12_Packed;
                case StreamFormat.S_RAW14:
                    return MvGvspPixelType.PixelType_Gvsp_Mono14;
                case StreamFormat.S_RAW16:
                    return MvGvspPixelType.PixelType_Gvsp_Mono16;

                // RGB/BGR格式映射
                case StreamFormat.S_BGR24:
                    return MvGvspPixelType.PixelType_Gvsp_BGR8_Packed;
                case StreamFormat.S_BGR32:
                    return MvGvspPixelType.PixelType_Gvsp_BGRA8_Packed;
                case StreamFormat.S_RGB24:
                    return MvGvspPixelType.PixelType_Gvsp_RGB8_Packed;
                case StreamFormat.S_RGB32:
                    return MvGvspPixelType.PixelType_Gvsp_RGBA8_Packed;
                case StreamFormat.S_BGR48:
                    return MvGvspPixelType.PixelType_Gvsp_BGR10_Packed;
                case StreamFormat.S_RGB48:
                    return MvGvspPixelType.PixelType_Gvsp_RGB16_Packed;

                // YUV格式映射
                case StreamFormat.S_YCBCR_411:
                    return MvGvspPixelType.PixelType_Gvsp_YCBCR411_8_CBYYCRYY;
                case StreamFormat.S_YCBCR_422:
                    return MvGvspPixelType.PixelType_Gvsp_YUV422_YUYV_Packed;
                case StreamFormat.S_YCBCR_444:
                    return MvGvspPixelType.PixelType_Gvsp_YUV444_Packed;

                // 灰度图像映射
                case StreamFormat.S_MONO8:
                    return MvGvspPixelType.PixelType_Gvsp_Mono8;
                case StreamFormat.S_MONO10:
                    return MvGvspPixelType.PixelType_Gvsp_Mono10;
                case StreamFormat.S_MONO12:
                    return MvGvspPixelType.PixelType_Gvsp_Mono12;
                case StreamFormat.S_MONO14:
                    return MvGvspPixelType.PixelType_Gvsp_Mono14;
                case StreamFormat.S_MONO16:
                    return MvGvspPixelType.PixelType_Gvsp_Mono16;

                // 特殊格式映射
                case StreamFormat.S_B8_G8_R8:
                    return MvGvspPixelType.PixelType_Gvsp_RGB8_Planar;
                case StreamFormat.S_B16_G16_R16:
                    return MvGvspPixelType.PixelType_Gvsp_RGB16_Planar;

                default:
                    throw new ArgumentException($"Unsupported stream format: {streamFormat}");
            }
        }




        // ch:回调函数 | en:Callback function
        private void cbExceptiondelegate(uint nMsgType, IntPtr pUser)
        {
            //if (nMsgType == MyCamera.MV_EXCEPTION_DEV_DISCONNECT)
            //{
            //    if (CurrentState != EnumHelper.DeviceState.DSClose)
            //    {
            //        int reTryTimes = 3;
            //        do
            //        {
            //            try
            //            {
            //                Task.Delay(1000).Wait();
            //                Stop();

            //                Start();
            //                reTryTimes = -1;
            //            }
            //            catch (Exception ex)
            //            {
            //                reTryTimes--;

            //                if (reTryTimes > 0)
            //                {
            //                    LogAsync(DateTime.Now, LogLevel.Information, $"{this.Name}重新连接异常,{ex.GetExceptionMessage()}");
            //                }
            //                else
            //                {
            //                    throw ex;
            //                }
            //            }
            //        } while (reTryTimes > 0);
            //    }
            //}
        }
 




    }
}