using FLY.IntegratedControl.Common;
using FLY.OBJComponents.Client;
using LiveCharts;
using LiveCharts.Configurations;
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;
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;

namespace FLY.IntegratedControl.UI.Client.UIModule
{
    /// <summary>
    /// IBCCtrlGraph.xaml 的交互逻辑
    /// </summary>
    public partial class IBCCtrlGraph : UserControl
    {
        IBCCtrlGraphModelView iBCCtrlGraphModelView;
        public IBCCtrlGraph()
        {
            InitializeComponent();
        }
        public void Init()
        {
            iBCCtrlGraphModelView = new IBCCtrlGraphModelView();
            iBCCtrlGraphModelView.InitData();

            grid_modelview.DataContext = iBCCtrlGraphModelView;
            grid_bufferwindow.DataContext = iBCCtrlGraphModelView.bufferWindow;
        }
        private void button_info_Click(object sender, RoutedEventArgs e)
        {
            Window_GraphSet w = new Window_GraphSet();
            w.Owner = FLY.ControlLibrary.COMMON.GetWindow(this);
            w.ShowDialog();
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            
        }

        private void button_newest_Click(object sender, RoutedEventArgs e)
        {
            iBCCtrlGraphModelView.Newest();
        }

        private void button_pre_Click(object sender, RoutedEventArgs e)
        {
            iBCCtrlGraphModelView.Pre();
        }

        private void button_next_Click(object sender, RoutedEventArgs e)
        {
            iBCCtrlGraphModelView.Next();
        }
    }
    public class IBCCtrlGraphModelView : INotifyPropertyChanged
    {
        const int MARKNO_TOVALUES = 1;
        /// <summary>
        /// 当前现在不是最新,而且没有移动动作,20秒自动按 Newest()
        /// </summary>
        DispatcherTimer timer;
        public event PropertyChangedEventHandler PropertyChanged;

        FLY.IntegratedControl.Client.ICSystemClient iCSystemClient;
        public FLY.OBJComponents.Client.BufferWindow<FlyData_IBCCtrl> bufferWindow;
        public IBCCtrlGraphParams graphParams;

        /// <summary>
        /// 画面只显示200个数据, 就算设置画面设置显示1000个数,也会整合为200个数据
        /// </summary>
        const int ValuesCap = 200;
        /// <summary>
        /// 自动按保持最新值,总时间
        /// </summary>
        const int AutoKeepNewestTimeCounter = 10;
        #region property

        /// <summary>
        ///自动按保持最新值,剩余时间
        /// </summary>
        public int AutoKeepNewestTimeRemaining { get; set; }

        /// <summary>
        /// 曲线, 是有 bufferWindow.Record 生成的
        /// Values 最大数量只有 ValuesCap
        /// 平均从 bufferWindow.Record提取
        /// </summary>
        public ChartValues<FlyData_IBCCtrl> Values { get; set; }

        /// <summary>
        /// 折径曲线 XY 定义
        /// </summary>
        public CartesianMapper<FlyData_IBCCtrl> Mapper_FilmWidth { get; set; }

        /// <summary>
        /// 进风-出风曲线 XY 定义
        /// </summary>
        public CartesianMapper<FlyData_IBCCtrl> Mapper_D { get; set; }

        /// <summary>
        /// X轴格式
        /// </summary>
        public Func<double, string> DateTimeFormatter { get; set; }

        /// <summary>
        /// y轴格式
        /// </summary>
        public Func<double, string> YFormatter { get; set; }

        /// <summary>
        /// 折径目标值
        /// </summary>
        public double FilmWidthAxisYTarget { get; set; }

        /// <summary>
        /// 折径 最大值
        /// </summary>
        public double FilmWidth_MaxValue { get; set; }
        /// <summary>
        /// 折径 最小值
        /// </summary>
        public double FilmWidth_MinValue { get; set; }

