using FLY.OBJComponents.Common;
using FLY.Thick.Base.Common;
using FLY.Thick.Base.IService;
using FLY.Thick.Base.Server;
using FLY.Thick.FilmCasting.Common;
using FLY.Thick.FilmCasting.IService;
using FLY.Thick.FilmCasting.Server.Model;
using FlyADBase;
using FObjBase;

using Misc;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Threading;
using DynArea = FLY.Thick.FilmCasting.Common.DynArea;
using FlyADIODefine = FLY.Thick.FilmCasting.Common.FlyADIODefine;

namespace FLY.Thick.FilmCasting.Server
{

    public class TDGage : FLY.Thick.Base.IService.ITDGageService,IThkGaugeService
    {
        #region 延时推送 MARKNO
        const int MARKNO_UPDATEV = 1;
        const int MARKNO_UPDATEBOLTMAP = 2;
        #endregion

        #region 初始化------------------------------------------------------------------
        /// <summary>
        /// 参数目录 m_path;数据文件的 根目录默认是 "Gage1", 不能有 @"\"
        /// 目前也是对外的服务器目录
        /// </summary>
        public string mParamDirectory;

        #endregion

        #region 数据--------------------------------------------------------------------

        /// <summary>
        /// 当前基本简单参数
        /// </summary>
        public FLY.Thick.Base.Common.DynArea DynArea => DynArea2;

        public DynArea DynArea2 { get; private set; }

        /// <summary>
        /// 设备参数
        /// </summary>
        public InitParam initParam;

        /// <summary>
        /// 膜位置检测
        /// </summary>
        FilmPositionDetect2 filmPositionDetect;

        /// <summary>
        /// 拉伸前膜位置检测
        /// </summary>
        FilmPositionDetect2 filmPositionDetectBeforeStretching;
        /// <summary>
        /// 运行参数
        /// </summary>
        public FilmCastingProfileParam profileParam;

        /// <summary>
        /// 运行参数的载体
        /// </summary>
        public FilmCastingProfile profile;

        /// <summary>
        /// 螺丝位分区数据
        /// </summary>
        public BoltMapFilmCasting boltmap;

        /// <summary>
        /// 边界查找，由 boltmap 独立出来的功能
        /// </summary>
        public BorderSearch borderSearch;

        /// <summary>
        /// AD曲线
        /// </summary>
        public CurveCollection curve;

        /// <summary>
        /// 剔除
        /// </summary>
        public Reject reject;

        /// <summary>
        /// 报警系统
        /// </summary>
        public FLY.OBJComponents.Server.WarningSystem2 warning;

        /// <summary>
        /// 扫描报警
        /// </summary>
        public ScanWarning scanWarning;

        #region 运行模式

        /// <summary>
        /// AD卡
        /// </summary>
        public FlyADBase.FlyAD7 flyAd;
        
        /// <summary>
        /// AD卡提供的服务
        /// </summary>
        public FlyAdService flyAdService;
        

        /// <summary>
        /// 样品修正
        /// </summary>
        public GSample getSample;
        /// <summary>
        /// GM管理器
        /// </summary>
        GageModeManager gmManager;
        /// <summary>
        /// 断开连接
        /// </summary>
        GM_Disconnected gmDisconnected;

        /// <summary>
        /// 暂停扫描
        /// </summary>
        GM_Pause gmPause;
        /// <summary>
        /// 自动启动扫描
        /// </summary>
        GM_AutoScan gmAutoScan;

        /// <summary>
        /// 前进
        /// </summary>
        GM_Forward gmForw;
        /// <summary>
        /// 后退
        /// </summary>
        GM_Backward gmBackw;
        /// <summary>
        /// 归零
        /// </summary>
        GM_Origin gmOrg;
        /// <summary>
        /// 停止
        /// </summary>
        GM_Stop gmStop;
        /// <summary>
        /// 运行到目标位置
        /// </summary>
        GM_Goto gmRunto;

        /// <summary>
        /// 机架校正模式，参数
        /// </summary>
        public GM_ScanCorr gmScanCorr;

        /// <summary>
        /// 正常扫描模式
        /// </summary>
        public GM_Scan gmScan;

        /// <summary>
        /// 定点模式
        /// </summary>
        public GM_Fix gmFix;

