using LiveCharts;
using LiveCharts.Configurations;
using LiveCharts.Wpf;
using MahApps.Metro.Controls.Dialogs;
using Microsoft.Win32;
using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using WSDDBBrowser.Core;

namespace WSDDBBrowser.Chart
{

        /// <summary>
        /// TrendGraph.xaml 的交互逻辑
        /// </summary>
        public partial class TrendGraph : UserControl, IDisposable
        {
            TrendGraphViewModel viewModel;
            public TrendGraph()
            {
                InitializeComponent();

            }
            public void Update()
            {
                chart.Update(true, true); //force chart redraw
            }
            public void Init(ScanDataItem scanDataItem)
            {
                viewModel = new TrendGraphViewModel();
                viewModel.Init(scanDataItem);
                this.DataContext = viewModel;
            }
            private void Button_info_click(object sender, RoutedEventArgs e)
            {

            }

            private void button_select_Click(object sender, RoutedEventArgs e)
            {
                var info = (sender as Button).Tag as SeriesInfo;
                if (info.BoltIndex == -1)
                {
                    //平均值，不能改变
                    return;
                }
                if (info.IsVisible)
                    info.IsVisible = false;
                else
                    info.IsVisible = true;

            }

            private async void ButtonXlsxClick(object sender, RoutedEventArgs e)
            {
                string strDesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
                string filename = "纵向趋势图_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".xlsx";
                SaveFileDialog sfd = new SaveFileDialog();
                sfd.Filter = "xlsx files (*.xlsx)|*.xlsx";
                sfd.InitialDirectory = strDesktopPath;
                sfd.FileName = filename;
                if (sfd.ShowDialog() == true)
                {
                    viewModel.SaveToXlsx(sfd.FileName);
                    await App.MetroWindow.ShowMessageAsync("输出成功",
                        sfd.FileName);
                }
            }


            private async void ButtonJpgClick(object sender, RoutedEventArgs e)
            {
                string strDesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
                string filename = "纵向趋势图_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".jpg";
                SaveFileDialog sfd = new SaveFileDialog();
                sfd.Filter = "jpg files (*.jpg)|*.jpg";
                sfd.InitialDirectory = strDesktopPath;
                sfd.FileName = filename;
                if (sfd.ShowDialog() == true)
                {
                    ChartToImage.SaveToJpeg(this, sfd.FileName);

                    await App.MetroWindow.ShowMessageAsync("输出成功",
                        sfd.FileName);
                }
            }

            public void Dispose()
            {
                viewModel.Dispose();
            }
        }

        public class TrendGraphViewModel : INotifyPropertyChanged, IDisposable
        {
            #region 图表控制
            public double YMax { get; set; }
            public double YMin { get; set; }
            public double Target { get; set; }
            public double ToleranceYMax { get; set; }
            public double ToleranceYMin { get; set; }
            public double CtrllineYMax { get; set; }
            public double CtrllineYMin { get; set; }


            public Func<double, string> XFormatter { get; set; }
            public Func<double, string> YFormatter { get; set; }

            public SeriesCollection Series { get; } = new SeriesCollection();
            #endregion

            #region 界面统计值
            /// <summary>
            /// 平均值
            /// </summary>
            public double Average { get; set; }
            /// <summary>
            /// 最大值
            /// </summary>
            public double Max { get; set; }
            /// <summary>
            /// 最小值
            /// </summary>
            public double Min { get; set; }

            /// <summary>
            /// 3sigma
            /// </summary>
            public double Sigma3 { get; set; }
            public int TotalValueCountInView { get; set; } = 500;
            #endregion
            ChartValues<TrendValue> AvgValues = new ChartValues<TrendValue>();
            ChartValues<BoltValue[]> BoltValues = new ChartValues<BoltValue[]>();

            object AvgMapper { get; set; }

            class BoltValueMapperCreate
            {
                private int index;
                public BoltValueMapperCreate(int index)
                {
                    this.index = index;
                    Mapper = Mappers.Xy<BoltValue[]>()
                        .X((value, idx) => idx)
                        .Y(value => value[this.index].Value);
                }
                public object Mapper { get; private set; }
            }

