using LiveCharts;
using System;
using System.Collections.Generic;
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 MathNet.Numerics.LinearAlgebra;
using MathNet.Numerics.LinearAlgebra.Double;
using LiveCharts.Wpf;
using System.Globalization;
using Unity;
using GalaSoft.MvvmLight.Command;

namespace FLY.HeatingHelper.UI.UiModule
{
    /// <summary>
    /// UC_AirRingShift.xaml 的交互逻辑
    /// </summary>
    public partial class UC_AirRingShift : UserControl
    {
        public UC_AirRingShiftViewModel mainVM;
        public UC_AirRingShift()
        {
            InitializeComponent();
        }

        private IUnityContainer container;

        [InjectionMethod]
        public void Initialize(IUnityContainer container,IThickHeatData dat)
        {
            this.container = container;
            mainVM = container.Resolve<UC_AirRingShiftViewModel>();
            mainVM.Init(dat);

            FP_select1.DataContext = mainVM.vm1;
            FP_select2.DataContext = mainVM.vm2;
            DataContext = mainVM;
        }

        private void AutoCal_Shift(object sender, RoutedEventArgs e)
        {
            // 根据选定的两幅数据
            mainVM.AutoCal_Shift();
        }

        private void AirRingShift_Add(object sender, RoutedEventArgs e)
        {
            // 手动右移一个位置
            mainVM.Change_Shift(1);
        }

        private void AirRingShift_Sub(object sender, RoutedEventArgs e)
        {
            // 手动左移一个位置
            mainVM.Change_Shift(-1);
        }

        private void AirRingShift_Reset(object sender, RoutedEventArgs e)
        {
            mainVM.Change_Shift(int.MaxValue);
        }

        private void UserControl_Unloaded(object sender, RoutedEventArgs e)
        {
            mainVM.UnLoaded(sender);
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            mainVM.Loaded(sender);
        }

        private void AutoSearch_Shift(object sender, RoutedEventArgs e)
        {
            mainVM.AutoSearchAndCal_Shift();
        }

        private void Angle_Sub(object sender, RoutedEventArgs e)
        {
            mainVM.Change_Angle(-0.5);
        }

        private void Angle_Add(object sender, RoutedEventArgs e)
        {
            mainVM.Change_Angle(0.5);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {

        }

        private void Angle_Reset(object sender, RoutedEventArgs e)
        {
            mainVM.RotAngle = mainVM.CurrentAngle;
        }
    }

    public class UC_AirRingShiftViewModel:INotifyPropertyChanged
    {
        [InjectionMethod]
        public void Initilize(FLY.Thick.Blowing.IService.IBlowingService blowingService,
            FLY.FeedbackRenZiJia.IService.IHeatCellService heatCellService,
            FLY.Thick.Blowing.IService.IBlowingDetectService blowingDetectService)
        {
            blowing = blowingService;
            bDetect = blowingDetectService;
            this.heatCellService = heatCellService;
            Misc.BindingOperations.SetBinding(blowing, "OrgBoltNo", this, "CurrentResetBolt");
            Misc.BindingOperations.SetBinding(bDetect, "RAngle", this, "CurrentAngle");
            Misc.BindingOperations.SetBinding(this.heatCellService, "Kp", this, "CurrentKp");
            Apply = new RelayCommand(Command_Apply);
        }

        FLY.Thick.Blowing.IService.IBlowingService blowing;
        FLY.Thick.Blowing.IService.IBlowingDetectService bDetect;
        FLY.FeedbackRenZiJia.IService.IHeatCellService heatCellService;

        public UC_FramePickerViewModel vm1 = new UC_FramePickerViewModel();
        public UC_FramePickerViewModel vm2 = new UC_FramePickerViewModel();

        public int CurrentResetBolt { get; set; }
        public double CurrentAngle { get; set; }

        public double CurrentKp { get; set; }
        public double Kp { get; set; }

        public int LockFrames { get; set; } = 1;

        public bool LockAngle { get; set; } = true;

        public int SearchProgressValue { get; set; } = 0;
        public bool SearchEnabled { get; set; } = true;

        public SeriesCollection VarSeries { get; set; } = new SeriesCollection();

        public double[] DS_vthick { get; protected set; } = null;
        public double[] DS_vheat { get; protected set; } = null;

