using FlyADBase;
using GalaSoft.MvvmLight.Command;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms.DataVisualization.Charting;

namespace Flyad7_WPF
{
    public class GridAdvVm : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public bool HasGridAdv { get; set; }

        public RelayCommand SaveCmd { get; private set; }
        public RelayCommand LoadCmd { get; private set; }

        public RelayCommand CalAdLagCmd { get; private set; }
        Chart chart3 = null;
        FlyAD7 flyad;
        int timeGridAdvIndex = 0;
        List<IEnumerable<GridAdvUnit>> gridAdvUnits = new List<IEnumerable<GridAdvUnit>>();

        public GridAdvVm(FlyAD7 flyad) 
        {
            SaveCmd = new RelayCommand(Save);
            LoadCmd = new RelayCommand(Load);
            CalAdLagCmd = new RelayCommand(CalAdLag);

            this.flyad = flyad;
            flyad.TimeGridAdvEvent += flyad_TimeGridAdvEvent;
        }
        public void Init(Chart chart) 
        {
            this.chart3 = chart;
        }



        #region timeGridAdv
        private async void flyad_TimeGridAdvEvent(object sender, TimeGridAdvEventArgs e)
        {
            if (chart3 == null)
                return;
            if (!HasGridAdv)
                return;

            if (gridAdvUnits == null)
                gridAdvUnits = new List<IEnumerable<GridAdvUnit>>();
            gridAdvUnits.Add(e.Data);

            await Task.Factory.StartNew(() =>
            {
                //画图
                DrawGridAdv(gridAdvUnits.Last());

                while (gridAdvUnits.Count > chart3.Series.Count())
                    gridAdvUnits.RemoveAt(0);

                if (gridAdvUnits.Count() >= 2)
                {
                    CurrR = CalGridAdvR(gridAdvUnits[gridAdvUnits.Count() - 1], gridAdvUnits[gridAdvUnits.Count() - 2], 0);
                }
            });
        }

        void DrawGridAdv(IEnumerable<GridAdvUnit> units, int adLag = 0)
        {
            if (chart3 == null)
                return;
            flyad.ToGrid(units, out int[] datas, adLag);
            //画图
            timeGridAdvIndex++;
            if (timeGridAdvIndex >= chart3.Series.Count())
                timeGridAdvIndex = 0;

            App.Current.Dispatcher.Invoke(() =>
            {
                System.Windows.Forms.DataVisualization.Charting.Series series = chart3.Series[timeGridAdvIndex];
                series.Points.Clear();

                int gridLen = flyad.PosLen / flyad.PosOfGrid;

                for (int i = 0; i < datas.Length; i++)
                {
                    int pos = i * flyad.PosOfGrid;
                    int ad = datas[i];
                    series.Points.AddXY(pos, ad);
                    if (ad == Misc.MyBase.NULL_VALUE)
                        series.Points[i].IsEmpty = true;
                }

                chart3.ChartAreas[0].AxisX.Minimum = 0;
                chart3.ChartAreas[0].AxisX.Maximum = flyad.PosLen;
            });
        }

        //计算相关性
        public int BestAdLag { get; private set; }
        public double BestR { get; private set; }
        public double CurrR { get; private set; }

        public double ProgressOfAdLag { get; private set; }
        public double ProgressOfR { get; private set; }

        double CalGridAdvR(IEnumerable<GridAdvUnit> units1, IEnumerable<GridAdvUnit> units2, int adLag)
        {
            flyad.ToGrid(units1, out int[] datas1, adLag);
            flyad.ToGrid(units2, out int[] datas2, adLag);
            return Misc.MyMath.Correl(datas1, datas2);
        }

