using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using FLY.Thick.Base.Common;
using FLY.Thick.Base.IService;

namespace FLY.Thick.Base.Server
{
    //1.剔除 偏离平均值 大于 设定值
    //2.权重 滤波
    public class Reject : IRejectService, INotifyPropertyChanged, Misc.ISaveToXml
    {
        private bool enable;
        public bool Enable
        {
            get { return enable; }
            set
            {
                if (enable != value)
                {
                    enable = value;
                    NotifyPropertyChanged("Enable");
                }
            }
        }
        private int number;
        public int Number
        {
            get { return number; }
            set
            {
                if (number != value)
                {
                    number = value;
                    NotifyPropertyChanged("Number");
                }
            }
        }
        private double threshold_ratio;
        public double ThresholdRatio
        {
            get { return threshold_ratio; }
            set
            {
                if (threshold_ratio != value)
                {
                    threshold_ratio = value;
                    NotifyPropertyChanged("ThresholdRatio");
                }
            }
        }
        private bool ispercent;
        /// <summary>
        /// 废弃,不用
        /// </summary>
        public bool IsPercent
        {
            get { return ispercent; }
            set
            {
                if (ispercent != value)
                {
                    ispercent = value;
                    NotifyPropertyChanged("IsPercent");
                }
            }
        }
        private double psigma;
        /// <summary>
        /// 废弃,不用
        /// </summary>
        public double PSigma
        {
            get { return psigma; }
            set
            {
                if (psigma != value)
                {
                    psigma = value;
                    NotifyPropertyChanged("PSigma");
                }
            }
        }
        private int sigma;
        public int Sigma
        {
            get { return sigma; }
            set
            {
                if (sigma != value)
                {
                    sigma = value;
                    NotifyPropertyChanged("Sigma");
                }
            }
        }
        private int range1;
        public int Range1
        {
            get { return range1; }
            set
            {
                if (range1 != value)
                {
                    range1 = value;
                    NotifyPropertyChanged("Range1");
                }
            }
        }
        private int range2;
        public int Range2
        {
            get { return range2; }
            set
            {
                if (range2 != value)
                {
                    range2 = value;
                    NotifyPropertyChanged("Range2");
                }
            }
        }
        private int target;
        public int Target
        {
            get { return target; }
            private set
            {
                if (target != value)
                {
                    target = value;
                    NotifyPropertyChanged("Target");
                }
            }
        }
        private bool[] bfilterdats;//该数据是否需要剔除
        private int[] filterdats;//滤波后的数据
        private int[] rejectdats;//剔除后的数据
        private int[] sigmadats;//剔除用sigma数据
        public int dats_len;//上面三个的数据长度

        private int poslen = 8900;
        public int PosLen
        {
            get { return poslen; }
            set
            {
                if (poslen != value)
                {
                    poslen = value;
                    NotifyPropertyChanged("PosLen");
                }
            }
        }
        private int posofgrid = 10;
        public int PosOfGrid
        {
            get { return posofgrid; }
            set
            {
                if (posofgrid != value)
                {
                    posofgrid = value;
                    NotifyPropertyChanged("PosOfGrid");
                }
            }
        }
        public int[] FilterDatas
        {
            get
            {
                return filterdats;
            }
        }
        public int[] RejectDatas
        {
            get
            {
                return rejectdats;
            }
        }
        public int[] SigmaDatas
        {
            get
            {
                return sigmadats;
            }
        }

        public void Clear()
        {
            for (int i = 0; i < dats_len; i++)
                filterdats[i] = Misc.MyBase.NULL_VALUE;
            for (int i = 0; i < dats_len; i++)
                rejectdats[i] = Misc.MyBase.NULL_VALUE;
            for (int i = 0; i < dats_len; i++)
                sigmadats[i] = Misc.MyBase.NULL_VALUE;
            for (int i = 0; i < dats_len; i++)
                bfilterdats[i] = false;
        }
        public void Test()
        {
            int[] buf = new int[dats_len];
            for (int i = 0; i < buf.Length; i++)
            {
                buf[i] = 6000;
            }
            for (int i = 200; i < 300; i++)
            {
                buf[i] += (i - 200);
            }

            DoFrameFilter(6100, 0, buf);
        }
        private string param_path = "reject.xml";
        public Reject()
        {
            SetDefault();

            this.PropertyChanged += new PropertyChangedEventHandler(Reject_PropertyChanged);
        }
        
        public Reject(string param_path) 
        {
            if (!string.IsNullOrEmpty(param_path))
                this.param_path = param_path;

            SetDefault();
            Load();
            this.PropertyChanged += new PropertyChangedEventHandler(Reject_PropertyChanged);
        }

