using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.IO;
using System.ComponentModel;
using System.Xml.Serialization;

using Misc;
using FObjBase;
using FlyADBase;
using FLY.Thick.Base.IService;
using PropertyChanged;
using Newtonsoft.Json;
using static Misc.ReverserInfo;

namespace FLY.Thick.Base.Server
{
    [JsonObject(MemberSerialization.OptIn)]
    public class GSample : IGetSampleService, Misc.ISaveToXml
    {
        #region IGetSampleService 接口

        /// <summary>
        /// 参数：使能
        /// </summary>
        [JsonProperty]
        public bool Enable { get; set; } = true;

        /// <summary>
        /// 参数：间隔
        /// </summary>
        [JsonProperty]
        public int Interval { get; set; } = 5;


        /// <summary>
        /// 采样计数
        /// </summary>
        public int Timer { get; set; }

        /// <summary>
        /// 参数：速度
        /// </summary>
        [JsonProperty]
        public UInt32 Velocity { get; set; } = 500;


        /// <summary>
        /// 参数：样品点范围
        /// </summary>
        [JsonProperty]
        public int Range { get; set; } = 100;


        /// <summary>
        /// 滤波窗口
        /// </summary>
        [JsonProperty]
        public int Window { get; set; } = 3;


        /// <summary>
        /// 样品
        /// </summary>
        [JsonProperty]
        public SampleCell[] Samples { get; set; }

        /// <summary>
        /// 查找公差
        /// </summary>
        [JsonProperty]
        public int Search { get; set; } = 100;

        /// <summary>
        /// 特征  相识度 0 正， 1 反
        /// </summary>
        [JsonProperty]
        public SampleFeature[] Features { get; set; } 


        /// <summary>
        /// 状态：从flyad7 得到的。 用于绘制图
        /// </summary>
        public int PosOfGrid { get; set; } = 10;


        #endregion
        List<TempFilter> tempFilters = new List<TempFilter>();
        List<DIRECTION> directions = new List<DIRECTION>();
        IGageInfoService mGageInfo;

        FlyAD7 flyad;

        public event SampleChangedEventHandler SampleChangedEvent;
        private string param_path;
        public GSample(FlyAD7 flyad):this(flyad,"gsample.xml")
        {

        }
        public GSample(FlyAD7 flyad, string param_path) 
        {
            this.param_path = param_path;
            this.flyad = flyad;
            
            Misc.BindingOperations.SetBinding(flyad, "PosOfGrid", this, "PosOfGrid");

            for (int i = 0; i < 3; i++)
            {
                TempFilter tempFilter = new TempFilter();
                tempFilter.SetWindow(Window);
                tempFilters.Add(tempFilter);

                directions.Add(DIRECTION.BACKWARD);
            }


            this.PropertyChanged += new PropertyChangedEventHandler(GSample_PropertyChanged);
            Load();
            if (Samples == null || Samples.Count() != 3) 
            {
                Samples = new SampleCell[3];
                Samples[0] = new SampleCell()
                {
                    Enable = true,
                    Position = 0,
                    OrgAD = 0
                };
                Samples[1] = new SampleCell()
                {
                    Enable = false,
                    Position = 2006,
                    OrgAD = 30000
                };
                Samples[2] = new SampleCell()
                {
                    Enable = false,
                    Position = 0,
                    OrgAD = 0
                };
            }
            if (Features == null || Features.Count() != 2)
            {
                Features = new SampleFeature[2];
                Features[0] = new SampleFeature();
                Features[1] = new SampleFeature();
            }
        }

        public void Init(IGageInfoService gageInfo) 
        {
            this.mGageInfo = gageInfo;
        }

        void GSample_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Window") 
            {
                for (int i = 0; i < 3; i++)
                {
                    tempFilters[i].SetWindow(Window);
                }
            }
        }

        public bool Load() 
        {
            try
            {
                string json = File.ReadAllText(param_path);

                Newtonsoft.Json.JsonConvert.PopulateObject(json, this);

            }
            catch 
            {
                return false;
            }
            return true;
        }

