using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.SCCore;
using MECF.Framework.Common.Communications;
using MvCameraControl;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;
using VM.PlatformSDKCS;
using CameraDevice = MvCameraControl.IDevice;

namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.MachineVision.HikVision
{
    public class HikGigeCamera : BaseDevice, IConnection, Aitex.Core.RT.Device.IDevice
    {
        IDeviceInfo deviceInfo = null;
        private CameraDevice device;

        // ch:枚举的相机类型 | en:TLayerType for enumerate devices
        readonly DeviceTLayerType enumTLayerType = DeviceTLayerType.MvGigEDevice | DeviceTLayerType.MvUsbDevice
    | DeviceTLayerType.MvGenTLGigEDevice | DeviceTLayerType.MvGenTLCXPDevice | DeviceTLayerType.MvGenTLCameraLinkDevice | DeviceTLayerType.MvGenTLXoFDevice;

        private List<IDeviceInfo> deviceInfoList = new List<IDeviceInfo>();

        private string _grabName;

        private bool _isSaveLocal = false;

        Thread receiveThread = null;    // ch:接收图像线程 | en: Receive image thread

        public HikGigeCamera(string module, string scRoot, string name) : base(module, name, name, name)
        {
            IsConnected = false;
            receiveThread = new Thread(ReceiveThreadProcess);
        }

        public string Address { get; private set; }

        public string ImageFilePath { get; private set; }

        public bool IsConnected { get; private set; } = false;

        public bool IsGrabbing { get; private set; } = false;

        public string Message { get; private set; }

        public ImageBaseData ImageData { get; private set; }

        public byte[] CamBitmap { get; private set; }

        public bool Connect()
        {
            return true;
        }

        public bool Disconnect()
        {
            return true;
        }

        public void CamInitialize()
        {
            if (IsConnected)
            {
                return;
            }
            // ch: 初始化 SDK | en: Initialize SDK
            SDKSystem.Initialize();

            // ch: 枚举设备 | en: Enum Device List
            RefreshDeviceList();

            if (deviceInfoList.Count == 0)
            {
                Message = "No Camera be found";
                return;
            }

            string sAddress = SC.GetStringValue($"{Name}.Address");
            Address = sAddress;
            var dinfo = deviceInfoList.Find(i=>i.SerialNumber == Address);
            if (dinfo == null)
            {
                Message = $"Can no find Camera{Address}";
                return;
            }
            // 打开摄像头（设备索引 0）
            try
            {
                // ch:打开设备 | en:Open device
                device = DeviceFactory.CreateDevice(dinfo);
            }
            catch (Exception ex)
            {
                Message = $"Create {Address} failed";
                return;
            }

            int result = device.Open();
            if (result != MvError.MV_OK)
            {
                ShowErrorMsg("Open Device fail!", result);
                return;
            }

            //ch: 判断是否为gige设备 | en: Determine whether it is a GigE device
            if (device is IGigEDevice)
            {
                //ch: 转换为gigE设备 | en: Convert to Gige device
                IGigEDevice gigEDevice = device as IGigEDevice;

                // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
                int optionPacketSize;
                result = gigEDevice.GetOptimalPacketSize(out optionPacketSize);
                if (result != MvError.MV_OK)
                {
                    ShowErrorMsg("Warning: Get Packet Size failed!", result);
                }
                else
                {
                    result = device.Parameters.SetIntValue("GevSCPSPacketSize", (long)optionPacketSize);
                    if (result != MvError.MV_OK)
                    {
                        ShowErrorMsg("Warning: Set Packet Size failed!", result);
                    }
                }
            }

            ImageFilePath = SC.SafeGetStringValue($"{Name}.ImageFilePath", "D:\\VMImage");
            
            IsConnected = true;
        }
        public bool Initialize()
        {
            
            DATA.Subscribe($"{Module}.{Name}.IsConnected", () => this.IsConnected);

            DATA.Subscribe($"{Module}.{Name}.Address", () => this.Address);

            DATA.Subscribe($"{Module}.{Name}.Message", () => this.Message);

            DATA.Subscribe($"{Module}.{Name}.CamBitmap", () => this.CamBitmap);

            //转至运行模式
            OP.Subscribe($"{Module}.{Name}.Grab", (cmd, param) =>
            {
                Grab((string)param[0]);
                return true;
            });

            OP.Subscribe($"{Module}.{Name}.Grabbing", (cmd, param) =>
            {
                Grabbing();
                return true;
            });

            OP.Subscribe($"{Module}.{Name}.Stop", (cmd, param) =>
            {
                Stop();
                return true;
            });

            //CamInitialize();

            return true;
        }

        public void Reset()
        {
            ;
        }

        public void Terminate()
        {
            Stop();
            SDKSystem.Finalize();
        }

        private void RefreshDeviceList()
        {
            // ch:创建设备列表 | en:Create Device List
            int nRet = DeviceEnumerator.EnumDevices(enumTLayerType, out deviceInfoList);
            if (nRet != MvError.MV_OK)
            {
                ShowErrorMsg("Enumerate devices fail!", nRet);
                return;
            }
        }

        /// <summary>
        /// ch:显示错误信息 | en:Show error message
        /// </summary>
        private void ShowErrorMsg(string message, int errorCode)
        {
            string errorMsg;
            if (errorCode == 0)
            {
                errorMsg = message;
            }
            else
            {
                errorMsg = message + ": Error =" + String.Format("{0:X}", errorCode);
            }

            switch (errorCode)
            {
                case MvError.MV_E_HANDLE: errorMsg += " Error or invalid handle "; break;
                case MvError.MV_E_SUPPORT: errorMsg += " Not supported function "; break;
                case MvError.MV_E_BUFOVER: errorMsg += " Cache is full "; break;
                case MvError.MV_E_CALLORDER: errorMsg += " Function calling order error "; break;
                case MvError.MV_E_PARAMETER: errorMsg += " Incorrect parameter "; break;
                case MvError.MV_E_RESOURCE: errorMsg += " Applying resource failed "; break;
                case MvError.MV_E_NODATA: errorMsg += " No data "; break;
                case MvError.MV_E_PRECONDITION: errorMsg += " Precondition error, or running environment changed "; break;
                case MvError.MV_E_VERSION: errorMsg += " Version mismatches "; break;
                case MvError.MV_E_NOENOUGH_BUF: errorMsg += " Insufficient memory "; break;
                case MvError.MV_E_UNKNOW: errorMsg += " Unknown error "; break;
                case MvError.MV_E_GC_GENERIC: errorMsg += " General error "; break;
                case MvError.MV_E_GC_ACCESS: errorMsg += " Node accessing condition error "; break;
                case MvError.MV_E_ACCESS_DENIED: errorMsg += " No permission "; break;
                case MvError.MV_E_BUSY: errorMsg += " Device is busy, or network disconnected "; break;
                case MvError.MV_E_NETER: errorMsg += " Network error "; break;
            }

            EV.PostWarningLog(Module,errorMsg);
        }

        public void Grab(string name)
        {
            CamInitialize();
            if (IsConnected)
            {
                _grabName = name;    
                if (IsGrabbing)
                {
                    _isSaveLocal = true;
                    return;
                }

                device.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous");
                device.Parameters.SetEnumValueByString("TriggerMode", "On");
                device.Parameters.SetEnumValueByString("TriggerSource", "Software");

                var result = device.StreamGrabber.StartGrabbing();
                if (MvError.MV_OK != result)
                {
                    ShowErrorMsg("Start grabbing Fail!", result);
                    return;
                }

                // ch:触发命令 | en:Trigger command
                var result2 = device.Parameters.SetCommandValue("TriggerSoftware");
                if (result2 != MvError.MV_OK)
                {
                    ShowErrorMsg("Trigger Software Fail!", result2);
                    return;
                }
                GetImage(device,true);

                Message = "Shot one picture";
                Stop();
            }
        }

        public void Grabbing()
        {
            CamInitialize();
            if (IsConnected)
            {
                if (!IsGrabbing)
                {
                    // ch:设置采集连续模式 | en:Set Continues Aquisition Mode
                    device.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous");
                    device.Parameters.SetEnumValueByString("TriggerMode", "Off");

                    try
                    {
                        // ch:标志位置位true | en:Set position bit true
                        IsGrabbing = true;
                        receiveThread = new Thread(ReceiveThreadProcess);
                        receiveThread.Start();
                    }
                    catch (Exception ex)
                    {
                        ShowErrorMsg("Start grabbing thread Fail!", 0);
                        return;
                    }

                    // ch:开始采集 | en:Start Grabbing
                    var result = device.StreamGrabber.StartGrabbing();
                    if (result != MvError.MV_OK)
                    {
                        IsGrabbing = false;
                        receiveThread.Join();
                        ShowErrorMsg("Start Grabbing Fail!", result);
                        return;
                    }
                    Message = "Grabbing pictures";
                }
                else
                {
                    Stop();
                }
            }
        }

        public void ReceiveThreadProcess()
        {
            while (IsGrabbing)
            {
                GetImage(device,_isSaveLocal);
            }
        }

        /// <summary>
        /// 抓取图像；单次抓取时需要存图
        /// </summary>
        /// <param name="cam"></param>
        /// <param name="isSaveLocal"></param>
        private void GetImage(CameraDevice cam,bool isSaveLocal)
        {
            IFrameOut frameOut = null;
            int result = MvError.MV_OK;

            result = device.StreamGrabber.GetImageBuffer(1000, out frameOut);
            if (result == MvError.MV_OK)
            {
                if(isSaveLocal)  //截图模式，原始图片进行保存
                {
                    var folderPath = ImageFilePath + DateTime.Now.ToString("yyyy-MM-dd");
                    if (!Directory.Exists(folderPath))
                    {
                        // 创建文件夹
                        Directory.CreateDirectory(folderPath);
                        Console.WriteLine($"Folder '{folderPath}' created successfully.");
                    }
                    var info = new ImageFormatInfo() { FormatType = ImageFormatType.Jpeg, JpegQuality = 80 };

                    var f = folderPath + $"\\{DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss-FFF")}_{_grabName}.{info.FormatType}";
                    device.ImageSaver.SaveImageToFile(f, frameOut.Image, info, CFAMethod.Equilibrated);
                    EV.PostInfoLog(Module, $"Hik CCD check,Save image in {f}");

                    ImageData = ConvertImage(frameOut.Image);   //注意克隆
                    _isSaveLocal = false;
                }

                CamBitmap = BitmapToBytes(frameOut.Image.ToBitmap());
                device.StreamGrabber.FreeImageBuffer(frameOut);
            }
        }

        public byte[] BitmapToBytes(Bitmap bitmap)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                bitmap.Save(ms, ImageFormat.Bmp); // 推荐Bmp格式保证数据完整性:ml-citation{ref="1,5" data="citationList"}
                return ms.ToArray(); // 比GetBuffer()更精确获取有效数据:ml-citation{ref="12" data="citationList"}
            }
        }

        public void Stop()
        {
            IsGrabbing = false;
            if (receiveThread.IsAlive)
            {
                receiveThread.Join();
            }
            Message = "Standby";
            if (device ==null)
            {
                return;
            }

            int result = device.StreamGrabber.StopGrabbing();
            if (result != MvError.MV_OK)
            {
                ShowErrorMsg("Stop Grabbing Fail!", result);
            }

            result = device.Close();
            if (MvError.MV_OK != result)
            {
                ShowErrorMsg("Close device failed", result);
            }

            // ch:销毁设备 | en:Destroy device
            device.Dispose();
            device = null;

            IsConnected = false;    
        }

        private ImageBaseData ConvertImage(IImage img)
        {
            return new ImageBaseData((byte[])img.PixelData.Clone(), (uint)img.ImageSize, (int)img.Width, (int)img.Height, 17301505);
        }
    }
}
