using CommunityToolkit.Mvvm.Input;
using FLY.Thick.Base.Common;
using FLY.Thick.Base.IService;
using FLY.Thick.Base.Server;
using Misc;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Controls;
using System.Windows.Forms.DataVisualization.Charting;
using Unity;

namespace FLY.Thick.Base.UI
{
    /// <summary>
    /// Page_BorderSearch.xaml 的交互逻辑
    /// </summary>
    public partial class PgBorderSearch : Page
    {
        PgBorderSearchVm viewModel;
        IUnityContainer container;
        public PgBorderSearch()
        {
            InitializeComponent();
            InitializeChart();
        }
        void InitializeChart()
        {
            System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
            System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
            System.Windows.Forms.DataVisualization.Charting.Series series_datas = new System.Windows.Forms.DataVisualization.Charting.Series();
            System.Windows.Forms.DataVisualization.Charting.Series series_border = new System.Windows.Forms.DataVisualization.Charting.Series();


            // 
            // chart1
            // 
            //this.chart1.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(211)), ((System.Byte)(223)), ((System.Byte)(240)));
            //this.chart1.BackSecondaryColor = System.Drawing.Color.White;
            //this.chart1.BackGradientStyle = System.Windows.Forms.DataVisualization.Charting.GradientStyle.TopBottom;
            //this.chart1.BorderlineColor = System.Drawing.Color.FromArgb(((System.Byte)(26)), ((System.Byte)(59)), ((System.Byte)(105)));
            //this.chart1.BorderlineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Solid;
            //this.chart1.BorderlineWidth = 2;
            //this.chart1.BorderSkin.SkinStyle = System.Windows.Forms.DataVisualization.Charting.BorderSkinStyle.Emboss;
            #region chartArea
            #region chartArea1

            chartArea1.Name = "chartArea1";

            chartArea1.AxisX.IsLabelAutoFit = false;
            chartArea1.AxisX.LabelStyle.Font = new System.Drawing.Font("Trebuchet MS", 8.25F, System.Drawing.FontStyle.Bold);
            //chartArea1.AxisX.LabelStyle.IsEndLabelVisible = false;
            chartArea1.AxisX.LineColor = System.Drawing.Color.FromArgb(((System.Byte)(64)), ((System.Byte)(64)), ((System.Byte)(64)), ((System.Byte)(64)));
            chartArea1.AxisX.MajorGrid.LineColor = System.Drawing.Color.FromArgb(((System.Byte)(64)), ((System.Byte)(64)), ((System.Byte)(64)), ((System.Byte)(64)));
            chartArea1.AxisX.Title = "位置(脉冲)";

            chartArea1.AxisY.IsLabelAutoFit = false;
            chartArea1.AxisY.LabelStyle.Font = new System.Drawing.Font("Trebuchet MS", 8.25F, System.Drawing.FontStyle.Bold);
            chartArea1.AxisY.LineColor = System.Drawing.Color.FromArgb(((System.Byte)(64)), ((System.Byte)(64)), ((System.Byte)(64)), ((System.Byte)(64)));
            chartArea1.AxisY.MajorGrid.LineColor = System.Drawing.Color.FromArgb(((System.Byte)(64)), ((System.Byte)(64)), ((System.Byte)(64)), ((System.Byte)(64)));
            chartArea1.AxisY.Title = "AD值";
            //chartArea1.AxisY.IsStartedFromZero = false;

            chartArea1.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(64)), ((System.Byte)(165)), ((System.Byte)(191)), ((System.Byte)(228)));
            chartArea1.BackSecondaryColor = System.Drawing.Color.White;
            chartArea1.BackGradientStyle = System.Windows.Forms.DataVisualization.Charting.GradientStyle.TopBottom;
            chartArea1.BorderColor = System.Drawing.Color.FromArgb(((System.Byte)(64)), ((System.Byte)(64)), ((System.Byte)(64)), ((System.Byte)(64)));
            chartArea1.BorderDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Solid;

            chartArea1.CursorX.IsUserEnabled = true;
            chartArea1.CursorX.IsUserSelectionEnabled = true;
            chartArea1.CursorX.SelectionColor = System.Drawing.SystemColors.Highlight;

