using CCDCount.DLL.AlarmTools;
using CCDCount.MODEL.CameraClass;
using CCDCount.MODEL.ConfigModel;
using LogClass;
using MvCameraControl;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;

namespace CCDCount.DLL
{
    public class CameraClass
    {
        #region 常量

        readonly DeviceTLayerType enumTLayerType = DeviceTLayerType.MvGigEDevice | DeviceTLayerType.MvUsbDevice
            | DeviceTLayerType.MvGenTLGigEDevice | DeviceTLayerType.MvGenTLCXPDevice 
            | DeviceTLayerType.MvGenTLCameraLinkDevice | DeviceTLayerType.MvGenTLXoFDevice;

        #endregion

        #region 变量

        private List<IDeviceInfo> CamList;      // 相机列表
        private IDevice device = null;          // 相机实例
        private long lastframeNum = -1;

        public int CamereNo { get { return _cameraNo; } }
        private int _cameraNo = -1;
        #endregion

        #region 公共方法
        /// <summary>
        /// 获取相机列表
        /// </summary>
        /// <param name="CamList"></param>
        /// <returns></returns>
        public void GetCameraList(out List<CameraInfoClass> CameraInfoList)
        {
            CamList = new List<IDeviceInfo>();
            CameraInfoList = new List<CameraInfoClass>();
            int nRet = DeviceEnumerator.EnumDevices(enumTLayerType, out CamList);
            if (nRet != MvError.MV_OK)
            {
                return;
            }
            else
            {
                //输出相机名称及SN码以方便选择设备
                foreach (var item in CamList)
                {
                    CameraInfoList.Add(new CameraInfoClass
                    {
                        //DeviceName = item.UserDefinedName == "" ? item.ModelName : item.UserDefinedName,
                        DeviceName =  item.ModelName,
                        DeviceSN = item.SerialNumber,
                    });
                }
            }
            return;
        }

        /// <summary>
        /// 更新相机列表
        /// </summary>
        public void UpdateCameraList()
        {
            CamList = new List<IDeviceInfo>();
            int nRet = DeviceEnumerator.EnumDevices(enumTLayerType, out CamList);
            if (nRet != MvError.MV_OK)
            {
                Console.WriteLine("相机列表更新失败");
                return;
            }
        }

