using FLY.Modbus;
using FLY.OBJComponents.Common;
using FLY.OBJComponents.IService;
using FLY.OBJComponents.Server;
using FLY.Winder.Common;
using FLY.Winder.IService;
using FObjBase;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace FLY.Winder.Server
{
    public class WinderSystem : IWinderSystemService
    {
        #region 延时推送 MARKNO
        const int MARKNO_SAVE = 1;
        const int MARKNO_DELAY_ISCONNECTED = 4;
        #endregion
        /// <summary>
        /// 收卷其它附件
        /// </summary>
        public WinderAccessory Accessory { get; private set; }

        /// <summary>
        /// 内收卷 外收卷
        /// </summary>
        public List<WinderInsideOutside> Items { get; private set; }

        private PLCProxySystem plcos = new PLCProxySystem();
        /// <summary>
        /// PLC代理系统
        /// </summary>
        public IPLCProxySystemService PLCos { get { return plcos; } }

        /// <summary>
        /// 报警系统
        /// </summary>
        public WarningSystem mWarning;

        static WinderSystem()
        {
            //Misc.SaveToXmlHepler.Regist(typeof(WinderSystemParams));
        }
        public WinderSystem()
        {
            Items = new List<WinderInsideOutside>();
            for (int i = 0; i < 2; i++)
            {
                Items.Add(new WinderInsideOutside());
            }
            Accessory = new WinderAccessory();


    
            mWarning = new WarningSystem();

            AddConfigFile("WS.xml");


            //--------------------------------------------------------------------------------
            //报警配置
            InitError();

            
            //--------------------------------------------------------------------------------
            //添加任务
            //Misc.BindingOperations.SetBinding(PLCos, "IsConnectedWithPLC", () =>
            //{
            //    if (PLCos.IsConnectedWithPLC)
            //    {

            //        PLCos.SetPlan("Winder0", new string[] {
            //            "Tension","TensionSet"
            //        }, 0);
            //        PLCos.SetPlan("Winder1", new string[] {
            //            "Tension","TensionSet"
            //        }, 0);

            //        PLCos.SetPlan("WinderAccessory", new string[] {
            //            "Traction2Gain","Traction2ITime"
            //        }, 0);
            //    }
            //});


            plcos.Init();
        }
        #region 报警
        class ErrorAction
        {
            public Dictionary<string, ERRNO> error_property;
            public object state;
            public delegate void ErrorHandler(ref byte errcode, ref string msg, object state);
            public ErrorHandler action;
        }
        Dictionary<INotifyPropertyChanged, ErrorAction> obj_error = new Dictionary<INotifyPropertyChanged, ErrorAction>();

        void InitError()
        {
            Dictionary<string, ERRNO> error_winder_property = new Dictionary<string, ERRNO>();
            error_winder_property.Add("IsError_VFD", ERRNOs.ERRNO_WINDER_VFD);
            error_winder_property.Add("IsError_Fan", ERRNOs.ERRNO_WINDER_FAN);
            error_winder_property.Add("IsError_Turnover", ERRNOs.ERRNO_WINDER_TURNOVER);
            error_winder_property.Add("IsError_Scram", ERRNOs.ERRNO_WINDER_SCRAM);
            error_winder_property.Add("IsError_AirRollerNoReady", ERRNOs.ERRNO_WINDER_AIRROLLERNOREADY);
            error_winder_property.Add("IsError_MeasurePreWarning", ERRNOs.ERRNO_WINDER_MEASUREPREWARNING);
            error_winder_property.Add("IsError_ChangeRoll", ERRNOs.ERRNO_WINDER_CHANGEROLL);
            error_winder_property.Add("IsError_UnloadArm", ERRNOs.ERRNO_WINDER_UNLOADARM);


            Dictionary<string, ERRNO> error_accessory_property = new Dictionary<string, ERRNO>();
            error_accessory_property.Add("IsError_Traction1Fan", ERRNOs.ERRNO_TRACTION1FAN);
            error_accessory_property.Add("IsError_Traction1VFD", ERRNOs.ERRNO_TRACTION1VFD);
            error_accessory_property.Add("IsError_Traction2VFD", ERRNOs.ERRNO_TRACTION2VFD);
            error_accessory_property.Add("IsError_Traction2Fan", ERRNOs.ERRNO_TRACTION2FAN);
            error_accessory_property.Add("IsError_RotaryVFD", ERRNOs.ERRNO_ROTARYVFD);
            error_accessory_property.Add("IsError_RotaryFan", ERRNOs.ERRNO_ROTARYFAN);
            error_accessory_property.Add("IsError_Traction2Scram", ERRNOs.ERRNO_TRACTION2SCRAM);
            error_accessory_property.Add("IsError_Scram", ERRNOs.ERRNO_SCRAM);
            error_accessory_property.Add("IsError_Traction1Scram", ERRNOs.ERRNO_TRACTION1SCRAM);
            error_accessory_property.Add("IsError_CustomerScram", ERRNOs.ERRNO_CUSTOMERSCRAM);
            error_accessory_property.Add("IsError_RotaryForwLimit", ERRNOs.ERRNO_ROTARYFORWLIMIT);
            error_accessory_property.Add("IsError_RotaryBackwLimit", ERRNOs.ERRNO_ROTARYBACKWLIMIT);
            error_accessory_property.Add("IsError_RotaryForwLock", ERRNOs.ERRNO_ROTARYFORWLOCK);
            error_accessory_property.Add("IsError_RotaryBackwLock", ERRNOs.ERRNO_ROTARYBACKWLOCK);

            obj_error.Add(Accessory, new ErrorAction()
            {
                error_property = error_accessory_property
            });

            obj_error.Add(Items[0], new ErrorAction()
            {
                error_property = error_winder_property,
                action = (ref byte code, ref string description, object state) => {
                    description = "内" + description;
                }
            });

            obj_error.Add(Items[1], new ErrorAction()
            {
                error_property = error_winder_property,
                action = (ref byte code, ref string description, object state) => {
                    description = "外" + description;
                    code += 10;
                }
            });


            foreach (var obj in obj_error.Keys)
            {
                obj.PropertyChanged += Obj_PropertyChanged_ForError;
            }

            //--------------------------------------------------------------------------------
            //添加任务
            Misc.BindingOperations.SetBinding(PLCos, "IsConnectedWithPLC", () =>
            {
                if (PLCos.IsConnectedWithPLC)
                {
                    foreach (var kv in obj_error)
                    {
                        string objname = PLCos.ObjNames.First(_kv => _kv.Value == kv.Key).Key;
                        PLCos.SetPlan(objname, kv.Value.error_property.Keys.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 = ERRNOs.ERRNO_PLC_DISCONNECTED;
                        byte errcode = errno.Code;
                        string description = errno.Descrption;
                        mWarning.Add(errcode, description, state);

                        if (PLCos.IsConnectedWithPLC)
                        {
                            //刚连上
                            //全部报警触发一次
                            foreach (var kv in obj_error)
                            {
                                object sender = kv.Key;
                                foreach (string propertyname in kv.Value.error_property.Keys)
                                {
                                    Obj_PropertyChanged_ForError(sender, new PropertyChangedEventArgs(propertyname));
                                }
                            }
                        }
                    });
                }, TimeSpan.FromSeconds(3), true, false, this, MARKNO_DELAY_ISCONNECTED, true);

        }


        void Obj_PropertyChanged_ForError(object sender, PropertyChangedEventArgs e)
        {
            ErrorAction errorAction = obj_error[sender as INotifyPropertyChanged];
 
            if (errorAction.error_property.ContainsKey(e.PropertyName))
            {
                bool b = (bool)Misc.PropertiesManager.GetValue(sender, e.PropertyName);

                ERRNO errno = errorAction.error_property[e.PropertyName];
                ERR_STATE state;
                if(!errno.OffIsError)
                    state = b ? ERR_STATE.ON : ERR_STATE.OFF;
                else
                    state = !b ? ERR_STATE.ON : ERR_STATE.OFF;

                byte errcode = errno.Code;
                string description = errno.Descrption;

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

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


        void AddConfigFile(string configfile)
        {
            PLCGroup plcgroup = new PLCGroup();
            plcgroup.Load(configfile);

            foreach (PLCGroup.PLCDevice device in plcgroup.Devices)
            {
                ModbusMapper_Client plc = new ModbusMapper_Client(new ClientTCP(device.EP));
                plcos.PLCs.Add(plc);
            }

            //objname 转 obj
            PLCos.ObjNames.Add("Accessory", Accessory);
            for (int i = 0; i < Items.Count(); i++)
                PLCos.ObjNames.Add("Items[" + i + "]", Items[i]);


            foreach (PLCGroup.PLCVariable var in plcgroup.Variables)
            {
                if (var.DeviceIndex < 0 || var.DeviceIndex >= plcos.PLCs.Count)
                    continue;

                List<ModbusMapper.DataToRegs> drs = plcos.DRMap;
                ModbusMapper_Client plc = plcos.PLCs[var.DeviceIndex];


                ModbusMapper.DataToRegs dr = plc.MapDataToRegs(
                    ModbusMapper.TranslateToPLCAddressArea(var.Mode),
                    var.Addr,
                    ModbusMapper.TranslateToREG_TYPE(var.Type),
                    var.Scale,
                    PLCos.ObjNames[var.OwnerName],
                    var.PropertyName);
                if (dr != null)
                    drs.Add(dr);
            }
        }


    }
}