using GalaSoft.MvvmLight.Command;
using LiveCharts;
using LiveCharts.Configurations;
using LiveCharts.Wpf;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FLY.Thick.Blowing.UI.Fix.Client
{
    public class PgBlowingExtVmUt : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        #region 曲线
        /// <summary>
        /// 画在图上的 限位信号
        /// </summary>
        public List<TimeValue> LimitValues { get; } = new List<TimeValue>();
        /// <summary>
        /// 画在图上的 速度曲线,限制最多100个数据
        /// </summary>
        public ChartValues<TimeValue> VelocityValues { get; } = new ChartValues<TimeValue>();
        /// <summary>
        /// 画在图上的 厚度曲线,限制最多100个数据
        /// </summary>
        public ChartValues<TimeValue> ThicknessValues { get; } = new ChartValues<TimeValue>();
        /// <summary>
        /// 画在图上的 膜距离增量曲线,限制最多100个数据
        /// </summary>
        public ChartValues<TimeValue> FilmLength3DValues { get; } = new ChartValues<TimeValue>();

        /// <summary>
        /// 画在图上的 当前应用的膜距离增量曲线,不用限制,本来就只有100个
        /// </summary>
        public ChartValues<double> CurrFilmLength3D { get; } = new ChartValues<double>();

        /// <summary>
        /// 画在图上的 计算出来的膜距离增量曲线,不用限制,本来就只有100个
        /// </summary>
        public ChartValues<double> NewFilmLength3D { get; } = new ChartValues<double>();

        /// <summary>
        /// 转换为分区号单位的 每幅图
        /// </summary>
        public SeriesCollection FrameSeries { get; } = new SeriesCollection();
        #endregion

        #region 参数
        /// <summary>
        /// 需要 膜距离增量曲线
        /// </summary>
        public bool Is3D { get; set; }

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

        /// <summary>
        /// 获取数据分钟数 min
        /// </summary>
        public int GetDataMinute { get; set; }

        /// <summary>
        /// 膜距离查找范围 m
        /// </summary>
        public int FLRange { get; set; }

        /// <summary>
        /// 速度滤波 s
        /// </summary>
        public int VelocityFilter { get; set; }

        /// <summary>
        /// 牵引1速度
        /// </summary>
        public double Velocity1 { get; set; }
        #endregion

        #region 状态
        public double VAvg { get; private set; }
        public double VMax { get; private set; }
        public double VMin { get; private set; }

        public double FAvg { get; private set; }
        public double FMax { get; private set; }
        public double FMin { get; private set; }

        #endregion

        #region 界面
        /// <summary>
        /// y轴格式
        /// </summary>
        public Func<double, string> YFormatter { get; set; } = value => value.ToString("F1");

        /// <summary>
        /// X轴格式
        /// </summary>
        public Func<double, string> DateTimeFormatter { get; set; } = value => new DateTime((long)value).ToString("HH:mm:ss");
        public Func<double, string> BoltNoFormatter { get; set; } = value => (value + 1).ToString();

        public CartesianMapper<TimeValue> MapperTv { get; set; } 
            = Mappers.Xy<TimeValue>()
            .X(value => value.Time.Ticks)
            .Y(value => value.Value);

        #endregion

        #region Command
        public RelayCommand GetDataCmd { get; private set; }
        public RelayCommand UpdateVCmd { get; private set; }

        public RelayCommand UpdateFilmLength3DCmd { get; private set; }

        public RelayCommand ApplyFilmLength3DCmd { get; private set; }

        public RelayCommand UpdateFramesCmd { get; private set; }

        public RelayCommand CalCmd { get; private set; }

        public RelayCommand ApplyFilmLengthCmd { get; private set; }

        public RelayCommand SaveCmd { get; private set; }

        public RelayCommand LoadCmd { get; private set; }
        #endregion

        public CalFilmLenUt Cfl { get; set; }
        public PgBlowingExtVmUt()
        {
            Init1();
            init_virtualdata();
        }

        void Init1()
        {
            #region 界面配置
            //MapperTv = Mappers.Xy<TimeValue>()
            //    .X(value => value.Time.Ticks)
            //    .Y(value => value.Value);

            //DateTimeFormatter = value => new DateTime((long)value).ToString("HH:mm:ss");
            //BoltNoFormatter = value => (value + 1).ToString();
            //YFormatter = value => value.ToString("F1");

            #endregion
        }

        /// <summary>
        /// 产生虚拟数据
        /// </summary>
        void init_virtualdata()
        {
            #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
            double RollPerimeter = 0.314;
            //线速度 m/min
            double FilmVelocity = 20;
            //旋转周期
            TimeSpan RInterval = TimeSpan.FromMinutes(6.1);
            //速度震荡周期 m
            double FV_Range = 2;
            TimeSpan DataLen = TimeSpan.FromMinutes(30);

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

            List<TimeValue> vList = new List<TimeValue>();
            List<TimeValue> tList = new List<TimeValue>();
            List<TimeValue> lList = new List<TimeValue>();

            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 / (RInterval.TotalMinutes / 2)) * FV_Range;

                vList.Add(new TimeValue() { Time = dt, Value = v });

                int n = ((int)(min / RInterval.TotalMinutes)) % 2;

                double m = min % RInterval.TotalMinutes;
                int idx = (int)(thicks.Count() * m / RInterval.TotalMinutes);
                if (idx < 0) idx = 0;
                else if (idx > thicks.Count()) idx = thicks.Count() - 1;

                double thick;

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


                tList.Add(new TimeValue()
                {
                    Time = dt,
                    Value = thick / 100.0
                });

                if (lList.Count() == 0)
                {
                    lList.Add(new TimeValue() { Time = dt_begin + RInterval, Value = n });
                }
                else if (dt >= lList.Last().Time)
                {
                    lList.Add(new TimeValue() { Time = lList.Last().Time + RInterval, Value = n });
                }
            }

            List<TimeValue> fList = new List<TimeValue>();
            double sum = 0;
            double avg = vList.Average(tv => tv.Value);

            foreach (var tv in vList)
            {
                sum += (tv.Value - avg) * TimeSpan.FromSeconds(1).TotalMinutes;

                fList.Add(new TimeValue() { Time = tv.Time, Value = sum });
            }
            {
                double min = fList.Min(tv => tv.Value);
                foreach (var tv in vList)
                {
                    tv.Value -= min;
                }
            }

            List<double> setFilmLength = new List<double>();
            foreach (var tv in fList)
            {
                if (tv.Time >= lList[0].Time && tv.Time <= lList[1].Time)
                {
                    setFilmLength.Add(tv.Value);
                }
                else if (tv.Time > lList[1].Time)
                {
                    break;
                }
            }
            Random r = new Random();
            List<double> currFilmLength = new List<double>();
            foreach (var f in setFilmLength)
            {
                currFilmLength.Add(f + r.NextDouble() - 0.5);
            }


            List<List<double>> frames = new List<List<double>>();
            for (int i = 0; i < lList.Count() - 1; i++)
            {
                List<double> frame = new List<double>();
                frame.AddRange(thicks.Select(t => (t + (r.NextDouble() - 0.5) * t * 2 / 100) / 100.0));
                frames.Add(frame);
            }
            #endregion


            foreach (var tv in lList)
            {
                LimitValues.Add(tv);
            }
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("LimitValues"));

            for (int i = 0; i < 100; i++)
            {
                int idx = vList.Count() * i / 100;
                if (idx >= vList.Count()) idx = vList.Count() - 1;
                VelocityValues.Add(vList[idx]);
            }

            for (int i = 0; i < 100; i++)
            {
                int idx = tList.Count() * i / 100;
                if (idx >= tList.Count()) idx = tList.Count() - 1;
                ThicknessValues.Add(tList[idx]);
            }

            for (int i = 0; i < 100; i++)
            {
                int idx = fList.Count() * i / 100;
                if (idx >= fList.Count()) idx = fList.Count() - 1;
                FilmLength3DValues.Add(fList[idx]);
            }

            for (int i = 0; i < 100; i++)
            {
                int idx = currFilmLength.Count() * i / 100;
                if (idx >= currFilmLength.Count()) idx = currFilmLength.Count() - 1;
                CurrFilmLength3D.Add(currFilmLength[idx]);
            }

            for (int i = 0; i < 100; i++)
            {
                int idx = setFilmLength.Count() * i / 100;
                if (idx >= setFilmLength.Count()) idx = setFilmLength.Count() - 1;
                NewFilmLength3D.Add(setFilmLength[idx]);
            }

            for (int i = 0; i < frames.Count(); i++)
            {
                var frame = frames[i];
                FrameSeries.Add(
                    new LineSeries()
                    {
                        Title = i.ToString(),
                        Values = new ChartValues<double>(frame),
                        LineSmoothness = 1,
                        StrokeThickness = 3,
                        PointGeometrySize = 0
                    });
            }
        }
    }

    public class CalFilmLenUt : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        #region 参数

        #endregion
        #region 状态

        /// <summary>
        /// 信息
        /// </summary>
        public string Msg { get; set; }

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

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

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

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

        /// <summary>
        /// 当前数据总分钟数 min
        /// </summary>
        public int DataMaxMinute { get; set; }

        /// <summary>
        /// 必须获取的最少数据量 min
        /// </summary>
        public int DataMinMinute { get; set; }

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


    }
}