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 Thread receiveThread = null;    // 接收图像线程
        private ConcurrentQueue<IFrameOut> FrameOuts = new ConcurrentQueue<IFrameOut>();
        private ConcurrentQueue<byte[]> ImageBytes = new ConcurrentQueue<byte[]>(); //图像接受队列
        private int OnImageSelectRows = 20;
        private long lastframeNum = -1;

        public int CamereNo { get { return _cameraNo; } }
        public int ImageNum { get { return FrameOuts.Count; }}
        private int _cameraNo = -1;
        private string cameraName = string.Empty;
        #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;
            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)
            {
                LOG.error("Create Device fail!" + ex.Message);
                return Blresult;
            }

            int result = device.Open();
            if (result != MvError.MV_OK)
            {
                LOG.error("Open Device fail!" + result);
                return Blresult;
            }

            // 判断是否为gige设备
            if (device is IGigEDevice)
            {
                // 转换为gigE设备
                IGigEDevice gigEDevice = device as IGigEDevice;

                // 探测网络最佳包大小(只对GigE相机有效)
                int optionPacketSize;
                result = gigEDevice.GetOptimalPacketSize(out 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.SetIntValue("Height", DeviceConfig.Height);
                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)
            {
                LOG.error("Create Device fail!" + ex.Message);
                return Blresult;
            }

            int result = device.Open();
            if (result != MvError.MV_OK)
            {
                Blresult = false;
                LOG.error("Open Device fail!" + result);
                return Blresult;
            }

            // 判断是否为gige设备
            if (device is IGigEDevice)
            {
                // 转换为gigE设备
                IGigEDevice gigEDevice = device as IGigEDevice;

                // 探测网络最佳包大小(只对GigE相机有效)
                int optionPacketSize;
                result = gigEDevice.GetOptimalPacketSize(out 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>
        public void StartCamera()
        {
            StartReceiveFuntion();
        }

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

        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));
                }
            }
        }
        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 - 1, lastframeNum), 6);
                Console.WriteLine("lost frame: Width[{0}] , Height[{1}] , FrameNum[{2}] ，Frevous[{3}]",
                    IFrameData.Image.Width, IFrameData.Image.Height, IFrameData.FrameNum - 1, lastframeNum);
                lastframeNum = IFrameData.FrameNum;
            }
            return result;
        }

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

        /// <summary>
        /// 获取Config信息
        /// </summary>
        /// <returns></returns>
        public CameraConfig GetConfigValue()
        { 
            CameraConfig result = null;
            device.Parameters.GetFloatValue("ExposureTime", out IFloatValue exposureTime);
            device.Parameters.GetIntValue("AcquisitionLineRate", out IIntValue acquisitionLineRate);
            device.Parameters.GetIntValue("OffsetX", out IIntValue offsetX);
            device.Parameters.GetIntValue("Height",  out IIntValue pixHeight);
            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,
                Height = (int)pixHeight.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 ? false : true;
        }

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

        #region 私有方法

        /// <summary>
        /// 开启采集
        /// </summary>
        private void StartReceiveFuntion()
        {
            try
            {
                device.StreamGrabber.SetImageNodeNum(100);
                device.StreamGrabber.StartGrabbing();
            }
            catch (Exception ex)
            {
                LOG.error("Start thread failed!, " + ex.Message);
                throw;
            }
        }

        /// <summary>
        /// 关闭采集
        /// </summary>
        private void StopReceiveFuntion()
        {
            try
            {
                if (device == null) return;
                int ret = device.StreamGrabber.StopGrabbing();
                if (ret != MvError.MV_OK)
                {
                    LOG.error(("Stop grabbing failed:{0:x8}", ret));
                    return;
                }
            }
            catch (Exception ex)
            {
                LOG.error("Stop thread failed!, " + ex.Message);
                throw;
            }
        }
        #endregion
    }
}
