using FLY.Thick.Blowing.IService;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FLY.Thick.Blowing.UI.Fix.Client
{
    public class CalFilmLen : INotifyPropertyChanged
    {

        #region 状态
        /// <summary>
        /// 信息
        /// </summary>
        public string Msg { get; private set; }

        /// <summary>
        /// 下载中
        /// </summary>
        public bool IsDownloading { get; private set; }

        /// <summary>
        /// 数据准备好了
        /// </summary>
        public bool IsDataReady { get; private set; }

        /// <summary>
        /// 计算中
        /// </summary>
        public bool IsCaling { get; private set; }

        /// <summary>
        /// 有足够的数据,可以下载
        /// </summary>
        public bool IsCanDownload { get; private set; }

        /// <summary>
        /// 当前数据总分钟数 min
        /// </summary>
        public int DataMaxMinute { get; private set; }
        /// <summary>
        /// 必须获取的最少数据量 min
        /// </summary>
        public int DataMinMinute { get; private set; }

        /// <summary>
        /// 最佳获取数据量 min
        /// </summary>
        public int DataBestMinute { get; private set; }
        #endregion

        #region 参数
        /// <summary>
        /// 第1牵引速度
        /// </summary>
        public double Velocity1 { get; private set; }
        
        /// <summary>
        /// 速度滤波 单位s
        /// </summary>
        public int VelocityFilter { get; private set; } = 1;

        /// <summary>
        /// 膜距离
        /// </summary>
        public double FilmLength { get; private set; }
        #endregion

        IBlowingFixService mCurrBlowing;
        IBlowingDetect mCurrRDetect;
        BlowingDetectCore mRDetectCore;

        List<ADCell> mADList = new List<ADCell>();
        List<LimitCell> mLimitList = new List<LimitCell>();
        List<RollCell> mRollList = new List<RollCell>();

#region 画图
        public List<TimeValue> LimitValues { get; } = new List<TimeValue>();

        public List<TimeValue> VelocityValues { get; } = new List<TimeValue>();

        public List<TimeValue> ThicknessValues { get; } = new List<TimeValue>();
        public List<TimeValue> FilmLength3DValues { get; } = new List<TimeValue>();

        [PropertyChanged.DoNotCheckEquality]
        public List<double> CurrFilmLength3D { get; set; } = new List<double>();

        [PropertyChanged.DoNotCheckEquality]
        public List<double> NewFilmLength3D { get; set; } = new List<double>();

        public class Frame
        {
            /// <summary>
            /// 厚度
            /// </summary>
            public double[] Thicks;
            /// <summary>
            /// 旋转方向
            /// </summary>
            public Misc.DIRECTION Direction;
            /// <summary>
            /// 旋转次数
            /// </summary>
            public int RotationCnt;
            /// <summary>
            /// 与上一幅图的相关性
            /// </summary>
            public double R;
            /// <summary>
            /// 大于30%数据 非 NaN
            /// </summary>
            public bool IsVaild;
        }
        [PropertyChanged.DoNotCheckEquality]
        public List<Frame> Frames { get; set; } = new List<Frame>();
#endregion

        int NBolts;
        int OrgBoltNo;

        DateTime dataBegin;
        /// <summary>
        /// 最小旋转次数
        /// </summary>
        const int minRotationCnt = 2;
        public CalFilmLen()
        {
            mRDetectCore = new BlowingDetectCore();
        }

        public void Init(IBlowingFixService mRenZiJiaFix, IBlowingDetect mRDetect)
        {
            this.mCurrBlowing = mRenZiJiaFix;
            this.mCurrRDetect = mRDetect;

            this.FilmLength = mRDetect.FilmLength;

            Misc.BindingOperations.SetBinding(mCurrRDetect, "BufTotalTime", () =>
            {
                DataMaxMinute = (int)(mCurrRDetect.BufTotalTime.TotalMinutes);
            });

            Misc.BindingOperations.SetBinding(mCurrRDetect, "RotationCnt", () =>
            {
                if (mRDetect.RotationCnt < minRotationCnt)
                {
                    IsCanDownload = false;
                }
                else
                {
                    IsCanDownload = true;
                }
            });

            Misc.BindingOperations.SetBinding(mCurrRDetect, "RenZiJiaPeriod", () =>
            {
                DataMinMinute = (int)(mRDetect.RenZiJiaPeriod.TotalMinutes * (minRotationCnt - 1));
                DataBestMinute = (int)Math.Round((mRDetect.RenZiJiaPeriod.TotalMinutes * 3));
            });



        }



        public bool DownloadData(int getDataMinute)
        {
            //应该在界面 检测错误原因
            if (IsDownloading)
                return false;

            if (IsCaling)
                return false;
            TimeSpan getBufTime = TimeSpan.FromMinutes(getDataMinute);
            if ( getBufTime > mCurrRDetect.BufTotalTime)
                return false;

            dataBegin = DateTime.Now - getBufTime;
            IsDownloading = true;
            IsDataReady = false;

            
            DownloadData_limit();
            return true;
        }
        void DownloadData_limit()
        {
            Msg = $"下载 转向信号数据 [{dataBegin} - Now]....";
            mCurrRDetect.GetLimitList(dataBegin, (object AsyncState, object retData) =>
            {
                Action act = AsyncState as Action;
                var p = retData as GetLimitListReponse;
                if ((p.datas == null) || p.datas.Count() < 2)
                {
                    Msg = $"数据下载异常, 转向信号数量<2";
                    IsDownloading = false;
                    return;
                }
                mLimitList = p.datas;


                DownloadData_roll();

            },null);
        }
        void DownloadData_roll()
        {
            Msg = $"下载 辊信号数据 [{dataBegin} - Now]....";
            mCurrRDetect.GetRollList(dataBegin,
            (object AsyncState, object retData) => {
                var p = retData as GetRollListReponse;
                if ((p.datas == null) || p.datas.Count() < 10)
                {
                    Msg = "数据下载异常, 辊信号数量 < 10";
                    IsDownloading = false;
                    return;
                }
                mRollList = p.datas;

                
                DownloadData_ad();
            }, null );
        }
        void DownloadData_ad()
        {
            Msg = $"下载 厚度数据 [{dataBegin} - Now]....";
            mCurrBlowing.GetADList(dataBegin,
            (object AsyncState, object retData) => {
                var p = retData as GetADListReponse;
                if ((p.datas == null) || p.datas.Count() < 10)
                {
                    Msg = "数据下载异常, 厚度数据数量 < 10";
                    IsDownloading = false;
                    return;
                }

                mADList = p.datas.Select(
                    a => new ADCell() {
                        Ad = a.thick,
                        Time = a.dt }
                    ).ToList();
                if (mCurrRDetect.Is3D)
                    DownloadData_CurrFilmLength3D();
                else
                    DownloadData_OK();
            }, null);
        }
        void DownloadData_CurrFilmLength3D()
        {
            Msg = $"下载 膜距离增量数据 [{dataBegin} - Now]....";
            mCurrRDetect.GetFilmLength3D(
                (object AsyncState, object retData) => {
                    var p = retData as GetFilmLength3DReponse;

                    CurrFilmLength3D = p.datas;

                    DownloadData_OK();

                }, null);
        }
        void DownloadData_OK()
        {
            NBolts = mCurrBlowing.NBolts;
            OrgBoltNo = mCurrBlowing.OrgBoltNo;
            if (OrgBoltNo < 1)
                OrgBoltNo = 1;

            mRDetectCore.Init(
                mCurrRDetect.RAngle,
                mCurrRDetect.RollPerimeter,
                mCurrRDetect.RenZiJiaPeriod,
                mCurrRDetect.FilmLength,
                mCurrRDetect.Is3D,
                mRollList,
                mLimitList,
                CurrFilmLength3D);

            UpdateLimitValues();
            UpdateThicknessValues();
            UpdateVelocityValues(VelocityFilter);

            UpdateADList();
            UpdateFrames();

            Msg = "数据下载完成";
            IsDownloading = false;
            IsDataReady = true;
        }

        public void UpdateVelocityValues(int velocity_filter)
        {
            VelocityFilter = velocity_filter;
            var filter_half =  TimeSpan.FromSeconds(VelocityFilter / 2);

            VelocityValues.Clear();
            
            for (int i = 0; i < mRollList.Count(); i++)
            {
                var dt_min = mRollList[i].dt - filter_half;
                var dt_max = mRollList[i].dt + filter_half;

                int i_begin = 0;
                int i_end = mRollList.Count()-1;

                for (int j = i; j >= 0; j--)
                {
                    if (mRollList[j].dt <= dt_min)
                    {
                        //找到了 
                        i_begin = j;
                        break;
                    }
                }

                for (int j = i; j < mRollList.Count(); j++)
                {
                    if (mRollList[j].dt >= dt_max)
                    {
                        //找到了 
                        i_end = j;
                        break;
                    }
                }

                if (i_begin == i_end)
                {
                    i_begin = i;
                    i_end = i + 1;
                    if (i_end >= mRollList.Count())
                    {
                        i_begin = i - 1;
                        i_end = i;
                    }
                }

                TimeSpan ts = mRollList[i_end].dt - mRollList[i_begin].dt;
                double minute = 1.0 * ts.Ticks / TimeSpan.TicksPerMinute;
                double v = (i_end - i_begin)*mCurrRDetect.RollPerimeter / 1000 / minute;
                VelocityValues.Add(
                    new TimeValue()
                    {
                        Time = mRollList[i].dt,
                        Value = v
                    });
            }
            OnPropertyChanged("VelocityValues");

            Velocity1 = VelocityValues.Average(tv => tv.Value);
            if (mCurrRDetect.Is3D)
                UpdateFilmLength3D(Velocity1);

        }
        public void UpdateFilmLength3D(double velocity1)
        {
            Velocity1 = velocity1;

            FilmLength3DValues.Clear();
            double sum = 0;
            FilmLength3DValues.Add(
                new TimeValue()
                {
                    Time = VelocityValues[0].Time,
                    Value = sum
                });
            for (int i = 1; i < VelocityValues.Count(); i++)
            {
                var ts = VelocityValues[i].Time - VelocityValues[i - 1].Time;
                double minute = 1.0* ts.Ticks / TimeSpan.TicksPerMinute;

                sum += ((VelocityValues[i].Value + VelocityValues[i - 1].Value) / 2 - Velocity1) * minute;
                FilmLength3DValues.Add(
                    new TimeValue()
                    {
                        Time = VelocityValues[i].Time,
                        Value = sum
                    });
            }
            double min_f = FilmLength3DValues.Min(tv => tv.Value);
            foreach (var tv in FilmLength3DValues)
                tv.Value -= min_f;

            OnPropertyChanged("FilmLength3DValues");

            UpdateNewFilmLength3D();
        }
        void UpdateThicknessValues()
        {
            ThicknessValues.Clear();
            foreach (var adcell in mADList)
            {
                ThicknessValues.Add(
                    new TimeValue() {
                        Time = adcell.Time,
                        Value = Misc.MyBase.ISVALIDATA(adcell.Ad)?
                        adcell.Ad / 100.0:double.NaN });
            }
            OnPropertyChanged("ThicknessValues");
        }
        void UpdateLimitValues()
        {
            LimitValues.Clear();
            foreach (var limit in mLimitList)
            {
                DateTime dt = limit.dt_begin;
                if (dt == DateTime.MinValue)
                    dt = limit.dt_end;

                LimitValues.Add(new TimeValue() { Time = dt, Value = limit.no });
            }
            OnPropertyChanged("LimitValues");
        }


        void UpdateADList()
        {
            for (int i = 0; i < mADList.Count(); i++)
            {
                ADCell c = mADList[i];
                if(i==143)
                {


                }
                int ret = mRDetectCore.GetFilmInfo(
                    out BlowingDetectCore.FilmInfo filminfo,
                    mADList[i].Time);
                if (ret > 0 )//发生在辊信号的未来,把数据删除!!!!
                {
                    //异常
                    mADList.RemoveRange(i, mADList.Count() - i);
                    return;
                }
                if (filminfo.rotationCnt == 1)
                {

                }
                else if (filminfo.rotationCnt != 1)
                {

                }
                if (filminfo.inCV)
                {

                }
                //计算相关性,只使用 膜边=0mm 模式
                c.Direction = filminfo.direction;
                c.Angles.Clear();
                c.Angles.Add(filminfo.angle);
                c.RotationCnt = filminfo.rotationCnt;
                c.Velocity = filminfo.filmVelocity;
                c.InCV = filminfo.inCV;
                
            }
        }


        void UpdateNewFilmLength3D()
        {
            int n = 100;
            List< IEnumerable<double>> fs = new List<IEnumerable<double>>();

            for (int i = 0; i < mLimitList.Count()-1; i++)
            {
                int no = mLimitList[i].no;
                DateTime begin_dt = mLimitList[i].dt_end;
                DateTime end_dt = mLimitList[i+1].dt_begin;
                if ((begin_dt == DateTime.MinValue) || (end_dt == DateTime.MinValue))
                {
                    //异常
                    continue;
                }

                var filmlength3d = FilmLength3DValues.Where(tv => tv.Time >= begin_dt && tv.Time <= end_dt);
                
                double[] f = new double[n];
                int k = 0;
                for (int j = 0; j < f.Count(); j++)
                {
                    DateTime dt = begin_dt + TimeSpan.FromTicks(j * (end_dt - begin_dt).Ticks / f.Count());
                    bool hadFind = false;
                    for (; k < filmlength3d.Count(); k++)
                    {
                        if (filmlength3d.ElementAt(k).Time >= dt)
                        {
                            //找到了
                            f[j] = filmlength3d.ElementAt(k).Value;
                            hadFind = true;
                            break;
                        }
                    }
                    if (!hadFind)//找不到
                    {
                        if (j > 0)
                            f[j] = f[j - 1];
                    }
                }

                if (no == 0)
                    fs.Add(f);
                else
                    fs.Add(f.Reverse());
            }
            //求均值
            List<double> newfilmlength3d = new List<double>();
            for (int i = 0; i < fs.First().Count(); i++)
            {
                double sum = 0;
                for (int j = 0; j < fs.Count(); j++)
                {
                    sum += fs[j].ElementAt(i);
                }
                newfilmlength3d.Add(sum / fs.Count());
            }
            NewFilmLength3D = newfilmlength3d;
        }

        public void SetFilmLength3D()
        {
            CurrFilmLength3D = NewFilmLength3D;
            mRDetectCore.mFilmLength3D = CurrFilmLength3D;
            if (mRDetectCore.Is3D)
            {
                UpdateFrames();
            }

            mCurrRDetect.SetFilmLength3D(NewFilmLength3D);
            FLY.ControlLibrary.Window_Tip.Show(
                "应用成功",
                $"立体式旋转 膜距离增量设置成功",
                TimeSpan.FromSeconds(2));
        }
        public void SetFilmLength(double filmLength)
        {
            FilmLength = filmLength;
            mRDetectCore.FilmLength = filmLength;
            UpdateADList();
            UpdateFrames();
        }
        void UpdateFrames()
        {
            Frames = GetFrames();
        }
        List<Frame> GetFrames()
        {
            List<Frame> frames = new List<Frame>();
            int boltIndex = -1;
            List<int> datas = new List<int>();

            int roationCnt = -1;
            Frame frame = null;

            foreach (ADCell c in mADList)
            {
                int bi = (int)(NBolts * c.Angles[0] / 360);
                if (bi < 0) bi = 0;
                else if (bi >= NBolts) bi = NBolts - 1;


                int boltno = bi + OrgBoltNo;
                if (boltno > NBolts)
                    boltno -= NBolts;

                //添加到
                if ((c.InCV == true) &&
                    ((roationCnt == -1) || (roationCnt != c.RotationCnt))
                    )
                {
                    roationCnt = c.RotationCnt;

                    frame = new Frame();
                    frame.RotationCnt = roationCnt;
                    frame.Direction = c.Direction;
                    frame.Thicks = new double[NBolts];
                    for (int j = 0; j < frame.Thicks.Count(); j++)
                        frame.Thicks[j] = double.NaN;

                    frames.Add(frame);
                    boltIndex = -1;
                }

                if ((boltIndex == -1) || (boltIndex != boltno - 1))
                {
                    datas.Clear();
                }

                datas.Add(c.Ad);
                boltIndex = boltno - 1;
                int avg = Misc.MyMath.Avg(datas);
                if (Misc.MyBase.ISVALIDATA(avg))
                    frame.Thicks[boltIndex] = avg / 100.0;

                
            }
            for (int i = 1; i < frames.Count; i++)
            {
                frames[i].IsVaild = 1.0 * frames[i].Thicks.Count(t => !double.IsNaN(t)) / frames[i].Thicks.Count() > 0.3;
                if (frames[i].IsVaild)
                {
                    //计算相关性
                    frames[i].R = Misc.MyMath.Correl(frames[i].Thicks, frames[i - 1].Thicks);
                }

            }
            return frames;
        }


        bool TestFilmLength(double filmlength, ref double max_r, ref double best_filmlength, out double r)
        {
            bool ret = false;
            mRDetectCore.FilmLength = filmlength;
            UpdateADList();
            var frames = GetFrames();
            r = frames.Max(f => f.R);
            if (r > max_r)
            {
                max_r = r;
                best_filmlength = mRDetectCore.FilmLength;
                ret = true;
            }

            
            return ret;
        }

        public async void Cal(double begin_filmlength, double end_filmlength)
        {
            if (mRDetectCore.RotationCnt < 3)
            {
                Msg = "---警告--- 没法自动计算,旋转次数少于3次";
                return;
            }
            if (begin_filmlength < 3)
                begin_filmlength = 3;

            if (end_filmlength > 50)
                end_filmlength = 50;

            IsCaling = true;

            double max_r=0;
            double best_filmlength=FilmLength;

            await Task.Factory.StartNew(() =>
            {
                for (double i = begin_filmlength; i < end_filmlength; i+=0.1)
                {
                    TestFilmLength(i, ref max_r, ref best_filmlength, out double r);
                    int progress = (int)((i - begin_filmlength) / (end_filmlength - begin_filmlength) * 100);
                    Msg = $"{progress:000}/100 {i:F1}m R={r:F3}  最合理[{best_filmlength:F1}m MaxR={max_r:F3}]";
                }
            });

            SetFilmLength(best_filmlength);
            Msg = $"最合理[{best_filmlength:F1}m MaxR={max_r:F3}]";
            IsCaling = false;
        }

        //public void Start()
        //{
        //    if (step == 0)
        //    {
        //        step = 1;
        //        dt_onpoll = DateTime.MinValue;
        //        RotationCnt = 3;
        //        TimeOfMin = DateTime.MinValue;
        //        TimeOfMax = DateTime.MinValue;
        //        mADList.Clear();
        //        OnPoll();
        //    }
        //}
        //bool Poll()
        //{
        //    switch (step)
        //    {
        //        case 1:
        //            {
        //                if (Step01())
        //                {
        //                    step = 2;
        //                    return true;
        //                }
        //            }
        //            break;
        //        case 2:
        //            {
        //                if (Step02())
        //                {
        //                    step = 3;
        //                    return true;
        //                }
        //            }
        //            break;
        //        case 3:
        //            {
        //                if (Step03())//已经成功获取了时间
        //                {
        //                    step = 4;
        //                    return true;
        //                }
        //                else
        //                {
        //                    if (TimeOfMin == DateTime.MinValue)
        //                    {
        //                        step = 2;
        //                    }
        //                }
        //            }
        //            break;
        //        case 4:
        //            {
        //                Step04();
        //                step = 5;
        //            }
        //            break;
        //    }
        //    return false;
        //}

        //DateTime dt_onpoll = DateTime.MinValue;

        public event PropertyChangedEventHandler PropertyChanged;

        ///// <summary>
        ///// 每次获取完所有angle,执行,每20秒触发一次
        ///// </summary>
        //public void OnPoll()
        //{
        //    DateTime now = DateTime.Now;
        //    if ((dt_onpoll != DateTime.MinValue) && ((now - dt_onpoll) < TimeSpan.FromSeconds(30)))
        //        return;

        //    dt_onpoll = now;
        //    while (Poll()) ;
        //}

        //bool Step01()
        //{
        //    //下载数据
        //    if (mCurrRDetect.RotationCnt < 3)
        //    {
        //        RotationCnt = 3;
        //        State = "RotationCnt=3 Wait";
        //        return true;
        //    }
        //    RotationCnt = mCurrBlowing.mPDetect.RotationCnt;
        //    return true;
        //}
        ///// <summary>
        ///// 确保三个rotationcnt 都存在
        ///// </summary>
        ///// <returns></returns>
        //bool Step02()
        //{
        //    if (RotationCnt > mCurrBlowing.mPDetect.RotationCnt)
        //    {
        //        State = "RotationCnt=" +
        //            RotationCnt.ToString() + ">" + mCurrBlowing.mPDetect.RotationCnt.ToString() + " Wait";

        //        return false;
        //    }

        //    DateTime min_time;
        //    DateTime max_time;
        //    double min_fl = MinFilmLength;
        //    double max_fl = MaxFilmLength;

        //    BlowingDetect.GetLimitTimeResult r1 =
        //        mCurrBlowing.mPDetect.GetLimitTime(
        //        RotationCnt - 2,
        //        min_fl,
        //        out min_time);

        //    BlowingDetect.GetLimitTimeResult r2 =
        //        mCurrBlowing.mPDetect.GetLimitTime(
        //        RotationCnt,
        //        max_fl,
        //        out max_time);

        //    string state = "[min_fl=" + min_fl.ToString() + "m (" + min_time.ToLongTimeString() + ") " + r1.ToString() + "]," +
        //    "[max_fl=" + max_fl.ToString() + "m (" + max_time.ToLongTimeString() + ") " + r2.ToString() + "] ";


        //    if ((r1 == BlowingDetect.GetLimitTimeResult.NOEXIST) ||
        //        (r2 == BlowingDetect.GetLimitTimeResult.NOEXIST))
        //    {
        //        //不可能存在的错误
        //        RotationCnt++;
        //        state += "Wait 不可能存在的错误 NOEXIST, RotationCnt=" + RotationCnt.ToString();
        //        State = state;
        //        return false;
        //    }
        //    else if ((r1 == BlowingDetect.GetLimitTimeResult.ISFURTURE) ||
        //        (r2 == BlowingDetect.GetLimitTimeResult.ISFURTURE))
        //    {
        //        //就是它,等!!!!

        //        state += "Wait ,it is the one!!!!";
        //        State = state;
        //        return false;
        //    }
        //    else if ((r1 != BlowingDetect.GetLimitTimeResult.OK) ||
        //        (r2 != BlowingDetect.GetLimitTimeResult.OK))
        //    {
        //        //不可能存在的错误
        //        RotationCnt++;
        //        state += "Wait 不可能存在的错误 ?????, RotationCnt=" + RotationCnt.ToString();
        //        State = state;
        //        return false;
        //    }
        //    TimeOfMin = min_time;
        //    TimeOfMax = max_time;
        //    return true;
        //}

        //bool Step03()
        //{
        //    int copy_index_b = -1;
        //    int copy_index_e = -1;
        //    int ret = mCurrBlowing.ADListFastSearchIndex(TimeOfMin, out copy_index_b);
        //    string state;
        //    state = "TimeOfMin(" + TimeOfMin.ToLongTimeString() + ") (" + copy_index_b.ToString() + ") ";

        //    if (ret == -1)//发生在过去
        //    {
        //        state += " PAST";
        //        State = state;

        //        RotationCnt++;
        //        TimeOfMin = DateTime.MinValue;
        //        TimeOfMax = DateTime.MinValue;
        //        return false;
        //    }
        //    else if (ret == 1)//发生在未来
        //    {
        //        state += " FUTURE";
        //        State = state;

        //        return false;
        //    }

        //    ret = mCurrBlowing.ADListFastSearchIndex(TimeOfMax, out copy_index_e);

        //    state += " TimeOfMax(" + TimeOfMax.ToLongTimeString() + ") (" + copy_index_e.ToString() + ")";


        //    if (ret == -1)//发生在过去
        //    {
        //        //异常出错
        //        throw new ArgumentOutOfRangeException("min_time 在列表中, 但max_time在列表前");
        //    }
        //    else if (ret == 1)//发生在未来
        //    {
        //        state += " FUTURE";
        //        return false;
        //    }

        //    //复制所有scaninfolist
        //    for (int i = copy_index_b; i <= copy_index_e; i++)
        //    {
        //        mADList.Add(mCurrBlowing.mADList[i].Clone());
        //    }
        //    //复制 旋转架检测器
        //    mCurrRDetect = mCurrBlowing.mPDetect.Clone();

        //    //数据足够了
        //    state += " READY";
        //    State = state;
        //    return true;
        //}

        //void Step04()
        //{
        //    //立刻计算
        //    Thread t = new Thread(Cal)
        //    {
        //        Priority = ThreadPriority.Lowest,
        //        IsBackground = true
        //    };
        //    t.Start();
        //}
        //void Cal()
        //{
        //    //限位时间点,肯定在缓存区的中间!!!!!
        //    //1.找到限位时间点所在的数据幅
        //    //2.以该点作为对称点,上下3幅计算thicks,再求相似度
        //    double min_fl = MinFilmLength;
        //    double max_fl = MaxFilmLength;
        //    double maxr = -1;
        //    double maxr_fl = -1;
        //    string state;
        //    double curr_r = CalR(FilmLength);

        //    for (double i = min_fl; i <= max_fl; i += 0.1)
        //    {
        //        double r = CalR(i);
        //        if (r > maxr)
        //        {
        //            maxr = r;
        //            maxr_fl = i;
        //        }
        //        state = "Cal";
        //        state += " (" + ((i - min_fl) / (max_fl - min_fl) * 100).ToString("F0") + "/100)";
        //        state += " [" + r.ToString("F3") + "," + i.ToString("N1") + "m]";
        //        state += " MaxR=[" + maxr.ToString("F3") + "," + maxr_fl.ToString("N1") + "m]";
        //        state += " CurrR=[" + curr_r.ToString("F3") + "," + FilmLength.ToString("N1") + "m]";
        //        State = state;
        //    }

        //    MaxR = maxr;
        //    MaxRFilmLength = maxr_fl;
        //    State = "Cal OK";
        //    step = 0;
        //}
        //double CalR(double filmLength)
        //{
        //    mCurrRDetect.FilmLength = filmLength;

        //    for (int i = 0; i < mADList.Count(); i++)
        //    {
        //        ADCell c = mADList[i];
        //        BlowingDetect.FilmInfo filminfo;
        //        int ret = mCurrRDetect.GetFilmInfo(out filminfo, mADList[i].dt, 2.3, 0);
        //        if (ret != 0)
        //        {
        //            //异常
        //            return 0;
        //        }
        //        //计算相关性,只使用 膜边=0mm 模式
        //        c.direction = filminfo.direction;
        //        c.angles.Add(filminfo.angle1);
        //        c.angles.Add(filminfo.angle2);
        //        c.rotationCnt = filminfo.rotationCnt;
        //        c.velocity = filminfo.filmVelocity;
        //        c.inCV = filminfo.inCV;
        //    }

        //    //找到 rotationCnt 为 RotationCnt-2, 与 RotationCnt-1 的数据,进行相似度计算
        //    //直接使用角度划分数据, 360° 
        //    //360个数据太多,使用120个数据

        //    int[] thicks1 = new int[120];
        //    int[] thicks2 = new int[120];
        //    for (int i = 0; i < 120; i++)
        //    {
        //        thicks1[i] = Misc.MyBase.NULL_VALUE;
        //        thicks2[i] = Misc.MyBase.NULL_VALUE;
        //    }

        //    int sum = 0;
        //    int cnt = 0;
        //    //int angle = -1;
        //    int angle_3 = -1;
        //    int rotationcnt = 0;
        //    for (int i = 0; i < mADList.Count(); i++)
        //    {
        //        ADCell c = mADList[i];
        //        if (cnt == 0)
        //        {
        //            if (Misc.MyBase.ISVALIDATA(c.ad))
        //            {
        //                sum += c.ad;
        //                cnt++;
        //            }

        //            angle_3 = (int)(c.angles.First() / 3);
        //            rotationcnt = c.rotationCnt;
        //        }
        //        else
        //        {
        //            bool change = false;
        //            if ((rotationcnt != c.rotationCnt) ||
        //                (angle_3 != (int)(c.angles.First() / 3)))
        //            {
        //                change = true;
        //            }
        //            if (!change)
        //            {
        //                if (Misc.MyBase.ISVALIDATA(c.ad))
        //                {
        //                    sum += c.ad;
        //                    cnt++;
        //                }
        //            }
        //            else
        //            {
        //                int[] thicks = null;
        //                if (rotationcnt == RotationCnt - 2)
        //                    thicks = thicks1;
        //                else if (rotationcnt == RotationCnt - 1)
        //                    thicks = thicks2;
        //                if (thicks != null)
        //                {
        //                    int index = angle_3;
        //                    if (index >= 120)
        //                        index = 119;
        //                    else if (index < 0)
        //                        index = 0;
        //                    if (cnt > 0)
        //                        thicks[index] = sum / cnt;
        //                    else
        //                        thicks[index] = Misc.MyBase.NULL_VALUE;
        //                }
        //                sum = 0;
        //                cnt = 0;
        //                if (Misc.MyBase.ISVALIDATA(c.ad))
        //                {
        //                    sum += c.ad;
        //                    cnt++;
        //                }
        //                rotationcnt = c.rotationCnt;
        //                angle_3 = (int)(c.angles.First() / 3);
        //            }
        //        }
        //    }


        //    //计算相似性
        //    return Misc.MyMath.Correl(thicks1, thicks2);
        //}

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        //string file_path = "bulkdb.json";
        public void Save(string file_path)
        {
            try
            {
                CalFilmLenJsonDB param = new CalFilmLenJsonDB()
                {
                    RAngle = mRDetectCore.RAngle,
                    RollPerimeter = mRDetectCore.RollPerimeter,
                    RenZiJiaPeriod = mRDetectCore.RenZiJiaPeriod,
                    FilmLength = mRDetectCore.FilmLength,
                    Is3D = mRDetectCore.Is3D,
                    mRollList = mRDetectCore.mRollList,
                    mLimitList = mRDetectCore.mLimitList,
                    mFilmLength3D = mRDetectCore.mFilmLength3D,

                    NBolts = NBolts,
                    OrgBoltNo = OrgBoltNo,
                    mADList = mADList.Select(a => new ADSingle() { dt = a.Time, thick = a.Ad }).ToList()
                };

                File.WriteAllText(file_path, JsonConvert.SerializeObject(param, Formatting.Indented));
            }
            catch
            {
                //异常,没有json 编码失败

            }
        }
        public void Load(string file_path)
        {
            try
            {
                if (File.Exists(file_path))
                {
                    string json = File.ReadAllText(file_path);

                    var param = JsonConvert.DeserializeObject<CalFilmLenJsonDB>(json);
                    Load(param);
                }
            }
            catch
            {
                //异常,没有json 解码失败

            }
        }

        void Load(CalFilmLenJsonDB param)
        {
            
            mRDetectCore.Init(
                param.RAngle,
                param.RollPerimeter,
                param.RenZiJiaPeriod,
                param.FilmLength,
                param.Is3D,
                param.mRollList,
                param.mLimitList,
                param.mFilmLength3D);
            NBolts = param.NBolts;
            OrgBoltNo = param.OrgBoltNo;
            if (OrgBoltNo < 1)
                OrgBoltNo = 1;
            FilmLength = param.FilmLength;

            mLimitList = param.mLimitList;
            mRollList = param.mRollList;

            mADList = param.mADList.Select(
                a => new ADCell()
                {
                    Ad = a.thick,
                    Time = a.dt
                }
                ).ToList();

            UpdateLimitValues();
            UpdateThicknessValues();
            UpdateVelocityValues(VelocityFilter);

            UpdateADList();
            UpdateFrames();

            IsDataReady = true;
        }

        public void Test()
        {
            CalFilmLenJsonDB param = new CalFilmLenJsonDB()
            {
                NBolts = 96,
                RAngle = 350,
                RollPerimeter = 314,
                FilmLength = 24,
                Is3D = false,
                mFilmLength3D = null,
                RenZiJiaPeriod = TimeSpan.FromMinutes(6.1),
                mADList = new List<ADSingle>(),
                mLimitList = new List<LimitCell>(),
                mRollList = new List<RollCell>()
            };

            #region 虚拟数据
            int[] thicks = new int[]{
                3518    ,
                3484    ,
                3634    ,
                3620    ,
                3579    ,
                3625    ,
                3635    ,
                3638    ,
                3635    ,
                3606    ,
                3611    ,
                3603    ,
                3590    ,
                3631    ,
                3646    ,
                3647    ,
                3710    ,
                3705    ,
                3607    ,
                3720    ,
                3680    ,
                3637    ,
                3659    ,
                3703    ,
                3860    ,
                3720    ,
                3615    ,
                3810    ,
                3772    ,
                3666    ,
                3614    ,
                3627    ,
                3618    ,
                3502    ,
                3575    ,
                3583    ,
                3615    ,
                3680    ,
                3730    ,
                3840    ,
                3927    ,
                3946    ,
                3923    ,
                3841    ,
                3797    ,
                3865    ,
                3810    ,
                3711    ,
                3754    ,
                3705    ,
                3723    ,
                3699    ,
                3723    ,
                3801    ,
                3786    ,
                3798    ,
                3907    ,
                3945    ,
                3828    ,
                3860    ,
                3846    ,
                3903    ,
                3871    ,
                3844    ,
                3759    ,
                3816    ,
                3886    ,
                3815    ,
                3789    ,
                3876    ,
                3942    ,
                3854    ,
                3842    ,
                3921    ,
                3846    ,
                3835    ,
                3886    ,
                3881    ,
                3820    ,
                3787    ,
                3730    ,
                3617    ,
                3650    ,
                3610    ,
                3536    ,
                3545    ,
                3564    ,
                3584    ,
                3580    ,
                3572    ,
                3571    ,
                3579    ,
                3620    ,
                3634    ,
                3484    ,
                3518    ,
                };

            //线速度 m/min
            double FilmVelocity = 20;
            TimeSpan Cool = TimeSpan.FromSeconds(2.3);
            //速度震荡周期 m
            double FV_Range = 2;
            TimeSpan DataLen = TimeSpan.FromMinutes(30);

            DateTime dt_begin = DateTime.Now;
            DateTime dt_end = dt_begin + DataLen;



            for (TimeSpan ts = TimeSpan.Zero; ts < DataLen; ts += TimeSpan.FromSeconds(1))
            {
                DateTime dt = dt_begin + ts;
                double min = ts.TotalMinutes;

                //速度以1/2旋转周期变化
                double v = FilmVelocity + Math.Sin(Math.PI * 2 * min / (param.RenZiJiaPeriod.TotalMinutes / 2)) * FV_Range;

                if (param.mRollList.Count() == 0)
                {
                    param.mRollList.Add(new RollCell() { dt = dt });
                }
                else
                {
                    while ((dt - param.mRollList.Last().dt).TotalMinutes * v > (param.RollPerimeter / 1000))
                    {
                        param.mRollList.Add(new RollCell()
                        {
                            dt = param.mRollList.Last().dt + TimeSpan.FromMinutes((param.RollPerimeter / 1000) / v)
                        });
                    }
                }
                
                int n = ((int)(min / param.RenZiJiaPeriod.TotalMinutes)) % 2;

                double min2 = min - param.FilmLength / v + param.RenZiJiaPeriod.TotalMinutes * 2;

                int n2 = ((int)(min2 / param.RenZiJiaPeriod.TotalMinutes)) % 2;
                double m = min2 % param.RenZiJiaPeriod.TotalMinutes;
                int idx = (int)(thicks.Count() * m / param.RenZiJiaPeriod.TotalMinutes);
                if (idx < 0) idx = 0;
                else if (idx > thicks.Count()) idx = thicks.Count() - 1;

                int thick;

                if (n2 == 0)
                    thick = thicks[idx];
                else
                    thick = thicks[thicks.Count() - 1 - idx];


                param.mADList.Add(new ADSingle
                {
                    dt = dt,
                    thick = thick
                });

                if (param.mLimitList.Count() == 0)
                {
                    if (dt >= dt_begin + param.RenZiJiaPeriod)
                    {
                        param.mLimitList.Add(new LimitCell()
                        {
                            dt_begin = dt_begin + param.RenZiJiaPeriod,
                            dt_end = dt_begin + param.RenZiJiaPeriod + Cool,
                            no = n
                        });
                    }
                }
                else if (dt >= param.mLimitList.Last().dt_end + param.RenZiJiaPeriod)
                {
                    param.mLimitList.Add(new LimitCell()
                    {
                        dt_begin = param.mLimitList.Last().dt_end  + param.RenZiJiaPeriod,
                        dt_end = param.mLimitList.Last().dt_end + param.RenZiJiaPeriod + Cool,
                        no = n
                    });
                }
            }





            #endregion

            Load(param);
        }
    }

    public class CalFilmLenJsonDB
    {
        /// <summary>
        /// 离开限位 到 撞下一个限位 的 旋转架转动总角度 单位°
        /// </summary>
        public double RAngle;
        /// <summary>
        /// 辊周长,单位mm
        /// </summary>
        public double RollPerimeter;
        /// <summary>
        /// 离开限位 到 撞下一个限位  的 旋转架转动时间, 需要初始值,以后测量出来的
        /// </summary>
        public TimeSpan RenZiJiaPeriod;
        /// <summary>
        /// 人字架到测厚仪膜长 单位m
        /// </summary>
        public double FilmLength;

        /// <summary>
        /// 旋转架为立式,测厚仪安装在二牵引前面,膜距离 与 旋转角度 一起变化, 旋转角度越大 膜距离越大
        /// </summary>
        public bool Is3D;

        /// <summary>
        /// 辊信号列表
        /// </summary>
        public List<RollCell> mRollList;

        /// <summary>
        /// 转向信号列表
        /// </summary>
        public List<LimitCell> mLimitList;

        /// <summary>
        /// 当为 立式旋转架时,膜距离与旋转角度有关系
        /// 列表的长度为 200, 列表的头为信号0离开, 尾为信号1进入
        /// </summary>
        public List<double> mFilmLength3D;

        public List<ADSingle> mADList;

        public int NBolts;
        public int OrgBoltNo=1;

    }
}