        /// <summary>
        /// 机架信息，不同于机架校正
        /// </summary>
        public GM_GageInfo gmGageInfo;
        #endregion

        /// <summary>
        /// 系统参数
        /// </summary>
        public SysParam sysParam;

        #region BULKDATA,历史数据
        DbModel dbModel;
        public HistoryDb historyDb;
        LocalDb localDb;
        public BulkDb bulkDb;

        #endregion

        #endregion
        public List<ERRNO> errnoList;

        public TDGage()
        {


            #region create
            sysParam = new SysParam(null);//系统参数

            initParam = new InitParam();
            if (!initParam.Load())
                initParam.Save();

            initParam.HasHold = false;
            initParam.HasProfileSample = false;
            initParam.HasPunch = false;
            initParam.HasVSign = false;
            initParam.HasHSign = false;
            initParam.HasScanCorr = true;


            profile = new FilmCastingProfile();//运行配置参数
            profileParam = profile.Param;
            borderSearch = new BorderSearch(null);//边界查找
            boltmap = new BoltMapFilmCasting();//分区信息



            curve = new CurveCollection(null);//AD转thick

            reject = new Reject(null);


            dbModel = new DbModel();
            localDb = new LocalDb();
            historyDb = new HistoryDb();
            bulkDb = new BulkDb();


            DynArea2 = new DynArea();

            filmPositionDetect = new FilmPositionDetect2();
            filmPositionDetectBeforeStretching = new FilmPositionDetect2();

            warning = new OBJComponents.Server.WarningSystem2();
            scanWarning = new ScanWarning();



            flyAd = new FlyAD7();

            flyAdService = new FlyAdService();
            flyAdService.Init(flyAd, Ad2Thk);


            gmManager = new GageModeManager();
            gmFix = new GM_Fix();
            gmAutoScan = new GM_AutoScan();
            gmDisconnected = new GM_Disconnected();
            gmPause = new GM_Pause();
            gmForw = new GM_Forward();
            gmBackw = new GM_Backward();
            gmRunto = new GM_Goto();
            gmOrg = new GM_Origin();
            gmStop = new GM_Stop();
            gmGageInfo = new GM_GageInfo();
            gmScanCorr = new GM_ScanCorr();
            getSample = new GSample();
            gmScan = new GM_Scan();
            #endregion



        }

        public async Task Init()
        {

            //数据库 配置----------------------------------------
            //就只是数据库操作会慢而已！！！！！！
            await Init_db();

            //数据库备份检查
            BackupDbCheckInit();


            errnoList = ERRNOs.GetAll();

            #region 配置



            //Boltmap 配置----------------------------------------
            boltmap.MidOffset = profileParam.MidOffset;
            boltmap.Init(
                initParam.PosLength,
                initParam.Encoder1_mmpp,
                profileParam.LeftEmptyBolts,
                profileParam.RightEmptyBolts,
                profileParam.UniformShrinkPercent);

            initParam.PropertyChanged += (s, e) =>
            {
                if ((e.PropertyName == nameof(initParam.Encoder1_mmpp))
                || (e.PropertyName == nameof(initParam.PosLength)))
                {
                    updateBoltmap();
                }
            };
            profileParam.PropertyChanged += (s, e) =>
            {
                if ((e.PropertyName == nameof(profileParam.LeftEmptyBolts))
                || (e.PropertyName == nameof(profileParam.RightEmptyBolts))
                || (e.PropertyName == nameof(profileParam.UniformShrinkPercent)))
                {
                    updateBoltmap();
                }
                else if (e.PropertyName == nameof(profileParam.MidOffset))
                {
                    boltmap.MidOffset = profileParam.MidOffset;
                }
            };

            //BorderSearch 配置----------------------------------------
            #region
            borderSearch.Init(warning);
            //检测边界查找参数


            Misc.BindingOperations.SetBinding(borderSearch, new string[] { nameof(borderSearch.Width) },
                () =>
                {
                    DynArea.Width = borderSearch.Width * initParam.Encoder1_mmpp;
                });

            initParam.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == nameof(initParam.Encoder1_mmpp))
                {
                    DynArea.Width = borderSearch.Width * initParam.Encoder1_mmpp;
                }
            };

