using AutoMapper;
using FLY.Thick.Base.Common;
using FLY.Thick.Base.Server;
using FLY.Thick.Blowing;
using FLY.Thick.Blowing.Common;
using FLY.Thick.Blowing.IService;
using FLY.Thick.Blowing.Server.Model;
using FlyADBase;
using FObjBase;
using FObjBase.Reflect;
using Misc;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;

namespace FLY.Thick.Blowing360.Server
{
    public class GM_BlowingFix360 : GM_Base, IBlowingFixService
    {
        NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

        const int MARKNO_PROFILE_ADD = 87;
        const int MARKNO_PROFILE_CHANGED = 88;



        #region 延时操作,markno
        const int MARKNO_CALFRAME = 2;
        #endregion




        #region IRenZiJiaService

        #region 分区设定


        /// <summary>
        /// 加热通道数
        /// </summary>
        public int ChannelCnt { get; set; } = 88;

        /// <summary>
        /// 分区数/加热通道数
        /// </summary>
        public int BPC { get; set; } = 1;

        /// <summary>
        /// 风环螺丝数
        /// </summary>
        public int NBolts => ChannelCnt * BPC;


        /// <summary>
        /// 复位时,探头测量的位置对应分区号
        /// </summary>
        public int OrgBoltNo { get; set; } = 1;


        /// <summary>
        /// 第1个螺丝号
        /// </summary>
        public int BoltNo1st = 1;
        /// <summary>
        /// 使用分区表
        /// </summary>
        public bool IsUsedMap { get; set; }
        bool IsNeedMap()
        {
            if (IsUsedMap && Map != null && Map.Count() > 0)
                return true;
            else
                return false;
        }
        private BoltMapCell[] map;
        /// <summary>
        /// 分区表,必须保证不能为null
        /// </summary>
        public BoltMapCell[] Map
        {
            get { return map; }
            set
            {
                //检测是否不一样
                if (!IsEquals(map, value))
                {
                    if (!IsValid(value))
                    {
                        IsUsedMap = false;
                        map = null;
                    }
                    else
                    {
                        map = value;
                    }
                }
            }
        }

        #endregion

        /// <summary>
        /// 测厚仪类型, 追边 or 扫描
        /// </summary>
        public BlowingType BType { get; } = BlowingType.Fix360;

        /// <summary>
        /// 测厚仪测量点位置方向:Left, Right (也就是三角形在左还是右)
        /// </summary>
        public bool IsProbeRight { get; set; } = true;


        /// <summary>
        /// 应用
        /// </summary>
        public void Apply()
        {

            Save();
        }
        [Push(typeof(RenZiJiaDataEventArgs))]
        public event EventHandler DataEvent;
        #endregion



        HistoryDb historyDb;
        BulkDb bulkDb;
        /// <summary>
        /// 人字架角度 &amp; 膜走带位置检测
        /// </summary>
        IBlowingDetectInServer mPDetect;
        DynArea mDynArea;
        BlowingFixProfileParam mProfileParam;
        /// <summary>
        /// 当前正在处理的 ADList 里面的数据.No
        /// </summary>
        int mADListToDoNo;
        /// <summary>
        /// 处理放入filminfo 的数据.No
        /// </summary>
        int mADListToDoNo_ToFilmInfo;

        /// <summary>
        /// 1s一个数据,
        /// </summary>

        RList<ADCell> mADList;


        class FRAME_INFO//一幅数据信息
        {

            public DateTime StartTime;//开始时间
            public DateTime EndTime;//结束时间
            public int NoStartAD;//在AD列表 处理的数据开始点
            public int NoEndAD;//在AD列表 处理的数据结束点
            public DIRECTION direction;//当前幅数据,方向
            public double velocity;//线速度 m/min
            public int rotationCnt;//人字架旋转次数
            /// <summary>
            /// 对应数据库的 id
            /// </summary>
            public Int64? scandata_id = null;
            /// <summary>
            /// 分区数据 N*long
            /// </summary>
            public double[] frame;
            /// <summary>
            /// 经过分区表后的结果
            /// </summary>
            public double[] frame_map;
            /// <summary>
            /// 推送出去的数据,也是数据库中的数据
            /// </summary>
            public RenZiJiaDataEventArgs renZiJiaDataEventArgs;
            /// <summary>
            /// 推送出去的数据 被修改了
            /// </summary>
            public bool renZiJiaDataEventArgsHasChanged = false;


            double frame_sum = 0;
            int frame_cnt = 0;


            public void SetNBolt(int nbolts)
            {
                frame = new double[nbolts];
                for (int i = 0; i < nbolts; i++)
                {
                    ClearFrameValue(i);
                }
            }