        void SetDefault() 
        {
            Enable = false;
            Number = 1;
            ThresholdRatio = 0.93;

            Range1 = 10;
            Range2 = Range1;
            Sigma = 80;
            int len = PosLen / PosOfGrid;
            Resize(len);
        }
        void Resize(int size)
        {
            dats_len = size;
            filterdats = new int[dats_len];
            rejectdats = new int[dats_len];
            sigmadats = new int[dats_len];
            bfilterdats = new bool[dats_len];
            Clear();
        }
        void Reject_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            //if (GetSavePropertyNames().Contains(e.PropertyName))
            //{
            //    FObjBase.PollModule.Current.Poll_JustOnce(new FObjBase.PollModule.PollHandler(delegate()
            //    {
            //        Save();
            //    }), this, 2);
            //}
            if ((e.PropertyName == "PosLen") || (e.PropertyName == "PosOfGrid"))
            {
                int len = PosLen / PosOfGrid;
                Resize(len);
            }
        }
        public void Load()
        {
            Misc.SaveToXmlHepler.Load(param_path, this);
        }
        public void Save()
        {
            Misc.SaveToXmlHepler.Save(param_path, this);
        }
        public void Apply() 
        {
            Save();
        }
        public void DoFrameFilter(int target, int start_grid, int[] frame)
        {
            //if (!Enable)
            //    return;
            Clear();

            int len = frame.Length;
            if ((start_grid + len) > dats_len)
            {
                len = dats_len - start_grid;
            }

            
            Array.Copy(frame, 0, rejectdats, start_grid, len);

            int range1 = Range1 / PosOfGrid;
            //滤波
            for (int i = start_grid; i < (len + start_grid); i++)
            {
                
                int b = i - range1;
                int e = i + range1;
                if (b < 0) b = 0;
                if (e >= dats_len) e = dats_len - 1;
                filterdats[i] = Misc.MyMath.Avg(rejectdats, b, e);
            }

            //sigma
            for (int i = start_grid; i < (len + start_grid); i++)
            {
                int b = i - Number;
                int e = i + Number;

                if (b < 0) b = 0;
                if (e >= dats_len) e = dats_len - 1;

                sigmadats[i] = Misc.MyMath.Sigma(filterdats, b, e);

            }

            int threshold = (int)(target * ThresholdRatio);


            //阀值剔除
            for (int i = start_grid; i < (len + start_grid); i++)
            {
                
                if (Misc.MyBase.ISVALIDATA(rejectdats[i]) && (rejectdats[i] < threshold))
                {
                    bfilterdats[i] = true;
                }
            }


            int sigma;

            sigma = Sigma;

            //sigma剔除
            for (int i = start_grid; i < (len + start_grid); i++)
            {
                
                if ((!Misc.MyBase.ISVALIDATA(sigmadats[i])) || (sigmadats[i] > sigma))
                {
                    bfilterdats[i] = true;
                }
            }

            int reject_b_idx= -1;
            int reject_e_idx = -1; 
            //半径内全部删除
            int range2 = Range2 / PosOfGrid;
            for (int i = start_grid; i < (start_grid+len); i++)
            {
                if (!bfilterdats[i])
                {
                    //之前有需要剔除的
                    if (reject_b_idx != -1)
                    {
                        int b = reject_b_idx - range2;
                        int e = reject_e_idx + range2;
                        if (b < 0) b = 0;
                        if (e >= dats_len) e = dats_len - 1;
                        for (int j = b; j <= e; j++)
                        {
                            rejectdats[j] = Misc.MyBase.NULL_VALUE;
                        }
                        reject_b_idx = -1;
                        i = e;
                    }
                }
                else
                {
                    if (reject_b_idx == -1)
                    {
                        reject_b_idx = i;
                    }
                    reject_e_idx = i;
                }
            }
            if (reject_b_idx != -1)
            {
                int b = reject_b_idx - range2;
                int e = reject_e_idx + range2;
                if (b < 0) b = 0;
                if (e >= dats_len) e = dats_len - 1;
                for (int j = b; j <= e; j++)
                {
                    rejectdats[j] = Misc.MyBase.NULL_VALUE;
                }
                reject_b_idx = -1;
            }


            if (Enable) 
            {
                Array.Copy(rejectdats, start_grid, frame, 0, len);
                //剩下的全部剔除
                for (int i = len; i < frame.Length; i++)
                {
                    frame[i] = Misc.MyBase.NULL_VALUE;
                }
            }

            Target = target;
            NotifyPropertyChanged("FilterDatas");
            NotifyPropertyChanged("RejectDatas");
            NotifyPropertyChanged("SigmaDatas");
        }

        int ToThick(double thk) {
            if (double.IsNaN(thk))
                return Misc.MyBase.NULL_VALUE;
            else
                return (int)(thk * 100);
        }
        public void DoFrameFilter(double _target, int start_grid, double[] _thks)
        {
            int[] frame = _thks.Select(d => ToThick(d)).ToArray();
            DoFrameFilter(ToThick(_target), start_grid, frame);
            for (int i = 0; i < frame.Count(); i++) {
                if (!Misc.MyBase.ISVALIDATA(frame[i]))
                {
                    _thks[i] = double.NaN;
                }
            }

        }

        #region INotifyPropertyChanged 成员
        protected void NotifyPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        public string[] GetSavePropertyNames()
        {
            return new string[]{
                "Enable",
                "ThresholdRatio",
                "Range1",
                "Range2",
                "Sigma"
            };
        }
    }
}