using AutoMapper;
using FLY.FilmCasting.AutoDie.Common;
using FLY.FilmCasting.AutoDie.IService;
using FLY.FilmCasting.AutoDie.Server.Model;
using FLY.OBJComponents.Common;
using FLY.OBJComponents.Server;
using FLY.Thick.FilmCasting.IService;
using FLY.Thick.FilmCasting.Server.Model;
using FObjBase;
using Newtonsoft.Json;
using PropertyChanged;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using HistoryDb = FLY.FilmCasting.AutoDie.Server.Model.HistoryDb;

namespace FLY.FilmCasting.AutoDie.Server
{
    public class FeedbackHeat : IFeedbackHeatService
    {
        const int INVALID_VELOCITY = 3;
        #region markno
        const int MARKNO_LOAD = 2;
        const int MARKNO_DELAY_ISCONNECTED = 3;
        #endregion


        #region IFeedbackHeat 成员
        #region 参数

        public IPEndPoint PLCep { get; set; }
        /// <summary>
        /// 自动控制使能
        /// </summary>
        public bool IsAuto { get; set; }


        /// <summary>
        /// 加热后起效延时(s)
        /// </summary>
        public int Delay { get; set; } = 10;

        /// <summary>
        /// 膜距离 m
        /// 模头到测厚仪的距离
        /// </summary>
        public double FilmLength { get; set; } = 20;

        /// <summary>
        /// 测厚仪厚度数据混合数
        /// </summary>
        public int Mix { get; set; } = 8;

        /// <summary>
        /// 检测功能使能
        /// </summary>
        public bool HasCheck { get; set; }

        /// <summary>
        /// 手动加热步进
        /// </summary>
        public int Step { get; set; } = 5;


        #endregion
        #region 动态数据
        /// <summary>
        /// 通道数， 从测厚仪获取的！！！！
        /// </summary>
        public int ChannelCnt { get; protected set; } = 88;

        /// <summary>
        /// 保存的加热策略名称
        /// </summary>
        public string HeatsProductName { get; protected set; } = "default";

        /// 连接到PLC?
        /// </summary>
        public bool IsConnectedWithPLC { get; set; }

        /// <summary>
        /// 上一次加热修改时间
        /// </summary>
        public DateTime LastChangedTime { get; set; } = DateTime.MinValue;

        /// <summary>
        /// 当前
        /// </summary>
        //public int[] Currs { get; set; }


        #endregion
        #region 异常检测

        /// <summary>
        /// 烧了的加热棒
        /// </summary>
        [DoNotCheckEquality]
        public bool[] Bads { get; set; }

        /// <summary>
        /// 当前风机启动中
        /// </summary>
        public bool HasFan { get; set; }

        /// <summary>
        /// 加热棒有电流
        /// </summary>
        public bool HasElectricity { get; set; }

        /// <summary>
        /// 线速度 大于 3m/min
        /// </summary>
        public bool HasFilmVelocity { get; set; }
        /// <summary>
        /// 检测线速度 使能
        /// </summary>
        public bool HasCheckFilmVelocity { get; set; }


        /// <summary>
        /// 当前正在检测的加热通道
        /// </summary>
        public int CheckNo { get; set; } = -2;


        /// <summary>
        /// 正在检测中
        /// </summary>
        public bool CheckEnable { get; set; } = false;

        /// <summary>
        /// 1块加热控制板 接多少路加热
        /// </summary>
        public int HeatsOfGroup { get; set; } = 12;


        #endregion
        #endregion



        IPLCLink plc;
        FLY.Thick.FilmCasting.IService.IBoltMapFilmCastingService boltMapFilmCasting;
        FLY.Thick.FilmCasting.IService.IBulkDbService bulkDb;
        FLY.Thick.Base.IService.ITDGageService gageService;

        public HeatCell mHeatCell = new HeatCell();
        public HeatBuf mHeatBuf = new HeatBuf();
        HeatCheck mHeatCheck = new HeatCheck();

        HistoryDb mHistoryDb;
        ChannelValuesMarkJsonDb channelValuesMarkJsonDb = new ChannelValuesMarkJsonDb();

