using FLY.OBJComponents.Server.Model;
using Misc;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FLY.Thick.FilmCasting.UI.DbViewer.Db
{
    #region 链接表的关系
    /// <summary>
    /// 包装 DB_Profile， 组织 DB_Profile， DB_ScanData....
    /// </summary>
    public class DbProfilePack : INotifyPropertyChanged
    {
        public FLY.Thick.FilmCasting.Server.Model.Db_Profile Profile;
        public List<FLY.Thick.FilmCasting.Server.Model.Lc_ScanData> ScanDatas;
        public List<Db_Error> Errors;

        #region 能重新调整的参数
        public double USL
        {
            get
            {
                return Target + Target * TolerancePercent;
            }
        }
        public double LSL
        {
            get
            {
                return Target - Target * TolerancePercent;
            }
        }
        public double Target { get; set; }
        public double YMax
        {
            get
            {
                return Target + Target * TolerancePercent * YRangePercent;
            }
        }
        public double YMin
        {
            get
            {
                return Target - Target * TolerancePercent * YRangePercent;
            }
        }
        public double TolerancePercent { get; set; }
        public double YRangePercent { get; set; } = 2;

        #endregion
        #region 统计结果，用于输出
        public int TotalCount { get; private set; }
        public double Average { get; private set; }
        public double Sigma2 { get; private set; }
        public double CPK { get; private set; }
        public double InTolerancePercentRange { get; private set; }
        #endregion
        /// <summary>
        /// 分区数
        /// </summary>
        public int NBolts { get; private set; }


        public void Init(bool isJustRunning)
        {
            if (ScanDatas.Count() > 0)
            {
                NBolts = ScanDatas.Last().Thicks.Count();
            }
            if (isJustRunning)
            {
                //把静止下的删除！！！！！
                ScanDatas.RemoveAll(sd => sd.FilmVelocity == 0);
            }


            Target = Profile.Target;
            TolerancePercent = Profile.TolerancePercent;
            UpdateStatistics();
        }


        void UpdateStatistics()
        {
            List<double> values = new List<double>();
            for (int i = 0; i < ScanDatas.Count(); i++)
            {
                var scanData = ScanDatas[i];
                //不统计NaN
                values.AddRange(scanData.Thicks.Where(t => !double.IsNaN(t)));

            }
            if (values.Count() == 0)
            {
                //没有数据
                Average = double.NaN;
                Sigma2 = double.NaN;
                CPK = double.NaN;
                TotalCount = 0;
                InTolerancePercentRange = double.NaN;
                return;
            }

            TotalCount = values.Count();

            Average = values.Average();

            double sigma = values.Sigma(d => d);
            Sigma2 = sigma * 2;
            int tolerance_cnt = values.Count(d => d <= USL && d >= LSL);

            InTolerancePercentRange = 1.0 * tolerance_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 event PropertyChangedEventHandler PropertyChanged;


        /// <summary>
        /// 统计 的 Y是 数量
        /// </summary>
        /// <param name="step"></param>
        /// <returns></returns>
        List<XY> GetHistogram(double step)
        {
            List<XY> list = new List<XY>();
            foreach (var scanData in ScanDatas)
            {
                foreach (var thk in scanData.Thicks)
                {
                    if (double.IsNaN(thk))
                        continue;

                    double x = ((int)(thk / 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>
        /// 以 YMin 到 YMax 为范围，统计直方图
        /// </summary>
        /// <returns></returns>
        public List<XY> GetHistogram2(double step)
        {
            double xmin = YMin;
            double xmax = YMax;

            int xmin_core = ((int)(xmin / step));
            int xmax_core = ((int)(xmax / step));


            List<XY> all_values = GetHistogram(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 / step) == x_core select v;
                if (list.Count() == 0)
                    values.Add(new XY(x_core * step, 0));
                else
                    values.Add(list.First());
            }
            return values;
        }

        public List<TrendValue> GetTrend()
        {
            List<TrendValue> trendValues = new List<TrendValue>();
            for (int i = 0; i < ScanDatas.Count(); i++)
            {
                var scanData = ScanDatas[i];

                double avg = scanData.Thicks.AverageNoNull();
                double sigma = scanData.Thicks.Sigma();
                trendValues.Add(new TrendValue() { Sigma = sigma, Time = scanData.Time, Value = avg });
            }
            return trendValues;
        }
    }
    #endregion


    public class TrendValue
    {
        public double Sigma { get; set; }
        public double Value { get; set; }
        public DateTime Time { get; set; }
    }
}
