using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WSDDBBrowser.Core.Model;

namespace WSDDBBrowser.Core
{
    public class ScanDataItem : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public string DeviceID { get; set; }
        public string DeviceName { get; set; }

        #region 工艺
        public double YRangePercent { get; set; }

        public double Target { get; set; }

        public double Tolerance { get; set; }
        public double Ctrlline { get; set; }


        public double USL => Target + Tolerance;
        public double LSL => Target - Tolerance;

        public double YMax => Target + Tolerance * YRangePercent;
        public double YMin => Target - Tolerance * YRangePercent;
        #endregion


        #region 统计结果
        public int TotalCount { get; set; }
        public double Average { get; set; }
        public double Sigma3 { get; set; }
        public double CPK { get; set; }
        public double TolerancePercent { get; set; }
        public double CtrllinePercent { get; set; }
        #endregion


        #region 图
        /// <summary>
        /// 原始 1cm 数据
        /// </summary>
        public List<lc_tgRecord> Values { get; } = new List<lc_tgRecord>();

        /// <summary>
        /// 混合后1cm 数据
        /// </summary>
        public List<double[]> MixValues { get; } = new List<double[]>();

        /// <summary>
        /// 混合后 分区数据
        /// </summary>
        public List<BoltValue[]> MixCuttingValues { get; } = new List<BoltValue[]>();

        /// <summary>
        /// 混合后 分区均值纵向趋势
        /// </summary>
        public List<double> MixCuttingAverages { get; } = new List<double>();


        /// <summary>
        /// 总体横向扫描均值
        /// </summary>
        public double[] MixValuesAverage { get; set; }
        /// <summary>
        /// 总体横向扫描分区均值
        /// </summary>
        public double[] MixCuttingValuesAverage { get; set; }

        #endregion