        /// <summary>
        /// 加载指定相机
        /// </summary>
        /// <param name="DeviceSN"></param>
        public bool LoadCamereDevice(CameraConfig DeviceConfig)
        {
            bool Blresult = false;
            if (device != null && device.IsConnected)
            {
                device.Close();
                device.Dispose();
            }
            UpdateCameraList();
            List<IDeviceInfo> deviceInfos = CamList.Where(o => o.SerialNumber == DeviceConfig.CameraSNNum).ToList();
            if(deviceInfos.Count == 0) return  Blresult;
            IDeviceInfo deviceInfo = deviceInfos.First();
            try
            {
                // 打开设备
                device = DeviceFactory.CreateDevice(deviceInfo);
            }
            catch (Exception ex)
            {
                //FaultLog.RecordErrorMessage("Create Device fail!" + DeviceConfig.CameraSNNum + ":" + ex.Message);
                SystemAlarm.AlarmAlert(AlarmMessageList.相机实例创建失败, "Create Device fail!" + DeviceConfig.CameraSNNum + ":" + ex.Message, "DLL:CameraClass-LoadCamereDevice");
                return Blresult;
            }
            SystemAlarm.AlarmCancel(AlarmMessageList.相机实例创建失败);
            int result = device.Open();
            if (result != MvError.MV_OK)
            {
                //FaultLog.RecordErrorMessage("Open Device fail!" + DeviceConfig.CameraSNNum + ":" + result);
                SystemAlarm.AlarmAlert(AlarmMessageList.开启相机失败, "Open Device fail!" + DeviceConfig.CameraSNNum + ":" + result, "DLL:CameraClass-LoadCamereDevice");
                return Blresult;
            }
            SystemAlarm.AlarmCancel(AlarmMessageList.开启相机失败);
            // 判断是否为gige设备
            if (device is IGigEDevice)
            {
                // 转换为gigE设备
                IGigEDevice gigEDevice = device as IGigEDevice;

                // 探测网络最佳包大小(只对GigE相机有效)
                result = gigEDevice.GetOptimalPacketSize(out int optionPacketSize);
                if (result != MvError.MV_OK)
                {
                    //Log("Warning: Get Packet Size failed!", result);
                }
                else
                {
                    result = device.Parameters.SetIntValue("GevSCPSPacketSize", (long)optionPacketSize);
                    if (result != MvError.MV_OK)
                    {
                        //Log("Warning: Set Packet Size failed!", result);
                    }
                }
            }
            //判断是否从配置文件读取的参数，是则设置参数，否则加载相机默认参数
            if(DeviceConfig.IsLoadCanfig)
            {
                //设置从配置文件读取的参数
                device.Parameters.GetStringValue("DeviceModelName", out IStringValue deviceModelName);
                _cameraNo = DeviceConfig.CamerNo;
                if (DeviceConfig.CameraName != deviceModelName.CurValue)
                    device.Parameters.SetStringValue("DeviceUserID", DeviceConfig.CameraName);
                device.Parameters.SetFloatValue("ExposureTime", DeviceConfig.ExposureTimeValue);
                device.Parameters.SetIntValue("AcquisitionLineRate", DeviceConfig.AcquistionLineRateValue);
                device.Parameters.GetIntValue("Height", out IIntValue height);
                device.Parameters.SetIntValue("Height", height.Min);
                device.Parameters.SetIntValue("Width", DeviceConfig.Width);
                device.Parameters.SetIntValue("OffsetX", DeviceConfig.OffsetX);
            }
            // 设置采集连续模式
            device.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous");
            device.Parameters.SetEnumValueByString("TriggerMode", "Off");
            Blresult = true;
            return Blresult;
        }

        /// <summary>
        /// 重新加载指定相机
        /// </summary>
        /// <param name="CameraSN"></param>
        /// <returns></returns>
        public bool ReLoadCameraDevice(string CameraSN)
        {
            bool Blresult = false;
            if(device!=null && device.IsConnected)
            {
                device.Close();
                device.Dispose();
            }
            UpdateCameraList();
            List<IDeviceInfo> deviceInfos = CamList.Where(o => o.SerialNumber == CameraSN).ToList();
            if (deviceInfos.Count == 0) return Blresult;
            IDeviceInfo deviceInfo = deviceInfos.First();
            try
            {
                // 打开设备
                device = DeviceFactory.CreateDevice(deviceInfo);
                Blresult = true;
            }
            catch (Exception ex)
            {
                //FaultLog.RecordErrorMessage("Create Device fail!" + CameraSN + ":" + ex.Message);
                SystemAlarm.AlarmAlert(AlarmMessageList.相机实例创建失败, "Create Device fail!" + CameraSN + ":" + ex.Message, "DLL:CameraClass-LoadCamereDevice");
                return Blresult;
            }
            SystemAlarm.AlarmCancel(AlarmMessageList.相机实例创建失败);
            int result = device.Open();
            if (result != MvError.MV_OK)
            {
                Blresult = false;
                //FaultLog.RecordErrorMessage("Open Device fail!" + CameraSN + ":" + result);
                SystemAlarm.AlarmAlert(AlarmMessageList.开启相机失败, "Open Device fail!" + CameraSN + ":" + result, "DLL:CameraClass-LoadCamereDevice");
                return Blresult;
            }
            SystemAlarm.AlarmCancel(AlarmMessageList.开启相机失败);
            // 判断是否为gige设备
            if (device is IGigEDevice)
            {
                // 转换为gigE设备
                IGigEDevice gigEDevice = device as IGigEDevice;

                // 探测网络最佳包大小(只对GigE相机有效)
                result = gigEDevice.GetOptimalPacketSize(out int optionPacketSize);
                if (result != MvError.MV_OK)
                {
                    //Log("Warning: Get Packet Size failed!", result);
                }
                else
                {
                    result = device.Parameters.SetIntValue("GevSCPSPacketSize", (long)optionPacketSize);
                    if (result != MvError.MV_OK)
                    {
                        //Log("Warning: Set Packet Size failed!", result);
                    }
                }
            }
            return Blresult;
        }

