using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
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 System.Windows.Threading;
using LiveCharts;
using LiveCharts.Configurations;
using LiveCharts.Helpers;
using LiveCharts.Wpf;
using Misc;

namespace FLY.Thick.Base.UI.UiModule
{
    /// <summary>
    /// Page_FixAnalyze.xaml 的交互逻辑
    /// </summary>
    public partial class PgFixAnalyze : Page
    {
        PgFixAnalyzeVm viewModel;
        public PgFixAnalyze()
        {
            InitializeComponent();
        }
        public void Init(double intervalms, List<double> datas)
        {
            viewModel = new PgFixAnalyzeVm();
            viewModel.Init(intervalms, datas);
            this.DataContext = viewModel;
        }

        private void UIElement_OnMouseMove(object sender, MouseEventArgs e)
        {
            var vm = viewModel;
            var chart = (LiveCharts.Wpf.CartesianChart)sender;

            //lets get where the mouse is at our chart
            var mouseCoordinate = e.GetPosition(chart);

            //now that we know where the mouse is, lets use
            //ConverToChartValues extension
            //it takes a point in pixes and scales it to our chart current scale/values
            var p = chart.ConvertToChartValues(mouseCoordinate);

            //in the Y section, lets use the raw value
            vm.YPointer = p.Y;
            vm.XPointer = p.X;
        }


        private void ButtonTestClick(object sender, RoutedEventArgs e)
        {
            viewModel.Test();
        }

        private void UIElement_OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            var vm = viewModel;
            var chart = (LiveCharts.Wpf.CartesianChart)sender;

            //lets get where the mouse is at our chart
            var mouseCoordinate = e.GetPosition(chart);

            //now that we know where the mouse is, lets use
            //ConverToChartValues extension
            //it takes a point in pixes and scales it to our chart current scale/values
            var p = chart.ConvertToChartValues(mouseCoordinate);

            //in the Y section, lets use the raw value
            vm.YPointer = p.Y;
            vm.XPointer = p.X;
        }
    }
    public class PgFixAnalyzeVm : INotifyPropertyChanged
    {

        /// <summary>
        /// X轴拖拉条 最大值
        /// </summary>
        public double XRangeSliderMax { get; set; } = 10000;

        /// <summary>
        /// X轴拖拉条 最小值
        /// </summary>
        public double XRangeSliderMin { get; set; } = 0;

        /// <summary>
        /// X轴 最大值
        /// </summary>
        public double XMax { get; set; } = 1000;

        /// <summary>
        /// X轴 最小值
        /// </summary>
        public double XMin { get; set; }


        public double LowerValue { get; set; }
        public double UpperValue { get; set; }

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


        public double YPointer { get; set; } = 3;
        public double XPointer { get; set; } = 3;
        public ChartValues<double> Values { get; private set; } = new ChartValues<double>();
        public Func<double, string> XFormatter { get; private set; }

        DispatcherTimer timer;
        public void Test()
        {
            List<double> datas = new List<double>();

            double intervalms = 1.28;

            for (int i = 0; i < 10000; i++)
            {
                double sum = 0;

                sum += getd(20, intervalms, i);
                sum += getd(100, intervalms, i);
                sum += getd(50, intervalms, i);


                datas.Add(sum);
            }
            
            Init(intervalms, datas);
        }
        double getd(double hz, double ms, int i)
        {
            double cnt = 1000 / ms / hz;
            return Math.Sin(Math.PI * 2 * i / cnt);
        }
        public PgFixAnalyzeVm()
        {

            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(1);
            timer.Tick += Timer_Tick;
            this.PropertyChanged += PgFixAnalyzeVm_PropertyChanged;
        }

        private void PgFixAnalyzeVm_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(UpperValue)
                || e.PropertyName == nameof(LowerValue)) {
                if (!timer.IsEnabled)
                    timer.Start();

            }
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            timer.Stop();
            if (LowerValue < UpperValue) {
                
                XMax = UpperValue;
                XMin = LowerValue;
            }
            
        }
        List<double> Magnitudes = new List<double>();
        public double MinFs { get; private set; } = 0.1;
        public void Init(double intervalms, List<double> datas)
        {
            MinFs = (1000 / intervalms) / datas.Count();
            XFormatter = (d) =>
            {
                int n = (int)d;
                return ((n) * MinFs).ToString("F1");
            };
            Values.Clear();
            //
            System.Numerics.Complex[] complexs = new System.Numerics.Complex[datas.Count()];
            for (int i = 0; i < datas.Count(); i++)
            {
                complexs[i] = new System.Numerics.Complex(datas[i], 0);
            }
            
            MathNet.Numerics.IntegralTransforms.Fourier.Forward(complexs);
            complexs[0] = new System.Numerics.Complex(0, 0);
            Magnitudes.Clear();
            Magnitudes.AddRange(complexs.Take(complexs.Count() / 2).Select(c=>c.Magnitude));

            Values.AddRange(Magnitudes);
            XRangeSliderMax = Values.Count();
            XRangeSliderMin = 0;
            UpperValue = XRangeSliderMax;
            LowerValue = 0;
        }
        public event PropertyChangedEventHandler PropertyChanged;
        protected void ToPropertyChanged(string propertyName) {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