        /// <summary>
        /// 报警系统
        /// </summary>
        WarningSystem2 mWarning;
        /// <summary>
        /// 加热记录文件夹
        /// </summary>
        string heats_dir = "feedbackheats";

        int[] lastHeats;
        /// <summary>
        /// 最后一次保存的记录,
        /// 用于当加热改变时，保存记录到数据库
        /// </summary>
        Lc_ThickHeat lastLcThickHeat = null;
        /// <summary>
        /// 上一次获取的扫描数据，时间
        /// </summary>
        DateTime lastScanDataEndTime;

        public FeedbackHeat()
        {
            PLCep = Misc.StringConverter.ToIPEndPoint("192.168.50.60:502");
            Load();

            plc = new PLCLink(PLCep);

        }


        public void Init(
            FLY.Thick.FilmCasting.IService.IBoltMapFilmCastingService boltMapFilmCasting,
            FLY.Thick.FilmCasting.IService.IBulkDbService bulkDb,
            FLY.Thick.Base.IService.ITDGageService gageService,
            FLY.OBJComponents.Server.WarningSystem2 warning,
            HistoryDb historyDb
            )
        {

            this.boltMapFilmCasting = boltMapFilmCasting;
            this.bulkDb = bulkDb;
            this.gageService = gageService;

            mWarning = warning;
            mHistoryDb = historyDb;

            plc.PropertyChanged += new PropertyChangedEventHandler(hmi_PropertyChanged);
            HasElectricity = plc.HasElectricity;
            HasFan = plc.HasFan;



            InitBuf();

            //-------------------------------------------------------------------


            PropertyChanged += new PropertyChangedEventHandler(FeedbackHeat_PropertyChanged);

            //-------------------------------------------------------------------
            //HeatBuf
            //UpdateTotalDelay();

            //-------------------------------------------------------------------
            //HeatCell
            mHeatCell.Init(mHeatBuf);

            mHeatCell.PreHeatApplyEvent = (c) =>
            {
                //有开风机才能加热
                if ((HasCheck) && (!HasFan))
                    return false;//返回false，不能加热

                //检测时，也是使用 HeatApply 确定加热的，要把下面注解掉。所以只能寄望于客户不要按HeatApply

                //检测中，不能改变加热
                //if (mHeatCheck.Enable)
                //    return false;

                return true;
            };

            mHeatCell.AfterHeatApplyEvent += (c) =>
            {
                //检测中，不保存加热
                if (mHeatCheck.Enable)
                    return;


                //复位undo模块
                resetUndo();

                lastHeats = mHeatCell.Heats.ToArray();
                LastChangedTime = DateTime.Now;

                //记录到数据库, 一次厚度数据都没有，就没法保存记录
                if (lastLcThickHeat != null)
                {
                    //
                    //检测 mHeatCell.Heats 与 lastLcThickHeat.Heats 是否一样
                    if (!Enumerable.SequenceEqual(lastLcThickHeat.Heats, lastHeats))
                    {
                        //不一样，记录
                        lastLcThickHeat.HTime = LastChangedTime;
                        lastLcThickHeat.Heats = lastHeats;
                        setLcThickHeatIsStable(lastLcThickHeat);
                        mHistoryDb.AddThickHeat(lastLcThickHeat);
                    }
                }
            };

            mHeatCell.AfterClearOffsetsEvent += (c) =>
            {
                //复位undo模块
                resetUndo();
            };


            mHeatCell.PropertyChanged += new PropertyChangedEventHandler(mHeatCell_PropertyChanged);//当HeatCell.Heats 修改后，设置到HMI

            Misc.BindingOperations.SetBinding(mHeatCell, nameof(mHeatCell.Kp), mHeatBuf, nameof(mHeatBuf.Kp), Misc.BindingOperations.BindingMode.TwoWay);


            if (!Directory.Exists(heats_dir))
                Directory.CreateDirectory(heats_dir);



            //-------------------------------------------------------------------
            //HeatCheck
            mHeatCheck.Init(mHeatCell);
            mHeatCheck.PropertyChanged += new PropertyChangedEventHandler(mHeatCheck_PropertyChanged);

            Misc.BindingOperations.SetBinding(this, nameof(HasElectricity), mHeatCheck, nameof(mHeatCheck.HasElectricity));
            Misc.BindingOperations.SetBinding(this, nameof(HasCheck), mHeatCheck, nameof(mHeatCheck.Has));
            Misc.BindingOperations.SetBinding(mHeatCheck, nameof(mHeatCheck.Enable), this, nameof(CheckEnable), Misc.BindingOperations.BindingMode.TwoWay);
            Misc.BindingOperations.SetBinding(mHeatCheck, nameof(mHeatCheck.CheckNo), this, nameof(CheckNo));
            Misc.BindingOperations.SetBinding(mHeatCheck, nameof(mHeatCheck.Bads), this, nameof(Bads));
            Misc.BindingOperations.SetBinding(this, nameof(HeatsOfGroup), mHeatCheck, nameof(mHeatCheck.HeatsOfGroup));


            //mHeatCell.Init3(blowingService);

            Misc.BindingOperations.SetBinding(boltMapFilmCasting, nameof(boltMapFilmCasting.NBolts), this, nameof(ChannelCnt));

            this.bulkDb.PropertyChanged += BulkDbService_PropertyChanged;
            this.gageService.DynArea.PropertyChanged += DynArea_PropertyChanged;

            mHistoryDb.GetFrame(0, (asyncContext, retData) =>
            {
                var reponse = retData as GetFrameReponse;
                if (reponse.thickHeat != null)
                {
                    lastScanDataEndTime = reponse.thickHeat.EndTime;
                }
            }, null);


            InitError();

            if (plc is PLCLink)
            {
                ((PLCLink)plc).Start();
            }
        }

