using CommunityToolkit.Mvvm.Input;
using FLY.Thick.Base.Common;
using FLY.Thick.Base.IService;
using FLY.Thick.Base.Server;
using LiveCharts;
using LiveCharts.Defaults;
using LiveCharts.Wpf;
using Misc;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Unity;

namespace FLY.Thick.Base.UI
{
    /// <summary>
    /// Page_BorderSearch.xaml 的交互逻辑
    /// </summary>
    public partial class PgBorderSearch : Page
    {
        PgBorderSearchVm viewModel;
        IUnityContainer container;
        public PgBorderSearch()
        {
            InitializeComponent();

            if (System.ComponentModel.LicenseManager.UsageMode != System.ComponentModel.LicenseUsageMode.Runtime)
                return;

            this.Loaded += UcGridGraph_Loaded;
            this.Unloaded += UcGridGraph_Unloaded;
        }

        private void UcGridGraph_Unloaded(object sender, RoutedEventArgs e)
        {
            viewModel.DisposeBinding();
        }

        private void UcGridGraph_Loaded(object sender, RoutedEventArgs e)
        {
            viewModel.SetBinding();
        }

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

            viewModel = new PgBorderSearchVm();
            viewModel.Init(borderSearch, initParamService, gageService, chart);

            this.DataContext = viewModel;
        }
    }

    public class IntConverter : IValueConverter
    {
        #region IValueConverter 成员

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            try
            {
                int v = (int)value;
                if (Misc.MyBase.ISVALIDATA(v))
                    return v.ToString();
                else
                    return "null";
            }
            catch
            {
                return "null";
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            try
            {
                int v;
                if (int.TryParse(value as string, out v))
                {
                    return v;
                }
                else
                {
                    return Misc.MyBase.NULL_VALUE;
                }
            }
            catch
            {
                return Misc.MyBase.NULL_VALUE;
            }
        }

        #endregion
    }
    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 CartesianChartZoomInHelper ZoomInHelper { get; private set; }

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

        public ChartValues<ObservablePoint> Values { get; } = new ChartValues<ObservablePoint>();

        /// <summary>
        /// 左边界 开始位置
        /// </summary>
        public int Sensor0AtBorderBegin { get; set; }
        /// <summary>
        /// 左边界 宽度
        /// </summary>
        public int Sensor0AtBorderWidth { get; set; }

        /// <summary>
        /// 右边界 开始位置
        /// </summary>
        public int Sensor1AtBorderBegin { get; set; }

        /// <summary>
        /// 右边 宽度
        /// </summary>
        public int Sensor1AtBorderWidth { get; set; }
        #endregion

        #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 int PosOfGrid { get; set; } = 20;
        public double Mmpp { get; set; } = 0.0943;
        public int PosLength { get; set; } = 20000;

        /// <summary>
        /// grid数据量
        /// </summary>
        public int GridLen => PosLength / PosOfGrid;

        public Misc.DIRECTION Direction { get; private set; } = DIRECTION.FIX;
        public IBorderSearchService BorderSearchService => borderSearch;
        public IInitParamService InitParamService => initParam;

        #region 注入的对象
        DynArea dynArea;
        CartesianChart chart;
        IBorderSearchService borderSearch;
        IInitParamService initParam;
        #endregion


        BorderSearchGetViewReponse getViewReponse;


        Dictionary<object, List<Misc.BindingOperations.PropertyChangedEventContexts>> bindingConexts = new Dictionary<object, List<Misc.BindingOperations.PropertyChangedEventContexts>>();

        /// <summary>
        /// 数据已经绑定了
        /// </summary>
        bool isBinding;

        public PgBorderSearchVm()
        {
            ApplyCmd = new RelayCommand(Apply);

            ZoomInHelper = new CartesianChartZoomInHelper();
            ZoomInHelper.XRangeSlider.SliderMax = 1000;
            ZoomInHelper.XRangeSlider.SliderMin = 0;
            ZoomInHelper.XRangeSlider.MinRange = 10;

            ZoomInHelper.YRangeSlider.SliderMax = 66000;
            ZoomInHelper.YRangeSlider.SliderMin = -1000;
            ZoomInHelper.YRangeSlider.MinRange = 100;

            XFormatter = (x) =>
            {
                int pos = (int)getPosFromGridIndex((int)x);
                int mm = (int)(pos * Mmpp);
                return $"{pos}\n{mm}mm";
            };
            YFormatter = (y) =>
            {
                return $"{y}";
            };
        }


        public void Init(
            IBorderSearchService borderSearch,
            IInitParamService initParamService,
            ITDGageService gageService,
            CartesianChart chart)
        {
            this.borderSearch = borderSearch;
            this.initParam = initParamService;

            dynArea = gageService.DynArea;
            this.chart = chart;

            SetBinding();
        }

        /// <summary>
        /// 参数绑定
        /// </summary>
        public void SetBinding()
        {
            if (isBinding)
                return;
            isBinding = true;

            //下面全部event保存在bindingConexts
            Misc.BindingOperations.StartMarkdownEvents(bindingConexts);
            Misc.BindingOperations.SetBinding(borderSearch, nameof(borderSearch.Enable), this, nameof(Enable));

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

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

            Misc.BindingOperations.SetBinding(initParam, nameof(initParam.PosLength), this, nameof(PosLength));
            Misc.BindingOperations.SetBinding(initParam, nameof(initParam.PosOfGrid), this, nameof(PosOfGrid));
            Misc.BindingOperations.SetBinding(initParam, nameof(initParam.Encoder1_mmpp), this, nameof(Mmpp));

            Misc.BindingOperations.SetBinding(this, nameof(PosLength), this, () =>
            {
                ZoomInHelper.XRangeSlider.SliderMax = PosLength;
            });

            //备份event完毕, 必须关闭记录
            Misc.BindingOperations.StopMarkdownEvents();

            ZoomInHelper.Init(chart);

            borderSearch.PropertyChanged += MborderSearch_PropertyChanged;

            getView();
        }
        /// <summary>
        /// 解除绑定
        /// </summary>
        public void DisposeBinding()
        {
            if (!isBinding)//已经解除绑定了
                return;
            isBinding = false;

            //释放全部 event
            Misc.BindingOperations.DisposeEventTargetObject(bindingConexts);

            ZoomInHelper.DisposeBinding();


            borderSearch.PropertyChanged -= MborderSearch_PropertyChanged;
        }

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

            if (e.PropertyName == nameof(BorderSearch.UpdateTime))
            {
                getView();
            }
        }
        void getView()
        {
            borderSearch.GetView((asyncContext, retData) =>
            {
                var response = retData as BorderSearchGetViewReponse;
                if (response == null)
                    return;
                this.getViewReponse = response;

                this.Direction = getViewReponse.direction;

                int[] grid = getViewReponse.dat;
                if (grid == null)
                    return;
 
                int posOfGrid = getViewReponse.posOfGrid;
                var thk0s = grid.Select((ad, index) =>
                {
                    int pos = (response.gridBegin + index) * posOfGrid;
                    double ad2 = Misc.MyBase.ISVALIDATA(ad) ? ad : double.NaN;
                    ObservablePoint point = new ObservablePoint(pos, ad2);
                    return point;
                });


                Values.Clear();
                Values.AddRange(thk0s);


                UpdateRange();

                Sensor0AtBorderBegin = response.border.Begin - SensorWidth / 2;
                Sensor0AtBorderWidth = SensorWidth;

                Sensor1AtBorderBegin = response.border.End - SensorWidth / 2;
                Sensor1AtBorderWidth = SensorWidth;

            }, this);
        }


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

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

            borderSearch.Apply();

            string tit = (string)Application.Current.TryFindResource("str.PgBorderSearch.ApplySuccessfully");
            FLY.ControlLibrary.Window_Tip.Show(tit,null,TimeSpan.FromSeconds(2));

        }

        void UpdateRange()
        {
            List<double> vlist = new List<double>();

            var value0s = Values.Where(v => !double.IsNaN(v.Y)).Select(v => v.Y);
            vlist.AddRange(value0s);

            if (vlist.Count() == 0)
            {
                //没有任何数据
                return;
            }
            else
            {

                double max = vlist.Max();
                double min = vlist.Min();
                double range = max - min;
                if (range < 10)
                    range = 10;

                ZoomInHelper.YRangeSlider.SliderMax = Math.Round(max + range / 10);
                ZoomInHelper.YRangeSlider.SliderMin = Math.Round(min - range / 10);
            }
        }





        int getPosFromGridIndex(int gridIndex)
        {
            return gridIndex * PosOfGrid;
        }
        int getGridIndexFromPos(int pos)
        {
            return pos / PosOfGrid;
        }
    }
}