            void ClearFrameValue(int index)
            {
                frame[index] = double.NaN;
            }
            public void Clear()
            {
                for (int i = 0; i < frame.Count(); i++)
                {
                    ClearFrameValue(i);
                }

                HasChanged = true;
                index_last = -1;
                frame_cnt = 0;
                frame_sum = 0;
            }

            public bool HasChanged = false;//数据被改变了!!!,是时候更新bulkdata

            /// <summary>
            /// 提交,完成一次操作。清除状态
            /// </summary>
            public void Submit()
            {
                HasChanged = false;
            }

            int index_last = -1;
            public void SetFrameValue(int index, double value)
            {
                int nbolts = frame.Count();

                if (index >= nbolts)
                    return;//异常
                else if (index < 0)
                    return;//异常
                else if (double.IsNaN(value))
                    return;//异常

                if (index_last != index)
                {
                    index_last = index;
                    HasChanged = true;
                    frame_cnt = 0;
                    frame_sum = 0;
                }

                frame_sum += value;
                frame_cnt++;

                frame[index] = frame_sum / frame_cnt;
            }

        }
        RList<FRAME_INFO> mFrameInfoList;


        AD2ThkHandler Ad2Thk;



        void checkParamErr()
        {
            if (ChannelCnt < 10 || ChannelCnt > 160)
            {
                ChannelCnt = 44;
            }

            if (BPC < 1 || BPC > 10)
            {
                BPC = 2;
            }

            if (OrgBoltNo < 1 || OrgBoltNo > NBolts)
            {
                OrgBoltNo = 1;
            }

            if (!IsValid(Map))
            {
                IsUsedMap = false;
                Map = null;
            }
        }

        /// <summary>
        /// 检测通过,返回true
        /// </summary>
        /// <returns></returns>
        bool IsValid(BoltMapCell[] mapCells)
        {
            bool map_err = false;
            bool g_o = false;
            bool g_n = false;
            if (mapCells == null)
                return true;

            //Map 检测
            //OldNo,NewNo不能 <1 >NBolts
            //Map OldNo 必须从小到大环形排列
            //Map NewNo 必须从小到大环形排列
            for (int i = 0; i < mapCells.Count(); i++)
            {
                var mapCell = mapCells[i];
                if (mapCell.NewNo < 1 || mapCell.NewNo > NBolts)
                {
                    map_err = true;
                    break;
                }
                if (mapCell.OldNo < 1 || mapCell.OldNo > NBolts)
                {
                    map_err = true;
                    break;
                }

                int i_next = i + 1;
                if (i_next >= mapCells.Count())
                    i_next = 0;

                var mapCell_next = mapCells[i_next];
                if (mapCell.OldNo >= mapCell_next.OldNo)
                {
                    if (!g_o)
                        g_o = true;
                    else
                    {
                        map_err = true;
                        break;
                    }

                }

                if (mapCell.NewNo >= mapCell_next.NewNo)
                {
                    if (!g_n)
                        g_n = true;
                    else
                    {
                        map_err = true;
                        break;
                    }

                }
            }

            if (map_err)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        bool IsEquals(BoltMapCell c1, BoltMapCell c2)
        {
            if (c1 == c2)
            {
                return true;
            }
            if (c1 == null && c2 != null)
                return false;
            if (c1 != null && c2 == null)
                return false;
            if (c1.NewNo != c2.NewNo)
                return false;
            if (c1.OldNo != c2.OldNo)
                return false;
            return true;
        }
        bool IsEquals(BoltMapCell[] mapCells1, BoltMapCell[] mapCells2)
        {
            if (mapCells1 == mapCells2)
                return true;
            if (mapCells1 == null && mapCells2 != null)
                return false;
            if (mapCells1 != null && mapCells2 == null)
                return false;
            if (mapCells1.Count() != mapCells2.Count())
                return false;

            //mapCells1 与 mapCells2 肯定都不是 null 且数量一样
            for (int i = 0; i < mapCells1.Count(); i++)
            {
                var c1 = mapCells1[i];
                var c2 = mapCells2[i];
                if (!IsEquals(c1, c2))
                    return false;
            }
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="flyad"></param>
        public GM_BlowingFix360()
        {
            GMState = CTRL_STATE.FIX;


            Load();


            //检测参数
            checkParamErr();

            InitList();



        }

        public void Init(
            FlyAD7 flyad,
            IBlowingDetectInServer blowingDetect,
            AD2ThkHandler ad2thk, DynArea dynarea,
            BlowingFixProfileParam profileParam,
            HistoryDb historyDb,
            BulkDb bulkDb
            )
        {
            base.Init(flyad);

            this.mPDetect = blowingDetect;
            Ad2Thk = ad2thk;
            mDynArea = dynarea;
            mProfileParam = profileParam;
            this.historyDb = historyDb;
            //this.orgHistoryDb = orgHistoryDb;
            this.bulkDb = bulkDb;
            this.bulkDb.GetTempFrameAction = GetTempFrame;

            PropertyChanged += new PropertyChangedEventHandler(RenZiJiaFix_PropertyChanged);
            mFlyAD.TimeGridEvent += new FlyADBase.TimeGridEventHandler(flyad_TimeGridEvent);

            mPDetect.FilmInfoChangedEvent += new FilmInfoChangedEventHandler(mPDetect_FilmInfoChangedEvent);
            mPDetect.ClearEvent += new ClearEventHandler(mPDetect_ClearEvent);

            Misc.BindingOperations.SetBinding(mPDetect, nameof(mPDetect.FilmVelocity), mDynArea, nameof(mDynArea.FilmVelocity));



            mProfileParam.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == nameof(mProfileParam.K))
                {
                    //重新计算当前幅数据
                    UpdateCurrFrame();
                }
            };
            //mDynArea.PropertyChanged += (s, e) =>
            //{
            //    if (e.PropertyName == nameof(mDynArea.SampleAD))
            //    {
            //        //重新计算当前幅数据
            //        UpdateCurrFrame();
            //    }
            //};

            //记录调试数据
            MarkDebugInit();
        }