        public void Save() 
        {
            try
            {
                string json = Newtonsoft.Json.JsonConvert.SerializeObject(this);
                File.WriteAllText(param_path, json);

            }
            catch
            {
            }
        }
        /// <summary>
        /// 1.判断样品取样方向
        /// 2.复位间隔计数
        /// 3.复位所有样品取样状态
        /// </summary>
        /// <param name="scanbegin"></param>
        /// <param name="scanend"></param>
        public virtual void Init(int scanbegin, int scanend)
        {
            for(int i=0;i<3;i++)
            {
                SampleCell sample = Samples[i];

                int pos = sample.Position;
                if (Math.Abs(pos - scanbegin) < Math.Abs(pos - scanend))
                    directions[i] = Misc.DIRECTION.BACKWARD;
                else
                    directions[i] = Misc.DIRECTION.FORWARD;
                sample.AD = -1;
                tempFilters[i].ResetSampleFailure();
            }

            Timer = Interval;
        }
        public void Init() 
        {
            for (int i = 0; i < 3; i++)
            {
                SampleCell sample = Samples[i];
                sample.AD = -1;
                tempFilters[i].ResetSampleFailure();
            }
            Timer = Interval;
        }
        /// <summary>
        /// 检测是否要样品校正
        /// </summary>
        /// <returns></returns>
        public virtual bool Check()
        {
            if (!Samples.Any(s => s.Enable))
            {
                return false;
            }

            if (Timer < Interval)
            {
                Timer++;
                return false;
            }
            else
            {
                return true;
            }
        }
        /// <summary>
        /// 获取样品测量范围
        /// </summary>
        /// <param name="direction"></param>
        /// <returns>当没有样品，也没有特征，返回null</returns>      
        public Range GetSampleRange(Misc.DIRECTION direction) 
        {
            int b, e;
            if (GetSampleRange(direction, out b, out e))
            {
                return new Range() { Begin = b, End = e };
            }
            else
            {
                return new Range();
            }
        }
        /// <summary>
        /// 获取样品测量范围
        /// </summary>
        /// <param name="direction"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns>当没有样品，也没有特征，返回False</returns>
        public virtual bool GetSampleRange(Misc.DIRECTION direction, out int start,out int end)
        {
            start = 0;
            end = 0;
            bool valid = false;
            int b=0, e=0;
            int r_idx = 0;
            if (direction == Misc.DIRECTION.BACKWARD)
                r_idx = 1;

            if (Features[r_idx].Enable)
            {
                b = Features[r_idx].StartPos;
                e = Features[r_idx].EndPos;
                valid = true;
            }

            for(int i=0;i<3;i++)
            {
                SampleCell sample = Samples[i];
                var sample_direction = directions[i];
                if ((sample.Enable) && (sample_direction == direction))
                {
                    int _b = sample.Position - Range;
                    int _e = sample.Position + Range;

                    if (!valid)
                    {
                        b = _b;
                        e = _e;
                        valid = true;
                    }
                    else
                    {
                        if (b > _b)
                            b = _b;

                        if (e < _e)
                            e = _e;
                    }
                }
            }




            if (valid)
            {
                if (Features[r_idx].Enable)
                {
                    b -= Search;
                    e += Search;
                }
                start = b;
                end = e;
            }

            return valid;
        }


        /// <summary>
        /// 检测参数合法性
        /// </summary>
        /// <returns></returns>
        protected bool CheckParamIsValid() 
        {
            //样品位置 要在 范围
            foreach(SampleCell sample in Samples)
            {
                if (sample.Enable)
                {                    
                    if(((sample.Position -  Range)<0) || ((sample.Position+Range)>= flyad.PosLen))
                        return false;
                }
            }
            foreach(SampleFeature feature in Features)
            {
                if (feature.Enable)
                {                    
                    if(((feature.StartPos -  Search)<0) || ((feature.EndPos+Search)>= flyad.PosLen))
                        return false;
                }
            }
            
            return true;
        }
        
        /// <summary>
        /// 样品取样，推送给thickm, 参数一定合法，不用检测
        /// </summary>
        /// <param name="direction"></param>
        public void Do(Misc.DIRECTION direction)
        {
            int[] dat;
            flyad.GetGrid(direction,0, flyad.PosLen/flyad.PosOfGrid, out dat);
            Do(direction, 0, dat);
        }


