using FLY.OBJComponents.Common;
using FLY.OBJComponents.IService;
using FObjBase;
using Misc;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FLY.OBJComponents.Server
{
    public class ErrorConf
    {
        #region 延时推送 MARKNO
        const int MARKNO_DELAY_ISCONNECTED = 4;
        #endregion
        string plcName;
        /// <summary>
        /// 需要设置
        /// </summary>
        PLCProxySystem PLCos;
        /// <summary>
        /// 报警系统
        /// </summary>
        WarningSystem2 mWarning;
        public byte ErrCode=0;
        public ErrorConf(PLCProxySystem PLCos, WarningSystem2 mWarning, string plcName)
        {
            this.PLCos = PLCos;
            this.mWarning = mWarning;
            this.plcName = plcName;
        }

        #region 报警
        public class ErrorAction
        {
            public List<ErrorInfo> error_property;
            public object state;
            public delegate void ErrorHandler(ref string msg, object state);
            public ErrorHandler action;
        }
        public class ErrorInfo
        {
            public string property;
            public byte code;
            public string msg;
        }
        Dictionary<INotifyPropertyChanged, ErrorAction> obj_error = new Dictionary<INotifyPropertyChanged, ErrorAction>();

        public void AddErrorAction(INotifyPropertyChanged sender, ErrorAction.ErrorHandler errorHandler = null, object state = null)
        {
            //反射找出全部是报警的property
            List<ErrorInfo> error_property = new List<ErrorInfo>();
            foreach (var propertyInfo in sender.GetType().GetProperties())
            {
                if (propertyInfo.GetCustomAttributes(typeof(IsErrorAttribute), false).Count() > 0)
                {
                    //肯定有，没有就让它出错！！！
                    string desp = (propertyInfo.GetCustomAttributes(typeof(DescriptionAttribute), false).First() as DescriptionAttribute).Description;
                    //报警如果是反向， 会被设置为放大=-1, 所以 最后属性 肯定是 true 时报警， offIsError没有用
                    
                    ErrorInfo errorInfo = new ErrorInfo()
                    {
                        property = propertyInfo.Name,
                        msg = desp,
                        code = ErrCode
                    };
                    error_property.Add(errorInfo);
                    ErrCode++;
                }
            }
            obj_error.Add(sender, new ErrorAction()
            {
                error_property = error_property,
                action = errorHandler,
                state = state
            });
        }

        /// <summary>
        /// 执行之前，需要调用 AddErrorAction， 向 obj_error 添加报警寄存器操作
        /// </summary>
        public void InitError()
        {
            foreach (var obj in obj_error.Keys)
            {
                obj.PropertyChanged += Obj_PropertyChanged_ForError;
            }

            //--------------------------------------------------------------------------------
            //添加任务
            foreach (var kv in obj_error)
            {
                string objname = PLCos.ObjNames.First(_kv => _kv.Value == kv.Key).Key;
                PLCos.SetPlan(objname, kv.Value.error_property.Select(ei => ei.property).ToArray(), 0);
            }

            //--------------------------------------------------------------------------------
            //连接断开事件, 3秒查一次，不能有复位的机会
            FObjBase.PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD,
                () =>
                {
                    for (int i = 0; i < PLCos.PLCs.Count(); i++)
                    {
                        bool b = !PLCos.PLCs[i].Client.IsConnected;
                        ERR_STATE state = b ? ERR_STATE.ON : ERR_STATE.OFF;

                        ERRNO errno = PlcErrNos.Instance.ERRNO_PLC_DISCONNECTED;
                        UInt16 errcode = (UInt16)(errno.Code - i);
                        string description;
                        if (PLCos.PLCs.Count() > 1)
                            description = $"{plcName} No.{i+1} " + errno.Descrption;
                        else
                            description = $"{plcName} " + errno.Descrption;

                        mWarning.Add(errcode, description, state);
                    }

                }, TimeSpan.FromSeconds(3), true, false, this, MARKNO_DELAY_ISCONNECTED, false);

            //--------------------------------------------------------------------------------
            //启动定时器，每1秒查报警，防止 以为报警复位了，但其实还在报警

            //FObjBase.PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD,
            //    () =>
            //    {
            //        foreach(var objError in obj_error) 
            //        {
            //            object sender = objError.Key;
            //            ErrorAction errorAction = objError.Value;
            //            foreach (var ei in errorAction.error_property) 
            //            {
            //                //获取描述
            //                var type = sender.GetType();
            //                var property = type.GetProperty(ei.property);
            //                bool b = (bool)property.GetValue(sender, null);
            //                string desp = ei.msg;

            //                ERR_STATE state = b ? ERR_STATE.ON : ERR_STATE.OFF;

            //                byte errcode = ei.code;//每个报警必须不一样！！
            //                string description = desp;

            //                errorAction.action?.Invoke(ref description, errorAction.state);

            //                mWarning.Add(errcode, description, state);
            //            }
            //        }
            //    }, TimeSpan.FromSeconds(1));
        }

        public void ResetError(INotifyPropertyChanged sender) 
        {
            var type = sender.GetType();
            foreach (var ei in obj_error[sender].error_property) 
            {
                var property = type.GetProperty(ei.property);
                property.SetValue(sender, false);
            }
        }
        public void ResetError()
        {
            foreach (var sender in obj_error.Keys) {
                ResetError(sender);
            }
        }
        void Obj_PropertyChanged_ForError(object sender, PropertyChangedEventArgs e)
        {
            ErrorAction errorAction = obj_error[sender as INotifyPropertyChanged];

            var eis = from ei in errorAction.error_property where ei.property == e.PropertyName select ei;
            if (eis.Count() > 0)
            {
                var ei = eis.First();

                //获取描述
                var type = sender.GetType();
                var property = type.GetProperty(ei.property);
                bool b = (bool)property.GetValue(sender, null);
                string desp = ei.msg;

                ERR_STATE state = b ? ERR_STATE.ON : ERR_STATE.OFF;

                byte errcode = ei.code;//每个报警必须不一样！！
                string description = desp;

                errorAction.action?.Invoke(ref description, errorAction.state);

                mWarning.Add(errcode, description, state);
            }
        }
        #endregion     
    }
}
