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.IO;
using System.Linq;
using System.Threading;

namespace CCDCount.DLL
{
    public class ShuLiClass
    {
        #region 变量
        /// <summary>
        /// 当活跃物体转变为历史物体时的回调事件
        /// </summary>
        public event EventHandler<ActiveObjectEventArgsClass> WorkCompleted;
        private List<ActiveObjectClass> activeObjects = new List<ActiveObjectClass>(); // 当前跟踪中的物体
        private List<ActiveObjectClass> historyActiveObjects = new List<ActiveObjectClass>(); // 历史物体
        private ConcurrentQueue<IImage> IFrameDatas = new ConcurrentQueue<IImage>(); //图像数据队列
        private Thread IdentifyImageProcessThread = null; // 识别线程
        private bool IsIdentify = false; //线程是否开始识别的标志
        private long currentLine = 0; //行数记录
        private ShuLiConfigClass shuLiConfig = null;// 数粒参数配置文件
        public List<int> ChannelsRoi{get{ return _ChannelsRoi; }}
        private List<int> _ChannelsRoi = new List<int>();
        private int ChannelWidth = 0;//每个区域的宽度
        private int IdentifyImageWidth = -1;
        private static readonly object _lockObj = new object(); // 专用锁对象\
        private int ObjectNum = 0;
        public int ImageNum { get { return IFrameDatas.Count; } }
        #endregion

        #region 公共方法
        /// <summary>
        /// 初始化构造方法
        /// </summary>
        public ShuLiClass()
        {
            // 加载默认参数
            shuLiConfig = new ShuLiConfigClass()
            {
                Channel = 8,
                PandingCode = 2
            };
        }
        public ShuLiClass(ShuLiConfigClass config)
        {
            if(config.IsLoadCanfig)
            {
                // 加载传出的参数
                shuLiConfig = config;
            }
            else
            {
                // 加载默认参数
                shuLiConfig = new ShuLiConfigClass()
                {
                    Channel = 8,
                    PandingCode = 2
                };
            }
            InitChannel();
        }

        /// <summary>
        /// 处理图像序列的主入口
        /// </summary>
        /// <param name="image">图像像素数据</param>
        /// <param name="ImageWidth">图像宽</param>
        /// <param name="currentLine">当前行数</param>
        /// <returns>检测到的物体总数</returns>
        public bool ProcessImageSequence(IImage image)
        {
            bool result = false;
            for (int i = 0;i<image.Height;i++)
            {
                result = ProcessLine(image,i);
                currentLine += 1;
            }
            return result;
        }

        /// <summary>
        /// 返回最后一个历史物品
        /// </summary>
        /// <returns></returns>
        public ActiveObjectClass GetLastActive()
        {
            if (historyActiveObjects.Count() == 0)
                return null;
            return historyActiveObjects.Last();
        }

        /// <summary>
        /// 返回历史物品
        /// </summary>
        /// <returns></returns>
        public List<ActiveObjectClass> GetHistoryActive()
        {
            lock (_lockObj) // 加锁
            {
                return historyActiveObjects.ToList();
            }
        }

        /// <summary>
        /// 返回缓存在内存的历史物品的总数量
        /// </summary>
        /// <returns></returns>
        public int GetHistoryActiveNum()
        {
            lock (_lockObj) // 加锁
                return historyActiveObjects.Count();
        }

        /// <summary>
        /// 获取历史数据中，正常数据数量
        /// </summary>
        /// <returns></returns>
        public int GetOkHistoryNum()
        {
            lock (_lockObj)
                return historyActiveObjects.Where(o=>o.StateCode == 0).Count();
        }

        /// <summary>
        /// 获取历史数据中，异常数据数量
        /// </summary>
        /// <returns></returns>
        public int GetNgHistoryNum()
        {
            lock (_lockObj)
                return historyActiveObjects.Where(o=>o.StateCode != 0).Count();
        }

        /// <summary>
        /// 清除历史数据
        /// </summary>
        /// <returns></returns>
        public bool ClearHistoryActive()
        {
            lock (_lockObj)
            {
                historyActiveObjects.Clear();
                return true;
            }
        }

