using FLY.FilmCasting.AutoDie.IService;
using FLY.FilmCasting.AutoDie.Server.Model;
using FObjBase;
using GalaSoft.MvvmLight.Command;
using LiveCharts;
using LiveCharts.Configurations;
using Misc;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using IBulkDbService = FLY.FilmCasting.AutoDie.IService.IBulkDbService;

namespace FLY.FilmCasting.AutoDie.UI.Client
{
    public class UcThickHeatVm : INotifyPropertyChanged
    {
        const int MARKNO_UPDATEFRAME = 1;

        public event PropertyChangedEventHandler PropertyChanged;


        #region 图表控制
        public Func<double, string> YFormatter { get; protected set; }
        public int XMax { get; set; } = 88;
        #endregion

        /// <summary>
        /// 厚度%
        /// </summary>
        public ChartValues<double> ThickPercents { get; } = new ChartValues<double>();
        public ChartValues<int> Heats { get; } = new ChartValues<int>();

        public double Kp { get; set; } = 3;

        public object MapperHeats { get; private set; }

        [PropertyChanged.DependsOn(nameof(Kp))]
        public object MapperThickPercents { get; private set; }


        /// <summary>
        /// 记录1 or 记录2
        /// </summary>
        public string Title { get; set; }

        /// <summary>
        /// 当前Id
        /// </summary>
        public long Id { get; set; }

        /// <summary>
        /// 最新Id
        /// </summary>
        public long LastId { get; set; }

        /// <summary>
        /// 输入的记录点
        /// </summary>
        public long Number { get; set; }


        /// <summary>
        /// 有效
        /// </summary>
        public bool IsVaild { get; set; }


        /// <summary>
        /// 加热起效
        /// </summary>
        public bool IsStable { get; set; }

        /// <summary>
        /// 开始测量时间！！！
        /// </summary>
        public DateTime Time { get; set; }

        /// <summary>
        /// 结束测量时间！！！
        /// </summary>
        public DateTime EndTime { get; set; }

        /// <summary>
        /// 扫描图的Id
        /// </summary>
        public long ScanDataId { get; set; }

        /// <summary>
        /// 膜宽度 mm
        /// </summary>
        public double FilmWidth { get; set; }

        /// <summary>
        /// 纵向速度
        /// </summary>
        public double FilmVelocity { get; set; }

        /// <summary>
        /// 开始改变加热时间
        /// </summary>
        public DateTime HTime { get; set; }

        public double Average { get; set; }
        public double Sigma2Percent { get; set; }



        public RelayCommand PreCmd { get; private set; }
        public RelayCommand NextCmd { get; private set; }
        public RelayCommand PreStableCmd { get; private set; }
        public RelayCommand NextStableCmd { get; private set; }
        public RelayCommand NewestCmd { get; private set; }

        public Lc_ThickHeat frame;
        IBulkDbService bulkDbService;

        public UcThickHeatVm()
        {
            YFormatter = (y) =>
            {
                string text = y + "%";
                return $"{text,6}";
            };

            MapperHeats = Mappers.Xy<int>()
                .X((value, index) =>
                {
                    return index + 1;
                })
                .Y((value, index) =>
                {
                    return value;
                });

            MapperThickPercents = Mappers.Xy<double>()
                .X((value, index) =>
                {
                    return index + 1;
                })
                .Y((value) =>
                {
                    return value * Kp + 50;
                });

            PreCmd = new RelayCommand(Pre);
            NextCmd = new RelayCommand(Next);
            PreStableCmd = new RelayCommand(PreStable);
            NextStableCmd = new RelayCommand(NextStable);
            NewestCmd = new RelayCommand(Newest);
        }



        public void Init(string title,
            IBulkDbService bulkDbService,
            int number, double kp)
        {
            this.bulkDbService = bulkDbService;
            Title = title;
            Kp = kp;
            Misc.BindingOperations.SetBinding(bulkDbService, nameof(bulkDbService.LastId), this, nameof(LastId));
            Number = number;
            UpdateFrame();


            this.PropertyChanged += UcThickHeatVm_PropertyChanged;

        }