        /// <summary>
        /// 重新加载相机参数
        /// </summary>
        /// <param name="RecameraConfig"></param>
        /// <returns></returns>
        public bool ReLoadCameraConfig(CameraConfig RecameraConfig)
        {
            bool Blresult = false;
            if (device != null && device.IsConnected)
            {
                //设置从配置文件读取的参数
                device.Parameters.GetStringValue("DeviceModelName", out IStringValue deviceModelName);
                _cameraNo = RecameraConfig.CamerNo;
                if (RecameraConfig.CameraName != deviceModelName.CurValue)
                    device.Parameters.SetStringValue("DeviceUserID", RecameraConfig.CameraName);
                device.Parameters.SetFloatValue("ExposureTime", RecameraConfig.ExposureTimeValue);
                device.Parameters.SetIntValue("AcquisitionLineRate", RecameraConfig.AcquistionLineRateValue);
                device.Parameters.GetIntValue("Height", out IIntValue height);
                device.Parameters.SetIntValue("Height", height.Min);
                device.Parameters.SetIntValue("Width", RecameraConfig.Width);
                device.Parameters.SetIntValue("OffsetX", RecameraConfig.OffsetX);
                // 设置采集连续模式
                device.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous");
                device.Parameters.SetEnumValueByString("TriggerMode", "Off");
                Blresult = true;
            }
            return Blresult;
        }

        /// <summary>
        /// 开启相机采集
        /// </summary>
        public bool StartCamera()
        {
            return StartReceiveFuntion();
        }

        /// <summary>
        /// 关闭相机采集
        /// </summary>
        public void StopCamera()
        {
            StopReceiveFuntion();
            //StopEventGetImage();
        }

        /// <summary>
        /// 释放相机资源
        /// </summary>
        public void DisPoseCamera()
        {
            if (device != null)
            {
                int result = device.StreamGrabber.StopGrabbing();
                device.Close();
                device.Dispose();
                if (result != MvError.MV_OK)
                {
                    LOG.log(("Stop Grabbing Fail!", result));
                }
            }
        }

        /// <summary>
        /// 获取一次图片
        /// </summary>
        /// <param name="IFrameData"></param>
        /// <returns></returns>
        public bool GetOnceImage(out IFrameOut IFrameData)
        {
            bool result = false;
            int BRet = device.StreamGrabber.GetImageBuffer(1000, out IFrameData);
            if (BRet == 0 && IFrameData != null) result = true;
            else return result;
            if (lastframeNum == -1)
            {
                lastframeNum = IFrameData.FrameNum;
            }
            else if (lastframeNum == IFrameData.FrameNum - 1)
            {
                lastframeNum = IFrameData.FrameNum;
            }
            else
            {
                //丢帧记录
                LOG.log(string.Format("lost frame: Width[{0}] , Height[{1}] , FrameNum[{2}] ，Frevous[{3}]",
                    IFrameData.Image.Width, IFrameData.Image.Height, IFrameData.FrameNum , lastframeNum), 6);
                Console.WriteLine("lost frame: Width[{0}] , Height[{1}] , FrameNum[{2}] ，Frevous[{3}]",
                    IFrameData.Image.Width, IFrameData.Image.Height, IFrameData.FrameNum , lastframeNum);
                lastframeNum = IFrameData.FrameNum;
            }
            return result;
        }

