using CCDCount.DLL.Tools;
using CCDCount.MODEL.CameraClass;
using CCDCount.MODEL.ConfigModel;
using CCDCount.MODEL.ShuLiClass;
using LogClass;
using MvCameraControl;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;

namespace CCDCount.DLL
{
    public class MainThreadClass
    {
        #region 变量与实例
        Thread SwitchIdentifyImageThread = null;
        private bool IsSwitch = false;
        public ShuLiClass shuLiClass = null;
        CameraClass cameraClass = new CameraClass();
        public ShuLiConfigClass shuLiConfig = null;
        public CameraConfig cameraConfig = null;
        public bool CameraConfigIsChange = false;
        public int ThisCamerNo = -1;

        public bool CameraStatic { get { return _CameraStatic; } }
        private bool _CameraStatic = false;

        // 返回交换线程状态
        public bool CameraRunStatic { get { return IsSwitch; } }

        public bool IsOpenLoadThread { get  { return _IsOpenLoadThread; }}
        private bool _IsOpenLoadThread = false;

        public int HistoryActiveNum { get { return shuLiClass.GetHistoryActiveNum(); } }
        public int OkHistoryNum { get { return shuLiClass.GetOkHistoryNum(); } }
        public int NgHistoryNum { get { return shuLiClass.GetNgHistoryNum(); } }

        // 数粒信息发送线程
        Thread SendBottLogicMessageThread = null;
        bool IsSend = false;

        // Modbus客户端实例
        ModbusTcpClient modbusTcpClient = null;

        // 颗粒结果待发送队列
        ConcurrentQueue<ushort> SendQueue = new ConcurrentQueue<ushort>();

        /// <summary>
        /// 数粒状态计时器
        /// </summary>
        Stopwatch stopwatch = Stopwatch.StartNew();
        /// <summary>
        /// 数粒状态
        /// </summary>
        private bool _ShuLiState = true;
        public bool ShuLiState { get { return _ShuLiState; } }

        private bool IsDebug = false;
        #endregion

        #region 公共方法
        /// <summary>
        /// 设置ModbusTcpClient
        /// </summary>
        /// <param name="modbusTcpClient"></param>
        public void SetModbusClient(ModbusTcpClient modbusTcpClient)
        {
            this.modbusTcpClient = modbusTcpClient;
            if (!this.modbusTcpClient.IsTcpClientConnected())
            {
                LOG.error("ModbusTcpClient Connect Failed!");
            }
            else
            {
                LOG.log("ModbusTcpClient Connect Success!", 6);
            }
        }

        /// <summary>
        /// 初始化构造方法
        /// </summary>
        /// <param name="configClass"></param>
        /// <param name="CameraConfig"></param>
        public MainThreadClass(ShuLiConfigClass configClass,CameraConfig CameraConfig)
        {
            shuLiConfig = configClass;
            cameraConfig = CameraConfig;
            // 数粒配置文件地址
            if (configClass!=null)
            {
                // 创建数粒对象(配置文件)
                shuLiClass = new ShuLiClass(shuLiConfig);
            }
            else
            {
                // 创建数粒对象(默认)
                shuLiClass = new ShuLiClass();
            }

            _IsOpenLoadThread = cameraConfig.IsOpenLoad;
            ThisCamerNo = cameraConfig.CamerNo;
        }

        public bool LoadCamera()
        {
            bool result = false;
            // 相机列表
            try
            {
                // 获取相机列表
                cameraClass.GetCameraList(out List<CameraInfoClass> list);
                if (list.Count == 0)
                {
                    LOG.error(string.Format("{0}：没有相机", "MainThreadClass-StartMianThread"));
                    // 如果没有相机，则退出
                    return result;
                }
                // 加载相机
                // cameraClass.LoadCamereDevice(list.First().DeviceSN);
                if (!cameraClass.LoadCamereDevice(cameraConfig))
                {
                    LOG.error(string.Format("{0}：相机加载失败", "MainThreadClass-StartMianThread"));
                    return result;
                }
                CameraConfigIsChange = false;
            }
            catch
            {

            }
            return result;
        }

        public void ReLoadCameraConfig()
        {
            if(CameraConfigIsChange)
            {
                CameraConfig  OldcameraConfig = cameraClass.GetConfigValue();
                if(OldcameraConfig.CameraSNNum != cameraConfig.CameraSNNum)
                {
                    cameraClass.LoadCamereDevice(cameraConfig);
                }
                else
                {
                    cameraClass.ReLoadCameraConfig(cameraConfig);
                }
            }
        }

