using AutoMapper;
using FLY.OBJComponents.Server;
using FLY.Thick.Base.Common;
using FLY.Thick.Blowing.IService;
using FLY.Thick.Blowing.Server.Model;
using Misc;
using Newtonsoft.Json;
using System;
using System.ComponentModel;
using System.IO;

namespace FLY.Thick.Blowing.Server
{
    public class ScanWarning : INotifyPropertyChanged, IScanWarningService
    {
        private WarningSystem2 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;


        public enum CheckResult
        {
            Idle,
            ToleranceWarning,
        }

        /// <summary>
        /// 数据是环形的。
        /// </summary>
        /// <param name="target"></param>
        /// <param name="tolerancePercent"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public 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(WarningSystem2 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(new { ScanDataID = lc_ScanData.ID });

            switch (result)
            {
                case CheckResult.ToleranceWarning:
                    //报警
                    mWarning.Update(
                        ERRNOs.Instance.SCAN_ERRNO_OVERTOL.Code,
                        ERRNOs.Instance.SCAN_ERRNO_OVERTOL.Descrption,
                        accessory
                        );
                    break;
                case CheckResult.Idle:
                    {
                        //报警解除
                        mWarning.Remove(ERRNOs.Instance.SCAN_ERRNO_OVERTOL.Code);
                    }
                    break;
            }

            ScanWarningCheck?.Invoke(this, new ScanWarningCheckEventArgs()
            {
                isWarning = (result != CheckResult.Idle),
                profile = dB_Profile,
                scandata = lc_ScanData
            });
        }


        string file_path = "scanwarning.json";
        public bool Load()
        {
            try
            {
                if (File.Exists(file_path))
                {
                    string json = File.ReadAllText(file_path);
                    var jsonDb = JsonConvert.DeserializeObject<ScanWarningJsonDb>(json);
                    ScanWarningJsonDb.Mapper.Map(jsonDb, this);
                    return true;
                }
            }
            catch
            {
                //异常,没有json 解码失败

            }
            return false;
        }

        bool Save()
        {
            try
            {
                var jsonDb = ScanWarningJsonDb.Mapper.Map<ScanWarningJsonDb>(this);
                string json = JsonConvert.SerializeObject(jsonDb, Formatting.Indented);
                File.WriteAllText(file_path, json);
                return true;
            }
            catch
            {
                //异常,没有json 编码失败

            }
            return false;
        }


        #region INotifyPropertyChanged 成员

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

    }
    public class ScanWarningJsonDb
    {
        public static Mapper Mapper { get; } = new AutoMapper.Mapper(new MapperConfiguration(c =>
        {
            c.CreateMap<ScanWarning, ScanWarningJsonDb>().ReverseMap();
        }));
        public bool Enable;
        public bool IsAutoTarget;
        public int AlarmCnt_Tolerance;
    }
    public class ScanWarningCheckEventArgs
    {
        public bool isWarning;
        public Db_Profile profile;
        public Lc_ScanData scandata;
    }
    public delegate void ScanWarningCheckEventHandler(object sender, ScanWarningCheckEventArgs e);


}