        public RelayCommand Apply { get; set; }
        private void Command_Apply()
        {
            if (!FLY.Thick.Base.UI.WdPassword.Authorize("Blowing"))
                return;

            var dlg = new Dlg_GetSaveSwitches.DLG_GetSaveSwitches();
            var vm = new Dlg_GetSaveSwitches.VM_GetSaveSwitches();
            dlg.Init(vm);
            dlg.ShowDialog();
            if (vm.IsCancel) return;
            if (vm.ResetBoltSave)
            {
                blowing.OrgBoltNo = NewResetBolt;
                blowing.Apply();
            }
                
            if (vm.RAngleSave)
            {
                bDetect.RAngle = RotAngle;
                bDetect.Apply();
            }
                
            if (vm.KpSave)
            {
                heatCellService.Kp = Kp;
                heatCellService.Apply();
            }

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

        private IThickHeatData _data;

        private int _NewResetBolt = 0;
        public int NewResetBolt
        {
            get
            {
                return _NewResetBolt;
            }
            internal set
            {
                if (_NewResetBolt != value)
                {
                    if(vth1 is null)
                    {
                        _NewResetBolt = value;
                        return;
                    }
                    int cnt = vth1.Count();
                    if (cnt > 0)
                    {
                        while (value < 1) value += cnt;
                        while (value > cnt) value -= cnt;
                        _NewResetBolt = value;
                        //while (_airRingShift < 0) _airRingShift += cnt;
                        //while (_airRingShift >= cnt) _airRingShift -= cnt;
                        //int rb = _airRingShift + resetBolt1;
                        //while (rb < 0) rb += cnt;
                        //while (rb >= cnt) rb -= cnt;
                        //ResetBolt = rb;
                        if (correls is null)
                            return;
                        TandH_Corel = correls[_NewResetBolt - 1];
                    }
                }
            }
        }
        public double TandH_Corel { get; internal set; } = 0;
        private double _rotAngle = 330;
        public double RotAngle
        {
            get { return _rotAngle; }
            set
            {
                if (Math.Abs(_rotAngle - value) > 0.00099)
                {
                    _rotAngle = value;
                    UpdateThickData();
                    UpdateVarChart();
                }
            }
        }
        //private int _resetBolt;
        //public int ResetBolt
        //{
        //    get { return _resetBolt; }
        //    set
        //    {
        //        if (_resetBolt != value)
        //        {
        //            _resetBolt = value;
        //            UpdateVarChart();
        //        }
        //    }
        //}

        public UC_AirRingShiftViewModel()
        {
            vm1.PropertyChanged += PickerVM_PropertyChanged;
            vm2.PropertyChanged += PickerVM_PropertyChanged;
        }

        public void Init(object dat)
        {
            _data = dat as IThickHeatData;

            //var tmpVM = ViewModel_HeatDetector.Instance;
            //vm1.InitData(dat, tmpVM.Selected_Idx_From, tmpVM.Selected_Idx_To);
            //vm2.InitData(dat, tmpVM.Selected_Idx_From, tmpVM.Selected_Idx_To);
            vm1.InitData(_data);
            vm2.InitData(_data);
        }

        public void Loaded(object s)
        {
            //var tmpVM = ViewModel_HeatDetector.Instance;
            //tmpVM.PropertyChanged += DataSelecter_PropertyChanged;
            //CurrentAngle = bDetect.Angle;
            RotAngle = CurrentAngle = bDetect.RAngle;
            NewResetBolt = CurrentResetBolt = blowing.OrgBoltNo;
            Kp = CurrentKp = heatCellService.Kp;

            vm1.OnLoaded(true);
            vm2.OnLoaded();
            UpdateData(1);
            UpdateData(2);
            UpdateVarChart();
        }

        public void UnLoaded(object s)
        {
            //var tmpVM = ViewModel_HeatDetector.Instance;
            //tmpVM.PropertyChanged -= DataSelecter_PropertyChanged;
        }

        private double[] vth1;
        private double[] vth2;
        private double[] vheat1;
        private double[] vheat2;
        private double rotAngle1;
        private int resetBolt1;
        private double rotAngle2;
        private int resetBolt2;
        private double[] correls;

        private void PickerVM_PropertyChanged(object s, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "SelectedFrame")
            {
                if (s.Equals(vm1))
                {
                    UpdateData(1);
                    UpdateVarChart();
                    return;
                }
                if (s.Equals(vm2))
                {
                    UpdateData(2);
                    UpdateVarChart();
                    return;
                }
            }
        }

        /// <summary>
        /// FramePicker改变时更新数据
        /// </summary>
        /// <param name="whichframe"></param>
        private void UpdateData(int whichframe)
        {
            switch (whichframe)
            {
                case 1:
                    vth1 = _data.GetThicksByIndex(vm1.SelectedFrame, 1, RotAngle);
                    vheat1 = _data.GetHeatsByIndex(vm1.SelectedFrame, -1, -1);
                    resetBolt1 = _data.GetResetBoltByIndex(vm1.SelectedFrame);
                    rotAngle1 = _data.GetRotAngleByIndex(vm1.SelectedFrame);
                    break;
                case 2:
                    vth2 = _data.GetThicksByIndex(vm2.SelectedFrame, 1, RotAngle);
                    vheat2 = _data.GetHeatsByIndex(vm2.SelectedFrame, -1, -1);
                    resetBolt2 = _data.GetResetBoltByIndex(vm2.SelectedFrame);
                    rotAngle2 = _data.GetRotAngleByIndex(vm2.SelectedFrame);
                    break;
                default:
                    return;
            }
            if ((vth1 == null) || (vth2 == null) || (vheat1 == null) || (vheat2 == null))
            {
                return;
            }
            correls = _data.CalculateCorrelVector(DataHelper.VectorSub(vth1, vth2), DataHelper.VectorSub(vheat2, vheat1));
            return;
        }

