using FLY.Thick.FilmCasting.Common;
using FLY.Thick.FilmCasting.IService;
using FLY.Thick.FilmCasting.Server.Model;
using FObjBase;
using LiveCharts;
using LiveCharts.Configurations;
using LiveCharts.Definitions.Series;
using LiveCharts.Wpf;
using Misc;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Threading;

namespace FLY.Thick.FilmCasting.UI.UiModule
{
    public class GiantMixScanGraph2Vm : INotifyPropertyChanged
    {
        protected const int NULL_VALUE = -100000;
        const int CellValuesMaxCount = 10;
        const int MARKNO_TEXTUP = 1;

        /// <summary>
        /// Y轴%显示，最小的中值
        /// </summary>
        const int MIN_PERCENT_TARGET = 5;
        /// <summary>
        /// Y轴最小公差范围
        /// </summary>
        const int MIN_TOLERANCE = 1;
        #region 图表控制
        public double YMax { get; set; } = double.NaN;
        public double YMin { get; set; } = double.NaN;
        public double Target { get; set; } = double.NaN;
        public double ToleranceYMax { get; set; } = double.NaN;
        public double ToleranceYMin { get; set; } = double.NaN;
        public double Tolerance2YMax { get; set; } = double.NaN;
        public double Tolerance2YMin { get; set; } = double.NaN;
        public double XMax { get; set; } = double.NaN;
        public double XMin { get; set; } = double.NaN;

        public int XStep { get; set; } = 10;

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

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

        #endregion



        #region 界面统计值
        /// <summary>
        /// 平均值
        /// </summary>
        public double Average { get; protected set; } = double.NaN;

        public double Sigma2 { get; protected set; } = double.NaN;
        /// <summary>
        /// 最大值
        /// </summary>
        public double Max { get; protected set; } = double.NaN;
        /// <summary>
        /// 最小值
        /// </summary>
        public double Min { get; protected set; } = double.NaN;

        public string Sigma2Text { get; protected set; }
        public string MaxText { get; protected set; }
        public string MinText { get; protected set; }

        /// <summary>
        /// 混合数,从服务器返回的
        /// </summary>
        public int Mix { get; protected set; } = 100;

        /// <summary>
        /// 曲线显示模式
        /// </summary>
        public bool IsLineMode { get; protected set; }

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

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

        /// <summary>
        /// 数据库中的序号, 最后一幅图的Id
        /// </summary>
        public long Id { get; protected set; }

        public double Velocity { get; protected set; }

        /// <summary>
        /// 测量拉伸前速度
        /// </summary>
        public bool HasVBeforeStretching { get; set; }

        /// <summary>
        /// 拉伸前速度
        /// </summary>
        public double VelocityBeforeStretching { get; set; }

        public double Position { get; protected set; }

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

        public int DataBegin { get; set; } = NULL_VALUE;
        public int DataBeginOfBoltNo => DataBegin + 1;
        public int DataEnd { get; set; } = NULL_VALUE;
        public int DataEndOfBoltNo => DataEnd + 1;
        #endregion

        protected List<Brush> AreaColors;

        //最大只能显示100个数据，大于100， 都会被/2
        //均值，黑色
        protected ChartValues<double> Values = new ChartValues<double>();

        /// <summary>
        /// 最多10条，单独的每条线，[0] 是最早的，[1] 最新的
        /// </summary>
        List<CellData> CellValues = new List<CellData>();
        class CellData 
        {
            public long ScanDataId;
            public ChartValues<double> Values = new ChartValues<double>();
            public SolidColorBrush Color;
        }
        
        //double 转 XY
        protected object Mapper;
        protected object Mapper2;
        protected FilmCastingProfileParam profileParam;
        protected GiantMixScanGraph2ItemParam graphparam;
        protected IBulkDbService bulkDb;
        protected IInitParamService initParamService;

        /// <summary>
        /// 组件中 存在的 缓存, scanDatas[0] 是最早的数据 
        /// </summary>
        protected List<Lc_ScanData> scanDatas = new List<Lc_ScanData>();
        
        protected double[] Averages { get; set; }
        
        protected ParamDictionary paramDictionary;
        protected DispatcherTimer timer;

        /// <summary>
        /// 正在下载中
        /// </summary>
        bool isDownloading = false;
        /// <summary>
        /// 需要下载以前的数据
        /// </summary>
        bool isDownloadPrev = false;
        /// <summary>
        /// 需要下载最新的数据
        /// </summary>
        bool isDownloadNext = false;