        private void DynArea_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(gageService.DynArea.FilmVelocity))
            {
                UpdateTotalDelay();
                HasFilmVelocity = !(gageService.DynArea.FilmVelocity < INVALID_VELOCITY);//大于3m/min 正常生产

                //当线速度 很小，肯定是没生产，停止加热，停止自控
                if (HasCheckFilmVelocity && (!HasFilmVelocity))
                {
                    StopAnyHeating();
                    //停止自控
                    IsAuto = false;
                }
            }
        }



        void mHeatCheck_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(mHeatCheck.Enable))
            {
                if (mHeatCheck.Enable)
                {
                    if (!IsConnectedWithPLC)
                    {
                        //连接断开
                        mHeatCheck.Enable = false;
                    }
                    else if ((HasCheck) && (!HasFan))
                    {
                        //风机没启动，要关闭加热
                        mHeatCheck.Enable = false;
                    }
                    else
                    {
                        //需要关闭自控
                        IsAuto = false;
                    }
                }
            }
        }

        #region 异常
        void InitError()
        {
            //--------------------------------------------------------------------------------
            //连接断开事件
            FObjBase.PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD,
                () =>
                {
                    Misc.BindingOperations.SetBinding(this, nameof(IsConnectedWithPLC), () =>
                    {
                        bool b = !IsConnectedWithPLC;

                        ERR_STATE state = b ? ERR_STATE.ON : ERR_STATE.OFF;

                        ERRNO errno = ERRNOs.ERRNO_PLC_DISCONNECTED;
                        mWarning.Add(errno.Code, errno.Descrption, state);
                    });
                }, TimeSpan.FromSeconds(3), true, false, this, MARKNO_DELAY_ISCONNECTED, true);


            //------------------------------------------------------------------------
            //检测功能的结果
            this.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == nameof(HasCheck))
                {
                    if (!HasCheck)
                    {
                        ERRNO[] eRRNOs = new ERRNO[] {
                            ERRNOs.ERRNO_NO_FAN,
                            ERRNOs.ERRNO_OPEN_CIRCUIT,
                            ERRNOs.ERRNO_SHORT_CIRCUIT,
                            ERRNOs.ERRNO_POWER_OFF
                        };
                        foreach (ERRNO eRRNO in eRRNOs)
                        {
                            mWarning.Add(eRRNO.Code, eRRNO.Descrption, ERR_STATE.OFF);
                        }
                    }
                    return;
                }
                else if (e.PropertyName == nameof(HasFan))
                {
                    if (HasCheck)
                    {
                        ERR_STATE state = (!HasFan) ? ERR_STATE.ON : ERR_STATE.OFF;

                        ERRNO errno = ERRNOs.ERRNO_NO_FAN;
                        mWarning.Add(errno.Code, errno.Descrption, state);
                    }
                }
            };

            //------------------------------------------------------------------------
            //检测功能的结果
            Dictionary<string, ERRNO> error_property = new Dictionary<string, ERRNO>();
            error_property.Add(nameof(mHeatCheck.OpenCircuit), ERRNOs.ERRNO_OPEN_CIRCUIT);
            error_property.Add(nameof(mHeatCheck.ShortCircuit), ERRNOs.ERRNO_SHORT_CIRCUIT);
            error_property.Add(nameof(mHeatCheck.PowerOff), ERRNOs.ERRNO_POWER_OFF);
            mHeatCheck.PropertyChanged += (s, e) =>
            {
                if (HasCheck)
                {
                    if (error_property.ContainsKey(e.PropertyName))
                    {
                        bool b = (bool)Misc.PropertiesManager.GetValue(mHeatCheck, e.PropertyName);

                        ERR_STATE state = b ? ERR_STATE.ON : ERR_STATE.OFF;

                        ERRNO errno = error_property[e.PropertyName];
                        mWarning.Add(errno.Code, errno.Descrption, state);
                    }
                }
            };

            //------------------------------------------------------------------------
            //线速度异常
            this.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == nameof(HasCheckFilmVelocity))
                {
                    if (!HasCheckFilmVelocity)
                    {
                        ERRNO eRRNO = ERRNOs.ERRNO_NO_VELOCITY;
                        mWarning.Add(eRRNO.Code, eRRNO.Descrption, ERR_STATE.OFF);
                    }
                }
                else if (e.PropertyName == nameof(HasFilmVelocity))
                {
                    if (HasCheckFilmVelocity)
                    {
                        ERR_STATE b = (!HasFilmVelocity) ? ERR_STATE.ON : ERR_STATE.OFF;
                        ERRNO eRRNO = ERRNOs.ERRNO_NO_VELOCITY;
                        mWarning.Add(eRRNO.Code, eRRNO.Descrption, b);
                    }
                }
            };
        }

        #endregion

        void InitBuf()
        {
            plc.ChannelCnt = (UInt16)ChannelCnt;
            //Currs = new int[ChannelCnt];
            mHeatBuf.Init(ChannelCnt);
            mHeatCell.Init2(ChannelCnt);

            lastHeats = mHeatCell.Heats.ToArray();
            LastChangedTime = DateTime.Now;

            //复位undo模块
            resetUndo();
        }
        void hmi_PropertyChanged(object s, PropertyChangedEventArgs _e)
        {
            FObjBase.PollModule.Current.Dispatcher.Invoke(
                new PropertyChangedEventHandler(
                (sender, e) =>
                {
                    if (e.PropertyName == nameof(plc.Errno))
                    {
                        if (plc.Errno == -1)
                        {
                            IsConnectedWithPLC = false;
                        }
                        else
                        {
                            IsConnectedWithPLC = true;
                            //刚成功连接上
                            //重新复制数据到 PLC
                            RecoverPLC();
                        }
                    }
                    else if (e.PropertyName == nameof(plc.HasElectricity))
                    {
                        HasElectricity = plc.HasElectricity;
                    }
                    else if (e.PropertyName == nameof(plc.HasFan))
                    {
                        HasFan = plc.HasFan;
                    }
                }), s, _e);
        }



        void mHeatCell_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(mHeatCell.Heats))
            {
                Output(mHeatCell.Heats);
            }

        }
        void FeedbackHeat_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(ChannelCnt))
            {
                //重新初始化！！！！
                InitBuf();
                //滞后触发
                PollModule.Current.Poll_JustOnce(new PollModule.PollHandler(delegate ()
                {
                    Redo();
                }), this, MARKNO_LOAD);

            }
            else if (e.PropertyName == nameof(Delay))
            {
                //重新计算总延时！！！！
                UpdateTotalDelay();
            }
            else if (e.PropertyName == nameof(HasFan))
            {
                if ((HasCheck) && (!HasFan))
                {
                    //风机没开，停止一切动作。
                    StopAnyHeating();
                }
            }
            else if (e.PropertyName == nameof(IsAuto))
            {
                if (IsAuto)
                {
                    //启动了自控，应该关闭检测
                    mHeatCheck.Enable = false;

                    //复位自动对位状态
                    //mHeatCell.ResetAuto();
                }

            }
            else if (e.PropertyName == nameof(IsConnectedWithPLC))
            {
                if (!IsConnectedWithPLC)
                {
                    mHeatCheck.Enable = false;
                    IsAuto = false;
                }
            }
            else if (e.PropertyName == nameof(FilmLength)) 
            {
                UpdateTotalDelay();
            }
        }


        private void BulkDbService_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(bulkDb.LastScanDataId))
            {
                //有新数据，向bulkDb获取
                bulkDb.GetFrame(
                    new Pack_GetFrameRequest() { Id = 0, Mix = Mix },
                    (asyncContext, retData) =>
                    {
                        var reponse = retData as Pack_GetFrameReponse;
                        if (reponse.scanData == null)
                            return;
                        var scanData = reponse.scanData;

                        //读取数据库，
                        if (lastScanDataEndTime == scanData.EndTime)
                        {
                            //这是以前的数据，不要
                            return;
                        }
                        lastScanDataEndTime = scanData.EndTime;

                        Add(scanData);

                    }, this);
            }
        }

        /// <summary>
        /// 停止任何加热行为
        /// </summary>
        void StopAnyHeating()
        {
            //停止自控
            IsAuto = false;

            //备份 加热策略
            int[] preheats = mHeatCell.PreHeats.ToArray();
            bool needrestore = true;

            //停止检测加热棒
            if (mHeatCheck.Enable)
            {
                mHeatCheck.Enable = false;
                needrestore = false;
            }

            //停止加热
            mHeatCell.ClearPreHeats();
            mHeatCell.HeatApply();

            //恢复 加热策略
            if (needrestore)
                mHeatCell.ModifyPreHeats(preheats);
        }
        
        
        void UpdateTotalDelay()
        {
            if (gageService == null)
                return;
            var filmVelocity = gageService.DynArea.FilmVelocity;
            if (filmVelocity < INVALID_VELOCITY)
                return;
            int totaldelay = (int)(Delay + FilmLength / filmVelocity * 60);
            int t = (int)(mHeatBuf.Delay.TotalSeconds);
            if (Math.Abs(totaldelay - t) > 5)//相差大于5秒才更新
            {
                mHeatBuf.Delay = TimeSpan.FromSeconds(totaldelay);
            }

        }

        void Output(int[] heats)
        {
            List<UInt16> list = new List<UInt16>();
            for (int i = 0; i < ChannelCnt; i++)
            {
                UInt16 heat = (UInt16)heats[i];
                if (heat < 0)
                    heat = 0;
                else if (heat > 100)
                    heat = 100;
                list.Add(heat);
            }
            plc.SetHeat(list);

            UInt16 heatupdate = (UInt16)(plc.HeatUpdate_R + 1);
            if (heatupdate > 100)
                heatupdate = 1;
            plc.HeatUpdate = heatupdate;
        }
        void RecoverPLC()
        {
            plc.ChannelCnt = (UInt16)ChannelCnt;
            if (lastHeats != null)
            {
                plc.SetHeat(lastHeats.Select(h => (UInt16)h));
            }
            else
            {

                //设置全部0进去
                plc.SetHeat(new UInt16[ChannelCnt]);
            }
            UInt16 heatupdate = (UInt16)(plc.HeatUpdate_R + 1);
            if (heatupdate > 100)
                heatupdate = 1;
            plc.HeatUpdate = heatupdate;
        }


        void setLcThickHeatIsStable(Lc_ThickHeat lcThickHeat)
        {
            DateTime time = lcThickHeat.Time;
            DateTime htime = lcThickHeat.HTime;
            double filmLength = lcThickHeat.FilmLength;
            double filmVelocity = lcThickHeat.FilmVelocity;
            if (filmVelocity < INVALID_VELOCITY)
            {
                //速度太慢，没生产
                lcThickHeat.IsStable = false;
                return;
            }


            lcThickHeat.IsStable = time > (htime + TimeSpan.FromSeconds(Delay) + TimeSpan.FromMinutes(filmLength / filmVelocity));

        }



        void Add(Lc_ScanData lc_ScanData)
        {
            //1.求平均值
            //2.每个螺丝，加热量的增量 = (Thick - Avg) * Factor;
            //3.求出输出量， 输出值 = 当前值 + 增量

            if (lc_ScanData.Thicks.Count() != ChannelCnt)
                return;//非常异常！！！

            //检测数据有效性
            int invalid_cnt = lc_ScanData.Thicks.Count(
                (_d) => { return double.IsNaN(_d); }
                );

            //工作的螺丝数
            int  workBolts = lc_ScanData.BoltMapInfo.BoltCnt - lc_ScanData.BoltMapInfo.LeftEmptyBolts + lc_ScanData.BoltMapInfo.RightEmptyBolts;

            if (invalid_cnt > workBolts / 2)//有一半数据都是无效的
                return;

            if (lc_ScanData.FilmVelocity < INVALID_VELOCITY)
            {
                //速度太慢，异常
                return;
            }

            var lcThickHeat = new Lc_ThickHeat()
            {
                ScanDataID = lc_ScanData.ID,
                ProfileID = lc_ScanData.ProfileID,
                Time = lc_ScanData.Time,
                EndTime = lc_ScanData.EndTime,
                Target = lc_ScanData.Target,
                TolerancePercent = lc_ScanData.TolerancePercent,
                K = lc_ScanData.K,
                B = lc_ScanData.B,
                FilmPosition = lc_ScanData.FilmPosition,
                FilmVelocity = lc_ScanData.FilmVelocity,
                FilmWidth = lc_ScanData.FilmWidth,
                Avg = lc_ScanData.Avg,
                Thicks = lc_ScanData.Thicks,
                SampleADs = lc_ScanData.SampleADs,
                BoltMapInfo = lc_ScanData.BoltMapInfo,
                FilmLength = FilmLength,
                Boltmap = mHeatBuf.Boltmap,
                HTime = LastChangedTime,
                Heats = lastHeats
            };
            setLcThickHeatIsStable(lcThickHeat);

            mHistoryDb.AddThickHeat(lcThickHeat);
            lastLcThickHeat = lcThickHeat;

            //添加到缓冲区, 计算分区平移
            if (!mHeatBuf.Add(lcThickHeat))
            {
                //数据有问题，不需要在处理
                return;
            }

            mHeatCell.SetThickPercents(mHeatBuf.ThickPercents);

            if (IsAuto)//如果自控中！！！ 
            {
                mHeatCell.Auto();
            }
        }

        string file_path = "feedback.json";
        bool Load()
        {
            if (File.Exists(file_path))
            {
                try
                {
                    string json = File.ReadAllText(file_path);
                    var jsonDb = JsonConvert.DeserializeObject<FeedbackHeatJsonDb>(json);
                    FeedbackHeatJsonDb.Mapper.Map(jsonDb, this);
                    return true;
                }
                catch
                {
                    //异常，没有json 解码失败

                }
                return false;
            }
            return false;
        }
        void Save()
        {
            try
            {
                var jsonDb = FeedbackHeatJsonDb.Mapper.Map<FeedbackHeatJsonDb>(this);
                string json = JsonConvert.SerializeObject(jsonDb, Formatting.Indented);
                File.WriteAllText(file_path, json);
            }
            catch
            {
                //异常，没有json 编码失败

            }
        }

        #region 撤销

        /// <summary>
        /// undo 的序号
        /// </summary>
        public long UndoId { get; private set; }
        /// <summary>
        /// 在撤销中
        /// </summary>
        public bool IsInUndo { get; private set; }

        /// <summary>
        /// 这次撤销动作的时间
        /// </summary>
        public DateTime UndoTime { get; private set; }
        //读取 UndoIdx 的 加热
        public void Undo()
        {
            updateUodo(UndoId, true);
        }
        public void Redo()
        {
            updateUodo(UndoId, false);
        }
        void updateUodo(long id, bool isPre)
        {
            if (id > mHistoryDb.LastId)
                return;
            if (id < 0)
                return;

            mHistoryDb.GetFrameAdv(id, isPre, false, true, (asyncContext, retData) =>
            {
                var reponse = retData as GetFrameReponse;
                if (reponse.thickHeat == null)
                {
                    //没有。。。。
                    return;
                }
                mHeatCell.ModifyPreHeats(reponse.thickHeat.Heats);
                UndoTime = reponse.thickHeat.HTime;
                IsInUndo = reponse.thickHeat.ID != mHistoryDb.LastId;
                UndoId = reponse.thickHeat.ID;
            }, this);
        }
        void resetUndo()
        {
            UndoId = mHistoryDb.LastId;
            UndoTime = DateTime.MinValue;
            IsInUndo = false;
        }
        #endregion

        #region IFeedbackHeat 成员

        public void Apply()
        {
            Save();
        }

        #region 加热配置读写
        public void SaveHeats(string productname)
        {
            HeatsProductName = productname;
            channelValuesMarkJsonDb.CurrMarkName = HeatsProductName;
            var mark = channelValuesMarkJsonDb.Marks.Find(m => m.name == HeatsProductName);
            if (mark == null)
            {
                mark = new ChannelValuesMark();
                mark.name = HeatsProductName;
                channelValuesMarkJsonDb.Marks.Add(mark);
            }
            mark.channelValues = mHeatCell.Heats.ToArray();
            channelValuesMarkJsonDb.Save();
        }

        /// <summary>
        /// 获取保存的加热量文件列表 返回类型为 List&lt;string&gt;
        /// </summary>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        public void GetHeatsFileList(AsyncCBHandler asyncDelegate, object asyncContext)
        {
            List<string> filenames = channelValuesMarkJsonDb.Marks.Select(mark => mark.name).ToList();
            asyncDelegate(asyncContext, filenames);
        }


        /// <summary>
        /// 删除 加热量文件
        /// </summary>
        /// <param name="productname"></param>
        public void DelHeatsFile(string productname)
        {
            int remove_cnt = channelValuesMarkJsonDb.Marks.RemoveAll(mark => mark.name == productname);
            if (remove_cnt != 0)
                channelValuesMarkJsonDb.Save();
        }

        /// <summary>
        /// 加载 加热量文件 
        /// </summary>
        /// <param name="filename"></param>
        public void LoadHeatsFile(string productname)
        {
            var mark = channelValuesMarkJsonDb.Marks.Find(m => m.name == productname);
            if ((mark != null) && (mark.channelValues != null))
            {
                HeatsProductName = productname;
                channelValuesMarkJsonDb.CurrMarkName = HeatsProductName;
                channelValuesMarkJsonDb.Save();
                mHeatCell.ModifyPreHeats(mark.channelValues);
            }
        }
        #endregion
        #endregion





        #region INotifyPropertyChanged 成员

        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged(string propertyname)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyname));
            }
        }
        #endregion

    }
    public class FeedbackHeatJsonDb
    {
        public static Mapper Mapper { get; } = new AutoMapper.Mapper(new MapperConfiguration(c =>
        {
            c.CreateMap<FeedbackHeat, FeedbackHeatJsonDb>()
                .ForMember(d => d.PLCep, opt =>
                {
                    opt.MapFrom(s => s.PLCep.ToString());
                })
                .ReverseMap()
                    .ForMember(d => d.PLCep, opt =>
                     {
                         opt.MapFrom(s => Misc.StringConverter.ToIPEndPoint(s.PLCep));
                     });
        }));

        #region 参数

        public string PLCep;

        /// <summary>
        /// 加热后起效延时(s)
        /// </summary>
        public int Delay = 10;

        public double FilmLength = 20;

        public int Mix = 8;
        /// <summary>
        /// 检测功能使能
        /// </summary>
        public bool HasCheck;

        /// <summary>
        /// 手动加热步进
        /// </summary>
        public int Step = 5;

        /// 保存的加热策略名称
        /// </summary>
        public string HeatsProductName = "default";

        /// <summary>
        /// 检测线速度 使能
        /// </summary>
        public bool HasCheckFilmVelocity;

        /// <summary>
        /// 1块加热控制板 接多少路加热
        /// </summary>
        public int HeatsOfGroup = 12;
        #endregion
    }

}