        /// <summary>
        /// 进风-出风 最大值
        /// </summary>
        public double D_MaxValue { get; set; }
        /// <summary>
        /// 进风-出风 最小值
        /// </summary>
        public double D_MinValue { get; set; }

        /// <summary>
        /// 开始时间
        /// </summary>
        public DateTime BeginTime { get; set; }

        /// <summary>
        /// 结束数据
        /// </summary>
        public DateTime EndTime { get; set; }
        #endregion

        public IBCCtrlGraphModelView()
        {
            Init();
        }
        void ToValues()
        {
            if (bufferWindow.Record.Count <= ValuesCap)
            {
                Values.Clear();
                Values.AddRange(bufferWindow.Record);
            }
            else
            {
                Values.Clear();
                List<FlyData_IBCCtrl> record = new List<FlyData_IBCCtrl>();
                for (int i = 0; i < ValuesCap; i++)
                {
                    int idx = i * bufferWindow.Record.Count / ValuesCap;
                    record.Add(bufferWindow.Record[idx]);
                }
                Values.AddRange(record);
            }
            if (Values.Count() > 0)
            {
                BeginTime = Values.First().Time;
                EndTime = Values.Last().Time;
            }
            else
            {
                BeginTime = DateTime.MinValue;
                EndTime = DateTime.MinValue;
            }
        }

        
        void Init()
        {
            Mapper_FilmWidth = Mappers.Xy<FlyData_IBCCtrl>()
                .X(value => value.Time.Ticks)
                .Y(value => value.FilmWidth);

            Mapper_D = Mappers.Xy<FlyData_IBCCtrl>()
                .X(value => value.Time.Ticks)
                .Y(value => value.DFreq);

            DateTimeFormatter = value => new DateTime((long)value).ToString("mm:ss");
            YFormatter = value => value.ToString("F0");

            Values = new ChartValues<FlyData_IBCCtrl>();
        }

        public void InitData()
        {
            graphParams = SysParam.Current.GraphParams;
            iCSystemClient = TDGage.Current.mICSystemService;

            bufferWindow = new BufferWindow<FlyData_IBCCtrl>(iCSystemClient.CtrlList, graphParams.WindowSize);

            Misc.BindingOperations.SetBinding(graphParams, "WindowSize", bufferWindow, "Size");

            bufferWindow.Record.CollectionChanged += (object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) =>
            {
                FObjBase.PollModule.Current.Poll_JustOnce(
                    () =>
                    {
                        ToValues();
                    }, this, MARKNO_TOVALUES);
            };

            Misc.BindingOperations.SetBinding(iCSystemClient.Item, "FilmWidthSet", this, "FilmWidthAxisYTarget");

            Update_filmwidth_y();
            Update_d_y();

            this.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "FilmWidthAxisYTarget")
                    Update_filmwidth_y();
            };

            graphParams.PropertyChanged += (s, e) => {
                if (e.PropertyName == "IsAxisYRangeAuto")
                {
                    Update_filmwidth_y();
                    Update_d_y();
                }
                else if (e.PropertyName == "FilmWidthAxisYRange")
                {
                    Update_filmwidth_y();
                }
                else if (
                    (e.PropertyName == "DAxisYTarget") ||
                    (e.PropertyName == "DAxisYRange"))
                {
                    Update_d_y();
                }
            };