        public GiantMixScanGraph2Vm()
        {
            #region 与数据无关界面参数

            AreaColors = FLY.Thick.FilmCasting.UI.Themes.Colors.AreaColors;

            YFormatter = (y) =>
            {
                //只显示 Target,ToleranceYMax,ToleranceYMin,Tolerance2YMax,Tolerance2YMin
                string text = "";
                double target = Target;
                if (graphparam.IsPercent && target > MIN_PERCENT_TARGET)
                {
                    if (y == target)
                    {
                        text = y.ToString("F1");
                    }
                    else
                    {
                        double percent = 100.0 * (y - target) / target;
                        if (percent > 0)
                        {
                            text = $"+{Math.Abs(percent):F1}%";
                        }
                        else
                        {
                            text = $"-{Math.Abs(percent):F1}%";
                        }
                    }
                }
                else
                {
                    text = y.ToString("F1");
                }
                return $"{text,6}";
            };

            XFormatter = (x) =>
            {
                return $"{x}";
            };

            Mapper = Mappers.Xy<double>()
                .X((value, index) =>
                {
                    return index + 1;
                })
                .Y(value => value)
                .Fill((value) =>
                {
                    if ((value > Tolerance2YMax) || (value < Tolerance2YMin))
                    {
                        return AreaColors[2];
                    }
                    else if ((value > ToleranceYMax) || (value < ToleranceYMin))
                    {
                        return AreaColors[1];
                    }
                    else
                    {
                        return AreaColors[0];
                    }
                });
            Mapper2 = Mappers.Xy<double>()
                .X((value, index) =>
                {
                    return index + 1;
                })
                .Y(value => value);
            #endregion

        }

        public void Init(
            GiantMixScanGraph2ItemParam graphparam,
            IBulkDbService bulkDb,
            ParamDictionary paramDictionary,
            FilmCastingProfileParam profileParam,
            IInitParamService initParamService
            )
        {
            this.graphparam = graphparam;
            this.bulkDb = bulkDb;
            this.paramDictionary = paramDictionary;
            this.profileParam = profileParam;
            this.initParamService = initParamService;

            Misc.BindingOperations.SetBinding(profileParam, nameof(profileParam.DataRange), () =>
            {
                if (profileParam.DataRange.IsValid)
                {
                    DataBegin = profileParam.DataRange.Begin;
                    DataEnd = profileParam.DataRange.End;
                }
                else
                {
                    DataBegin = NULL_VALUE;
                    DataEnd = NULL_VALUE;
                }
            });

            Misc.BindingOperations.SetBinding(this.graphparam, nameof(graphparam.IsLineMode), this, nameof(IsLineMode));

            UpdateSeriesType();
            UpdateY();
            UpdateX();

            Id = -1;
            Download();

            bulkDb.PropertyChanged += BulkDb_PropertyChanged;
            graphparam.PropertyChanged += Graphparam_PropertyChanged;
            profileParam.PropertyChanged += ProfileParam_PropertyChanged;
            this.PropertyChanged += ScanGraphVm_PropertyChanged;
            Misc.BindingOperations.SetBinding(initParamService, nameof(initParamService.HasVBeforeStretching), this, nameof(HasVBeforeStretching));

            Init2();
        }
        protected void ClearValues()
        {
            Values.Clear();
            CellValues.Clear();
            
            if (graphparam.IsLineMode) {
                while (Series.Count > 1)
                    Series.RemoveAt(Series.Count() - 1);
            }
        }
        protected virtual void Init2()
        {
            // 绑定全局的 X轴 间隔
            paramDictionary.SetBinding(this, nameof(XStep), Base.UI.ParamDistItemKeys.XStep, XStep);

        }


        static string[] propertyname_updateMaxMinText = new string[] {
            nameof(Average),nameof(Max),nameof(Min),nameof(Sigma2)};

        private void ScanGraphVm_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {

            if (e.PropertyName == nameof(Target))//nameof(Average)
            {
                if (graphparam.IsPercent)
                {
                    NotifyPropertyChanged(nameof(YFormatter));
                }
            }

            if (propertyname_updateMaxMinText.Contains(e.PropertyName))
                UpdateMaxMinText_delay();

        }