            //有效范围
            Misc.BindingOperations.SetBinding(initParam, new string[] { nameof(initParam.PosLength) },
                () =>
                {
                    borderSearch.Valid = new RangeStruct(0, initParam.PosLength - 1);
                });
            #endregion





            //DynArea 配置----------------------------------------
            DynArea.PropertyChanged += new PropertyChangedEventHandler(mDynArea_PropertyChanged);



            //GageModeManager 配置----------------------------------------
            Misc.BindingOperations.SetBinding(
                gmManager, nameof(gmManager.State),
                DynArea, nameof(DynArea.ControllerState));


            //FlyAd7 配置----------------------------------------
            #region
            if (!flyAd.Load())
                flyAd.Save();

            flyAd.Connect();

            FlyADIODefine.SetInstance(new FlyADIODefine());
            FlyADIODefine.Instance.SetFlyAD(flyAd);

            Misc.BindingOperations.SetBinding(initParam, nameof(initParam.PosLength), flyAd, nameof(flyAd.PosLen));
            
            Misc.BindingOperations.SetBinding(flyAd, nameof(flyAd.HardwareVersion), ()=> {
                if (flyAd.HardwareVersion < 3)
                {
                    DynArea.IsIOShowNo = true;
                }
                else {
                    DynArea.IsIOShowNo = false;
                }
            });
            Misc.BindingOperations.SetBinding(flyAd, nameof(flyAd.IStatus), DynArea, nameof(DynArea.IStatus));
            Misc.BindingOperations.SetBinding(flyAd, nameof(flyAd.OStatus), DynArea, nameof(DynArea.OStatus));
            Misc.BindingOperations.SetBinding(flyAd, nameof(flyAd.Position), DynArea, nameof(DynArea.Position));

            Misc.BindingOperations.SetBinding(flyAd, nameof(flyAd.Position), () =>
            {
                DynArea.PosMm = flyAd.Position * initParam.Encoder1_mmpp;//mm
            });

            Misc.BindingOperations.SetBinding(flyAd, nameof(flyAd.Position2), DynArea, nameof(DynArea.Position2));
            Misc.BindingOperations.SetBinding(flyAd, nameof(flyAd.Surplus), DynArea, nameof(DynArea.Hrs));
            Misc.BindingOperations.SetBinding(flyAd, nameof(flyAd.IsConnected), DynArea, nameof(DynArea.FLYADIsConnect));

            Misc.BindingOperations.SetBinding(flyAd, nameof(flyAd.PosOfGrid), initParam, nameof(initParam.PosOfGrid));

            Misc.BindingOperations.SetBinding(flyAd, nameof(flyAd.Speed), () =>
            {
                double speed = flyAd.Speed * initParam.Encoder1_mmpp;//mm/s
                speed = speed * 60 / 1000;//m/min
                DynArea.Velocity = speed;
            });

            Misc.BindingOperations.SetBinding(
                flyAd, new string[] { nameof(flyAd.Ratio02), nameof(flyAd.Ratio01) },
                () =>
                {
                    initParam.Speed1Scale = (double)flyAd.Ratio02 / flyAd.Ratio01;
                });

            Misc.BindingOperations.SetBinding(initParam, new string[] {
                nameof(initParam.SVelocity),
                nameof(initParam.ATime),
                nameof(initParam.DTime),
                nameof(initParam.HVelocity1),
                nameof(initParam.HVelocity2)
            }, delegate ()
            {
                PollModule.Current.Poll_JustOnce(delegate ()
                {
                    flyAd.SetPosParam(0xffffffff, initParam.SVelocity, initParam.ATime, initParam.DTime, initParam.HVelocity1, initParam.HVelocity2);

                }, this, MARKNO_UPDATEV);
            });

            Misc.BindingOperations.SetBinding(flyAd, new string[] { nameof(flyAd.IsConnected) },
                delegate ()
                {
                    if (flyAd.IsConnected == true)
                    {
                        //还需要在flyad 重新连接上时，设置！！！！！
                        PollModule.Current.Poll_JustOnce(delegate ()
                        {
                            flyAd.SetPosParam(0xffffffff, initParam.SVelocity, initParam.ATime, initParam.DTime, initParam.HVelocity1, initParam.HVelocity2);

                        }, this, MARKNO_UPDATEV);
                    }
                });