            chartArea1.CursorY.IsUserEnabled = true;
            chartArea1.CursorY.IsUserSelectionEnabled = true;
            chartArea1.CursorY.SelectionColor = System.Drawing.SystemColors.Highlight;

            chartArea1.Position.Auto = true;
            chartArea1.ShadowColor = System.Drawing.Color.Transparent;

            #endregion

            this.chart1.ChartAreas.Add(chartArea1);
            #endregion

            #region legend
            legend1.Name = "legend1";

            legend1.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Right;
            legend1.Alignment = System.Drawing.StringAlignment.Far;
            legend1.LegendStyle = LegendStyle.Column;
            legend1.IsDockedInsideChartArea = true;
            legend1.DockedToChartArea = chartArea1.Name;

            legend1.IsTextAutoFit = false;
            legend1.BackColor = System.Drawing.Color.Transparent;
            legend1.Font = new System.Drawing.Font("Trebuchet MS", 8.25F, System.Drawing.FontStyle.Bold);
            legend1.Position.Auto = true;
            chart1.Legends.Add(legend1);
            #endregion

            #region series
            series_datas.Name = "series_datas";
            series_datas.BorderColor = System.Drawing.Color.FromArgb(((System.Byte)(180)), ((System.Byte)(26)), ((System.Byte)(59)), ((System.Byte)(105)));
            series_datas.BorderWidth = 2;
            series_datas.ChartArea = chartArea1.Name;
            series_datas.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
            series_datas.Color = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(65)))), ((int)(((byte)(140)))), ((int)(((byte)(240)))));

            series_datas.LegendText = "AD数据";
            series_datas.IsVisibleInLegend = true;
            series_datas.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Int32;
            series_datas.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Int32;

            series_datas.ShadowColor = System.Drawing.Color.Black;
            series_datas.ShadowOffset = 2;

            series_border.Name = "series_border";
            series_border.LegendText = "边界点";
            series_border.ChartArea = chartArea1.Name;
            series_border.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Point;
            series_border.Color = System.Drawing.Color.Violet;
            series_border.BorderColor = System.Drawing.Color.DarkViolet;
            series_border.BorderWidth = 3;

            series_border.MarkerSize = 6;
            series_border.MarkerStyle = System.Windows.Forms.DataVisualization.Charting.MarkerStyle.Circle;
            series_border.MarkerBorderColor = System.Drawing.Color.DarkViolet;
            series_border.MarkerColor = System.Drawing.Color.Violet;

            series_border.ShadowColor = System.Drawing.Color.Black;
            series_border.ShadowOffset = 2;

            chart1.Series.Add(series_datas);
            chart1.Series.Add(series_border);
            #endregion

            chart1.Name = "chart1";
            chart1.Palette = System.Windows.Forms.DataVisualization.Charting.ChartColorPalette.BrightPastel;
            //chart1.Location = new System.Drawing.Point(0, 0);

            //chart1.PrePaint += Chart1_PrePaint;
        }

        [InjectionMethod]
        public void Init(
            IUnityContainer container,
            IBorderSearchService borderSearchService,
            IInitParamService initParamService,
            ITDGageService gageService)
        {
            this.container = container;
            container.BuildUp(mircoGage);

            viewModel = new PgBorderSearchVm();
            viewModel.Init(borderSearchService, initParamService, gageService, chart1);

            this.DataContext = viewModel;
        }
    }

    public class PgBorderSearchVm : INotifyPropertyChanged
    {
        #region 延时推送 MARKNO
        const int MARKNO_UPDATE_BORDER = 0;
        const int MARKNO_UPDATE_DATAS = 1;

        #endregion
        public event PropertyChangedEventHandler PropertyChanged;

        #region 参数
        /// <summary>
        /// 启动与否
        /// </summary>
        public bool Enable { get; set; }

        /// <summary>
        /// 单一材料
        /// </summary>
        public bool IsOneMaterial { get; set; }
        /// <summary>
        /// 边界拐点检测，找到的边界更加精确
        /// </summary>
        public bool IsBreakDetect { get; set; }

        /// <summary>
        /// 有限范围
        /// </summary>
        public Range Valid { get; set; }

        /// <summary>
        /// 手动设置温修AD值
        /// </summary>
        public bool TempADBySet { set; get; }
        /// <summary>
        /// 温修AD值
        /// </summary>
        public int TempAD { get; set; }

        /// <summary>
        /// AD超过了范围， 就认为开始找到边界
        /// </summary>
        public int TempRange { get; set; }
        /// <summary>
        /// 温修范围是温修的百分比
        /// </summary>
        public bool IsTempRangeByPercent { get; set; }

        /// <summary>
        ///  温修范围百分比
        /// </summary>
        public double TempRangePercent { get; set; }
        /// <summary>
        /// 有滤波器，只有非空的连续N个pos以上，才开始算边界开始
        /// </summary>
        public int N { get; set; }

        /// <summary>
        /// 探头直径，单位脉冲， 膜宽 = 边界范围 - 探头直径
        /// </summary>
        public int SensorWidth { get; set; }

        /// <summary>
        /// 找到边界后，边界 + 探头半径  + N2个脉冲。 这个是数据有效的开始
        /// </summary>
        public int N2 { get; set; }

        /// <summary>
        /// 记录两个边界以后扫描，以它们再外扩N3个脉冲，作为扫描范围 
        /// </summary>
        public int N3 { get; set; }

        #endregion
        #region Command
        public RelayCommand ApplyCmd { get; private set; }
        #endregion

        public Misc.DIRECTION Direction { get; private set; } = DIRECTION.FIX;
        public IBorderSearchService BorderSearchService { get; private set; }
        public IInitParamService InitParamService { get; private set; }
        DynArea dynArea;
        BorderSearchGetViewReponse getViewReponse;

        System.Windows.Forms.DataVisualization.Charting.Chart chart1;
        public PgBorderSearchVm()
        {
            ApplyCmd = new RelayCommand(Apply);
        }


        public void Init(
            IBorderSearchService borderSearchService,
            IInitParamService initParamService,
            ITDGageService gageService,
            System.Windows.Forms.DataVisualization.Charting.Chart chart)
        {
            BorderSearchService = borderSearchService;
            InitParamService = initParamService;

            dynArea = gageService.DynArea;
            chart1 = chart;

            Misc.BindingOperations.SetBinding(BorderSearchService, nameof(BorderSearchService.Enable), this, nameof(Enable));

            Misc.BindingOperations.SetBinding(BorderSearchService, nameof(BorderSearchService.IsOneMaterial), this, nameof(IsOneMaterial));
            Misc.BindingOperations.SetBinding(BorderSearchService, nameof(BorderSearchService.IsBreakDetect), this, nameof(IsBreakDetect));
            Misc.BindingOperations.SetBinding(BorderSearchService, nameof(BorderSearchService.Valid), () =>
            {
                Valid = new Range(BorderSearchService.Valid);
            });

            Misc.BindingOperations.SetBinding(BorderSearchService, nameof(BorderSearchService.TempADBySet), this, nameof(TempADBySet));
            Misc.BindingOperations.SetBinding(BorderSearchService, nameof(BorderSearchService.TempAD), this, nameof(TempAD));
            Misc.BindingOperations.SetBinding(BorderSearchService, nameof(BorderSearchService.TempRange), this, nameof(TempRange));
            Misc.BindingOperations.SetBinding(BorderSearchService, nameof(BorderSearchService.IsTempRangeByPercent), this, nameof(IsTempRangeByPercent));
            Misc.BindingOperations.SetBinding(BorderSearchService, nameof(BorderSearchService.TempRangePercent), this, nameof(TempRangePercent));
            Misc.BindingOperations.SetBinding(BorderSearchService, nameof(BorderSearchService.N), this, nameof(N));
            Misc.BindingOperations.SetBinding(BorderSearchService, nameof(BorderSearchService.SensorWidth), this, nameof(SensorWidth));
            Misc.BindingOperations.SetBinding(BorderSearchService, nameof(BorderSearchService.N2), this, nameof(N2));
            Misc.BindingOperations.SetBinding(BorderSearchService, nameof(BorderSearchService.N3), this, nameof(N3));


            BorderSearchService.PropertyChanged += MBorderSearchService_PropertyChanged;
            InitParamService.PropertyChanged += MInitParamService_PropertyChanged;
            UpdateX();

            chart1.PrePaint += Chart1_PrePaint;

            getView();
        }
        private void MInitParamService_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(InitParamService.PosLength))
            {
                UpdateX();
            }
        }

        private void MBorderSearchService_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {

            if (e.PropertyName == nameof(BorderSearch.UpdateTime))
            {
                getView();
            }
            else if ((e.PropertyName == nameof(BorderSearch.TempAD)) ||
                (e.PropertyName == nameof(BorderSearch.TempRange)))
            {
                chart1.Invalidate();
            }
        }
        void getView()
        {
            BorderSearchService.GetView((asyncContext, retData) =>
            {
                this.getViewReponse = retData as BorderSearchGetViewReponse;
                UpdateDatas();
                UpdateBorder();
                UpdateSensorWidth();
            }, this);
        }
        private void Chart1_PrePaint(object sender, ChartPaintEventArgs e)
        {
            if (e.ChartElement is ChartArea)
            {
                ChartArea area = (ChartArea)e.ChartElement;
                if (Double.IsNaN(area.AxisY.Minimum))
                    return;

                //阀值线
                System.Drawing.Pen pen = new System.Drawing.Pen(System.Drawing.Color.Red, 2);

                int threshold = BorderSearchService.TempAD - BorderSearchService.TempRange;
                DrawYGridTick(e.ChartGraphics, pen, threshold);

                threshold = BorderSearchService.TempAD + BorderSearchService.TempRange;
                DrawYGridTick(e.ChartGraphics, pen, threshold);
            }
        }

        private void Apply()
        {
            if (!WdPassword.Authorize("BorderSearch"))
                return;

            BorderSearchService.Enable = Enable;
            BorderSearchService.IsOneMaterial = IsOneMaterial;
            BorderSearchService.IsBreakDetect = IsBreakDetect;
            BorderSearchService.Valid = Valid.ToStruct();
            BorderSearchService.TempADBySet = TempADBySet;
            BorderSearchService.TempAD = TempAD;
            BorderSearchService.TempRange = TempRange;
            BorderSearchService.IsTempRangeByPercent = IsTempRangeByPercent;
            BorderSearchService.TempRangePercent = TempRangePercent;
            BorderSearchService.N = N;
            BorderSearchService.SensorWidth = SensorWidth;
            BorderSearchService.N2 = N2;
            BorderSearchService.N3 = N3;

            BorderSearchService.Apply();
            FLY.ControlLibrary.Window_Tip.Show("应用成功",
                null,
                TimeSpan.FromSeconds(2));

        }
        void DrawYGridTick(ChartGraphics cg, System.Drawing.Pen pen, double y)
        {
            ChartArea area = chart1.ChartAreas[0];

            if (y > area.AxisY.Maximum || y < area.AxisY.Minimum)
                return;

            // Take Graphics object from chart
            Graphics graph = cg.Graphics;

            // Convert X and Y values to screen position
            double py = cg.GetPositionFromAxis(area.Name, AxisName.Y, y);

            double XMin = cg.GetPositionFromAxis(area.Name, AxisName.X, area.AxisX.Minimum);
            double XMax = cg.GetPositionFromAxis(area.Name, AxisName.X, area.AxisX.Maximum);

            System.Drawing.PointF[] points = new System.Drawing.PointF[2];
            points[0].X = (float)XMin;
            points[1].X = (float)XMax;
            points[0].Y = points[1].Y = (float)py;

            // Convert relative coordinates to absolute coordinates.
            points[0] = cg.GetAbsolutePoint(points[0]);
            points[1] = cg.GetAbsolutePoint(points[1]);

            graph.DrawLine(pen, points[0], points[1]);

        }
        void UpdateY()
        {
            if (getViewReponse == null)
                return;
            int[] grid = getViewReponse.dat;
            if (grid == null)
                return;

            int max = Misc.MyMath.Max(grid);
            int min = Misc.MyMath.Min(grid);
            if (Misc.MyBase.ISVALIDATA(max))
            {
                if (max != min)
                {
                    chart1.ChartAreas[0].AxisY.Maximum = max + (max - min) * 0.1;
                    chart1.ChartAreas[0].AxisY.Minimum = min - (max - min) * 0.1;
                    if (chart1.ChartAreas[0].AxisY.Minimum < 0)
                        chart1.ChartAreas[0].AxisY.Minimum = 0;
                }
                else
                {
                    chart1.ChartAreas[0].AxisY.Minimum = 0;
                    chart1.ChartAreas[0].AxisY.Maximum = dynArea.ADMax;
                }
            }
            else
            {
                chart1.ChartAreas[0].AxisY.Minimum = 0;
                chart1.ChartAreas[0].AxisY.Maximum = dynArea.ADMax;
            }

            if (chart1.ChartAreas[0].AxisY.Minimum == chart1.ChartAreas[0].AxisY.Maximum)
            {
                chart1.ChartAreas[0].AxisY.Minimum -= 1000;
                chart1.ChartAreas[0].AxisY.Maximum += 1000;
            }
        }
        void UpdateX()
        {
            chart1.ChartAreas[0].AxisX.Minimum = 0;
            chart1.ChartAreas[0].AxisX.Maximum = InitParamService.PosLength;
        }
        void UpdateDatas()
        {
            System.Windows.Forms.DataVisualization.Charting.Series series = chart1.Series["series_datas"];

            series.Points.Clear();
            if (getViewReponse == null)
                return;

            this.Direction = getViewReponse.direction;
            int[] grid = getViewReponse.dat;
            if (grid == null)
                return;
            int posOfGrid = getViewReponse.posOfGrid;

            for (int i = 0; i < grid.Length; i++)
            {
                series.Points.AddXY((i + getViewReponse.gridBegin) * posOfGrid, grid[i]);
                if (!Misc.MyBase.ISVALIDATA(grid[i]))
                {
                    series.Points[i].IsEmpty = true;
                }
            }
            UpdateY();
        }


        #region 更新边界
        bool UpdateBorder_pos(
            System.Windows.Forms.DataVisualization.Charting.Series series,
            int pos)
        {
            if (getViewReponse == null)
                return false;

            int[] grid = getViewReponse.dat;
            if (grid == null)
                return false;

            int posOfGrid = getViewReponse.posOfGrid;

            int grid_idx = pos / posOfGrid - getViewReponse.gridBegin;
            if (grid_idx < 0)
                return false;
            if (grid_idx >= grid.Length)
                return false;

            int d = grid[grid_idx];
            if (!Misc.MyBase.ISVALIDATA(d))
                return false;

            series.Points.AddXY(pos, d);
            return true;
        }


        void UpdateBorder()
        {
            System.Windows.Forms.DataVisualization.Charting.Series series = chart1.Series["series_border"];
            series.Points.Clear();
            if (getViewReponse == null)
                return;

            Misc.Range border = getViewReponse.border;
            if (border == null)
                return;

            if (!border.IsValid)
                return;

            if (!UpdateBorder_pos(series, border.Begin))
                return;

            if (!UpdateBorder_pos(series, border.End))
                return;
        }

        void UpdateSensorWidth()
        {
            StripLinesCollection stripLines = chart1.ChartAreas[0].AxisX.StripLines;

            stripLines.Clear();
            if (getViewReponse == null)
                return;
            Misc.Range border = getViewReponse.border;

            if (border == null)
                return;

            if (!border.IsValid)
                return;

            StripLine stripline = new StripLine();
            stripline.BackColor = System.Drawing.Color.FromArgb(64, System.Drawing.Color.Green);
            stripline.Interval = 0;
            stripline.IntervalOffset = border.Begin - BorderSearchService.SensorWidth / 2;
            stripline.StripWidth = BorderSearchService.SensorWidth;
            stripLines.Add(stripline);

            stripline = new StripLine();
            stripline.BackColor = System.Drawing.Color.FromArgb(64, System.Drawing.Color.Green);
            stripline.Interval = 0;
            stripline.IntervalOffset = border.End - BorderSearchService.SensorWidth / 2;
            stripline.StripWidth = BorderSearchService.SensorWidth;
            stripLines.Add(stripline);
        }

        #endregion
    }
}