            List<BoltValueMapperCreate> BoltValueMappers = new List<BoltValueMapperCreate>();

            public ObservableCollection<SeriesInfo> SeriesInfos { get; } = new ObservableCollection<SeriesInfo>();


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


                XFormatter = (x) =>
                {
                    int index = (int)x;
                    if ((index < 0) || (index >= AvgValues.Count()))
                        return "";
                    else
                        return $"{AvgValues[index].Position:F1}m\n{AvgValues[index].Time:HH:mm}";
                };

                YFormatter = (y) =>
                {
                    string name = null;
                    if (y == Target)
                    {
                        name = "目标值";
                    }
                    else if (y == ToleranceYMax)
                    {
                        name = "规格线";
                    }
                    else if (y == ToleranceYMin)
                    {
                        name = "规格线";
                    }
                    else if (y == CtrllineYMax)
                    {
                        name = "控制线";
                    }
                    else if (y == CtrllineYMin)
                    {
                        name = "控制线";
                    }

                    if (!string.IsNullOrEmpty(name))
                        return $"{name} {y:F1}";
                    else
                        return y.ToString("F1");
                };

                AvgMapper = Mappers.Xy<TrendValue>()
                    .X((value, index) => index)
                    .Y(value => value.Value);

                #endregion
            }

            ScanDataItem scanDataItem;
            public void Init(ScanDataItem scanDataItem)
            {
                this.scanDataItem = scanDataItem;
                UpdateY();

                InitSeries();
                UpdateStatistics();

                scanDataItem.PropertyChanged += ScanDataItem_PropertyChanged;
            }