        /// <summary>
        /// 开始主线程
        /// </summary>
        public bool StartMianThread()
        {
            bool result = false;
            try
            {
                // 取图线程开启
                cameraClass.StartCamera();
                _CameraStatic = true;
                StartSendBottLogicMessageThread();
                // 数据交换线程开启
                StartSwitchThread();
                // 为数粒算法的识别成功一粒回调函数添加方法
                shuLiClass.WorkCompleted += Worker_OneGrainCompleted;
                // 开启识别线程
                shuLiClass.StartIdentifyFuntion(cameraClass.GetCamereImageSize().Width);
                result = true;
            }
            catch
            {

            }
            return result;
        }

        /// <summary>
        /// 停止主线程
        /// </summary>
        public bool StopMianThread()
        {
            bool result = false;
            try
            {
                _CameraStatic = false;
                shuLiClass.WorkCompleted -= Worker_OneGrainCompleted;
                // 相机取图关闭
                cameraClass.StopCamera();
                // 数据交换线程关闭
                StopSwitchThread();
                // 数粒识别线程关闭
                shuLiClass.StopIdentifyFuntion();
                StopSendBottLogicMessageThread();
                result = true;
            }
            catch
            {
            }
            return result;
        }

        /// <summary>
        /// 释放相机资源
        /// </summary>
        public void DisposeCamera()
        {
            cameraClass.StopCamera();
            cameraClass.DisPoseCamera();
        }

        /// <summary>
        /// 重加载相机
        /// </summary>
        /// <param name="CameraSN"></param>
        /// <returns></returns>
        public bool ReLoadCamera(string CameraSN)
        { 
            bool result = false;
            result = cameraClass.ReLoadCameraDevice(CameraSN);
            if (result)
            {
                cameraConfig = cameraClass.GetConfigValue();
            }
            return  result;
             
        }

        /// <summary>
        /// 获取显示用的图片数据
        /// </summary>
        /// <param name="ImageHeight"></param>
        /// <param name="Data"></param>
        public void GetShowImage(int ImageHeight,out Bitmap ImageData)
        {
            List<RowStartEndCol> RowsShowList = new List<RowStartEndCol>();
            ActiveObjectClass NewActive = shuLiClass.GetLastActive();
            if (NewActive == null)
            {
                LOG.log(string.Format("{0}：没有获取到数粒数据", "MainThreadClass-GetShowImage"));
                ImageData = null;
                return;
            }
            List<ActiveObjectClass> Data = shuLiClass.GetHistoryActive().Where(o => o.LastSeenLine > NewActive.LastSeenLine - ImageHeight).ToList();
            Data.ForEach(o => o.RowsData.ForEach(p => RowsShowList.Add(p)));
            Bitmap BitmapImage = new Bitmap(NewActive.ImageWidth, ImageHeight);
            using (Graphics g = Graphics.FromImage(BitmapImage))
            {
                g.Clear(Color.White);
                using (Pen RedPan = new Pen(Color.Red, 5))
                {
                    for (int i = 0; i < shuLiClass.ChannelsRoi.Count - 1; i++)
                    {
                        g.DrawLine(RedPan, new Point(shuLiClass.ChannelsRoi[i], 0), new Point(shuLiClass.ChannelsRoi[i], BitmapImage.Height));
                    }
                }
                using (Pen BlackPen = new Pen(Color.Black, 1))
                {
                    List<RowStartEndCol> ShowList = RowsShowList.Where(o => o.RowsCol > NewActive.LastSeenLine - BitmapImage.Height).ToList();
                    RowsShowList.Where(o => o.RowsCol < NewActive.LastSeenLine - BitmapImage.Height).ToList().ForEach(o => RowsShowList.Remove(o));
                    RowsShowList.Clear();
                    ShowList.ForEach(o => g.DrawLine(BlackPen, new Point(o.StartCol, (int)(NewActive.LastSeenLine - o.RowsCol)), new Point(o.EndCol, (int)(NewActive.LastSeenLine - o.RowsCol))));
                    ShowList.Clear();
                }
            }
            ImageData = BitmapImage.Clone() as Bitmap;
            BitmapImage.Dispose();
            //GC.Collect();
        }

        /// <summary>
        /// 获取无数据的图片
        /// </summary>
        /// <param name="ImageWidth"></param>
        /// <param name="ImageHeight"></param>
        /// <param name="ImageData"></param>
        public void GetNullShowImage(int ImageWidth, int ImageHeight, out Bitmap ImageData)
        {
            Bitmap BitmapImage = new Bitmap(ImageWidth, ImageHeight);
            using (Graphics g = Graphics.FromImage(BitmapImage))
            {
                g.Clear(Color.White);
                using (Pen RedPan = new Pen(Color.Red, 8))
                {
                    for (int i = 0; i < shuLiClass.ChannelsRoi.Count - 1; i++)
                    {
                        g.DrawLine(RedPan, new Point(shuLiClass.ChannelsRoi[i], 0), new Point(shuLiClass.ChannelsRoi[i], BitmapImage.Height));
                    }
                }
            }
            ImageData = BitmapImage.Clone() as Bitmap;
            BitmapImage.Dispose();
        }