        #region 图操作
        public List<double> GetCuttingValue(int boltIndex)
        {
            List<double> list = new List<double>();

            if (boltIndex < 0)
            {
                foreach (var boltvalues in MixCuttingValues)
                {
                    foreach (var boltvalue in boltvalues)
                    {
                        list.Add(boltvalue.Value);
                    }
                }
            }
            else if (boltIndex < MixCuttingValues.First().Count())
            {
                foreach (var boltvalues in MixCuttingValues)
                {
                    var boltvalue = boltvalues[boltIndex];
                    list.Add(boltvalue.Value);
                }
            }
            return list;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="boltIndexs">必须独立无二</param>
        /// <param name="step"></param>
        /// <returns></returns>
        public List<XY> GetHistogram(IEnumerable<int> boltIndexs, double step)
        {
            List<XY> list = new List<XY>();

            if (boltIndexs.Contains(-1))
            {
                foreach (var boltvalues in MixCuttingValues)
                {
                    foreach (var boltvalue in boltvalues)
                    {
                        if (double.IsNaN(boltvalue.Value))
                            continue;

                        double x = ((int)(boltvalue.Value / step)) * step;
                        XY xy = list.Find(_xy => _xy.X == x);
                        if (xy != null)
                        {
                            xy.Y++;
                        }
                        else
                        {
                            xy = new XY(x, 1);
                            list.Add(xy);
                        }
                    }
                }
                list.Sort();
            }
            else
            {
                foreach (int boltIndex in boltIndexs)
                {
                    if (boltIndex < MixCuttingValues.First().Count() && boltIndex >= 0)
                    {
                        foreach (var boltvalues in MixCuttingValues)
                        {
                            var boltvalue = boltvalues[boltIndex];
                            if (double.IsNaN(boltvalue.Value))
                                continue;
                            double x = ((int)(boltvalue.Value / step)) * step;
                            XY xy = list.Find(_xy => _xy.X == x);
                            if (xy != null)
                            {
                                xy.Y++;
                            }
                            else
                            {
                                xy = new XY(x, 1);
                                list.Add(xy);
                            }
                        }
                    }
                }
                list.Sort();
            }
            return list;
        }



        /// <summary>
        /// 当boltIndex 小于0 为 平均值
        /// </summary>
        /// <param name="boltIndex"></param>
        /// <returns></returns>
        public List<TrendValue> GetTrend(int boltIndex)
        {
            List<TrendValue> trendValues = new List<TrendValue>();

            if (boltIndex < 0)
            {
                for (int i = 0; i < MixCuttingAverages.Count(); i++)
                {
                    lc_tgRecord scanData = Values[i];
                    trendValues.Add(new TrendValue(MixCuttingAverages[i], (double)scanData.nProcessLen, (DateTime)scanData.tTime));
                }
            }
            else if (boltIndex < MixCuttingValues.First().Count())
            {
                for (int i = 0; i < MixCuttingValues.Count(); i++)
                {
                    lc_tgRecord scanData = Values[i];
                    trendValues.Add(new TrendValue(MixCuttingValues[i][boltIndex].Value, (double)scanData.nProcessLen, (DateTime)scanData.tTime));
                }
            }
            return trendValues;
        }




        /// <summary>
        /// 以 DBViewerModel.Instance.YMin 到 DBViewerModel.Instance.YMax 为范围，统计直方图
        /// </summary>
        /// <returns></returns>
        public List<XY> GetHistogram()
        {
            double xmin = YMin;
            double xmax = YMax;

            int xmin_core = ((int)(xmin / DBViewerModel.Instance.Step));
            int xmax_core = ((int)(xmax / DBViewerModel.Instance.Step));


            List<XY> all_values = GetHistogram(new int[] { -1 }, DBViewerModel.Instance.Step);

            List<XY> values = new List<XY>();
            for (int x_core = xmin_core; x_core <= xmax_core; x_core++)
            {
                var list = from v in all_values where (int)(v.X / DBViewerModel.Instance.Step) == x_core select v;
                if (list.Count() == 0)
                    values.Add(new XY(x_core * DBViewerModel.Instance.Step, 0));
                else
                    values.Add(list.First());
            }
            return values;
        }
        public List<double> GetHistogramTrend()
        {
            List<double> list = new List<double>();
            foreach (var boltvalues in MixCuttingValues)
            {
                foreach (var boltvalue in boltvalues)
                {
                    if (double.IsNaN(boltvalue.Value))
                        continue;
                    list.Add(boltvalue.Value);
                }
            }
            list.Sort();
            return list;
        }
        #endregion

        public void UpdateStatistics()
        {
            List<double> values1 = new List<double>();
            //不统计平均值曲线
            values1.AddRange(GetCuttingValue(-1));
            //不统计NaN
            var values = values1.Where(d => !double.IsNaN(d));
            if (values.Count() == 0)
            {
                //没有数据
                Average = double.NaN;
                Sigma3 = double.NaN;
                CPK = double.NaN;
                TotalCount = 0;
                TolerancePercent = double.NaN;
                CtrllinePercent = double.NaN;
                return;
            }

            TotalCount = values.Count();

            double CtrllineMax = Target + Ctrlline;
            double CtrllineMin = Target - Ctrlline;
            Average = values.Average();


            double sigma = values.Sigma(d => d);
            Sigma3 = sigma * 3;
            int tolerance_cnt = values.Count(d => d <= USL && d >= LSL);
            int ctrline_cnt = values.Count(d => d <= CtrllineMax && d >= CtrllineMin);

            TolerancePercent = 1.0 * tolerance_cnt / TotalCount;
            CtrllinePercent = 1.0 * ctrline_cnt / TotalCount;

            CPK = values.CPK(USL, LSL);

            //NormValues.Clear();
            //var normvalues =
            //    from xy in Values select new XY(xy.X, MathExt.NormDist(xy.X, Average, sigma));

            //double sum = normvalues.Sum(xy => xy.Y);
            //NormValues.AddRange(normvalues.Select(xy => new XY(xy.X, total * xy.Y / sum)));
        }


        public void NotifyPropertyChanged(string propertyname)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
        }
    }
}