        /// <summary>
        /// 旋转角度变化时更新厚度数据
        /// </summary>
        /// <returns></returns>
        private bool UpdateThickData()
        {
            vth1 = _data.GetThicksByIndex(vm1.SelectedFrame, 1, RotAngle);
            vth2 = _data.GetThicksByIndex(vm2.SelectedFrame, 1, RotAngle);
            if ((vth1 == null) || (vth2 == null) || (vheat1 == null) || (vheat2 == null))
            {
                return false;
            }
            correls = _data.CalculateCorrelVector(DataHelper.VectorSub(vth1, vth2), DataHelper.VectorSub(vheat2, vheat1));
            return true;
        }

        private ChartValues<double> tv = new ChartValues<double>();
        private ChartValues<double> hv = new ChartValues<double>();

        /// <summary>
        /// 更新图形,触发点:  vm1,vm2的SelectFrame变化,
        ///                     ResetBolt的变化
        ///                     RotAngle的变化
        /// </summary>
        public void UpdateVarChart()
        {
            if ((vth1 == null) || (vth2 == null) || (vheat1 == null) || (vheat2 == null))
            {
                return;
            }
            //var vth = vth1 - vth2;
            //var vheat = vheat2 - vheat1;
            //int cnt = vth.Count();

            //int s = AirRingShift % cnt;
            //var tmp = vth.Concat(vth).Skip(s).Take(cnt);
            int cnt = vth1.Count();
            int s = NewResetBolt - 1;
            //if (ResetBolt == int.MaxValue)
            //{
            //    s = 0;
            //}
            //else
            //{
            //    s = ResetBolt - resetBolt1;
            //    //s = resetBolt1 + ResetBolt;
            //}
            //while (s >= cnt) s -= cnt;
            //while (s < 0) s += cnt;
            var vth = DataHelper.VectorSub(vth1, vth2);
            var tmp = vth.Concat(vth).Skip(cnt-s).Take(cnt).ToArray();

            var vheat = DataHelper.VectorSub(vheat2, vheat1);

            DS_vthick = tmp;
            DS_vheat = vheat;

            tv.Clear();tv.AddRange(tmp);
            hv.Clear();hv.AddRange(vheat);
            if (VarSeries.Count == 0)
            {
                LineSeries ts = new LineSeries
                {
                    Title = "厚度变化量",
                    Values = tv,
                    DataLabels = false,
                    Fill = new SolidColorBrush(Colors.Transparent),
                    ScalesYAt = 0,
                };

                LineSeries hs = new LineSeries
                {
                    Title = "加热变化量",
                    Values = hv,
                    DataLabels = false,
                    Fill = new SolidColorBrush(Colors.Transparent),
                    ScalesYAt = 1,
                };
                VarSeries.Add(ts);
                VarSeries.Add(hs);
            }
        }

        public void AutoCal_Shift()
        {// 根据选定两幅计算偏转量
            double[] corels = _data.CalculateCorrelVector(DataHelper.VectorSub(vth1, vth2), DataHelper.VectorSub(vheat2, vheat1));
            var r = _data.CalculateAirRingShiftFromCorelVector(corels);
            NewResetBolt = r.Item1;
            TandH_Corel = r.Item2;
        }

        public void Change_Shift(int s)
        {
            if(s == int.MaxValue)
            {
                NewResetBolt = 1;
                //ResetBolt = _data.GetResetBoltByID(vm1.SelectedFrame);
            }
            else
            {
                NewResetBolt += s;
            }
            UpdateVarChart();
        }

        public void Change_Angle(double angle)
        {
            if (double.IsNaN(angle))
            {
                RotAngle = _data.GetRotAngleByIndex(vm1.SelectedFrame);
                return;
            }
            else
            {
                double tmp = RotAngle + angle;
                if ((tmp > 1) && (tmp < 360.0001))
                {
                    RotAngle = tmp;
                }
                return;
            }
        }