        /// <summary>
        /// 开启识别
        /// </summary>
        public void StartIdentifyFuntion(int ImaageWidth)
        {
            UpdateIdentifyImageWidth(ImaageWidth);
            InitChannel();
            try
            {
                // 标志位置位true
                IsIdentify = true;
                // 打开识别线程
                IdentifyImageProcessThread = new Thread(IdentifyImageProcess)
                {
                    Priority = ThreadPriority.Highest
                };
                IdentifyImageProcessThread.Start();
            }
            catch (Exception ex)
            {
                LOG.error("Start thread failed!, " + ex.Message);
                throw;
            }
        }

        /// <summary>
        /// 关闭识别
        /// </summary>
        public void StopIdentifyFuntion()
        {
            try
            {
                // 标志位设为false
                IsIdentify = false;
                if(IdentifyImageProcessThread!=null&& IdentifyImageProcessThread.IsAlive)
                    IdentifyImageProcessThread.Join();
            }
            catch (Exception ex)
            {
                LOG.error("Stop thread failed!, " + ex.Message);
                throw;
            }
        }

        /// <summary>
        /// 向识别队列添加一个数据
        /// </summary>
        /// <param name="items"></param>
        public void SetOnceIdentifyImageData(IImage items)
        {
            IFrameDatas.Enqueue(items.Clone() as IImage);
        }

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

        /// <summary>
        /// 更新检测宽度信息
        /// </summary>
        /// <param name="Width"></param>
        public void UpdateIdentifyImageWidth(int Width)
        {
            IdentifyImageWidth = Width;
        }

        /// <summary>
        /// 初始化通道划分
        /// </summary>
        /// <param name="ImageWidth"></param>
        public void InitChannel()
        {
            _ChannelsRoi.Clear();
            shuLiConfig.ImageWidth = IdentifyImageWidth==-1? shuLiConfig.ImageWidth: IdentifyImageWidth;
            if (shuLiConfig.Channel > 0)
            {
                if (shuLiConfig.IsIdentifyRoiOpen)
                {
                    ChannelWidth = (shuLiConfig.IdentifyStopX - shuLiConfig.IdentifyStartX) / shuLiConfig.Channel;
                }
                else
                {
                    ChannelWidth = shuLiConfig.ImageWidth / shuLiConfig.Channel;
                }
                for (int i = 0; i < shuLiConfig.Channel; i++)
                {
                    _ChannelsRoi.Add(ChannelWidth + i * ChannelWidth);
                }
            }
        }

        /// <summary>
        /// 获取配置信息
        /// </summary>
        /// <returns></returns>
        public ShuLiConfigClass GetConfigValue()
        {
            ShuLiConfigClass result = shuLiConfig;

            return result;
        }

        public int GetConfigImageWidth()
        {
            int result = -1;
            if(shuLiConfig != null)
                result = shuLiConfig.ImageWidth;
            return result;
        }
        #endregion

        #region 私有方法

        /// <summary>
        /// 对外通知事件
        /// </summary>
        private void OnWorkCompleted(List<ActiveObjectClass> activeObject)
        {
            ActiveObjectEventArgsClass activeObjectEventArgs = new ActiveObjectEventArgsClass(activeObject);
            // 触发事件
            WorkCompleted?.Invoke(this, activeObjectEventArgs);
        }