        void mPDetect_ClearEvent(object sender)
        {
            //没信号,清空所有数据!!!
        }
        /// <summary>
        /// 从1幅数据,获取头部,尾部,为于 ADList 的位置
        /// </summary>
        /// <param name="frameinfo"></param>
        /// <param name="index_start"></param>
        /// <param name="index_end"></param>
        /// <returns>false 数据不存在</returns>
        bool GetFilmInfoADIndex(FRAME_INFO frameinfo, out int index_start, out int index_end)
        {
            index_start = mADList.No2Index(frameinfo.NoStartAD);

            index_end = mADList.No2Index(frameinfo.NoEndAD);

            if ((index_start < 0) || (index_end < 0) ||
                (index_start >= mADList.Count) || (index_end >= mADList.Count))
            {
                //数据已经不存在,删除
                return false;
            }
            return true;
        }

        void mPDetect_FilmInfoChangedEvent(object sender, FilmInfoChangedEventArgs e)
        {
            var ret = ADListFastSearchIndex(e.Time, out int idx);
            switch (ret)
            {
                case ADListFastSearchIndexResult.Before://发送在过去
                    {
                        mADListToDoNo = mADList.Index2No(0);
                        mADListToDoNo_ToFilmInfo = mADListToDoNo;
                    }
                    break;
                case ADListFastSearchIndexResult.Now://发生在列表时间内
                    {
                        mADListToDoNo = mADList.Index2No(idx);
                        mADListToDoNo_ToFilmInfo = mADListToDoNo;
                    }
                    break;
                case ADListFastSearchIndexResult.Future:
                    {
                        //未来的,不处理
                    }
                    break;
            }

        }

