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

namespace FLY.Thick.Base.UI
{
    class PgGridVmUt : IPgGridVm
    {
        public event PropertyChangedEventHandler PropertyChanged;

        #region IPgGridVm Property
        /// <summary>
        /// 目标位置 单位:脉冲
        /// </summary>
        public int TargetPos { get; set; }
        /// <summary>
        /// 目标位置 单位:mm
        /// </summary>
        public double TargetMm => TargetPos * Mmpp;
        /// <summary>
        /// AD值模式
        /// </summary>
        public bool IsADMode { get; set; }



        /// <summary>
        /// 最多6条曲线
        /// </summary>
        public ObservableCollection<SeriesInfo> SeriesInfos { get; } = new ObservableCollection<SeriesInfo>();



        #region 曲线
        public Func<double, string> XFormatter { get; private set; }
        public Func<double, string> YFormatter { get; private set; }

        public double XUpper { get; set; } = 1024;
        public double XLower { get; set; } = 0;

        public double YUpper { get; set; } = double.NaN;
        public double YLower { get; set; } = double.NaN;

        public double XMax { get; private set; } = 1024;
        public double XMin { get; private set; } = 0;

        public double YMax { get; private set; } = double.NaN;
        public double YMin { get; private set; } = double.NaN;

        public double SectionValue  => MeasureValuePos / PosOfGrid;
        public double SectionWidth => MeasureWidthPos / PosOfGrid;
        public SeriesCollection Series { get; } = new SeriesCollection();
        #endregion

        #region 测量
        /// <summary>
        /// 测量开始位置 单位:脉冲
        /// </summary>
        public int MeasureValuePos { get; set; }
        /// <summary>
        /// 测量开始位置 单位:mm
        /// </summary>
        public double MeasureValueMm => MeasureValuePos * Mmpp;
        /// <summary>
        /// 测量宽度 单位:脉冲
        /// </summary>
        public int MeasureWidthPos { get; set; }
        /// <summary>
        /// 测量宽度 单位:mm
        /// </summary>
        public double MeasureWidthMm => MeasureWidthPos * Mmpp;
        #endregion

        #endregion
        #region command
        public RelayCommand RunToCmd { get; }
        public RelayCommand GetFDataCmd { get; }
        public RelayCommand GetBDataCmd { get; }

        public RelayCommand ClearCmd { get; }
        public RelayCommand MeasureCmd { get; }

        public RelayCommand SaveCmd { get; }

        public RelayCommand<SeriesInfo> SelectCmd { get; }
        #endregion

        public int PosOfGrid { get; set; } = 10;
        public double Mmpp { get; set; } = 0.1;

        public PgGridVmUt()
        {
            #region 与数据无关界面参数

            XFormatter = (x) =>
            {
                int index = (int)x;
                int pos = index * PosOfGrid;
                int mm = (int)(pos * Mmpp);
                return $"{pos}\n{mm}mm";
            };
            YFormatter = (y) =>
            {
                if (IsADMode)
                {
                    return $"{y}";
                }
                else
                {
                    return $"{y:F1}";
                }
            };

            for (int i = 0; i < 6; i++)
            {
                SeriesInfo info = new SeriesInfo()
                {
                    Title = $"{i}",
                    Fill = FLY.ControlLibrary.Themes.Styles.GetForeground(i),
                };
                LineSeries lineSeries = new LineSeries
                {
                    StrokeThickness = 2,
                    Fill = new SolidColorBrush(System.Windows.Media.Colors.Transparent),
                    PointGeometry = null
                };
                lineSeries.SetBinding(LineSeries.StrokeProperty, "Fill");
                lineSeries.DataContext = info;
                Series.Add(lineSeries);
                info.Series = lineSeries;
                SeriesInfos.Add(info);
            }

            #endregion

            IsADMode = false;
            UpdateADMode();
            //-----------------------------------------------------------------
            //虚拟数据
            TargetPos = 800;
            MeasureValuePos = 7000;
            MeasureWidthPos = 500;

            Random r = new Random();
            for (int i = 0; i < 4; i++)
            {
                var info = SeriesInfos[i];
                int period = r.Next(200, 600);
                info.ADs.Clear();
                info.Thicks.Clear();
                info.ADs.AddRange(GetADs(period));
                info.Thicks.AddRange(GetValues(info.ADs));
                info.IsBackw = i % 2 == 0;
            }
            
            SeriesInfos[0].IsSelected = true;

            UpdateMeasure();
        }

        void UpdateADMode()
        {
            if (IsADMode)
            {
                foreach (var info in SeriesInfos)
                    info.Series.SetBinding(LineSeries.ValuesProperty, "ADs");
            }
            else
            {
                foreach (var info in SeriesInfos)
                    info.Series.SetBinding(LineSeries.ValuesProperty, "Thicks");
            }
        }
        void UpdateMeasure()
        {
            int begin_grid = MeasureValuePos / PosOfGrid;
            int end_grid = (MeasureValuePos+MeasureWidthPos) / PosOfGrid;

            foreach (var info in SeriesInfos)
            {
                if (IsADMode)
                {
                    double sum = 0;
                    int cnt = 0;
                    for (int i = begin_grid; i <= end_grid && i < info.ADs.Count() && i >= 0; i++)
                    {
                        sum += info.ADs[i];
                        cnt++;
                    }
                    if (cnt == 0)
                        info.Avg = double.NaN;
                    else
                        info.Avg = sum / cnt;
                }
                else
                {
                    double sum = 0;
                    int cnt = 0;
                    for (int i = begin_grid; i <= end_grid && i < info.Thicks.Count() && i >= 0; i++)
                    {
                        sum += info.Thicks[i];
                        cnt++;
                    }
                    if (cnt == 0)
                        info.Avg = double.NaN;
                    else
                        info.Avg = sum / cnt;
                }
            }
        }

        IEnumerable<double> GetADs(int period)
        {
            List<double> ads = new List<double>();

            Random r = new Random();
            for (int i = 0; i < 1000; i++)
            {
                if (i < 100 || i > 800)
                {
                    ads.Add(double.NaN);
                }
                else
                {
                    int ad = (int)(Math.Sin(Math.PI * 2 * i / period) * 2000) + r.Next(200) - 100 + 10000;
                    ads.Add(ad);
                }
            }
            return ads;
        }
        IEnumerable<double> GetValues(IEnumerable<double> ADs)
        {
            return ADs.Select(ad =>
            {
                if (double.IsNaN(ad))
                    return double.NaN;
                else
                    return ad / 100.0;
            });
        }
    }
}