            private void ScanDataItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                if ((e.PropertyName == "Target") || (e.PropertyName == "Tolerance") || (e.PropertyName == "Ctrlline") || (e.PropertyName == "YRangePercent"))
                {
                    UpdateY();
                }
                else if (e.PropertyName == "MixCuttingValues")
                {
                    InitSeries();
                    UpdateStatistics();
                }
            }


            void UpdateStatistics()
            {
                List<double> values = new List<double>();
                //不统计平均值曲线
                foreach (var info in SeriesInfos)
                {
                    if (info.IsVisible && info.BoltIndex != -1)
                        values.AddRange(scanDataItem.GetCuttingValue(info.BoltIndex));
                }
                if (values.Count() == 0)
                {
                    //没有数据，统计平均值
                    values.AddRange(scanDataItem.GetCuttingValue(-1));
                }
                var values2 = values.Where(d => !double.IsNaN(d));
                if (values2.Count() == 0)
                {
                    Average = double.NaN;
                    Sigma3 = double.NaN;
                    Max = double.NaN;
                    Min = double.NaN;
                }
                else
                {
                    Average = values2.Average();
                    double sigma = values2.Sigma(d => d);
                    Sigma3 = sigma * 3;
                    Max = values2.Max();
                    Min = values2.Min();
                }
            }

            List<T> ToViewValues<T>(List<T> list)
            {
                List<T> newlist = new List<T>();
                int p = list.Count() / TotalValueCountInView;
                if (p <= 0)
                    p = 1;
                int j = 0;
                for (int i = 0; i < list.Count(); i++, j++)
                {
                    if (j >= p)
                    {
                        j = 0;
                        newlist.Add(list[i]);
                    }
                }
                return newlist;
            }


            void InitSeries()
            {
                Series.Clear();
                SeriesInfos.Clear();

                AvgValues.Clear();
                AvgValues.AddRange(ToViewValues(scanDataItem.GetTrend(-1)));

                BoltValues.Clear();
                BoltValues.AddRange(ToViewValues(scanDataItem.MixCuttingValues));


                {
                    LineSeries lineSeries = new LineSeries
                    {
                        Title = "均值",
                        Values = AvgValues,
                        StrokeThickness = 4,
                        Stroke = new SolidColorBrush(System.Windows.Media.Colors.Black),
                        Fill = new SolidColorBrush(System.Windows.Media.Colors.Transparent),
                        PointGeometry = null,
                        Configuration = AvgMapper
                    };
                    lineSeries.SetValue(Panel.ZIndexProperty, 10);
                    Series.Add(lineSeries);
                    SeriesInfos.Add(new SeriesInfo()
                    {
                        Title = lineSeries.Title,
                        Fill = lineSeries.Stroke,
                        Series = lineSeries,
                        IsVisible = true
                    });
                }

                for (int i = 0; i < DBViewerModel.Instance.CuttingMap.Count(); i++)
                {
                    //LineSeries lineSeries = new LineSeries();
                    LineSeries lineSeries = new LineSeries
                    {
                        Title = $"{i}",
                        Values = BoltValues,
                        StrokeThickness = 2,
                        Stroke = Themes.Styles.GetForeground(i),
                        Fill = new SolidColorBrush(System.Windows.Media.Colors.Transparent),
                        PointGeometry = null,
                        Configuration = (new BoltValueMapperCreate(i)).Mapper,
                        //Visibility = Visibility.Hidden
                    };
                    Series.Add(lineSeries);
                    SeriesInfos.Add(new SeriesInfo()
                    {
                        Title = lineSeries.Title,
                        Fill = lineSeries.Stroke,
                        Series = lineSeries,
                        IsVisible = true// false
                    });
                };
                foreach (var info in SeriesInfos)
                {
                    info.PropertyChanged += Info_PropertyChanged;
                }
            }

            private void Info_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                if (e.PropertyName == "IsVisible")
                {
                    SeriesInfo info = sender as SeriesInfo;
                    if (info.IsVisible)
                    {
                        info.Series.Visibility = Visibility.Visible;
                    }
                    else
                    {
                        info.Series.Visibility = Visibility.Hidden;
                    }
                    UpdateStatistics();
                }
            }

            void UpdateY()
            {
                Target = scanDataItem.Target;
                ToleranceYMax = scanDataItem.USL;
                ToleranceYMin = scanDataItem.LSL;
                CtrllineYMax = Target + scanDataItem.Ctrlline;
                CtrllineYMin = Target - scanDataItem.Ctrlline;

                YMax = scanDataItem.YMax;
                YMin = scanDataItem.YMin;
            }

            public bool SaveToXlsx(string filepath)
            {
                if (BoltValues.Count() == 0 || AvgValues.Count() == 0)
                    return false;
                if (File.Exists(filepath))
                {
                    File.Delete(filepath);
                }

                using (ExcelPackage p = new ExcelPackage(new FileInfo(filepath)))
                {
                    //Get the Worksheet created in the previous codesample. 
                    var ws = p.Workbook.Worksheets.Add("Sheet1");//创建worksheet
                                                                 //var ws = p.Workbook.Worksheets["MySheet"];

                    //Set the cell value using row and column.
                    //添加标题
                    ws.Cells[1, 1].Value = "时间";
                    ws.Cells[1, 2].Value = "纵向位置m";
                    ws.Cells[1, 3].Value = "涂布速度m/min";
                    ws.Cells[1, 4].Value = "目标值g/m²";
                    ws.Cells[1, 5].Value = "规格线g/m²";
                    ws.Cells[1, 6].Value = "控制线g/m²";
                    ws.Cells[1, 7].Value = "开始位置mm";
                    ws.Cells[1, 8].Value = "结束位置mm";
                    ws.Cells[1, 9].Value = "平均值g/m²";
                    int col = 10;
                    for (int i = 0; i < DBViewerModel.Instance.CuttingMap.Count(); i++)
                    {
                        ws.Cells[1, col].Value = $"分条{i}";
                        col++;
                    }

                    //格式
                    ws.Column(1).Style.Numberformat.Format = "yyyy-MM-dd HH:mm:ss";
                    ws.Column(2).Style.Numberformat.Format = "0.00";
                    for (int i = 3; i < col; i++)
                        ws.Column(i).Style.Numberformat.Format = "0.0";
                    ws.Column(7).Style.Numberformat.Format = "0";
                    ws.Column(8).Style.Numberformat.Format = "0";

                    //内容
                    int row = 2;
                    for (int i = 0; i < AvgValues.Count(); i++)
                    {
                        ws.Cells[row, 1].Value = AvgValues[i].Time;
                        ws.Cells[row, 2].Value = AvgValues[i].Position;
                        ws.Cells[row, 4].Value = scanDataItem.Target;
                        ws.Cells[row, 5].Value = scanDataItem.Tolerance;
                        ws.Cells[row, 6].Value = scanDataItem.Ctrlline;
                        ws.Cells[row, 9].Value = AvgValues[i].Value;

                        col = 10;
                        for (int j = 0; j < DBViewerModel.Instance.CuttingMap.Count(); j++)
                        {
                            if (j < BoltValues[i].Count())
                            {
                                if (!double.IsNaN(BoltValues[i][j].Value))
                                    ws.Cells[row, col].Value = BoltValues[i][j].Value;
                            }
                            col++;
                        }
                        row++;
                    }


                    //Save and close the package.
                    p.Save();
                }

                return true;
            }

            public void Dispose()
            {
                scanDataItem.PropertyChanged -= ScanDataItem_PropertyChanged;
            }

            public event PropertyChangedEventHandler PropertyChanged;
        }
        public class TrendGraphViewModel_UnitTest : INotifyPropertyChanged
        {
            #region 图表控制
            public double YMax { get; set; }
            public double YMin { get; set; }
            public double Target { get; set; }
            public double ToleranceYMax { get; set; }
            public double ToleranceYMin { get; set; }
            public double CtrllineYMax { get; set; }
            public double CtrllineYMin { get; set; }
            public double XMax { get; set; }
            public double XMin { get; set; }

            public Func<double, string> XFormatter { get; set; }
            public Func<double, string> YFormatter { get; set; }

            public SeriesCollection Series { get; set; }
            #endregion

            #region 界面统计值
            /// <summary>
            /// 平均值
            /// </summary>
            public double Average { get; set; }
            /// <summary>
            /// 最大值
            /// </summary>
            public double Max { get; set; }
            /// <summary>
            /// 最小值
            /// </summary>
            public double Min { get; set; }

            /// <summary>
            /// 3sigma
            /// </summary>
            public double Sigma3 { get; set; }
            #endregion
            ChartValues<TrendValue> AvgValues = new ChartValues<TrendValue>();
            ChartValues<BoltValue[]> BoltValues = new ChartValues<BoltValue[]>();

            object AvgMapper { get; set; }

            class BoltValueMapperCreate
            {
                private int index;
                public BoltValueMapperCreate(int index)
                {
                    this.index = index;
                    Mapper = Mappers.Xy<BoltValue[]>()
                        .X((value, idx) => idx)
                        .Y(value => value[this.index].Value);
                }
                public object Mapper { get; private set; }
            }

            List<BoltValueMapperCreate> BoltValueMappers = new List<BoltValueMapperCreate>();

            public ObservableCollection<SeriesInfo> SeriesInfos { get; } = new ObservableCollection<SeriesInfo>();


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


                XFormatter = (x) =>
                {
                    int index = (int)x;
                    if ((index < 0) || (index >= AvgValues.Count()))
                        return "";
                    else
                        return $"{AvgValues[index].Position:F1}m\n{AvgValues[index].Time:HH:mm}";
                };

                YFormatter = (y) =>
                {
                    string name = null;
                    if (y == Target)
                    {
                        name = "目标值";
                    }
                    else if (y == ToleranceYMax)
                    {
                        name = "规格线";
                    }
                    else if (y == ToleranceYMin)
                    {
                        name = "规格线";
                    }
                    else if (y == CtrllineYMax)
                    {
                        name = "控制线";
                    }
                    else if (y == CtrllineYMin)
                    {
                        name = "控制线";
                    }

                    if (!string.IsNullOrEmpty(name))
                        return $"{name} {y:F1}";
                    else
                        return y.ToString("F1");
                };

                AvgMapper = Mappers.Xy<TrendValue>()
                    .X((value, index) => index)
                    .Y(value => value.Value);

                #endregion
                #region 数据
                double target = 150;
                double tolerance = target * 0.02;
                double ctrlline = tolerance * 0.6;
                double yrangepercent = 1.5;

                List<BoltValue[]> boltValues = new List<BoltValue[]>();
                List<TrendValue> trendValues = new List<TrendValue>();
                Random random = new Random();
                int boltmap_cnt = 6;
                DateTime time = DateTime.Now;
                for (int i = 0; i < 2000; i++)
                {
                    BoltValue[] bvs = new BoltValue[boltmap_cnt];
                    for (int j = 0; j < boltmap_cnt; j++)
                    {
                        bvs[j] = new BoltValue(0, 0,
                            (Math.Sin(i * Math.PI / 400.0) * 0.6) * tolerance + target + (random.NextDouble() - 0.5) * 1);
                    }
                    boltValues.Add(bvs);
                    trendValues.Add(new TrendValue(bvs.Average(b => b.Value), i * 1.4, time + TimeSpan.FromSeconds(i * 1.4 / 15 * 60)));
                }

                #endregion
                #region 界面数据
                Target = target;
                ToleranceYMax = Target + tolerance;
                ToleranceYMin = Target - tolerance;
                CtrllineYMax = Target + ctrlline;
                CtrllineYMin = Target - ctrlline;
                YMax = Target + tolerance * yrangepercent;
                YMin = Target - tolerance * yrangepercent;
                XMin = 0;// scanrange.Begin;
                XMax = boltValues.Count() - 1;


                AvgValues.AddRange(trendValues);
                BoltValues.AddRange(boltValues);

                //Average = BoltValues.Average((b) => b.Value);
                //Max = BoltValues.Max(b => b.Value);
                //Min = BoltValues.Min(b => b.Value);
                #endregion

                SeriesInfos.Add(new SeriesInfo()
                {
                    BoltIndex = -1,
                    Title = "均值",
                    Fill = new SolidColorBrush(System.Windows.Media.Colors.Black),
                    Series = new LineSeries
                    {
                        Title = "均值",
                        Values = AvgValues,
                        StrokeThickness = 4,
                        Stroke = new SolidColorBrush(System.Windows.Media.Colors.Black),
                        Fill = new SolidColorBrush(System.Windows.Media.Colors.Transparent),
                        PointGeometry = null,
                        Configuration = AvgMapper,
                    }
                });

                for (int i = 0; i < boltmap_cnt; i++)
                {
                    SeriesInfos.Add(new SeriesInfo()
                    {
                        BoltIndex = i,
                        Title = $"{i}",
                        Fill = Themes.Styles.GetForeground(i),
                        Series = new LineSeries()
                        {
                            Title = $"{i}",
                            Values = BoltValues,
                            StrokeThickness = 2,
                            Stroke = Themes.Styles.GetForeground(i),
                            Fill = new SolidColorBrush(System.Windows.Media.Colors.Transparent),
                            PointGeometry = null,
                            Configuration = (new BoltValueMapperCreate(i)).Mapper
                        }
                    });
                };
                //SeriesInfos[0].Series.SetValue()
                SeriesInfos[0].IsVisible = true;
                SeriesInfos[1].IsVisible = true;
                SeriesInfos[3].IsVisible = true;

                Series = new SeriesCollection();
                for (int i = 0; i < SeriesInfos.Count(); i++)
                {
                    int index = SeriesInfos.Count() - 1 - i;
                    if (SeriesInfos[index].IsVisible)
                    {
                        Series.Add(SeriesInfos[index].Series);
                    }
                }
            }

            public event PropertyChangedEventHandler PropertyChanged;
        }

        public class SeriesInfo : INotifyPropertyChanged
        {
            public int BoltIndex { get; set; }
            public string Title { get; set; }

            public Brush Fill { get; set; }

            public Series Series { get; set; }

            public bool IsVisible { get; set; }

            public event PropertyChangedEventHandler PropertyChanged;
        }
       
    
}