            //数据有效----------------------------------------
            flyAd.IStatusChangedEvent += (s, e) =>
            {
                if (initParam.DataValidSrc != DATAVALIDSRC.BYINPUT)
                    return;

                if (Misc.MyBase.CHECKBIT(e.IChanged, FlyADIODefine.Instance.InNo_DataValid))
                {
                    DynArea.DataValid = !Misc.MyBase.CHECKBIT(e.IStatus, FlyADIODefine.Instance.InNo_DataValid);
                }
            };

            Misc.BindingOperations.SetBinding(
                initParam, nameof(initParam.DataValidSrc),
                update_datavalid);

            //扫描按钮，及指示----------------------------------------
            flyAd.IStatusChangedEvent += (s, e) =>
            {
                if (Misc.MyBase.CHECKBIT(e.IChanged, FlyADIODefine.Instance.InNo_Scan))
                {
                    if (!Misc.MyBase.CHECKBIT(e.IStatus, FlyADIODefine.Instance.InNo_Scan))
                    {
                        if (DynArea.ControllerState == CTRL_STATE.SCAN)
                            StartP2(STARTP2_MODE.STOP);
                        else
                            StartP1();
                    }
                }
            };
            Misc.BindingOperations.SetBinding(DynArea, nameof(DynArea.ControllerState), () =>
            {
                if (DynArea.ControllerState == CTRL_STATE.SCAN)
                {
                    if (flyAd.MotorType == FlyADBase.MOTORTYPE.SERVO)
                    {
                        flyAd.SetOutputBit(FlyADIODefine.Instance.OutNo_Scan, false);//亮灯
                    }
                }
                else {
                    if (flyAd.MotorType == FlyADBase.MOTORTYPE.SERVO)
                    {
                        flyAd.SetOutputBit(FlyADIODefine.Instance.OutNo_Scan,true);//灭灯
                    }
                }

            });
            
            #endregion

            //FilmPositionDetect 配置----------------------------------------
            #region
            filmPositionDetect.Init(flyAd);
            filmPositionDetect.InNo_Roll = FlyADIODefine.Instance.InNo_Roll;
            Misc.BindingOperations.SetBinding(initParam, nameof(initParam.FilmVThreshold), filmPositionDetect, nameof(filmPositionDetect.FilmVThreshold));
            Misc.BindingOperations.SetBinding(initParam, nameof(initParam.FilmVSrc), filmPositionDetect, nameof(filmPositionDetect.FilmVSrc));
            Misc.BindingOperations.SetBinding(initParam, nameof(initParam.Encoder2_mmpp), filmPositionDetect, nameof(filmPositionDetect.Encoder2_mmpp));
            Misc.BindingOperations.SetBinding(initParam, nameof(initParam.MmOfR), filmPositionDetect, nameof(filmPositionDetect.MmOfR));

           

            Misc.BindingOperations.SetBinding(filmPositionDetect, nameof(filmPositionDetect.FilmPosition), DynArea, nameof(DynArea.FilmPosition));
            Misc.BindingOperations.SetBinding(filmPositionDetect, nameof(filmPositionDetect.FilmVelocity), DynArea, nameof(DynArea.FilmVelocity));
            #endregion

            //FilmPositionDetectBeforeStretching 配置----------------------------------------
            #region
            filmPositionDetectBeforeStretching.Init(flyAd);
            filmPositionDetectBeforeStretching.FilmVSrc = FilmVSRC.ROUND;
            filmPositionDetectBeforeStretching.InNo_Roll = FlyADIODefine.Instance.InNo_VBeforeStretching;
            Misc.BindingOperations.SetBinding(initParam, nameof(initParam.FilmVThreshold), filmPositionDetectBeforeStretching, nameof(filmPositionDetectBeforeStretching.FilmVThreshold));
            Misc.BindingOperations.SetBinding(initParam, nameof(initParam.MmOfR_VBefore), filmPositionDetectBeforeStretching, nameof(filmPositionDetectBeforeStretching.MmOfR));
            
            

            Misc.BindingOperations.SetBinding(filmPositionDetectBeforeStretching, nameof(filmPositionDetectBeforeStretching.FilmVelocity), DynArea2, nameof(DynArea2.FilmVelocityBeforeStretching));
            #endregion