        private void UcThickHeatVm_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(Number))
            {
                if (IsSkipNumberChanged)
                    return;
                UpdateFrame();
            }
        }
        public event Action FrameUpdated;
        public void UpdateFrame()
        {
            PollModule.Current.Poll_JustOnce(() =>
            {
                _updateFrame();
            }, this, MARKNO_UPDATEFRAME);

        }

        void SetFrame(Lc_ThickHeat thickHeat) 
        {
            if (thickHeat != null)
            {
                frame = thickHeat;
                Id = frame.ID;
                ScanDataId = frame.ScanDataID;
                Time = frame.Time;
                EndTime = frame.EndTime;
                FilmWidth = frame.FilmWidth;
                FilmVelocity = frame.FilmVelocity;

                Average = frame.Thicks.AverageNoNull();
                Sigma2Percent = frame.Thicks.Sigma() / Average * 2;

                Heats.Clear();
                Heats.AddRange(frame.Heats);
                XMax = frame.Heats.Count() + 1;

                double[] thickPercents = GetThickPercents();
                ThickPercents.Clear();
                ThickPercents.AddRange(thickPercents);

                IsStable = frame.IsStable;
                HTime = frame.HTime;

                IsVaild = true;

                IsSkipNumberChanged = true;
                Number = Id;
                IsSkipNumberChanged = false;
            }
            else
            {
                IsVaild = false;
            }

            FrameUpdated?.Invoke();
        }
        void _updateFrame()
        {
            if (IsGetStableFrame)
            {
                IsGetStableFrame = false;
                bulkDbService.GetStableFrame(Number, IsPre, (asyncContext, retData) =>
                 {
                     var reponce = retData as GetStableFrameReponse;

                     SetFrame(reponce.thickHeat);
                 }, null);
            }
            else
            {
                bulkDbService.GetFrame(Number, (asyncContext, retData) =>
                {
                    var reponce = retData as GetFrameReponse;

                    SetFrame(reponce.thickHeat);
                    
                }, null);
            }
        }
        private void Next()
        {
            if (Number < bulkDbService.LastId)
                Number++;
        }
        private void Pre()
        {
            Number--;
        }
        bool IsGetStableFrame;
        bool IsPre;
        bool IsSkipNumberChanged;
        private void NextStable()
        {
            IsGetStableFrame = true;
            IsPre = false;
            Number++;
        }
        private void Newest()
        {
            Number = bulkDbService.LastId;
        }
        private void PreStable()
        {
            IsGetStableFrame = true;
            IsPre = true;
            Number--;
        }


        /// <summary>
        /// 以指定分区表 导出厚度%
        /// </summary>
        /// <param name="boltmap">分区表</param>
        /// <returns></returns>
        public double[] GetThickPercents(IEnumerable<BoltMapCell> boltmap)
        {
            if (frame == null)
                return null;
            double[] thks = frame.Thicks;
            //把数据量放大10倍计算， 移动，放大！！！
            double[] thks_x10 = FLY.FilmCasting.AutoDie.Common.MyMath.ZoomIn(thks, 10);

            //偏移量
            //int midOffsetIdx_x10 = (int)(frame.BoltMapInfo.MidOffset / (frame.BoltMapInfo.BoltWidth * (1 - frame.BoltMapInfo.UniformShrinkPercent)) * 10);

            //计算 thks_x10 中间的螺丝序号
            //int r_l = frame.BoltMapInfo.RightEmptyBolts - frame.BoltMapInfo.LeftEmptyBolts;
            //int midBoltIdx_x10 = 10 * (frame.BoltMapInfo.BoltCnt - r_l * 2) / 2;
            //偏移后
            //midBoltIdx_x10 += midOffsetIdx_x10;


            //if (Math.Abs(frame.BoltMapInfo.UniformShrinkPercent - uniformShrinkPercent) > 0.01) //大于1%以上
            //{
            //    //放大
            //    thks_x10 = FLY.FilmCasting.AutoDie.Common.MyMath.ZoomX(thks_x10, midBoltIdx_x10, uniformShrinkPercent / frame.BoltMapInfo.UniformShrinkPercent);
            //}

            //新的偏移量
            //int midOffsetIdx_new_x10 = (int)(midOffset / (frame.BoltMapInfo.BoltWidth * (1 - frame.BoltMapInfo.UniformShrinkPercent)) * 10.0);

            //if (Math.Abs(midOffsetIdx_new_x10- midOffsetIdx_x10)>=1)
            //{
            //    //平移
            //    thks_x10 = FLY.FilmCasting.AutoDie.Common.MyMath.Move(thks_x10, midOffsetIdx_new_x10 - midOffsetIdx_x10);
            //}

            //分区表处理
            if (boltmap != null && boltmap.Count() != 0)
            {
                //10倍后的分区表
                Dictionary<int, int> map_x10 = new Dictionary<int, int>();

                IEnumerable<BoltMapCell> maps = boltmap;
                for (int i = 0; i < maps.Count(); i++)
                {
                    int oldIdx_x10 = (maps.ElementAt(i).OldNo - 1) * 10 + 5;
                    int newIdx_x10 = (maps.ElementAt(i).NewNo - 1) * 10 + 5;
                    map_x10.Add(oldIdx_x10, newIdx_x10);
                }
                thks_x10 = FLY.FilmCasting.AutoDie.Common.MyMath.MapX(thks_x10, map_x10);
            }

            //缩小数据量
            thks = FLY.FilmCasting.AutoDie.Common.MyMath.ZoomOut(thks_x10, 10);
            double[] thickpercents = new double[thks.Count()];
            double avg = thks.AverageNoNull();
            if (!double.IsNaN(avg))
            {
                for (int i = 0; i < thks.Count(); i++)
                {
                    thickpercents[i] = (thks[i] - avg) / avg * 100;
                }
            }
            return thickpercents;
        }
        public double[] GetThickPercents()
        {
            //return GetThickPercents(frame.BoltMapInfo.UniformShrinkPercent, frame.BoltMapInfo.MidOffset, frame.Boltmap);
            return GetThickPercents(frame.Boltmap);
        }
        public int[] GetHeats()
        {
            return frame.Heats.ToArray();
        }
    }
}