        public void SearchAngle()
        {
            var tmp = _data.SearchMaxSimilarity(vm1.SelectedFrame, vm2.SelectedFrame, 15, true);
            RotAngle = tmp.Item3;
            TandH_Corel = tmp.Item2;
            NewResetBolt = tmp.Item1;
            //int rb = AirRingShift + vm1.ResetBolt;
            //while (rb >= _data.BoltCnt) rb -= _data.BoltCnt;
            //while (rb < 0) rb += _data.BoltCnt;
            //ResetBolt = rb;
        }

        public void AutoSearchAndCal_Shift()
        {
            SearchEnabled = false;
            MaxSimilarityResult result = new MaxSimilarityResult();
            int searchCnt = int.MaxValue;
            int start = vm1.MinFrame;
            int end = vm1.MaxFrame;
            if (LockFrames == 2)
            {
                int idx1 = vm1.SelectedFrame;
                int idx2 = vm2.SelectedFrame;
                if (!LockAngle) SearchAngle();
                else
                {
                    UpdateThickData();
                    var tmp = _data.CalculateAirRingShiftFromCorelVector(correls);
                    NewResetBolt = tmp.Item1;
                    TandH_Corel = tmp.Item2;
                }
                var heat = DataHelper.VectorSub(_data.GetHeatsByIndex(idx1, -1, -1), 
                                                _data.GetHeatsByIndex(idx2, -1, -1));
                var t1 = _data.GetThicksByIndex(idx1, NewResetBolt, double.MaxValue);
                var th = DataHelper.VectorSub(_data.GetThicksByIndex(idx2, NewResetBolt, double.MaxValue), t1);
                Kp = _data.CalculateHeatToThickFactor(heat, th, Misc.MyMath.Avg(t1));
                //double b;
                //double a;
                //Misc.MyMath.Linest(heat, th, out a, out b);
                //Kp = a;
                SearchEnabled = true;
                UpdateVarChart();
                return;
            }
            if (LockFrames == 1)
            {
                searchCnt = 1;
                end = vm2.SelectedFrame;
            }
            _data.StartSearchMaxSimilarity(start, end, searchCnt, 5, result,
               (o, e) =>
               {
                   SearchProgressValue = e.ProgressPercentage;
               },
               (o, e) =>
               {
                   if (result.frameIdx1 < 0 || result.frameIdx2 < 0) return;
                   int rb = _data.GetResetBoltByIndex(result.frameIdx2);
                   double ra = _data.GetRotAngleByIndex(result.frameIdx2);
                   SearchProgressValue = 0;
                   SearchEnabled = true;
                   vm2.SelectedFrame = result.frameIdx1;
                   vm1.SelectedFrame = result.frameIdx2;
                   NewResetBolt = result.frameShift;
                   TandH_Corel = result.similarity;
                   Kp = result.ThickToHeatFactor;
                   //rb += AirRingShift;
                   //while (rb >= _data.BoltCnt) rb -= _data.BoltCnt;
                   //while (rb < 0) rb += _data.BoltCnt;
                   //ResetBolt = rb;
                   if (result.deltaAngle > 100)
                       RotAngle = result.deltaAngle;
                   UpdateVarChart();
               }, int.MaxValue, 15, !LockAngle, true);
        }

        public double[] ExpandOrShrinkData(double[] ori, int orideg, int dstdeg)
        {
            double[] ori_dat = new double[360];
            double[] dst_dat = new double[360];
            int bolts = ori.Count();
            double org_deg_per_bolt = 360 / bolts;
            double curr_deg_bolt = org_deg_per_bolt;
            int bolt_idx = 0;
            int i;
            for (i = 0; i < orideg; i++)
            {
                if (i < curr_deg_bolt)
                {
                    ori_dat[i] = ori[bolt_idx];
                }
                else
                {
                    bolt_idx++;
                    curr_deg_bolt += org_deg_per_bolt;
                }
            }
            for (; i < 360; i++)
            {
                ori_dat[i] = double.NaN;
            }
            int i1 = dstdeg, j1 = 0, j = 0;
            i = 0;
            double acc = 0;
            int remain = orideg;
            while (j < dstdeg)
            {
                while (remain > 0)
                {
                    if (i1 >= j1 + remain)
                    {
                        acc += remain * ori_dat[i];
                        dst_dat[j++] = acc / orideg;
                        acc = 0;
                        j1 += remain;
                        remain = orideg;
                        break;
                    }
                    else if (i1 > j1)
                    {
                        acc += (i1 - j1) * ori_dat[i];
                        j1 = i1;
                        remain -= (i1 - j1);
                        i++;
                        i1 += dstdeg;
                        continue;
                    }
                    else
                    {
                        i++;
                        i1 += dstdeg;
                        continue;
                    }
                }
            }
            for (; j < 360; j++)
            {
                dst_dat[j] = double.NaN;
            }
            return dst_dat;
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }


}