using FLY.Thick.Base.Common;
using FLY.Thick.Base.Server;
using FLY.Thick.FilmCasting.Common;
using FLY.Thick.FilmCasting.IService;
using FLY.Thick.FilmCasting.Server.Model;
using FlyADBase;
using Misc;
using System;
using System.Linq;
using System.Windows.Threading;

namespace FLY.Thick.FilmCasting.Server
{
    public class GM_Scan : GM_Base, IScanService
    {
        const int MARKNO_PROFILE_ADD = 87;
        const int MARKNO_PROFILE_CHANGED = 88;

        BoltMapFilmCasting boltmap;
        BorderSearch borderSearch;
        Reject reject;
        DynArea dynArea;

        AD2ThkHandler Ad2Thk;
        FilmPositionDetect filmPositionDetect;
        FilmCastingProfileParam profileParam;

        HistoryDb historyDB;
        BulkDb bulkDB;
        GSample gsample;
        InitParam initParam;

        ScanMotion scanMotion;
        OBJComponents.Server.WarningSystem2 warningSystem;

        /// <summary>
        /// 需要手动复位纵向位置m
        /// </summary>
        bool IsResetFilmPositionByManual;
        /// <summary>
        /// 喂狗模式， 必须5秒内喂一次，不然扫描就停止
        /// </summary>
        bool IsFeedMode;
        /// <summary>
        /// 喂狗模式 定时器
        /// </summary>
        DispatcherTimer feed_timer;
        /// <summary>
        /// 喂狗 饲料， =0, 就会停止扫描
        /// </summary>
        int FeedFodder;

        public GM_Scan()
        {
            GMState = CTRL_STATE.SCAN;
            scanMotion = new ScanMotion();

            feed_timer = new DispatcherTimer();
            feed_timer.Interval = TimeSpan.FromSeconds(1);
            feed_timer.Tick += (s, e) =>
            {
                if (!IsFeedMode) {
                    //不是喂狗模式
                    feed_timer.Stop();
                }
                if (!IsRunning) {
                    //已经提前停止了
                    feed_timer.Stop();
                }
                FeedFodder--;
                if (FeedFodder <= 0) {
                    feed_timer.Stop();
                    Stop();
                }
            };
        }

        public void Init(
            FlyAD7 flyAd,
            GSample gsample, InitParam initParam, OBJComponents.Server.WarningSystem2 warningSystem,
            BoltMapFilmCasting boltmap, BorderSearch bordersearch, Reject reject,
            DynArea dynarea, AD2ThkHandler ad2thk,
            FilmCastingProfileParam profileParam, FilmPositionDetect filmPositionDetect,
            HistoryDb historyDB, BulkDb bulkDB
            )
        {
            base.Init(flyAd);

            this.gsample = gsample;
            this.initParam = initParam;
            this.warningSystem = warningSystem;

            this.boltmap = boltmap;
            this.borderSearch = bordersearch;
            this.reject = reject;

            this.dynArea = dynarea;
            this.Ad2Thk = ad2thk;

            this.profileParam = profileParam;
            this.filmPositionDetect = filmPositionDetect;

            this.historyDB = historyDB;
            this.bulkDB = bulkDB;

            scanMotion.Init(flyAd, gsample, initParam, warningSystem);
        }