        /// <summary>
        /// 获取此刻的Config数据
        /// </summary>
        /// <param name="config"></param>
        public void GetAllConfigValue(out CameraConfig Camconfig,out ShuLiConfigClass shuLiConfig)
        {
            //判断是否加载了相机
            if(cameraClass.IsLoadCamera())
            {
                //获取已经加载的相机的配置
                cameraConfig = cameraClass.GetConfigValue();
                Camconfig = cameraConfig;
            }
            else
            {
                cameraConfig = new CameraConfig();
                Camconfig = cameraConfig;
            }
            //读取视觉配置
            shuLiConfig = shuLiClass.GetConfigValue();
            this.shuLiConfig = shuLiConfig;
        }

        /// <summary>
        /// 获取相机此刻的Config数据
        /// </summary>
        /// <param name="CameraConfig"></param>
        public CameraConfig GetCameraConfig()
        {
            CameraConfig result = null;
            //判断是否加载了相机
            if (cameraClass.IsLoadCamera())
            {
                //获取已经加载的相机的配置
                result = cameraClass.GetConfigValue();
                cameraConfig = result;
            }
            return result;
        }

        /// <summary>
        /// 保存所有Config
        /// </summary>
        public void SaveAllConfig()
        {
            shuLiClass.SaveConfig();
        }

        /// <summary>
        /// 获取相机连接状态
        /// </summary>
        /// <returns></returns>
        public bool GetCameraConnectStatic()
        {
            bool result = false;
            if(cameraClass != null)
                result = cameraClass.IsConnectCamera();
            return result;
        }

        /// <summary>
        /// 清除历史数据
        /// </summary>
        /// <returns></returns>
        public bool ClearHistoryActive()
        {
            bool result = false;
            if(shuLiClass != null)
                result = shuLiClass.ClearHistoryActive();
            return result;
        }

        /// <summary>
        /// 获取过去一秒内颗粒数量
        /// </summary>
        /// <returns></returns>
        public int GetOneSecondActiveNum()
        {
            int result = 0;
            if(shuLiClass != null)
                result = shuLiClass.GetHistoryActive().Where(o=>o.EndCheckTime>DateTime.Now-TimeSpan.FromSeconds(1)).Count();
            return result;
        }
        #endregion

        #region 私有方法


        //bool IsFill = false;
        //bool IsXuanZhuanCloseFaMen = false;
        /// <summary>
        /// 每数完一粒识别线程执行的事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Worker_OneGrainCompleted(object sender, ActiveObjectEventArgsClass e)
        {
            LOG.log("有活跃物体转换为了历史物体，回调事件被触发！", 6);
            LOG.log(string.Format("图像处理实例中的待识别图像缓存队列长度{0}", shuLiClass.ImageNum), 6);

            if (e.Actives.Where(o => o.StateCode == 7).Count() > 0)
            {
                stopwatch.Restart();
                _ShuLiState = false;
            }
            else if (stopwatch.ElapsedMilliseconds > 1000)
            {
                stopwatch.Stop();
                _ShuLiState = true;
            }
            //往数组中计数
            ushort result = new ushort();
            // 事件处理逻辑
            foreach (ActiveObjectClass oneActive in e.Actives)
            {
                Console.WriteLine(string.Format("输出当前颗粒信息，开始行：{0},结束行：{1},开始时间：{2}结束时间：{3},颗粒状态：{4},通道数：{5}",
                    oneActive.StartLine, oneActive.LastSeenLine, oneActive.StartCheckTime.ToString("O"), oneActive.EndCheckTime.ToString("O"), oneActive.StateCode, oneActive.ChannelNO));
                LOG.log(string.Format("输出当前颗粒信息，开始行：{0},结束行：{1},开始时间：{2}结束时间：{3},颗粒状态：{4},通道数：{5}",
                    oneActive.StartLine, oneActive.LastSeenLine, oneActive.StartCheckTime.ToString("O"), oneActive.EndCheckTime.ToString("O"), oneActive.StateCode, oneActive.ChannelNO), 6);

                if (oneActive.StateCode == 0 && oneActive.ChannelNO != -1)
                {
                    //单通道合格计数
                    result |= (ushort)(1 << (oneActive.ChannelNO));
                }
                else
                {
                    //单通道不合格计数
                    result |= (ushort)(1 << 8);
                }
            }
            LOG.log("当前待发送队列数量：" + SendQueue.Count, 6);
            if(IsSend)
            {
                SendQueue.Enqueue(result);
            }
        }

        #endregion

        #region 线程方法