        void CalAdLag(IEnumerable<GridAdvUnit> units1, IEnumerable<GridAdvUnit> units2, int adLag, int range, double targetR, out int bestAdLag, out double bestR)
        {
            int step = range / 5;
            if (step < 0)
                step = 1;

            List<AdLagAndR> rList = new List<AdLagAndR>();
            for (int i = 0; i < range; i += step)
            {
                int _adLag = adLag - i;
                double _r = CalGridAdvR(units1, units2, _adLag);
                rList.Add(new AdLagAndR() { AdLag = _adLag, R = _r });
                ProgressOfAdLag = _adLag;
                ProgressOfR = _r;
            }
            for (int i = step; i < range; i += step)
            {
                int _adLag = adLag + i;
                double _r = CalGridAdvR(units1, units2, _adLag);
                rList.Add(new AdLagAndR() { AdLag = _adLag, R = _r });
                ProgressOfAdLag = _adLag;
                ProgressOfR = _r;
            }
            double maxR = rList.Max(lr => lr.R);
            adLag = rList.Find(_lr => _lr.R == maxR).AdLag;

            if (step == 1)
            {
                //已经是最小查找步进
                bestAdLag = adLag;
                bestR = maxR;
                return;
            }
            if (maxR >= targetR)
            {
                //找到了
                bestAdLag = adLag;
                bestR = maxR;
                return;
            }

            //缩小范围,继续找
            range = step * 2;
            CalAdLag(units1, units2, adLag, range, targetR, out bestAdLag, out bestR);

        }
        class AdLagAndR
        {
            public int AdLag;
            public double R;
        }

        private void Save()
        {
            string strDesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
            string path = System.IO.Path.Combine(strDesktopPath, $"{DateTime.Now.ToString("yyyyMMdd_HHmmss")}.json");


            string json = Newtonsoft.Json.JsonConvert.SerializeObject(gridAdvUnits);
            File.WriteAllText(path, json);

            MessageBox.Show($"成功保存到 {path}");
        }

        private async void Load()
        {
            string strDesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.DefaultExt = ".json";
            openFileDialog.Filter = "json文件|*.json";
            openFileDialog.InitialDirectory = strDesktopPath;
            if (openFileDialog.ShowDialog() != true)
                return;

            string path = openFileDialog.FileName;
            string json = File.ReadAllText(path);
            try
            {
                gridAdvUnits = Newtonsoft.Json.JsonConvert.DeserializeObject<List<IEnumerable<GridAdvUnit>>>(json);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"读取失败 {ex}");
                return;
            }
            if (gridAdvUnits == null)
            {
                gridAdvUnits = new List<IEnumerable<GridAdvUnit>>();
                MessageBox.Show($"读取失败 没有数据");
            }
            else
            {
                await Task.Factory.StartNew(() =>
                {
                    foreach (var units in gridAdvUnits)
                    {

                        DrawGridAdv(units);
                    }
                    if (gridAdvUnits.Count > chart3.Series.Count())
                        gridAdvUnits.RemoveAt(0);

                    if (gridAdvUnits.Count() >= 2)
                    {
                        CurrR = CalGridAdvR(gridAdvUnits[gridAdvUnits.Count() - 1], gridAdvUnits[gridAdvUnits.Count() - 2], 0);
                    }
                });

                MessageBox.Show($"读取成功");
            }

        }
        private async void CalAdLag()
        {
            if (gridAdvUnits.Count() < 2)
            {
                MessageBox.Show("数量小于2次");
                return;
            }
            int bestAdLag = 0;
            double bestR = -1;
            await Task.Factory.StartNew(() => {
                CalAdLag(gridAdvUnits[gridAdvUnits.Count() - 1], gridAdvUnits[gridAdvUnits.Count() - 2],
                    0, (int)(1000 / 1.28), 0.99, out bestAdLag, out bestR);
            });
            BestAdLag = bestAdLag;
            BestR = bestR;
            await Task.Factory.StartNew(() => {
                DrawGridAdv(gridAdvUnits[gridAdvUnits.Count() - 1], BestAdLag);
                DrawGridAdv(gridAdvUnits[gridAdvUnits.Count() - 2], BestAdLag);
            });
            MessageBox.Show($"计算完成 最佳滞后={BestAdLag}");
        }
        #endregion
    }
}