        void RenZiJiaFix_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(NBolts))
            {
                //所有数据删除
                mFrameInfoList.Clear();

            }
            else if (e.PropertyName == nameof(OrgBoltNo))
            {
                //TODO 只处理3幅图
                int idx = mFrameInfoList.Count - 3;
                if (idx < 0)
                    idx = 0;

                if (idx >= mFrameInfoList.Count)
                    return;
                mADListToDoNo_ToFilmInfo = mFrameInfoList[idx].NoStartAD;
            }
        }





        BulkDbTempFrameChangedEventArgs GetTempFrame()
        {
            if (mFrameInfoList.Count() > 0)
            {
                var frameInfo = mFrameInfoList.Last();
                var thicks = IsNeedMap() ? frameInfo.frame_map : frameInfo.frame;

                return new BulkDbTempFrameChangedEventArgs()
                {
                    Time = frameInfo.StartTime,
                    EndTime = frameInfo.EndTime,
                    StartIndex = 0,
                    D = thicks
                };

            }
            else
            {
                return new BulkDbTempFrameChangedEventArgs();
            }
        }

        #region 记录测试数据
        DateTime markdebug_dt = DateTime.MinValue;
        void MarkDebugInit()
        {
            if (markdebug_dt == DateTime.MinValue)
                markdebug_dt = DateTime.Now;

            //启动1分钟定时器
            FObjBase.PollModule.Current.Poll_Config(
                FObjBase.PollModule.POLL_CONFIG.ADD,
                () =>
                {
                    //mPDetect.GetSignList(markdebug_dt, (asyncContext, retData) =>
                    //{
                    //    var reponse = retData as GetSignListReponse;
                    //    var cells = reponse.datas;
                    //    if (cells.Count > 0)
                    //    {
                    //        orgHistoryDb.AddSignData(
                    //            new Lc_Sign()
                    //            {
                    //                Time = cells.First().Time,
                    //                Signs = cells.ToArray()
                    //            });
                    //    }
                    //}, null);
                    //mPDetect.GetRollList(markdebug_dt, (asyncContext, retData) =>
                    //{
                    //    var reponse = retData as GetRollListReponse;
                    //    var cells = reponse.datas;
                    //    if (cells.Count > 0)
                    //    {
                    //        orgHistoryDb.AddRollData(
                    //            new Lc_Roll()
                    //            {
                    //                Time = cells.First().dt,
                    //                Signs = cells.ToArray()
                    //            });
                    //    }
                    //}, null);
                    this.GetADList(markdebug_dt, (asyncContext, retData) =>
                    {
                        var reponse = retData as GetADListReponse;
                        var cells = reponse.datas;
                        if (cells.Count > 0)
                        {
                            var thicks = cells.Select(c => c.thk).ToArray();
                            historyDb.AddTrendData(
                                new Lc_TrendData()
                                {
                                    Time = cells.First().dt,
                                    K = mProfileParam.K,

                                    Thicks = thicks
                                });
                        }
                    }, null);
                    markdebug_dt = DateTime.Now;
                },
                TimeSpan.FromMinutes(1));
        }
        #endregion

        void UpdateCurrFrame()
        {
            FObjBase.PollModule.Current.Poll_JustOnce(
                new FObjBase.PollModule.PollHandler(delegate ()
                {
                    if (mFrameInfoList.Count > 0)
                    {
                        mADListToDoNo_ToFilmInfo = mFrameInfoList.Last().NoStartAD;
                    }

                }), this, MARKNO_CALFRAME);
        }



        TimeSpan datOf1s_ts = TimeSpan.Zero;
        TimeSpan datOf1s_interval = TimeSpan.FromSeconds(1);
        List<int> datOf1s = new List<int>();

        void flyad_TimeGridEvent(object sender, FlyADBase.TimeGridEventArgs e)
        {
            bool issample = false;

            TimeSpan ts = e.Ts;//准确

            DateTime dt = e.Time;//准确
            int[] data = e.Data;

            DateTime datOf100ms_dt = DateTime.MinValue;
            for (int i = 0; i < data.Length; i++)
            {
                if (issample)//采样中,数据都是无效的
                {
                    datOf1s.Add(Misc.MyBase.NULL_VALUE);
                }
                else if (data[i] > UInt16.MaxValue)
                {
                    datOf1s.Add(Misc.MyBase.NULL_VALUE);
                }
                else if (data[i] < 0)
                {
                    datOf1s.Add(Misc.MyBase.NULL_VALUE);
                }
                else
                {
                    datOf1s.Add(data[i]);
                }

                datOf1s_ts = datOf1s_ts + ts;

                if (datOf100ms_dt == DateTime.MinValue)
                    datOf100ms_dt = dt;
                else
                    datOf100ms_dt = datOf100ms_dt + ts;

                if (datOf1s_ts >= datOf1s_interval)//1s 一个数据
                {
                    datOf1s_ts = datOf1s_ts - datOf1s_interval;

                    int avgad = Misc.MyBase.NULL_VALUE;

                    if (datOf1s.Count() > 0)
                    {
                        avgad = Misc.MyMath.Avg(datOf1s.ToArray());
                        datOf1s.Clear();
                    }
                    else if (mADList.Count() > 0)
                    {
                        avgad = mADList.Last().Ad;
                    }


                    mADList.RAdd(
                        new ADCell()
                        {
                            Time = DateTime.Now,
                            Ad = avgad
                        });

                }
            }
        }


        private void InitList()//初始化列表
        {
            if (mADList == null)
            {
                mADList = new RList<ADCell>(4000);
                mADListToDoNo = mADList.GetLastNo();
                mADListToDoNo_ToFilmInfo = mADListToDoNo;
            }
            if (mFrameInfoList == null)
                mFrameInfoList = new RList<FRAME_INFO>(6);
        }



        //复位
        void Clear()
        {
            if (mADList != null)
                mADList.Clear();
            if (mFrameInfoList != null)
            {
                mFrameInfoList.Clear();
            }
        }

        int Angle2BoltIndex(double angle)
        {
            if (angle < 0)
            {
                angle += 360;
            }

            int boltindex = (int)(OrgBoltNo - BoltNo1st + angle * NBolts / 360);
            if (boltindex >= NBolts)
            {
                boltindex -= NBolts;
            }
            else if (boltindex < 0)//不应该发生,可能是 OrgBoltNo 出错了。
            {
                boltindex += NBolts;
            }
            return boltindex;
        }

        enum ADListFastSearchIndexResult
        {
            /// <summary>
            /// 时间点在列表以前;
            /// </summary>
            Before = -1,
            /// <summary>
            /// 时间点在列表中;
            /// </summary>
            Now = 0,
            /// <summary>
            /// 时间点在列表的未来;
            /// </summary>
            Future = 1
        }
        /// <summary>
        /// 找到在 dt 前最近的 ADList 序号;
        /// 当ADList 没有数据,返回 Future;
        /// 已知AD列表每个数据之间的时间差,快速推断结果;
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        ADListFastSearchIndexResult ADListFastSearchIndex(DateTime dt, out int index)
        {
            index = 0;

            if (mADList.Count <= 0)//列表没有数据, 只能当它在未来
                return ADListFastSearchIndexResult.Future;


            if (dt > mADList.Last().Time)
                return ADListFastSearchIndexResult.Future;
            else if (dt < mADList.First().Time)
                return ADListFastSearchIndexResult.Before;
            else
            {

                int offset = (int)((mADList.Last().Time - dt).TotalSeconds / datOf1s_interval.TotalSeconds);
                index = mADList.Count - offset - 1;//大约在这个位置附近

                //安全限制
                if (index >= mADList.Count)
                    index = mADList.Count() - 1;
                else if (index < 0)
                    index = 0;

                if (mADList[index].Time == dt)
                {
                    //已经找到就是它!!!!
                }
                else if (mADList[index].Time > dt)
                {
                    while (true)
                    {
                        index--;
                        if (index <= 0)
                        {
                            index = 0;//最前面一个了
                            break;
                        }
                        if (mADList[index].Time <= dt)
                        {
                            //找到了
                            break;
                        }
                    }
                }
                else
                {
                    while (true)
                    {
                        index++;//测试一下
                        if (index >= mADList.Count)
                        {
                            //到顶了,不找了
                            index--;
                            break;
                        }
                        else if (mADList[index].Time == dt)
                        {
                            //找到了,就是它
                            break;
                        }
                        else if (mADList[index].Time > dt)
                        {
                            //上一个小于,现在大于,上一个就对了
                            index--;
                            break;
                        }
                    }
                }

                return ADListFastSearchIndexResult.Now;
            }
        }




        void OnPoll_UpdateADList()
        {

            int adlist_index = mADList.No2Index(mADListToDoNo);
            if (adlist_index >= mADList.Count)
                return;//没有数据需要处理
            if (adlist_index < 0)
                adlist_index = 0;


            for (int i = adlist_index; i < mADList.Count; i++)
            {
                mADListToDoNo = mADList.Index2No(i);

                if (!OnPoll_UpdateADList_Edge(i))
                    return;
            }
            mADListToDoNo = mADList.Index2No(mADList.Count);
        }

        bool OnPoll_UpdateADList_Edge(int idx)
        {
            FilmInfo filminfo;
            int ret = mPDetect.GetFilmInfo(out filminfo, mADList[idx].Time, 2.3, 0);
            if (ret == 1)//发生在未来
            {
                return false;
            }
            if (filminfo == null)//异常,FilmPosH 错误
            {
                return false;
            }
            if (mADListToDoNo != mADList.Index2No(idx))//触发了事件
            {
                return false;
            }


            ADCell adcell = mADList[idx];
            adcell.Angles.Clear();
            adcell.Angles.Add(filminfo.angle1);
            adcell.Direction = filminfo.direction;
            adcell.Velocity = filminfo.filmVelocity;
            adcell.RotationCnt = filminfo.rotationCnt;
            adcell.InCV = filminfo.inCV;
            return true;
        }
        /// <summary>
        /// 状态不一样,人字架已经转了新一圈,需要增加新一幅数据
        /// </summary>
        /// <param name="adcell"></param>
        /// <param name="frameinfo"></param>
        /// <returns></returns>
        bool FrameInfoCheckToNew(ADCell adcell, FRAME_INFO frameinfo)
        {
            if (//(adcell.Direction != frameinfo.direction) ||//永远是正方向。。。。不可能执行
                (adcell.RotationCnt != frameinfo.rotationCnt))
            //(Math.Abs(adcell.velocity - frameinfo.velocity) > 2))
            {
                return true;
            }
            else
            {
                return false;
            }
        }




        /// <summary>
        /// 输出的数据都必须是稳定,可靠的。 生成一幅幅测厚仪数据!!!!!!!!!!!!
        /// </summary>
        void OnPoll_UpdateFrameInfo()
        {


            int adlist_index = mADList.No2Index(mADListToDoNo_ToFilmInfo);//当前在处理的 数据点
            if (adlist_index >= mADList.Count)
                return;//没有数据需要处理

            if (adlist_index < 0)//全部都要处理
                adlist_index = 0;

            //当没有任何一幅数据时, frameinfo_index = mFrameInfoList.Count = 0
            int frameinfo_index = Math.Max(mFrameInfoList.Count - 1, 0);

            //查找adlist_index 属于哪个frameinfo;
            //当找到,清空里面的.frame,一切重新开始!!!
            //当不能找到,说明只是接着上次的处理而已,不需要重新开始
            for (int i = 0; i < mFrameInfoList.Count; i++)
            {
                int index_start;
                int index_end;
                FRAME_INFO frameinfo = mFrameInfoList[i];
                if (!GetFilmInfoADIndex(frameinfo, out index_start, out index_end))
                {
                    //数据已经不存在,删除
                    mFrameInfoList.RemoveAt(i);
                    i--;
                    continue;
                }
                if (adlist_index <= index_end)
                {
                    //要处理的数据点,位于 这幅数据 (frameinfo); 重新计算整幅数据 
                    frameinfo_index = i;
                    //adlist_index = mADList.No2Index(frameinfo.NoStartAD);
                    break;
                }
            }

            int adlist_todo_index = mADList.No2Index(mADListToDoNo);//已经成功获取完位置信息的数据尽头
            for (int i = adlist_index; (i < mADList.Count && i < adlist_todo_index); i++)
            {
                ADCell adcell = mADList[i];
                //mADListToDoNo_ToFilmInfo = mADList.Index2No(i);


                FRAME_INFO frameinfo;
                //--------------------------------------------------------------------------------------------------------
                //条件检测
                if (frameinfo_index >= mFrameInfoList.Count)//根本没数据,新建
                {
                    frameinfo = new FRAME_INFO();
                    frameinfo.StartTime = adcell.Time;
                    frameinfo.EndTime = adcell.Time;
                    frameinfo.direction = adcell.Direction;
                    frameinfo.velocity = adcell.Velocity;
                    frameinfo.rotationCnt = adcell.RotationCnt;
                    frameinfo.NoStartAD = mADList.Index2No(i);
                    frameinfo.NoEndAD = mADList.Index2No(i);
                    frameinfo.SetNBolt(NBolts);
                    mFrameInfoList.RAdd(frameinfo);
                    frameinfo_index = mFrameInfoList.Count - 1;
                }
                else
                {
                    frameinfo = mFrameInfoList[frameinfo_index];
                    if (i <= mADList.No2Index(frameinfo.NoEndAD))
                    {
                        //当为新数据, i应该>mADList.No2Index(frameinfo.NoEndAD)
                        //能进这里,证明是要重新计算
                        //清空数据,重新来过

                        frameinfo.StartTime = adcell.Time;
                        frameinfo.EndTime = adcell.Time;
                        frameinfo.direction = adcell.Direction;
                        frameinfo.velocity = adcell.Velocity;
                        frameinfo.rotationCnt = adcell.RotationCnt;
                        frameinfo.NoStartAD = mADList.Index2No(i);
                        frameinfo.NoEndAD = mADList.Index2No(i);
                        frameinfo.Clear();
                    }
                }
                //--------------------------------------------------------------------------------------------------------


                if (FrameInfoCheckToNew(adcell, frameinfo))
                {

                    //重新分区
                    if (IsNeedMap())
                    {
                        //上面已经检查了 Map == null 的情况
                        Dictionary<int, int> m = new Dictionary<int, int>();
                        for (int j = 0; j < Map.Count(); j++)
                            m.Add(Map[j].OldNo - 1, Map[j].NewNo - 1);
                        frameinfo.frame_map = Misc.MyMath.Map(frameinfo.frame, m);
                    }

                    //更新数据库内容
                    {
                        double[] frame;
                        List<BoltMapCell> map;
                        if (IsNeedMap())
                        {
                            //上面已经检查了 Map == null 的情况
                            frame = frameinfo.frame_map;
                            map = new List<BoltMapCell>();
                            foreach (var m in Map)
                                map.Add(m.Clone());
                        }
                        else
                        {
                            frame = frameinfo.frame;
                            map = null;
                        }
                        //限制小数点
                        for (int j = 0; j < frame.Count(); j++)
                        {
                            if (!double.IsNaN(frame[j]))
                                frame[j] = Math.Round(frame[j], 2);
                        }

                        frameinfo.renZiJiaDataEventArgs = new RenZiJiaDataEventArgs()
                        {
                            Time = frameinfo.StartTime,
                            EndTime = frameinfo.EndTime,
                            IsBackw = frameinfo.direction == DIRECTION.BACKWARD,
                            RPeriod = mPDetect.RenZiJiaPeriod,
                            RCnt = frameinfo.rotationCnt,
                            OrgBoltNo = OrgBoltNo,
                            RAngle = 360,
                            FilmLength = Math.Round(mPDetect.FilmLength, 2),
                            FilmVelocity = Math.Round(mPDetect.FilmVelocity, 2),
                            K = Math.Round(mProfileParam.K, 3),
                            Thicks = frame,
                            Boltmap = map
                        };
                        frameinfo.renZiJiaDataEventArgsHasChanged = true;
                    }

                    //更新到下一个frameinfo
                    frameinfo_index++;


                    i--;
                    continue;
                }

                double thk = Ad2Thk(adcell.Ad);
                frameinfo.SetFrameValue(Angle2BoltIndex(adcell.Angles.First()), thk);

                frameinfo.EndTime = adcell.Time;
                frameinfo.NoEndAD = mADList.Index2No(i);
            }
            mADListToDoNo_ToFilmInfo = mADListToDoNo;


            //检测数据更新情况,放入bulkdata
            for (int i = 0; i < mFrameInfoList.Count; i++)
            {
                FRAME_INFO frameinfo = mFrameInfoList[i];
                if (frameinfo.HasChanged)//数据检测过,需要更新bulkdata里面的数据, 大部分发生在扫描过程中,还没结束一幅图
                {
                    //重新分区
                    if (IsNeedMap())
                    {
                        //上面已经检查了 Map == null 的情况
                        Dictionary<int, int> m = new Dictionary<int, int>();
                        for (int j = 0; j < Map.Count(); j++)
                            m.Add(Map[j].OldNo - 1, Map[j].NewNo - 1);
                        frameinfo.frame_map = Misc.MyMath.Map(frameinfo.frame, m);
                    }

                    //TODO 更新即时图!!!!
                    //var thicks = IsNeedMap() ? frameinfo.frame_map : frameinfo.frame;
                }
            }

            //检查数据是否被修改, 推送出去!!!!!
            if (mFrameInfoList.Count() > 0)
            {
                FRAME_INFO frameinfo = mFrameInfoList.Last();
                if (frameinfo.HasChanged)
                {
                    var thicks = IsNeedMap() ? frameinfo.frame_map : frameinfo.frame;
                    //TODO, 推送的数据,可能太多了!!!!
                    bulkDb.SetTempFrame(frameinfo.StartTime, frameinfo.EndTime, 0, thicks);
                }
            }

            foreach (var frameinfo in mFrameInfoList)
            {
                frameinfo.Submit();
            }

            #region sqlite3 历史数据保存
            if (mFrameInfoList.Any((frameinfo) => frameinfo.renZiJiaDataEventArgsHasChanged))
            {
                //下辊检测
                if (historyDb.localDb.IsProfileFinished)
                {
                    AddProfile();
                }
            }

            //检测数据更新情况,放入数据库, 数据不能被修改

            RenZiJiaDataEventArgs renZiJiaDataEventArgs = null;//当数据被修改,推送事件!!!,当只有最后一幅图被推送

            foreach (var frameinfo in mFrameInfoList)
            {
                if (frameinfo.renZiJiaDataEventArgsHasChanged)
                {
                    frameinfo.renZiJiaDataEventArgsHasChanged = false;

                    if (frameinfo.scandata_id == null)
                    {
                        if (frameinfo.renZiJiaDataEventArgs.FilmVelocity < 2)
                        {
                            //异常
                            continue;
                        }
                        //添加数据
                        var lc_scandata = Lc_AutoMapperProfile.Mapper.Map<Lc_ScanData>(frameinfo.renZiJiaDataEventArgs);

                        historyDb.AddScanData(lc_scandata);
                        frameinfo.scandata_id = lc_scandata.ID;
                        renZiJiaDataEventArgs = frameinfo.renZiJiaDataEventArgs;
                    }
                }
            }
            #endregion
            //当数据被修改,只推送最后一次的数据
            if (renZiJiaDataEventArgs != null)
                DataEvent?.Invoke(this, renZiJiaDataEventArgs);
        }


        protected override void OnPoll()
        {
            OnPoll_UpdateADList();
            OnPoll_UpdateFrameInfo();
        }

        public override void Start()
        {
            //AD盒有没断开,也能触发,一直触发中!!!
            IsRunning = true;

            #region sqlite3 历史数据保存
            CheckProfile();
            mProfileParam.PropertyChanged += MProfileParam_PropertyChanged;
            #endregion

            FObjBase.PollModule.Current.Poll_Config(
                FObjBase.PollModule.POLL_CONFIG.ADD,
                onpoll_func,
                TimeSpan.FromSeconds(1));
        }
        #region sqlite3 历史数据保存
        string[] profile_propertynames_add = new string[]{
                nameof(BlowingFixProfileParam.PName),
                nameof(BlowingFixProfileParam.OrderNo),
                nameof(BlowingFixProfileParam.Number)
            };
        string[] profile_propertynames_update = new string[]{
                nameof(BlowingFixProfileParam.Target),
                nameof(BlowingFixProfileParam.TolerancePercent)
            };
        void CheckProfile()
        {
            if (historyDb.localDb.IsProfileFinished)
            {
                //复位 膜纵向位置
                AddProfile();
            }
            else
            {
                if (historyDb.localDb.CurrProfile != null)
                {
                    Db_Profile dB_Profile = historyDb.localDb.CurrProfile;
                    if ((dB_Profile.PName != mProfileParam.PName) ||
                    (dB_Profile.OrderNo != mProfileParam.OrderNo) ||
                    (dB_Profile.Number != mProfileParam.Number))
                    {
                        AddProfile();
                    }
                    else
                    {
                        //继续上一次生产!!!!
                        UpdateProfile();


                    }
                }
                else
                {
                    //异常
                    AddProfile();
                }

            }
        }
        void AddProfile()
        {
            historyDb.AddProfile(new Db_Profile()
            {
                PName = mProfileParam.PName,
                OrderNo = mProfileParam.OrderNo,
                Number = mProfileParam.Number,
                Target = mProfileParam.Target,
                TolerancePercent = mProfileParam.TolerancePercent,
                StartTime = DateTime.Now,
                EndTime = DateTime.Now
            });
        }
        void UpdateProfile()
        {
            historyDb.UpdateProfile(new Db_Profile()
            {
                PName = mProfileParam.PName,
                OrderNo = mProfileParam.OrderNo,
                Number = mProfileParam.Number,
                Target = mProfileParam.Target,
                TolerancePercent = mProfileParam.TolerancePercent,
            });
        }
        private void MProfileParam_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (profile_propertynames_add.Contains(e.PropertyName))
            {
                FObjBase.PollModule.Current.Poll_JustOnce(
                    () =>
                    {
                        if (!historyDb.localDb.IsProfileFinished)
                        {
                            historyDb.FinishProfile();
                        }
                        AddProfile();//新
                    }, this, MARKNO_PROFILE_ADD);
            }
            else if (profile_propertynames_update.Contains(e.PropertyName))
            {
                FObjBase.PollModule.Current.Poll_JustOnce(
                    () =>
                    {
                        UpdateProfile();//修改
                    }, this, MARKNO_PROFILE_CHANGED);
            }
        }
        #endregion

        string file_path = "blowingfix360.json";
        bool Load()
        {
            return BlowingFix360JsonDb.Load(this, file_path);

        }
        bool Save()
        {
            return BlowingFix360JsonDb.Save(this, file_path);
        }

        /// <summary>
        /// 获取 厚度列表
        /// </summary>
        /// <param name="begin">开始时间</param>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        [Call(typeof(GetADListReponse))]
        public void GetADList(DateTime begin, AsyncCBHandler asyncDelegate, object asyncContext)
        {
            var p = new GetADListReponse
            {
                datas = mADList.FindAll(a => a.Time >= begin).Select(a => new ADSingle()
                {
                    dt = a.Time,
                    thk = Ad2Thk(a.Ad)
                }).ToList()
            };

            asyncDelegate(asyncContext, p);
        }

    }

    public class BlowingFix360JsonDb
    {
        static Mapper Mapper { get; } = new AutoMapper.Mapper(new MapperConfiguration(c =>
        {
            c.CreateMap<GM_BlowingFix360, BlowingFix360JsonDb>().ReverseMap();
        }));

        public static bool Load(GM_BlowingFix360 src, string file_path)
        {
            if (File.Exists(file_path))
            {
                try
                {
                    string json = File.ReadAllText(file_path);
                    var jsonDb = JsonConvert.DeserializeObject<BlowingFix360JsonDb>(json);
                    Mapper.Map(jsonDb, src);
                    return true;
                }
                catch
                {
                    //异常,没有json 解码失败

                }
            }

            return false;
        }
        public static bool Save(GM_BlowingFix360 src, string file_path)
        {
            try
            {
                var jsonDb = Mapper.Map<BlowingFix360JsonDb>(src);
                string json = JsonConvert.SerializeObject(jsonDb, Formatting.Indented);
                File.WriteAllText(file_path, json);
                return true;
            }
            catch
            {
                //异常,没有json 编码失败

            }
            return false;
        }

        public int ChannelCnt = 88;
        public int BPC = 1;
        public int OrgBoltNo = 1;
        public bool IsUsedMap;
        public BoltMapCell[] Map;
        public bool IsProbeRight = true;
        public bool IsUsedEncoder = false;
    }
}