using AutoMapper;
using FLY.OBJComponents.Server;
using FLY.Thick.Base.Common;
using FLY.Thick.FilmCasting.IService;
using FLY.Thick.FilmCasting.Server.Model;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FLY.Thick.FilmCasting.Server
{
    public class ScanWarning : INotifyPropertyChanged, IScanWarningService
    {
        private WarningSystem2 mWarning;
        private IBulkDbService mBulkDB;
        private DynArea dynArea;
        /// <summary>
        /// 使能
        /// </summary>
        public bool Enable { get; set; }

        /// <summary>
        /// 目标值，绑定 profileparam.Target
        /// </summary>
        public double Target { get; set; }

        /// <summary>
        /// 产品公差%，绑定 profileparam.Tolerance
        /// </summary>
        public double TolerancePercent { get; set; }

        /// <summary>
        /// 连续N个点，大于报警线才算报警
        /// </summary>
        public int AlarmCnt { get; set; } = 2;

        public double AlarmPercent { get; set; } = 100;

        public int Mix { get; set; } = 6;
        enum CheckResult
        {
            Idle,
            Warning
        }
        CheckResult Check(double[] data)
        {
            int cnt = 0;
            for (int i = 0; i < data.Length; i++)
            {
                double d = data[i];
                if (double.IsNaN(d))
                {
                    cnt = 0;
                }
                else
                {

                    double delta = Math.Abs(d - Target);
                    double alarm = Target * TolerancePercent / 100 * AlarmPercent / 100;

                    if (delta > alarm)
                    {
                        //触发
                        cnt++;
                        if (cnt >= AlarmCnt)
                        {
                            //需要报警
                            return CheckResult.Warning;
                        }
                    }
                    else
                    {
                        cnt = 0;
                    }
                }
            }
            return CheckResult.Idle;
        }
        public void Apply()
        {
            Save();
        }
        public ScanWarning()
        {
            Load();
        }

        public void Init(
            WarningSystem2 warning,
            FLY.Thick.FilmCasting.Common.FilmCastingProfileParam profileParam,
            IBulkDbService bulkDB,
            DynArea dynArea)
        {
            mWarning = warning;
            mBulkDB = bulkDB;
            this.dynArea = dynArea;
            Misc.BindingOperations.SetBinding(profileParam, nameof(profileParam.Target), this, nameof(Target));
            Misc.BindingOperations.SetBinding(profileParam, nameof(profileParam.TolerancePercent), this, nameof(TolerancePercent));
            mBulkDB.PropertyChanged += MBulkDB_PropertyChanged;
        }

        private void MBulkDB_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(mBulkDB.LastScanDataId))
            {
                if (!Enable)//没启动
                    return;

                if (!dynArea.DataValid)//停着，不报警
                    return;

                mBulkDB.GetFrame(
                new Pack_GetFrameRequest()
                {
                    Id = -1,
                    StartTime = DateTime.Now - TimeSpan.FromMinutes(5),
                    Mix = Mix
                },
                GetFrameCB, null);

            }
        }

        void GetFrameCB(object AyncContext, object retData)
        {
            Pack_GetFrameReponse reponse = retData as Pack_GetFrameReponse;

            CheckResult result;
            if (reponse.scanData != null && reponse.scanData.Thicks.Count() > 0)
            {
                Lc_ScanData lc_ScanData = reponse.scanData;
                //lc_ScanData.Velocity


                result = Check(lc_ScanData.Thicks);
            }
            else
            {
                result = CheckResult.Idle;
            }

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

        private string file_path = "scanwarning.json";

        void Load()
        {
            try
            {
                if (File.Exists(file_path))
                {
                    string json = File.ReadAllText(file_path);
                    var p = JsonConvert.DeserializeObject<ScanWarningJsonDb>(json);
                    ScanWarningJsonDb.Mapper.Map(p, this);
                }
            }
            catch
            {
                //异常，没有json 解码失败
            }


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

            }


        }


        #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();
        }));
        /// <summary>
        /// 使能
        /// </summary>
        public bool Enable { get; set; }

        /// <summary>
        /// 连续N个点，大于报警线才算报警
        /// </summary>
        public int AlarmCnt { get; set; } = 2;

        public double AlarmPercent { get; set; } = 100;

        public int Mix { get; set; } = 6;

    }
}