        /// <summary>
        /// 样品取样，推送给thickm, 参数一定合法，不用检测
        /// </summary>
        /// <param name="direction"></param>
        public virtual void Do(Misc.DIRECTION direction, int grid_start, int[] buf)
        {
            bool isFailure = false;//取样失败了

            if(CheckParamIsValid() == false)
                return;
            int grid_offset = 0;//经过相识性计算后的偏移量

            //在这里处理gsample->m_timer
            int dir_idx = 0;
            if (direction == Misc.DIRECTION.FORWARD)
                dir_idx = 0;
            else
                dir_idx = 1;

            //数据在 gsample -> gagedata[0]
            SampleFeature psr = Features[dir_idx] as SampleFeature;

            if (psr.Enable)
            {
                //检测机架数据，当为空时，不能作相识性计算
                if (!mGageInfo.DataOK)
                    goto _corr_end;

                int pos1 = psr.StartPos;
                int pos2 = psr.EndPos;
                int posOfGrid = flyad.PosOfGrid;

                int grid1 = pos1 / posOfGrid;
                int grid2 = pos2 / posOfGrid;
                int grid_searchtol = Search / posOfGrid;

                int[] gagedata;
                if (direction == Misc.DIRECTION.FORWARD)
                    gagedata = mGageInfo.ForwData.ToArray();
                else
                    gagedata = mGageInfo.BackwData.ToArray();


                //合格,查找最大相识性的点
                int grid_b = grid1 - grid_searchtol;
                int grid_e = grid2 + grid_searchtol;
                int grid_len = grid_e - grid_b + 1;
                psr.ScanData = new int[grid_len];
                Array.Copy(buf, grid_b - grid_start, psr.ScanData, 0, grid_len);

                double max_relvency = 0;
                int max_grid_offset = 0;

                for (int i = 0; i < grid_searchtol * 2; i++)
                {
                    double r = Misc.MyMath.Correl(gagedata, grid1, psr.ScanData, i, grid2 - grid1 + 1);
                    if (r > max_relvency)
                    {
                        max_relvency = r;
                        max_grid_offset = i - grid_searchtol;
                    }
                }
                psr.MaxRelevancy = max_relvency;
                psr.MaxOffset = max_grid_offset * posOfGrid;

                if (max_relvency > 0.8) //相识度必须高于0.8
                    grid_offset = max_grid_offset;
                else
                {
                    //相似性太低，取样失败！！！
                    isFailure = true;
                }
            }

        _corr_end:
            int ad = -1;
            for (int i = 0; i < Samples.Count(); i++)
            {
                SampleCell sample = Samples[i] as SampleCell;
                TempFilter tempre = tempFilters[i];
                var sample_direction = directions[i];
                if ((sample_direction == direction) && (sample.Enable) )
                {
                    ad=-1;
                    if (!isFailure)
                    {
                        //获取grid 数据
                        int posOfGrid = flyad.PosOfGrid;
                        int grid = sample.Position / posOfGrid + grid_offset;
                        int grid_range = Range / posOfGrid;
                        int grid1 = grid - grid_range;
                        int grid_len = grid_range * 2;

                        int grid_b = grid1 - grid_start;
                        int grid_e = grid_b + grid_len - 1;
                        //计算平均值
                        ad = Misc.MyMath.Avg(buf, grid_b, grid_e);

                        if (!Misc.MyBase.ISVALIDATA(ad))//AD无效。。。异常，复位
                        {
                            isFailure = true;
                        }
                        else
                        {
                            ad = tempre.CalSampleAD(ad);//ad filter	
                            if (tempre.IsSampleFailure())//AD突变。。。异常，复位
                            {
                                isFailure = true;
                            }
                        }
                    }
                    if (isFailure)
                    {
                        tempre.ResetSampleFailure();
                        ad = -1;
                    }

                    sample.AD = ad;
                }
            }



            if (SampleChangedEvent != null)
                SampleChangedEvent(this);


            if (isFailure)//样品获取失败，下次继续！！！
                    return;
            //只有当所有都成功，Timer=0
            if(Samples.All(s => (s.Enable && s.AD > 0) || (!s.Enable)))
                Timer = 0;
        }

        /// <summary>
        /// 检测是否成功
        /// </summary>
        /// <returns></returns>
        public virtual bool OK()
        {
            if (Enable)
            {
                foreach (SampleCell sample in Samples)
                {
                    if ((sample.Enable) && (sample.AD < 0))
                    {
                        return false;
                    }
                }
            }

            return true;
        }

        /// <summary>
        /// 获取N秒的数据，
        /// </summary>
        /// <param name="buf"></param>
        /// <returns></returns>
        public void DoFix(int idx, int[] buf)
        {
            if (idx >= Samples.Count())
                return;
            else if (idx < 0)
                return;

            int avg = Misc.MyMath.Avg(buf);
            SampleCell sample = Samples[idx] as SampleCell;
            sample.AD = avg;

            if (SampleChangedEvent != null)
                SampleChangedEvent(this);


            //只有当所有都成功，Timer=0
            if (Samples.All(s => (s.Enable && s.AD > 0) || (!s.Enable)))
                Timer = 0;
        }
        /// <summary>
        /// 重新获取样品
        /// </summary>
        //public void Reset()
        //{
        //    foreach (SampleCell sample in Samples) 
        //    {
        //        TempFilter tempre = sample.TempF;
        //        tempre.ResetSampleFailure();
        //    }
        //}


        #region ISaveToXml 成员

        public string[] GetSavePropertyNames()
        {
            return new string[]{
                "Enable",
                "Interval",
                "Range",
                "Window",
                "Samples",
                "Search",
                "Features"
            };
        }

        #endregion
        public event PropertyChangedEventHandler PropertyChanged;


        public void Apply()
        {
            //通知上层
            Save();
        }
    }

    public delegate void SampleChangedEventHandler(GSample gsample);
}