        private void ProfileParam_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(profileParam.Target))
            {
                UpdateY();
            }
            else if (e.PropertyName == nameof(profileParam.TolerancePercent))
            {
                UpdateY();
            }
            else if (e.PropertyName == nameof(profileParam.ScanRange)) {
                UpdateX();
            }
        }

        private void BulkDb_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(bulkDb.LastScanDataId))
            {
                isDownloadNext = true;
                Download();
            }
            else if (e.PropertyName == nameof(FObjBase.FObjServiceClient.IsConnected))
            {
                if ((bulkDb as FObjBase.FObjServiceClient).IsConnected)
                {
                    //删除全部缓存，重新下载
                    scanDatas.Clear();
                    Download();
                }
            }
        }
        void mixChanged()
        {
            if (scanDatas.Count == graphparam.Mix)
            {
                return;
            }

            if (scanDatas.Count > graphparam.Mix)
            {
                //删除多余的
                scanDatas.RemoveRange(0, scanDatas.Count - graphparam.Mix);
                scanDatasChanged();
            }
            else
            {
                isDownloadPrev = true;
                //添加更多
                Download();
            }
        }
        public void MarkFromTime()
        {
            if (scanDatas.Count() == 0)
                return;
            graphparam.FromId = scanDatas.Last().ID;
            GiantMixScanGraph2Params.Current.Save();
            clearScanDatas();
        }

        void clearScanDatas()
        {
            //清空数据
            scanDatas.Clear();

            //清除全部数据
            ClearValues();

            Averages = null;

            //更新平均值,它会引起 YFormatter 刷新
            UpdateAverage();

            //更新Target
            UpdateY();

            //UpdateX();
        }

        public void ClearFromTime()
        {
            graphparam.FromId = 0;
            GiantMixScanGraph2Params.Current.Save();
            scanDatas.Clear();
            Download();
        }


        private void Graphparam_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(graphparam.Mix))
            {
                mixChanged();
            }
            else if (e.PropertyName == nameof(graphparam.YRangePercent))
            {
                UpdateY();
            }
            else if (e.PropertyName == nameof(graphparam.IsPercent))
            {
                NotifyPropertyChanged(nameof(YFormatter));
                UpdateY();
                UpdateMaxMinText_delay();

            }
            else if (e.PropertyName == nameof(graphparam.IsAutoTarget))
            {
                UpdateY();
            }
            else if (e.PropertyName == nameof(graphparam.IsLineMode))
            {
                UpdateSeriesType();
            }
            else if (e.PropertyName == nameof(graphparam.IsSideCutHidden)) 
            {
                UpdateValues();
            }

        }

        SolidColorBrush GetCellColor(int index) 
        {
            byte min = 0x30;
            byte max = 0xd0;

            byte a = (byte)((max - min) * index / (CellValuesMaxCount-1) + min);
            return new SolidColorBrush(System.Windows.Media.Color.FromArgb(a, 0, 0, 0));
        }
        SolidColorBrush GetCellColor()
        {
            byte a = 0x30;//= (byte)((max - min) * index / (cnt-1) + min);
            return new SolidColorBrush(System.Windows.Media.Color.FromArgb(a, 0, 0, 0));
        }

        protected void UpdateY()
        {
            //使用 profileParam 的参数显示
            UpdateY_profileParam();
        }
        void UpdateY_profileParam()
        {
            double target = this.profileParam.Target;

            if (graphparam.IsAutoTarget)
            {
                if (!double.IsNaN(Average))
                    target = Average;
            }

            double tolerance = this.profileParam.TolerancePercent * target;

            //确保没有负数，Y轴显示范围正确
            if (tolerance < MIN_TOLERANCE)
                tolerance = MIN_TOLERANCE;

            Target = target;
            ToleranceYMax = target + tolerance;
            ToleranceYMin = target - tolerance;
            Tolerance2YMax = target + tolerance * 2;
            Tolerance2YMin = target - tolerance * 2;

            YMax = target + tolerance * graphparam.YRangePercent;
            YMin = target - tolerance * graphparam.YRangePercent;
        }

        protected void UpdateX()
        {
            if (profileParam.ScanRange.IsValid)
            {
                //数据的X轴，是螺丝号，从1开始
                //profileParam.ScanRange 扫描范围 是序号，从0开始
                //当显示全部螺丝时， 扫描范围 = 0~119  （120个螺丝）
                //XMin = 0， XMax = 121
                XMin = profileParam.ScanRange.Begin;
                XMax = profileParam.ScanRange.End + 2;
            }
        }

        void UpdateMaxMinText_delay()
        {
            PollModule.Current.Poll_JustOnce(UpdateMaxMinText, this, MARKNO_TEXTUP);
        }
        protected void UpdateMaxMinText() 
        {
            if (graphparam.IsPercent && (Average > MIN_PERCENT_TARGET))
            {
                MaxText = $"+{((Max - Average) / Average) * 100.0:F1}%";
                MinText = $"-{((Average - Min) / Average) * 100.0:F1}%";
                Sigma2Text = $"{(Sigma2 / Average) * 100.0:F1}%";
            }
            else
            {
                MaxText = $"{Max:F1}";
                MinText = $"{Min:F1}";
                Sigma2Text = $"{Sigma2:F1}";
            }
        }
        void updateThicks()
        {
            if (this.scanDatas.Count() != 0)
            {
                int dataCnt = this.scanDatas.Last().Thicks.Count();
                double[] averages = new double[dataCnt];

                for (int j = 0; j < dataCnt; j++)
                {
                    List<double> list = new List<double>();
                    for (int i = 0; i < this.scanDatas.Count(); i++)
                    {
                        int index = this.scanDatas.Count() - 1 - i;
                        var thks = this.scanDatas[index].Thicks;
                        if (j >= thks.Count())
                            break;
                        list.Add(thks[j]);
                    }

                    averages[j] = list.AverageNoNull();
                }


                Averages = averages;
            }
            else
            {
                Averages = null;
            }
        }
        protected virtual void UpdateAverage()
        {
            if (this.scanDatas.Count() == 0)
            {
                Time = DateTime.MinValue;
                EndTime = DateTime.MinValue;
                Id = -1;
                Position = -1;
                Velocity = -1;
                VelocityBeforeStretching = -1;
                FilmWidth = -1;

                Average = double.NaN;
                Max = double.NaN;
                Min = double.NaN;
                Sigma2 = double.NaN;

                return;
            }
            var scanData = this.scanDatas.Last();
            Time = this.scanDatas.First().Time;
            EndTime = scanData.EndTime;
            Id = scanData.ID;
            Position = scanData.FilmPosition;
            Velocity = scanData.FilmVelocity;
            VelocityBeforeStretching = scanData.FilmVelocityBeginStretching;
            FilmWidth = scanData.FilmWidth;



            List<double> list = new List<double>();
            double[] values = Averages;
            if (this.profileParam.DataRange.IsValid)
            {
                int beginIndex = this.profileParam.DataRange.Begin;
                int endIndex = this.profileParam.DataRange.End;

                for (int i = beginIndex; i <= endIndex; i++)
                {
                    if (i < 0)
                        i = 0;
                    if (i >= values.Count())
                        break;
                    double v = values[i];
                    if (!double.IsNaN(v))
                        list.Add(values[i]);
                }
            }

            if (list.Count() > 0)
            {
                Average = list.Average();
                Max = list.Max();
                Min = list.Min();
                Sigma2 = list.Sigma() * 2;
            }
            else
            {
                Average = double.NaN;
                Max = double.NaN;
                Min = double.NaN;
                Sigma2 = double.NaN;
            }
        }



        void Download()
        {
            var client = bulkDb as FObjBase.Reflect.Reflect_SeviceClient;
            if (!client.IsConnected)//还没连接上。。。。
                return;
            if (!client.IsSynced)//还没同步完成。。。。
                return;

            if (isDownloading)//已经在下载中了，等等。。。。
                return;

            long id;
            int count;
            if (scanDatas.Count() == 0)
            {
                //需要下载全部数据
                id = bulkDb.LastScanDataId;
                count = graphparam.Mix;

                isDownloadNext = false;
                isDownloadPrev = false;
            }
            else
            {
                //1. graphparam.Mix 变化了，需要下载
                //2. bulkDb.LastScanDataId 更新了，需要下载更多

                if (isDownloadPrev)
                {
                    isDownloadPrev = false;

                    id = scanDatas.First().ID - 1;
                    count = graphparam.Mix - scanDatas.Count;
                }
                else
                {
                    isDownloadNext = false;

                    id = bulkDb.LastScanDataId;
                    count = (int)(id - scanDatas.Last().ID);
                    if (count < 0)
                    {
                        //异常，未来的数据，清空 scanDatas
                        scanDatas.Clear();
                        count = graphparam.Mix;
                    }
                }
            }


            if (graphparam.FromId > 0)
            {
                int c = (int)(id - graphparam.FromId);
                if (c < 0)
                    c = 0;
                if (c < count)
                    count = c;
            }

            if (count <= 0)
            {
                //什么都不需要做
                return;
            }

            isDownloading = true;
            bulkDb.GetRecentFrames(
                new Pack_GetRecentFramesRequest()
                {
                    Id = id,
                    Count = count
                },
                (object asyncContext, object retData) =>
                {
                    Pack_GetRecentFramesReponse reponse = retData as Pack_GetRecentFramesReponse;

                    var reponse_scanDatas = reponse.scanDatas;
                    if (reponse_scanDatas == null)
                    {

                    }
                    else
                    {
                        scanDatas.AddRange(reponse_scanDatas);
                        scanDatas.Sort((s1, s2) => s1.ID.CompareTo(s2.ID));
                        //TODO 把重复的删除

                        //删除超数量数据
                        if (scanDatas.Count > graphparam.Mix)
                            scanDatas.RemoveRange(0, scanDatas.Count - graphparam.Mix);
                    }
                     
                    scanDatasChanged();

                    isDownloading = false;

                    //再次检测 是否需要下载

                    Download();
                }, this);
        }

        void scanDatasChanged()
        {

            updateThicks();

            Mix = scanDatas.Count;

            //更新平均值,它会引起 YFormatter 刷新
            UpdateAverage();

            //更新Target
            UpdateY();

            //UpdateX();

            UpdateValues();
            UpdateCellValues();
        }

        protected void UpdateValues()
        {
            Values.Clear();
            if (Averages != null)
            {
                if (graphparam.IsSideCutHidden)
                {
                    var thks = Averages.ToArray();
                    for (int i = 0; i < DataBegin; i++)
                    {
                        thks[i] = double.NaN;
                    }
                    for (int i = DataEnd + 1; i < thks.Count(); i++)
                    {
                        thks[i] = double.NaN;
                    }
                    Values.AddRange(thks);
                }
                else
                {
                    Values.AddRange(Averages);
                }
            }
        }

        /// <summary>
        /// 画后面的10条线
        /// </summary>
        protected void UpdateCellValues() 
        {
 
            if (scanDatas.Count < graphparam.CellMix)
                return;//一条线都不画
            double interval = 1;
            int count = scanDatas.Count - graphparam.CellMix + 1;
            //count <= cellValuesMaxCount 时 间隔为1
            if (count > CellValuesMaxCount) 
            {
                interval = 1.0 * (count-1) / (CellValuesMaxCount-1);
            }

            //计算出10条曲线每条曲线的计算位置
            Dictionary<long, int> Ids = new Dictionary<long, int>();
            double index_d = 0 + graphparam.CellMix - 1;
            int index = (int)Math.Round(index_d);
            while (index < scanDatas.Count) 
            {
                long id = scanDatas[index].ID;
                if (!Ids.ContainsKey(id)) 
                    Ids.Add(id, index);
                index_d += interval;
                index = (int)Math.Round(index_d);
            }

            //删除多出来的
            if (CellValues.Count() > Ids.Count())
            {
                CellValues.RemoveRange(Ids.Count(), CellValues.Count() - Ids.Count());
            }

            //更新当前存在的曲线
            for (int i = 0; i < Ids.Count(); i++) {
                if (i < CellValues.Count())
                {
                    var cellValue = CellValues[i];
                    if (Ids.Keys.ElementAt(i) == cellValue.ScanDataId)
                    {
                        //这个曲线不用刷新 
                    }
                    else
                    {
                        int index_from = Ids.Values.ElementAt(i) - graphparam.CellMix + 1;
                        int index_to = Ids.Values.ElementAt(i);
                        var thks = GetMixScanData(scanDatas, index_from, index_to);

                        cellValue.ScanDataId = Ids.Keys.ElementAt(i);
                        cellValue.Values.Clear();
                        cellValue.Values.AddRange(thks);
                    }
                }
                else 
                {
                    //曲线不够
                    int index_from = Ids.Values.ElementAt(i) - graphparam.CellMix + 1;
                    int index_to = Ids.Values.ElementAt(i);
                    var thks = GetMixScanData(scanDatas, index_from, index_to);

                    var cellValue = new CellData();
                    cellValue.Color = GetCellColor(i);
                    cellValue.ScanDataId = Ids.Keys.ElementAt(i);
                    cellValue.Values.AddRange(thks);
                    CellValues.Add(cellValue);
                }
            }


            updateSeriesForCellValuesChanged();
        }
        void updateSeriesForCellValuesChanged() 
        {
            if (!graphparam.IsLineMode)
                return;

            //更新实际的曲线
            foreach (var cellValue in CellValues)
            {
                if (!Series.Any(s => s.Values == cellValue.Values))
                {
                    //没有，添加
                    LineSeries lineSeries = new LineSeries
                    {
                        Values = cellValue.Values,
                        StrokeThickness = 1,
                        Stroke = cellValue.Color,
                        Fill = new SolidColorBrush(System.Windows.Media.Colors.Transparent),
                        PointGeometry = null,
                        Configuration = Mapper2
                    };
                    Series.Add(lineSeries);
                }
            }

            //多出来的，删除
            List<ISeriesView> seriesViews = new List<ISeriesView>();

            for(int i=1;i<Series.Count();i++) 
            {
                var seriesView = Series[i];
                if (!CellValues.Any(c => c.Values == seriesView.Values))
                {
                    seriesViews.Add(seriesView);
                }
            }

            try
            {
                foreach (var seriesView in seriesViews)
                    Series.Remove(seriesView);
            }
            catch (Exception e) {
                //Series 还没绑定到chart时，Remove 会出错
            }

        }

        protected void UpdateSeriesType()
        {
            if (graphparam.IsLineMode)
            {
                Series.Clear();
                LineSeries series_avg = new LineSeries
                {
                    Values = Values,
                    StrokeThickness = 3,
                    Stroke = new SolidColorBrush(Colors.DarkBlue),
                    Fill = new SolidColorBrush(System.Windows.Media.Colors.Transparent),
                    PointGeometry = null,
                    Configuration = Mapper2
                };
                series_avg.SetValue(System.Windows.Controls.Panel.ZIndexProperty, 20);
                Series.Add(series_avg);

                foreach (var cellValue in CellValues)
                {
                    LineSeries lineSeries = new LineSeries
                    {
                        Values = cellValue.Values,
                        StrokeThickness = 1,
                        Stroke = cellValue.Color,
                        Fill = new SolidColorBrush(System.Windows.Media.Colors.Transparent),
                        PointGeometry = null,
                        Configuration = Mapper2
                    };
                    Series.Add(lineSeries);
                }
            }
            else
            {
                Series.Clear();
                var series_avg = new Column2Series
                {
                    Values = Values,
                    Stroke = new SolidColorBrush(Colors.Black),
                    StrokeThickness = 1,
                    PointGeometry = null,
                    Configuration = Mapper
                };

                series_avg.SetValue(System.Windows.Controls.Panel.ZIndexProperty, 20);
                series_avg.SetBinding(Column2Series.YAxisCrossingProperty, new Binding(nameof(Target)) { Source = this });
                Series.Add(series_avg);

                //foreach (var cellValue in CellValues)
                //{
                //    LineSeries lineSeries = new LineSeries
                //    {
                //        Values = cellValue.Values,
                //        StrokeThickness = 1,
                //        Stroke = cellValue.Color,
                //        Fill = new SolidColorBrush(System.Windows.Media.Colors.Transparent),
                //        PointGeometry = null,
                //        Configuration = Mapper2
                //    };
                //    Series.Add(lineSeries);
                //}
            }

        }
        double[] GetMixScanData(List<Lc_ScanData> lc_scanDatas, int index_from, int index_to)
        {
            var scanDatas = new List<Lc_ScanData>();
            for (int j = index_from; j <= index_to; j++)
            {
                scanDatas.Add(lc_scanDatas[index_from]);
            }
            return GetMixScanData(scanDatas);
        }
        double[] GetMixScanData(List<Lc_ScanData> lc_scanDatas)
        {

            var lc_scanData = lc_scanDatas[0];
            //求均值
            double[] thks = new double[lc_scanData.Thicks.Count()];
            int[] cnt = new int[thks.Count()];
            for (int j = 0; j < lc_scanDatas.Count(); j++)
            {
                int index = j;
                if (lc_scanDatas[index].Thicks.Count() != thks.Count())
                {
                    //结束，异常
                    break;
                }

                for (int i = 0; i < thks.Count(); i++)
                {
                    var v = lc_scanDatas[index].Thicks[i];
                    if (!double.IsNaN(v))
                    {
                        thks[i] += v;
                        cnt[i]++;
                    }
                }
            }
            for (int i = 0; i < thks.Count(); i++)
            {
                if (cnt[i] > 0)
                    thks[i] /= cnt[i];
                else
                    thks[i] = double.NaN;
            }

            return thks;
        }

        protected void NotifyPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
}