        void DataEndEvent(object sender, MiniGridEventArgs e)
        {
            DIRECTION direction = e.direction;
            DateTime now = DateTime.Now;

            int posOfGrid = e.posOfGrid;
            int start_grid = e.grid_start;
            int start_pos = e.grid_start * e.posOfGrid;

            int[] dat = e.buf;
            bulkDB.SetTempFrame(now, now, 0, null);

            boltmap.InitBoltAD();

            //if (gsample.Enable) 必须有样品，之前已经检查过！！！
            if (!gsample.OK())
                return;//样品还没获取成功

            if (!dynArea.IsTest && borderSearch.Enable)
            {
                //找边界
                if (!borderSearch.FindFilm(direction, posOfGrid, start_grid, dat))//不能找到边界!
                {
                    borderSearch.Reset();
                    boltmap.InitExChange();
                }

                //设置扫描范围
                //POLLSCAN----------------------------------------	
                Range scanr = borderSearch.GetScanRange();//获取边界查找需要的扫描范围

                //更新扫描范围
                scanMotion.ScanRange = scanr.ToStruct();

                Range border = borderSearch.GetBorder(direction);//返回X光测量 膜的斜波中间位置

                boltmap.CalExChange(direction, border);

                if (!border.IsValid)
                {
                    return;//不能找到膜
                }
            }
            //----------------------------------------------------
            //FRAME
            int len = dat.Length;
            double[] _temp_thks = new double[len];//减少数据量, 降低噪声，避免剔除时，把噪声剔除。剔除的目前只是为了剔走基材，不是为了滤波


            //AD值转厚度值
            for (int i = 0; i < len; i++)
            {
                _temp_thks[i] = Ad2Thk(dat[i]);
            }

            //基材剔除
            reject.DoFrameFilter(profileParam.Target, posOfGrid, start_grid, _temp_thks);

            //分区 变为1cm一个数据
            double[] m_boltmap_thk = boltmap.Map(direction, start_pos, posOfGrid, _temp_thks);


            //把数据范围外删除
            int dataBeginIdx = profileParam.DataRange.Begin;
            int dataEndIdx = profileParam.DataRange.End;

            for (int i = 0; i < dataBeginIdx; i++)
                m_boltmap_thk[i] = double.NaN;

            for (int i = dataEndIdx; i < m_boltmap_thk.Length; i++)
                m_boltmap_thk[i] = double.NaN;

            double[] thicks = m_boltmap_thk;

            //当整幅都没有数据，不保存！！！
            if (thicks.All(d => double.IsNaN(d)))
                return;



            #region sqlite3 历史数据保存
            //----------------------------------------------------------------
            //sqlite3 历史数据保存
            //----------------------------------------------------------------
            //下辊检测
            if (historyDB.localDb.IsProfileFinished)
            {
                AddProfile();
            }

            for (int i = 0; i < thicks.Count(); i++) {
                if (!double.IsNaN(thicks[i]))
                    thicks[i] = Math.Round(thicks[i], 2);
            }

            var sampleAds = from sc in gsample.Samples where sc.Enable select sc.AD;


            historyDB.AddScanData(
                new Lc_ScanData()
                {
                    Time = scanMotion.StartDataEndTime,
                    EndTime = now,
                    Target = profileParam.Target,
                    TolerancePercent = profileParam.TolerancePercent,
                    K = profileParam.K,
                    B = profileParam.B,
                    FilmVelocity = Math.Round(dynArea.FilmVelocity, 1),
                    FilmPosition = Math.Round(dynArea.FilmPosition, 2),
                    FilmWidth = Math.Round(dynArea.Width, 0),
                    Thicks = thicks,
                    SampleADs = sampleAds.ToArray()
                });

            #endregion
        }


        void DataPosEvent(object obj, MiniGridEventArgs e)
        {

            Misc.DIRECTION direction = e.direction;

            int posOfGrid = e.posOfGrid;
            int start_grid = e.grid_start;
            int start_pos = e.grid_start * e.posOfGrid;

            int[] data = e.buf;

            dynArea.AD = data[0];

            //2.转为thick
            double[] dataValue = data.Select(i => Ad2Thk(i)).ToArray();
            //3.动态分区
            if (boltmap.UpdateBoltValue(dataValue, start_pos, posOfGrid, direction, out int start_boltIndex, out double[] boltThick))
            {
                dynArea.Thk = boltThick[0];
                bulkDB.SetTempFrame(scanMotion.StartDataEndTime, DateTime.Now, start_boltIndex, boltThick);
            }
        }