        /// <summary>
        /// 处理单行像素数据
        /// 返回值为false的时候无活跃物体转变为历史物体
        /// 返回值为true的时候有活跃物体转变为历史物体
        /// </summary>
        /// <param name="image">当前行像素数组</param>
        private bool ProcessLine(IImage imagedata,int RowNo)
        {
            bool result = false;
            // 步骤1：检测当前行的有效区域
            var currentRegions = FindValidRegions(imagedata,RowNo);

            if (currentRegions.Count == 1)
            {
                if (currentRegions[0].End - (currentRegions[0]).Start + 1 == imagedata.Width)
                {
                    LOG.error("当前行有效区域为整行,检查视野和光源");
                    return false;
                }
            }
            // 步骤2：处理当前行每个区域
            for (int i = 0; i < currentRegions.Count; i++)
            {
                var region = currentRegions[i];
                // 查找全部可合并的活跃物体（有重叠+在允许间隔内）
                var matcheds = activeObjects.Where(o =>
                    IsOverlapping(o, region) &&
                    (currentLine - o.LastSeenLine - 1) <= shuLiConfig.MAX_GAP).ToList();
                //当有多个可合并的活跃物体时，将多个物体合并
                if (matcheds.Count >= 2)
                {
                    // 合并有效区域队列
                    var CopeRowsData = new List<RowStartEndCol>();
                    matcheds.ForEach(o => CopeRowsData = CopeRowsData.Concat(o.RowsData).ToList());
                    // 合并有效区域并保存在新的区域中
                    var MergeMatched = new ActiveObjectClass
                    {
                        MinStartCol = matcheds.Min(o => o.MinStartCol),
                        MaxEndCol = matcheds.Max(o => o.MaxEndCol),
                        StartLine = matcheds.Min(o => o.StartLine),
                        LastSeenLine = matcheds.Max(o => o.LastSeenLine),
                        LastSeenLineStartCol = matcheds.Min(o => o.LastSeenLineStartCol),
                        LastSeenLineEndCol = matcheds.Max(o => o.LastSeenLineEndCol),
                        StartCheckTime = matcheds.Min(o => o.StartCheckTime),
                        EndCheckTime = matcheds.Max(o => o.EndCheckTime),
                        Area = matcheds.Sum(o => o.Area),
                        RowsData = CopeRowsData,
                        ImageWidth = matcheds.FirstOrDefault().ImageWidth,
                    };
                    // 从活跃区域中删除被合并的区域
                    matcheds.ForEach(o => activeObjects.Remove(o));
                    // 保存新的区域到活跃区域中
                    activeObjects.Add(MergeMatched);
                }

                // 搜获可用且可合并的活跃区域
                var matched = activeObjects.FirstOrDefault(o =>
                    IsOverlapping(o, region) &&
                    (currentLine - o.LastSeenLine - 1) <= shuLiConfig.MAX_GAP);
                if (matched != null)
                {
                    // 合并区域：扩展物体边界并更新状态
                    matched.MinStartCol = Math.Min(matched.MinStartCol, region.Start);
                    matched.MaxEndCol = Math.Max(matched.MaxEndCol, region.End);
                    matched.Area += region.End - region.Start + 1;
                    matched.LastSeenLine = currentLine;
                    matched.RowsData.Add(new RowStartEndCol
                    {
                        StartCol = region.Start,
                        EndCol = region.End,
                        RowsCol = currentLine,
                    });
                }
                else
                {
                    // 创建新物体（首次出现的区域）
                    activeObjects.Add(new ActiveObjectClass
                    {
                        MinStartCol = region.Start,
                        MaxEndCol = region.End,
                        StartLine = currentLine,
                        LastSeenLine = currentLine,
                        LastSeenLineStartCol = region.Start,
                        LastSeenLineEndCol = region.End,
                        StartCheckTime = DateTime.Now,
                        Area = region.End - region.Start + 1,
                        ImageWidth = IdentifyImageWidth,
                        RowsData = new List<RowStartEndCol> {
                            new RowStartEndCol {
                                StartCol = region.Start,
                                EndCol = region.End,
                                RowsCol = currentLine,
                            }
                        }
                    });
                }
            }
            currentRegions.Clear();
            // 更新有效物体的最后一行的起始点
            activeObjects.Where(o => o.LastSeenLine == currentLine).ToList().ForEach(o => o.LastSeenLineStartCol = o.RowsData.Where(p => p.RowsCol == currentLine).Min(p => p.StartCol));
            activeObjects.Where(o => o.LastSeenLine == currentLine).ToList().ForEach(o => o.LastSeenLineEndCol = o.RowsData.Where(p => p.RowsCol == currentLine).Max(p => p.EndCol));

            // 步骤3：清理超时未更新的物体
            var lostObjects = activeObjects
                .Where(o => (currentLine - o.LastSeenLine) > shuLiConfig.MAX_GAP || (o.LastSeenLine - o.StartLine) > shuLiConfig.MAX_Idetify_Height)
                .ToList();

            List<ActiveObjectClass> OneActive = new List<ActiveObjectClass>();

            // 有物体转变为活跃物体，返回值转为true
            if (lostObjects.Count() > 0)
            {
                result = true;
                foreach (var item in lostObjects)
                {
                    //噪点判定
                    if (item.LastSeenLine - item.StartLine < shuLiConfig.NoiseFilter_Threshold ||
                        item.RowsData.Max(o => o.EndCol - o.StartCol) < shuLiConfig.NoiseFilter_Threshold)
                        continue;
                    //转为历史物体，添加缺少的参数
                    item.Num = ObjectNum += 1;
                    item.ChannelNO = ActiveChannel(item);
                    item.EndCheckTime = DateTime.Now;
                    OneActive.Add(item);
                    if ((item.LastSeenLine - item.StartLine) > shuLiConfig.MAX_Idetify_Height)
                    {
                        item.StateCode = 7;
                        LOG.error("ShuLiClass-ProcessLine：非颗粒，视野异常");
                        Console.WriteLine("ShuLiClass-ProcessLine：非颗粒，视野异常");
                    }
                    else if (shuLiConfig.PandingCode != -1)
                    {
                        if (item.Area < shuLiConfig.MinArea
                            && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 1))
                        {
                            item.StateCode = 5;
                            LOG.log(string.Format("颗粒编号{0}：面积过小", item.Num));
                            Console.WriteLine("颗粒编号{0}：面积过小", item.Num);
                        }
                        else if (item.Area > shuLiConfig.MaxArea
                            && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 1))
                        {
                            item.StateCode = 6;
                            LOG.log(string.Format("颗粒编号{0}：面积过大", item.Num));
                            Console.WriteLine("颗粒编号{0}：面积过大", item.Num);
                        }
                        else if (item.LastSeenLine - item.StartLine < shuLiConfig.MIN_OBJECT_HEIGHT
                            && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
                        {
                            item.StateCode = 2;
                            LOG.log(string.Format("颗粒编号{0}：超短粒", item.Num));
                            Console.WriteLine("颗粒编号{0}：超短粒", item.Num);
                        }
                        else if (item.LastSeenLine - item.StartLine > shuLiConfig.MAX_OBJECT_HEIGHT
                            && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
                        {
                            item.StateCode = 1;
                            LOG.log(string.Format("颗粒编号{0}：超长粒", item.Num));
                            Console.WriteLine("颗粒编号{0}：超长粒", item.Num);
                        }
                        else if (item.RowsData.Max(o => o.EndCol - o.StartCol) > shuLiConfig.MAX_OBJECT_WIDTH
                            && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
                        {
                            item.StateCode = 3;
                            LOG.log(string.Format("颗粒编号{0}：超宽粒", item.Num));
                            Console.WriteLine("颗粒编号{0}：超宽粒", item.Num);
                        }
                        else if (item.RowsData.Max(o => o.EndCol - o.StartCol) < shuLiConfig.MIN_OBJECT_WIDTH
                            && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
                        {
                            item.StateCode = 4;
                            LOG.log(string.Format("颗粒编号{0}：超窄粒", item.Num));
                            Console.WriteLine("颗粒编号{0}：超窄粒", item.Num);
                        }
                        else
                        {
                            item.StateCode = 0;
                            LOG.log(string.Format("颗粒编号{0}：正常粒", item.Num));
                            Console.WriteLine("颗粒编号{0}：正常粒", item.Num);
                        }
                    }

                }

                if (OneActive.Count > 0)
                    //触发回调事件
                    OnWorkCompleted(OneActive);
            }
            else
            {
                OneActive = null;
            }
            lock (_lockObj)
            {
                // 累加到总数并从活跃物体转移到历史物体
                lostObjects.Where(o => o.LastSeenLine - o.StartLine >= shuLiConfig.NoiseFilter_Threshold && o.StateCode != 7).ToList().ForEach(o => historyActiveObjects.Add(o));
                lostObjects.ForEach(o => activeObjects.Remove(o));
                lostObjects.ForEach(o => historyActiveObjects.Where(P => P.Num == o.Num - 100).ToList().ForEach(P => P.RowsData.Clear()));
            }
            return result;
        }

        /// <summary>
        /// 检测有效物体区域（横向连续黑色像素段）
        /// </summary>
        /// <param name="line">当前行像素数组</param>
        /// <returns>有效区域列表（起始/结束位置）</returns>
        private List<(int Start, int End)> FindValidRegions(IImage image,int RowNo)
        {
            List<(int Start, int End)> regions = new List<(int Start, int End)>();
            int start = -1; // 当前区域起始标记
            // 遍历所有像素列
            if (shuLiConfig.IsIdentifyRoiOpen)
            {
                for (int i = (int)image.Width*RowNo + shuLiConfig.IdentifyStartX; i < (int)image.Width * RowNo + shuLiConfig.IdentifyStopX; i++)
                {
                    if (image.PixelData[i] < shuLiConfig.RegionThreshold) // 发现黑色像素
                    {
                        if (start == -1) start = i%(int)image.Width; // 开始新区域
                    }
                    else if (start != -1) // 遇到白色像素且存在进行中的区域
                    {
                        // 检查区域宽度是否达标
                        if (i - start >= shuLiConfig.MIN_OBJECT_WIDTH)
                        {
                            regions.Add((start, (i - 1)% (int)image.Width)); // 记录有效区域
                        }
                        start = -1; // 重置区域标记
                    }
                }
            }
            else
            {
                for (int i = (int)image.Width * RowNo; i < (int)image.Width * (RowNo+1); i++)
                {
                    if (image.PixelData[i] < shuLiConfig.RegionThreshold) // 发现黑色像素
                    {
                        if (start == -1) start = i % (int)image.Width; // 开始新区域
                    }
                    else if (start != -1) // 遇到白色像素且存在进行中的区域
                    {
                        // 检查区域宽度是否达标
                        if (i - start >= shuLiConfig.MIN_OBJECT_WIDTH)
                        {
                            regions.Add((start, (i - 1) % (int)image.Width)); // 记录有效区域
                        }
                        start = -1; // 重置区域标记
                    }
                }
            }


            // 处理行尾未闭合的区域
            if (start != -1 && image.Width - start >= shuLiConfig.MIN_OBJECT_WIDTH)
            {
                regions.Add((start, (int)image.Width - 1));
            }
            return regions;
        }

        /// <summary>
        /// 判断区域重叠（与活跃物体的横向坐标重叠检测）
        /// </summary>
        /// <param name="obj">活跃物体</param>
        /// <param name="region">当前区域</param>
        /// <returns>是否发生重叠</returns>
        private bool IsOverlapping(ActiveObjectClass obj, (int Start, int End) region)
        {
            // 判断区域是否不相交的逆条件
            return !(region.End < obj.LastSeenLineStartCol || region.Start > obj.LastSeenLineEndCol);
        }

        /// <summary>
        /// 通道区域判定
        /// </summary>
        /// <param name="activeObject"></param>
        /// <returns></returns>
        private int ActiveChannel(ActiveObjectClass activeObject)
        {
            int result = -1;
            int StartChannel = activeObject.MinStartCol / ChannelWidth;
            int EndChannel = activeObject.MaxEndCol / ChannelWidth;
            if (StartChannel == EndChannel)
            {
                result = StartChannel;
            }
            else if (EndChannel - StartChannel>1)
            {
                Console.WriteLine("ActiveChannel-Error");
                //error
            }
            else
            {
                result = _ChannelsRoi[StartChannel] - activeObject.MinStartCol > activeObject.MaxEndCol - _ChannelsRoi[StartChannel]? StartChannel: EndChannel;
            }
            return result;
        }
        #endregion

        #region 线程方法
        /// <summary>
        /// 识别图像线程
        /// </summary>
        private void IdentifyImageProcess()
        {
            //Stopwatch stopwatch = Stopwatch.StartNew();
            IImage IframeData = null;
            while (IsIdentify)
            {
                //判断队列中是否有数据
                if (IFrameDatas.Count() > 0)
                {
                    //stopwatch.Restart();
                    IFrameDatas.TryDequeue(out IframeData);
                    //是否成功取得数据
                    if (IframeData != null)
                    {
                        //识别
                        ProcessImageSequence(IframeData);
                    }
                    else
                    {
                        Console.WriteLine("识别数据为空");
                        continue;
                    }
                    //输出耗时
                    //stopwatch.Stop();
                    ///Console.WriteLine("识别线程单次运行耗时：" + stopwatch.Elapsed.ToString());
                }
                else
                {
                    Thread.Sleep(1);
                }
            }
        }
        #endregion
    }
}