        /// <summary>
        /// 开启交换线程
        /// </summary>
        private void StartSwitchThread()
        {
            IsSwitch = true;

            SwitchIdentifyImageThread = new Thread(SwitchIdentifyImageProcess);
            SwitchIdentifyImageThread.Start();
        }

        /// <summary>
        /// 关闭交换线程
        /// </summary>
        private void StopSwitchThread()
        {
            try
            {
                // 标志位设为false
                IsSwitch = false;
                if (SwitchIdentifyImageThread != null && SwitchIdentifyImageThread.IsAlive)
                    SwitchIdentifyImageThread.Join();
            }
            catch (Exception ex)
            {
                LOG.error("Start thread failed!, " + ex.Message);
                throw;
            }
        }

        /// <summary>
        /// 交换线程
        /// </summary>
        private void SwitchIdentifyImageProcess()
        {
            IFrameOut IFramedata = null;
            Stopwatch stopwatch = Stopwatch.StartNew();
            stopwatch.Start();
            while (IsSwitch)
            {
                if (stopwatch.ElapsedMilliseconds > 1000)
                {
                    //Console.WriteLine("交换线程-图像处理实例中的待识别图像缓存队列长度{0}", shuLiClass.ImageNum);
                    GC.Collect();
                    stopwatch.Restart();
                }
                //Thread.Sleep(5);
                bool result = cameraClass.GetOnceImage(out IFramedata);
                if (result)
                {
                    //Debug模式,不进行图像处理
                    if (IsDebug)
                    {
                        continue;
                    }
                    if (IFramedata == null)
                        continue;
                    shuLiClass.SetOnceIdentifyImageData(IFramedata.Image);
                }
                else
                    continue;
                IFramedata.Dispose();
            }
            stopwatch.Stop();
        }

        /// <summary>
        /// 启动发送消息线程
        /// </summary>
        private void StartSendBottLogicMessageThread()
        {
            try
            {
                //zmcauxClass.OpenZmcauxCard();

                timeBeginPeriod(1); // 设置为1ms精度
                IsSend = true;
                SendBottLogicMessageThread = new Thread(SendBottLogicMessageProcess);
                SendBottLogicMessageThread.Start();
            }
            catch (Exception ex)
            {
                LOG.error("Start thread failed!, " + ex.Message);
                throw;
            }
        }
        /// <summary>
        /// 停止发送消息线程
        /// </summary>
        private void StopSendBottLogicMessageThread()
        {
            try
            {
                // 标志位设为false
                IsSend = false;
                if (SendBottLogicMessageThread != null && SendBottLogicMessageThread.IsAlive)
                    SendBottLogicMessageThread.Join();
                if (modbusTcpClient != null) modbusTcpClient.Disconnect();
            }
            catch (Exception ex)
            {
                LOG.error("Start thread failed!, " + ex.Message);
                throw;
            }
        }

        /// <summary>
        /// 信息发送线程
        /// </summary>
        private void SendBottLogicMessageProcess()
        {
            //获取数据
            ushort sendMessage = 0;
            bool AllowTransfer = false;
            bool TransferDone = false;
            Stopwatch sw = Stopwatch.StartNew();
            while (IsSend)
            {
                //LOG.log("进入线程", 6);
                sw.Restart();
                sendMessage = new ushort();
                //读取装瓶状态
                AllowTransfer = false;
                TransferDone = false;
                bool[] ReadResult = modbusTcpClient.ReadCoilsRegister(slaveId: 1, startAddress: 11, numRegisters: 2);
                if (ReadResult == null)
                {
                    continue;
                }
                AllowTransfer = ReadResult[1];
                TransferDone = ReadResult[0];
                //LOG.log(string.Format("读取值：AllowTransfer[0]:{0},TransferDone[1]:{1}", AllowTransfer, TransferDone), 6);
                //当允许写入且处于未写入的状态时
                if (AllowTransfer && !TransferDone)
                {
                    if (SendQueue.Count() > 0)
                    {
                        if (!SendQueue.TryDequeue(out sendMessage))
                        {
                            LOG.error("MainThreadClass-SendBottLogicMessageProcess-SendQueue.TryDequeue failed!");
                        }
                    }
                    if (sendMessage != 0)
                    {
                        //写入数据
                        modbusTcpClient.WriteSingleRegister(slaveId: 1, registerAddress: 100, value: sendMessage);
                        modbusTcpClient.WriteCoilsRegister(slaveId: 1, CoilsAddress: 11, values: true);
                    }
                    sw.Stop();
                    LOG.log(string.Format("sendMessage[1]:{0},此次写值耗时：{1}", sendMessage, sw.Elapsed), 6);
                }
                Thread.Sleep(1);
            }
        }
        #endregion

        #region 外部函数
        [DllImport("winmm.dll")]
        static extern uint timeBeginPeriod(uint period);
        #endregion
    }
}