        void StartCore() 
        {
            if (IsRunning)
                return;

            base.Start();

            if (IsRunning == false)
            {
                warningSystem.Add(
                    ERRNOs.Instance.SCAN_ERRNO_FATAL.Code,
                    ERRNOs.Instance.SCAN_ERRNO_FATAL.Descrption + " :AD卡连接断开");
                return;
            }
            //设置扫描范围
            int beginPos = 0, endPos = initParam.PosLength;

            if (!borderSearch.Enable && !dynArea.IsTest)
            {
                warningSystem.Add(
                    ERRNOs.Instance.SCAN_ERRNO_FATAL.Code,
                    ERRNOs.Instance.SCAN_ERRNO_FATAL.Descrption + " :边界查找未启动");
                return;
            }


            borderSearch.Reset();
            borderSearch.GetScanRange(out beginPos, out endPos);


            if (beginPos < 0)
                beginPos = 0;

            if (endPos > initParam.PosLength)
                endPos = initParam.PosLength;


            boltmap.InitBoltAD();



            var now = DateTime.Now;
            //清空临时数据
            bulkDB.SetTempFrame(now, now, 0, null);

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

            scanMotion.DataEndEvent += DataEndEvent;
            scanMotion.DataPosEvent += DataPosEvent;
            if (!scanMotion.Start(beginPos, endPos))
            {
                Stop();
                return;
            }

            if (IsFeedMode) {
                Feed();
                feed_timer.Start();
            }
        }
        /// <summary>
        /// 正常
        /// </summary>
        public override void Start()
        {
            IsResetFilmPositionByManual = false;
            IsFeedMode = false;
            StartCore();
        }
        #region sqlite3 历史数据保存
        string[] profile_propertynames_add = new string[]{
                nameof(FilmCastingProfileParam.PName),
                nameof(FilmCastingProfileParam.Batch),
                nameof(FilmCastingProfileParam.Number)
            };
        string[] profile_propertynames_update = new string[]{
                nameof(FilmCastingProfileParam.Target),
                nameof(FilmCastingProfileParam.TolerancePercent),
                nameof(FilmCastingProfileParam.ScanRange)
            };
        void CheckProfile()
        {
            if (historyDB.localDb.IsProfileFinished)
            {
                AddProfile();
            }
            else
            {
                if (historyDB.localDb.CurrProfile != null)
                {
                    Db_Profile dB_Profile = historyDB.localDb.CurrProfile;
                    if ((dB_Profile.PName != profileParam.PName) ||
                    (dB_Profile.Batch != profileParam.Batch) ||
                    (dB_Profile.Number != profileParam.Number))
                    {
                        //任何一个不一致
                        AddProfile();
                    }
                    else
                    {
                        //继续上一次生产！！！！
                        UpdateProfile();
                    }
                }
                else
                {
                    //异常
                    AddProfile();
                }
            }
        }

        void AddProfile()
        {
            //复位 膜纵向位置
            if(!IsResetFilmPositionByManual)
                filmPositionDetect.Reset(0);

            historyDB.AddProfile(new Db_Profile()
            {
                PName = profileParam.PName,
                Batch = profileParam.Batch,
                Number = profileParam.Number,
                Target = profileParam.Target,
                TolerancePercent = profileParam.TolerancePercent,
                StartTime = scanMotion.StartDataEndTime,
                EndTime = DateTime.Now,
                ScanBegin = profileParam.ScanRange.Begin,
                ScanEnd = profileParam.ScanRange.End
            });
        }
        void UpdateProfile()
        {
            historyDB.UpdateProfile(new Db_Profile()
            {
                PName = profileParam.PName,
                Batch = profileParam.Batch,
                Number = profileParam.Number,
                Target = profileParam.Target,
                TolerancePercent = profileParam.TolerancePercent,
                ScanBegin = profileParam.ScanRange.Begin,
                ScanEnd = profileParam.ScanRange.End
            });
        }
        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

        public override void Stop()
        {
            feed_timer.Stop();

            scanMotion.DataEndEvent -= DataEndEvent;
            scanMotion.DataPosEvent -= DataPosEvent;

            scanMotion.Stop();
            #region sqlite3 历史数据保存
            profileParam.PropertyChanged -= MProfileParam_PropertyChanged;
            #endregion
            base.Stop();
        }
        protected override void OnPoll()
        {
            bool isError = false;
            if (scanMotion.OnPoll())
            {
                isError = true;
            }
            if (isError)
                Stop();
        }


        public void ResetFilmPosition()
        {
            filmPositionDetect.Reset(0);
        }

        
        public void StartWithNoReset()
        {
            IsResetFilmPositionByManual = true;
            IsFeedMode = true;
            StartCore();
        }
        
        public void Feed() 
        {
            FeedFodder = 5;
        }
    }
}