            //WarningSystem 配置----------------------------------------
            warning.Init(historyDb.ErrorBuffer);
            warning.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == nameof(warning.IsRinging))
                {
                    flyAd.SetOutputBit(FlyADIODefine.Instance.OutNo_Alarm, !warning.IsRinging);
                }
            };

            //ScanWarning 配置----------------------------------------
            scanWarning.Init(warning, profileParam, bulkDb, DynArea);

            //GM_Fix 配置----------------------------------------
            gmFix.Init(flyAd, DynArea, Ad2Thk);
            gmManager.AddGM(gmFix);

            //GM_AutoScan 配置----------------------------------------
            gmAutoScan.Init(flyAd, StartP1);
            Misc.BindingOperations.SetBinding(
                gmAutoScan, nameof(gmAutoScan.Counter),
                DynArea, nameof(DynArea.AutoScanCounter));
            gmManager.AddGM(gmAutoScan);


            //GM_Disconnected 配置----------------------------------------
            gmDisconnected.Init(flyAd, DynArea, gmAutoScan);
            gmManager.AddGM(gmDisconnected);

            //GM_Pause 配置----------------------------------------
            gmPause.Init(flyAd, DynArea, gmAutoScan);
            Misc.BindingOperations.SetBinding(initParam, nameof(initParam.ReStartDelay), gmPause, nameof(gmPause.Delay));
            Misc.BindingOperations.SetBinding(initParam, nameof(initParam.AutoF1F3), gmPause, nameof(gmPause.Enable));
            gmManager.AddGM(gmPause);

            //GM_Forward 配置----------------------------------------
            gmForw.Init(flyAd);
            Misc.BindingOperations.SetBinding(initParam, nameof(initParam.VJOG), gmForw, nameof(gmForw.Velocity));
            gmManager.AddGM(gmForw);


            //GM_Backward 配置----------------------------------------
            gmBackw.Init(flyAd);
            Misc.BindingOperations.SetBinding(initParam, nameof(initParam.VJOG), gmBackw, nameof(gmBackw.Velocity));
            gmManager.AddGM(gmBackw);

            //GM_Goto 配置----------------------------------------
            gmRunto.Init(flyAd);
            Misc.BindingOperations.SetBinding(initParam, nameof(initParam.VJOG), gmRunto, nameof(gmRunto.Velocity));
            gmManager.AddGM(gmRunto);

            //GM_Origin 配置----------------------------------------
            gmOrg.Init(flyAd);
            gmManager.AddGM(gmOrg);

            //GM_Stop 配置----------------------------------------
            gmStop.Init(flyAd);
            gmManager.AddGM(gmStop);

            //GM_GageInfo 配置----------------------------------------
            gmGageInfo.Init(flyAd, initParam);

            gmManager.AddGM(gmGageInfo);

            //GM_ScanCorr 配置----------------------------------------
            gmScanCorr.Init(flyAd, initParam);
            gmManager.AddGM(gmScanCorr);
            flyAd.CorrectADs = gmScanCorr.CorrectADs;


            //GSample 配置----------------------------------------
            getSample.Init(flyAd, gmGageInfo, warning);
            Misc.BindingOperations.SetBinding(getSample.Samples.First(), nameof(SampleCell.AD), borderSearch, nameof(borderSearch.CurrTempAD));
            Misc.BindingOperations.SetBinding(initParam, nameof(initParam.VAccuracy), getSample, nameof(getSample.Velocity));
            getSample.SampleChangedEvent += getSample_SampleChangedEvent;


            //GM_Scan 配置----------------------------------------

            gmScan.Init(flyAd,
                getSample, initParam, warning,
                boltmap, borderSearch, reject,
                DynArea2, Ad2Thk,
                profileParam, profile, filmPositionDetect,
                historyDb, bulkDb);
            gmManager.AddGM(gmScan);
            ErrNoForCheckInit();

            #endregion`

            gmFix.Start();
        }

        async Task Init_db()
        {
            //数据库 配置----------------------------------------
            //就只是数据库操作会慢而已！！！！！！


            await Task.Factory.StartNew(() =>
            {
                dbModel.Init();

                //删除不需要的备份数据
                dbModel.KeepBackupSize(12);

                //备份上一个月之前的数据到 yyyy-MM 文件夹
                dbModel.BackupBbInSize(12);

                //当前的数据库只保存上个月与这个月的数据
                dbModel.KeepDBSize(1);
            });

            historyDb.Init(dbModel, localDb);
            bulkDb.Init(historyDb, localDb, dbModel);
            Misc.BindingOperations.SetBinding(profile, nameof(profile.RollDown_AvgChanged), bulkDb, nameof(bulkDb.MixDataAvgRange));
        }
        void updateBoltmap()
        {
            FObjBase.PollModule.Current.Poll_JustOnce(() =>
            {
                boltmap.Init(
                    initParam.PosLength,
                    initParam.Encoder1_mmpp,
                    profileParam.LeftEmptyBolts,
                    profileParam.RightEmptyBolts,
                    profileParam.UniformShrinkPercent);
            }, this, MARKNO_UPDATEBOLTMAP);
        }

        #region 异常检测
        class ErrNoForCheckItem
        {
            public FLY.OBJComponents.Common.ERRNO errno;
            public Func<bool> conditional;
            /// <summary>
            /// 持续时间，单位s
            /// </summary>
            public int cnt;

            int timer = -1;
            public FLY.OBJComponents.Server.WarningSystem2 mWarning;
            public void Clear()
            {
                if (timer == 0)
                {
                    mWarning.Remove(errno.Code);
                }
                timer = -1;
            }
            public void OnPoll()
            {
                if (conditional())
                {
                    if (timer < 0)
                        timer = cnt;
                    else
                    {
                        if (timer > 0)
                            timer--;

                        if (timer == 0)
                        {
                            mWarning.Add(errno.Code, errno.Description);
                        }
                    }
                }
                else
                {
                    Clear();
                }
            }
        }

        List<ErrNoForCheckItem> ErrNoForCheckItems = new List<ErrNoForCheckItem>();

        public event PropertyChangedEventHandler PropertyChanged;

        void ErrNoForCheckInit()
        {
            #region 时间触发的报警
            ErrNoForCheckItems.Add(//AD值太小
                new ErrNoForCheckItem()
                {
                    errno = ERRNOs.ERRNO_AD_MIN,
                    cnt = 20,
                    conditional = delegate ()
                    {
                        CTRL_STATE[] states = new CTRL_STATE[] {
                            CTRL_STATE.GAGEINFO,
                            CTRL_STATE.SCAN,
                            CTRL_STATE.CORR
                        };
                        //只有在扫描时，才会报警
                        if (!states.Contains(DynArea.ControllerState))
                        {
                            return false;
                        }
                        return DynArea.AD < 1000;
                    }
                });

            ErrNoForCheckItems.Add(//AD值太大
                new ErrNoForCheckItem()
                {
                    errno = ERRNOs.ERRNO_AD_MAX,
                    cnt = 20,
                    conditional = delegate ()
                    {
                        return DynArea.AD > 63000;
                    }
                });

            ErrNoForCheckItems.Add(//限位
                new ErrNoForCheckItem()
                {
                    errno = ERRNOs.ERRNO_LIMIT,
                    cnt = 2,
                    conditional = delegate ()
                    {
                        if (flyAd.MotorType == FlyADBase.MOTORTYPE.VF0)
                            return false;


                        return (
                        (Misc.MyBase.CHECKBIT(DynArea.IStatus, FlyADIODefine.Instance.InNo_Limit_Forw) == true)
                        || (Misc.MyBase.CHECKBIT(DynArea.IStatus, FlyADIODefine.Instance.InNo_Limit_Backw) == true));
                    }
                });

            ErrNoForCheckItems.Add(//急停
                new ErrNoForCheckItem()
                {
                    errno = ERRNOs.ERRNO_SCRAM,
                    cnt = 2,
                    conditional = delegate ()
                    {
                        CTRL_STATE[] states = new CTRL_STATE[] {
                            CTRL_STATE.GAGEINFO,
                            CTRL_STATE.SCAN,
                            CTRL_STATE.CORR
                        };

                        bool isEMERGENCY = (Misc.MyBase.CHECKBIT(DynArea.IStatus, FlyADIODefine.Instance.InNo_Manual_Forw) == false) || (Misc.MyBase.CHECKBIT(DynArea.IStatus, FlyADIODefine.Instance.InNo_Manual_Backw) == false);
                        if (isEMERGENCY) 
                        {
                            if (states.Contains(DynArea.ControllerState))
                            {
                                //急停，且当前状态在运行中
                                //触发停止
                                StartP2(STARTP2_MODE.STOP);
                            }
                        }
                        return isEMERGENCY;
                    }
                });



            foreach (ErrNoForCheckItem item in ErrNoForCheckItems)
            {
                item.mWarning = warning;
            }

            FObjBase.PollModule.Current.Poll_Config(
                FObjBase.PollModule.POLL_CONFIG.ADD,
                onpoll_checkErrNo, TimeSpan.FromSeconds(1));

            #endregion

            #region 状态触发的报警
            Misc.BindingOperations.SetBinding(DynArea, nameof(DynArea.Hrs), () =>
            {
                if (DynArea.Hrs < 72 && DynArea.Hrs > 0)//授权限制提醒
                {
                    warning.Add(ERRNOs.ERRNO_WILL_EXP);
                }
                else
                {
                    warning.Remove(ERRNOs.ERRNO_WILL_EXP);
                }
            });

            Misc.BindingOperations.SetBinding(DynArea, nameof(DynArea.SecuteLock), () =>
            {
                if (DynArea.SecuteLock)
                {
                    warning.Add(ERRNOs.ERRNO_AUTH_EXP);
                }
                else
                {
                    warning.Remove(ERRNOs.ERRNO_AUTH_EXP);
                }
            });




            #endregion
        }


        void onpoll_checkErrNo() //1秒执行一次
        {
            if (!DynArea.FLYADIsConnect)
            {
                //AD盒连接断开，这个不能让它复位，通过时间查询
                warning.Add(ERRNOs.ERRNO_FLYAD7_DC);

                foreach (ErrNoForCheckItem item in ErrNoForCheckItems)
                    item.Clear();
            }
            else
            {
                warning.Remove(ERRNOs.ERRNO_FLYAD7_DC);

                foreach (ErrNoForCheckItem item in ErrNoForCheckItems)
                    item.OnPoll();
            }
        }
        #endregion

        void mDynArea_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(DynArea.FilmVelocity))
            {
                update_datavalid();
            }
        }

        void update_datavalid()
        {
            switch (initParam.DataValidSrc)
            {
                case DATAVALIDSRC.VALID:
                    DynArea.DataValid = true;
                    break;
                case DATAVALIDSRC.INVALID:
                    DynArea.DataValid = false;
                    break;
                case DATAVALIDSRC.BYEN2:
                    {
                        if (DynArea.FilmVelocity >= initParam.FilmVThreshold)
                            DynArea.DataValid = true;
                        else
                            DynArea.DataValid = false;
                    }
                    break;
                case DATAVALIDSRC.BYINPUT:
                    {
                        if (!Misc.MyBase.CHECKBIT(flyAd.IStatus, FlyADIODefine.Instance.InNo_DataValid))
                            DynArea.DataValid = false;
                        else
                            DynArea.DataValid = true;
                    }
                    break;
            }
        }


        public double Ad2Thk(int ad)
        {
            if (Misc.MyBase.ISVALIDATA(ad))
            {
                double thk;
                if (getSample.Enable)//动态温修
                    thk = curve.AD2Value(ad, AD2ValueFlag.Revised);
                else
                    thk = curve.AD2Value(ad, AD2ValueFlag.NoRevised);

                thk = profile.Param.K * thk + profile.Param.B;
                thk = Math.Round(thk, 2);
                return thk;
            }
            return double.NaN;
        }

        void getSample_SampleChangedEvent(FLY.Thick.Base.Server.GSample _gsample)
        {
            var gsample = _gsample;
            CurveCollection pCurve = curve;

            if (gsample.OK())//这个很重要！！！！！！！
            {

                historyDb.AddSample(
                    new Lc_Sample()
                    {
                        Time = DateTime.Now,
                        SampleADs = gsample.Samples.Select(c => c.AD).ToArray()
                    });

                List<CurveCollection.ExChange> list = new List<CurveCollection.ExChange>();
                for (int i = 0; i < gsample.Samples.Count(); i++)
                {
                    var sample = gsample.Samples[i];
                    if ((sample.Enable) && (!sample.JustForCheck) && (sample.AD > 0))
                    {
                        list.Add(new CurveCollection.ExChange() { OrgAD = sample.OrgAD, CurrAD = sample.AD });
                    }
                }
                pCurve.ModifyExChange(list);
                pCurve.ReviseCurve();

                for (int i = 0; i < gsample.Samples.Count(); i++)
                {
                    var sample = gsample.Samples[i];
                    if ((sample.Enable) && (sample.AD > 0))
                    {
                        int value = (int)(curve.AD2Value(sample.AD, AD2ValueFlag.Revised) * 100);
                        sample.SampleValue = value;
                    }
                }
            }
        }


        #region 数据库备份检测
        DispatcherTimer backupDbTimer;
        DateTime startupTime;
        DateTime lastTipBackupTime;

        void BackupDbCheckInit()
        {
            startupTime = DateTime.Now;
            lastTipBackupTime = startupTime;
            //定时检查提示
            backupDbTimer = new DispatcherTimer();
            backupDbTimer.Interval = TimeSpan.FromHours(1);
            backupDbTimer.Tick += BackupDbTimer_Tick;
            backupDbTimer.Start();
        }


        private void BackupDbTimer_Tick(object sender, EventArgs e)
        {
            //只有在9:00 到 21:00 才会检查，避免深夜出问题
            DateTime now = DateTime.Now;
            if (now.Hour < 9 || now.Hour > 20)
                return;

            if (now - startupTime < TimeSpan.FromDays(93))
                return;//超过3个月，才能提示

            if (now.Day == lastTipBackupTime.Day)
                return;//一天只提醒一次

            lastTipBackupTime = DateTime.Now;
            //已经连续开机1个月，需要重新启动程序, 
            warning.Add(ERRNOs.ERRNO_DB_BACKUP);
        }
        #endregion


        #region ITDGageService

        public void StartP1()
        {
            gmScan.Start();
        }

        public void StartP2(STARTP2_MODE mode)
        {
            StartP2(mode, 0);
        }
        public void StartP2(STARTP2_MODE mode, int targetpos)
        {
            switch (mode)
            {
                case STARTP2_MODE.ORG:
                    gmOrg.Start();
                    break;
                case STARTP2_MODE.STOP:
                    gmStop.Start();
                    break;
                case STARTP2_MODE.FORW:
                case STARTP2_MODE.FORW_UNTIL_STOP:
                    gmForw.Start();
                    break;
                case STARTP2_MODE.BACKW:
                case STARTP2_MODE.BACKW_UNTIL_STOP:
                    gmBackw.Start();
                    break;
                case STARTP2_MODE.RUNTO:
                    gmRunto.Start(targetpos);
                    break;
            }
        }


        #endregion

        #region IThkGaugeService
        /// <summary>
        /// 扫描
        /// </summary>
        public void Scan()
        {
            StartP1();
        }

        /// <summary>
        /// 停止
        /// </summary>
        public void Stop()
        {
            StartP2(STARTP2_MODE.STOP);
        }

        /// <summary>
        /// 归零
        /// </summary>
        public void Home()
        {
            StartP2(STARTP2_MODE.ORG);
        }

        /// <summary>
        /// 前进
        /// </summary>
        public void Forward()
        {
            StartP2(STARTP2_MODE.FORW);
        }

        /// <summary>
        /// 后退
        /// </summary>
        public void Backward()
        {
            StartP2(STARTP2_MODE.BACKW);
        }
        /// <summary>
        /// 运行到targetPos
        /// </summary>
        public void Runto(int targetpos) 
        {
            StartP2(STARTP2_MODE.RUNTO, targetpos);
        }

        /// <summary>
        /// 一直前进
        /// </summary>
        public void ForwUntilStop()
        {
            StartP2(STARTP2_MODE.FORW_UNTIL_STOP);
        }

        /// <summary>
        /// 一直后退
        /// </summary>
        public void BackwUntilStop()
        {
            StartP2(STARTP2_MODE.BACKW_UNTIL_STOP);
        }
        #endregion
    }
}
