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>
        IPLCProxySystemService PLCos;
        /// <summary>
        /// 报警系统
        /// </summary>
        WarningSystem mWarning;
        public byte ErrCode=0;
        public ErrorConf(IPLCProxySystemService PLCos, WarningSystem 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;
            public bool offIsError;
        }
        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;
                    //bool offIsError = (propertyInfo.GetCustomAttributes(typeof(IsErrorAttribute), false).First() as IsErrorAttribute).OffIsError;


                    ErrorInfo errorInfo = new ErrorInfo()
                    {
                        property = propertyInfo.Name,
                        msg = desp,
                        //offIsError = offIsError,
                        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);
            }

            //--------------------------------------------------------------------------------
            //连接断开事件
            FObjBase.PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD,
                () =>
                {
                    Misc.BindingOperations.SetBinding(PLCos, "IsConnectedWithPLC", () =>
                    {
                        bool b = !PLCos.IsConnectedWithPLC;

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

                        ERRNO errno = PlcErrNos.ERRNO_PLC_DISCONNECTED;
                        byte errcode = errno.Code;
                        string description = $"{plcName} "+errno.Descrption;
                        mWarning.Add(errcode, description, state);
                    });
                }, TimeSpan.FromSeconds(3), true, false, this, MARKNO_DELAY_ISCONNECTED, true);

            //--------------------------------------------------------------------------------
            //把全部报警状态取反，也就是不报警！！！
            foreach (var kv in obj_error)
            {
                object sender = kv.Key;
                foreach (var ei in kv.Value.error_property)
                {
                    if (ei.offIsError)
                    {
                        Misc.PropertiesManager.SetValue(sender, ei.property, true);
                    }
                    //false 不用写，默认值就是
                }
            }

        }


        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;
                bool offIsError = ei.offIsError;

                ERR_STATE state;
                if (offIsError)
                    state = !b ? ERR_STATE.ON : ERR_STATE.OFF;
                else
                    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     
    }
}