            //当不是最新数据时,10秒内无操作,自动按 [最新]
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(1);
            timer.Tick += Timer_Tick;
            bufferWindow.PropertyChanged += BufferWindow_PropertyChanged;
        }
        private void Timer_Tick(object sender, EventArgs e)
        {
            AutoKeepNewestTimeRemaining--;
            if (AutoKeepNewestTimeRemaining <= 0)
            {
                AutoKeepNewestTimeRemaining = AutoKeepNewestTimeCounter;
                bufferWindow.MoveNewest();
            }
        }
        private void BufferWindow_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsKeepNewest")
            {
                if (!bufferWindow.IsKeepNewest)
                {
                    //当前不是最新,开始倒计时
                    AutoKeepNewestTimeRemaining = AutoKeepNewestTimeCounter;
                    timer.Start();
                }
                else
                {
                    timer.Stop();
                }
            }
        }

        void Update_filmwidth_y()
        {
            if (graphParams.IsAxisYRangeAuto)
            {
                FilmWidth_MaxValue = double.NaN;
                FilmWidth_MinValue = double.NaN;
            }
            else
            {
                FilmWidth_MaxValue = FilmWidthAxisYTarget + graphParams.FilmWidthAxisYRange;
                FilmWidth_MinValue = FilmWidthAxisYTarget - graphParams.FilmWidthAxisYRange;
            }
        }
        void Update_d_y()
        {
            if (graphParams.IsAxisYRangeAuto)
            {
                D_MaxValue = double.NaN;
                D_MinValue = double.NaN;
            }
            else
            { 
                D_MaxValue = graphParams.DAxisYTarget + graphParams.DAxisYRange;
                D_MinValue = graphParams.DAxisYTarget - graphParams.DAxisYRange;
            }
        }
        void Debug()
        {
            Values = new ChartValues<FlyData_IBCCtrl>();

            double target_filmwidth = 1000;
            double filmwidth = 800;
            double inletfreq = 30;
            double outletfreq = 30;
            double pid_p = 0.01;
            double p_f = 8;

            DateTime date = DateTime.Now;

            Random r = new Random();
            double noise = 2;


            double last_filmwidth = filmwidth;
            for (int i = 0; i < 1000; i++)
            {
                double e = target_filmwidth - filmwidth;
                last_filmwidth = filmwidth;

                double e_freq = e * pid_p;

                inletfreq = e_freq + outletfreq;


                e_freq = inletfreq - outletfreq;

                filmwidth += e_freq * p_f;

                filmwidth += (r.NextDouble() * noise - noise / 2);

                Values.Add(new FlyData_IBCCtrl()
                {
                    Time = date.AddSeconds(1 * i),
                    FilmWidth = (float)filmwidth,
                    InletAirFreq = (float)inletfreq,
                    OutletAirFreq = (float)outletfreq
                });
            }
            FilmWidthAxisYTarget = target_filmwidth;


        }

        public void Newest()
        {
            bufferWindow.MoveNewest();
        }
        public void Next()
        {
            bufferWindow.MoveNextPage();
        }
        public void Pre()
        {
            bufferWindow.MovePrePage();
        }
    }
    public class IBCCtrlGraphParams : INotifyPropertyChanged, Misc.ISaveToXml
    {
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// 窗口显示数据总量
        /// </summary>
        public int WindowSize { get; set; } = 1000;

        /// <summary>
        /// 折径,进风-出风, Y轴 自动设置 MaxValue, MinValue, 
        /// </summary>
        public bool IsAxisYRangeAuto { get; set; }
        /// <summary>
        /// 折径,Y轴显示范围, 中间值一定是 FilmWidthSet, 单位mm
        /// MaxValue = FilmWidthSet+FilmWidthAxisYRange
        /// MinValue = FilmWidthSet-FilmWidthAxisYRange
        /// </summary>
        public int FilmWidthAxisYRange { get; set; } = 20;


        /// <summary>
        /// 进风-出风 Y轴显示范围 单位Hz
        /// </summary>
        public int DAxisYRange { get; set; } = 10;

        /// <summary>
        /// 进风-出风 Y轴 中间显示值 单位Hz
        /// </summary>
        public int DAxisYTarget { get; set; } = 0;



        public string[] GetSavePropertyNames()
        {
            return new string[]{
                "WindowSize",
                "FilmWidthAxisYRange",
                "IsAxisYRangeAuto",
                "DAxisYRange",
                "DAxisYTarget",
            };
        }
    }
}