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


using System.ComponentModel;

using FLY.OBJComponents.Server;

using FLY.OBJComponents.Common;
using FLY.Thick.Blowing.IService;
using FLY.Thick.Blowing.Common;
using Misc;
using FLY.Thick.Blowing.Server.Model;

namespace FLY.Thick.Blowing.Server
{
    public class ScanWarning : Misc.ISaveToXml, INotifyPropertyChanged, IScanWarningService
    {
        private WarningSystem mWarning;
        private IShareDbService shareDb;
        
        /// <summary>
        /// 使能
        /// </summary>
        public bool Enable { get; set; }

        /// <summary>
        /// 自动目标值
        /// </summary>
        public bool IsAutoTarget { get; set; } = true;
        
        /// <summary>
        /// 连续N个点,大于规格线(公差)才算报警
        /// </summary>
        public int AlarmCnt_Tolerance { get; set; } = 10;

        public event ScanWarningCheckEventHandler ScanWarningCheck;


        enum CheckResult
        {
            Idle,
            ToleranceWarning,
        }

        /// <summary>
        /// 数据是环形的。
        /// </summary>
        /// <param name="target"></param>
        /// <param name="tolerancePercent"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        CheckResult Check(double target, double tolerancePercent, double[] data)
        {
            double avg = data.AverageNoNull();
            if (double.IsNaN(avg))
                return CheckResult.Idle;

            if (IsAutoTarget)
                target = avg;


            double tolerance = target * tolerancePercent;
            int cnt_tolerance = 0;
            int valid_index = -1;//第1个合格范围数据

            for (int i = 0; i < data.Length; i++) 
            {
                double d = data[i];
                if (double.IsNaN(d))
                    continue;
                double delta = Math.Abs(d - target);
               

                if (delta > tolerance)
                {
                    //触发
                    cnt_tolerance++;
                    if (cnt_tolerance >= AlarmCnt_Tolerance)
                    {
                        //需要报警
                        return CheckResult.ToleranceWarning;
                    }
                }
                else
                {
                    cnt_tolerance = 0;
                    if(valid_index==-1)
                        valid_index = i;
                }
            }
            if (cnt_tolerance > 0)
            {
                for (int i = 0; i < valid_index; i++)
                {
                    double d = data[i];
                    if (double.IsNaN(d))
                        continue;
                    double delta = Math.Abs(d - target);
                    if (delta > tolerance)
                    {
                        //触发
                        cnt_tolerance++;
                        if (cnt_tolerance >= AlarmCnt_Tolerance)
                        {
                            //需要报警
                            return CheckResult.ToleranceWarning;
                        }
                    }
                }
            }

            return CheckResult.Idle;
        }
        public void Apply() {
            Save();
        }
        public ScanWarning() 
        {
            Load();
        }

        public void Init(WarningSystem warning, IShareDbService shareDB) 
        {
            mWarning = warning;
            shareDb = shareDB;

            shareDb.ScanDataAdded += MshareDB_ScanDataAdded;
        }

        private void MshareDB_ScanDataAdded(object sender, EventArgs _e)
        {
            var e = (ScanDataAddedEventArgs)_e;
            if (!Enable)
                return;
            shareDb.GetProfile((asyncContext, retData) =>
            {
                Db_Profile dB_Profile = retData as Db_Profile;
                if (dB_Profile == null)
                    return;

                GetFrameCB(dB_Profile, e.scandata);
            }, null);
            
        }

        void GetFrameCB(Db_Profile dB_Profile,Lc_ScanData lc_ScanData) 
        {
            CheckResult result = Check(dB_Profile.Target, dB_Profile.TolerancePercent, lc_ScanData.Thicks);


            string accessory = "";
            if (result != CheckResult.Idle)
                accessory = Newtonsoft.Json.JsonConvert.SerializeObject(lc_ScanData.ID);

            switch (result)
            {
                case CheckResult.ToleranceWarning:
                    //报警
                    mWarning.Add(
                        ERRNOs.SCAN_ERRNO_OVERTOL.Code,
                        ERRNOs.SCAN_ERRNO_OVERTOL.Descrption,
                        ERR_STATE.ON,
                        accessory
                        );
                    break;
                case CheckResult.Idle:
                    {
                        //报警解除
                        mWarning.Add(
                            ERRNOs.SCAN_ERRNO_OVERTOL.Code,
                            ERRNOs.SCAN_ERRNO_OVERTOL.Descrption,
                            ERR_STATE.OFF);
                    }
                    break;
            }

            ScanWarningCheck?.Invoke(this, new ScanWarningCheckEventArgs()
            {
                isWarning = (result != CheckResult.Idle),
                profile = dB_Profile,
                scandata = lc_ScanData
            });
        }
        
        
        public void Save() 
        {
            Misc.SaveToXmlHepler.Save("scanwarning.xml", this);
        }
        public bool Load() 
        {
            return Misc.SaveToXmlHepler.Load("scanwarning.xml", this);
        }
        #region INotifyPropertyChanged 成员

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion




        public string[] GetSavePropertyNames()
        {
            return new string[]{
                "Enable","IsAutoTarget","AlarmCnt_Tolerance"};
        }
    }

    public class ScanWarningCheckEventArgs
    {
        public bool isWarning;
        public Db_Profile profile;
        public Lc_ScanData scandata;
    }
    public delegate void ScanWarningCheckEventHandler(object sender, ScanWarningCheckEventArgs e);
}