        /// <summary>
        /// 获取相机图像尺寸信息
        /// </summary>
        /// <returns></returns>
        public CameraImageSizeClass GetCamereImageSize()
        { 
            CameraImageSizeClass cameraImageSize =new CameraImageSizeClass();
            if(device != null)
            {
                device.Parameters.GetIntValue("Width", out IIntValue PixWidth);
                device.Parameters.GetIntValue("Height", out IIntValue PixHeight);
                cameraImageSize.Height = (int)PixHeight.CurValue;
                cameraImageSize.Width = (int)PixWidth.CurValue;
            }
            return cameraImageSize;
        }

        /// <summary>
        /// 获取当前相机的参数生成Config信息
        /// </summary>
        /// <returns></returns>
        public CameraConfig GetConfigValue()
        { 
            CameraConfig result;
            device.Parameters.GetFloatValue("ExposureTime", out IFloatValue exposureTime);
            device.Parameters.GetIntValue("AcquisitionLineRate", out IIntValue acquisitionLineRate);
            device.Parameters.GetIntValue("OffsetX", out IIntValue offsetX);
            device.Parameters.GetIntValue("Width", out IIntValue pixWidth);
            device.Parameters.GetStringValue("DeviceUserID", out IStringValue deviceUserID);
            device.Parameters.GetStringValue("DeviceModelName", out IStringValue deviceModelName);
            device.Parameters.GetStringValue("DeviceSerialNumber", out IStringValue deviceSerialNumber);
            result = new CameraConfig()
            {
                CameraSNNum = deviceSerialNumber.CurValue,
                ExposureTimeValue = exposureTime.CurValue,
                AcquistionLineRateValue = (int)acquisitionLineRate.CurValue,
                Width = (int)pixWidth.CurValue,
                OffsetX = (int)offsetX.CurValue,
                CameraName = deviceUserID.CurValue,
                DeviceName = deviceModelName.CurValue,
                CamerNo = _cameraNo
            };
            return result;
        }

        /// <summary>
        /// 保存参数
        /// </summary>
        public void SaveConfig()
        {
            CameraConfig camerasConfig = null;
            if (!Directory.Exists(".\\Config\\")) Directory.CreateDirectory(".\\Config\\");
                XmlStorage.SerializeToXml(camerasConfig, ".\\Config\\CameraConfig.xml");
        }

        public bool IsLoadCamera()
        {
            return device != null;
        }

        public bool IsConnectCamera()
        {
            if (device == null) return false;
            else
            {
                return device.IsConnected;
            }
        }
        #endregion

        #region 私有方法

        /// <summary>
        /// 开启采集
        /// </summary>
        private bool StartReceiveFuntion()
        {
            bool result = false;
            try
            {
                if(device == null) return result;
                device.StreamGrabber.SetImageNodeNum(100);
                device.StreamGrabber.StartGrabbing();
                result = true;
                SystemAlarm.AlarmCancel(AlarmMessageList.相机采集开始失败);
            }
            catch (Exception ex)
            {
                //FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message);
                SystemAlarm.AlarmAlert(AlarmMessageList.相机采集开始失败, "Start thread failed!, " + ex.Message, "DLL:CamerClass-StartReceiveFuntion");
                throw;
            }
            return result;
        }

        /// <summary>
        /// 关闭采集
        /// </summary>
        private void StopReceiveFuntion()
        {
            try
            {
                if (device == null) return;
                int ret = device.StreamGrabber.StopGrabbing();
                if (ret != MvError.MV_OK)
                {
                    //FaultLog.RecordErrorMessage($"Stop grabbing failed:{ret:x8}");
                    SystemAlarm.AlarmAlert(AlarmMessageList.相机采集停止失败, "Stop grabbing failed:{ret:x8}", "DLL:CamerClass-StopReceiveFuntion");
                    return;
                }
                SystemAlarm.AlarmCancel(AlarmMessageList.相机采集停止失败);
            }
            catch (Exception ex)
            {
                //FaultLog.RecordErrorMessage("Stop thread failed!, " + ex.Message);
                SystemAlarm.AlarmAlert(AlarmMessageList.相机采集停止失败, "Stop thread failed!, " + ex.Message, "DLL:CamerClass-StopReceiveFuntion");
                throw;
            }
        }
        #endregion
    }
}
