using FLY.IBC.Common;
using FLY.IBC.IService;
using FLY.Modbus;
using FLY.OBJComponents.Common;
using FLY.OBJComponents.IService;
using FLY.OBJComponents.Server;
using FObjBase;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FLY.IBC.Server
{
    public class IBCSystem : IIBCSystemService, Misc.ISaveToXml
    {
        #region 延时推送 MARKNO
        const int MARKNO_SAVE = 1;
        const int MARKNO_NOTIFY1 = 2;
        const int MARKNO_NOTIFY2 = 3;
        const int MARKNO_DELAY_ISCONNECTED = 4;
        #endregion
        #region IIBCSystem
        /// <summary>
        /// 数据
        /// </summary>
        public IBCData Item { get; } = new IBCData();
        /// <summary>
        /// IBC控制历史列表参数
        /// </summary>
        public IBCCtrlListData CtrlListData { get; } = new IBCCtrlListData();

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

        /// <summary>
        /// IBC控制历史列表
        /// </summary>
        public Buffer<FlyData_IBCCtrl> CtrlList = new Buffer<FlyData_IBCCtrl>();


        public WarningSystem mWarning;

        static IBCSystem()
        {
            Misc.SaveToXmlHepler.Regist(typeof(IBCCtrlListData));
        }
        public IBCSystem()
        {
            Load();



            mWarning = new WarningSystem();


            AddConfigFile("WS.xml");


            
            
            CtrlListData.PropertyChanged += CtrlListData_PropertyChanged;


            FObjBase.PollModule.Current.Poll_Config(
                FObjBase.PollModule.POLL_CONFIG.ADD, OnPoll, TimeSpan.FromSeconds(1));

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

            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);
                    });
                }, TimeSpan.FromSeconds(3), true, false, this, MARKNO_DELAY_ISCONNECTED, true);

            //--------------------------------------------------------------------------------
            //流量记录
            Misc.BindingOperations.SetBinding(CtrlListData, "Size", CtrlList, "Capacity");

            //--------------------------------------------------------------------------------
            //添加任务
            Misc.BindingOperations.SetBinding(PLCos, "IsConnectedWithPLC", () =>
            {
                if (PLCos.IsConnectedWithPLC)
                {
                    PLCos.SetPlan("Item", new string[] {
                        "FilmWidth","InletAirFreq","OutletAirFreq",

                        "IsInletAirMotorError","IsOutletAirMotorError",
                        "IsInletAirCommError","IsOutletAirCommError"
                    }, 0);
                }
            });
            
            
            //--------------------------------------------------------------------------------
            //设置修改后通知
            Item.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "OutletAirFreqSet")
                {
                    Item.IsOutletAirFreqChanged = true;

                    //1秒后再设置为false
                    FObjBase.PollModule.Current.Poll_Config(
                        FObjBase.PollModule.POLL_CONFIG.ADD, () =>
                        {
                            Item.IsOutletAirFreqChanged = false;
                        }, TimeSpan.FromSeconds(1), true, false, this, MARKNO_NOTIFY1, true);
                }
                else if (e.PropertyName == "FilmWidthSet")
                {
                    Item.IsOutletAirFreqChanged = true;

                    //1秒后再设置为false
                    FObjBase.PollModule.Current.Poll_Config(
                        FObjBase.PollModule.POLL_CONFIG.ADD, () =>
                        {
                            Item.IsFilmWidthChanged = false;
                        }, TimeSpan.FromSeconds(1), true, false, this, MARKNO_NOTIFY2, true);
                }
            };
            
            plcos.Init();
        }

        private void CtrlListData_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            FObjBase.PollModule.Current.Poll_JustOnce(
                new FObjBase.PollModule.PollHandler(delegate ()
                {
                    Save();
                }), this, MARKNO_SAVE);
        }

        Stopwatch stopwatch = new Stopwatch();
        void OnPoll()
        {
            if (!stopwatch.IsRunning)
            {
                stopwatch.Start();
                return;
            }
            else
            {
                if (stopwatch.Elapsed < TimeSpan.FromSeconds(CtrlListData.Interval))
                    return;
                else
                    stopwatch.Restart();
            }

            if (!PLCos.IsConnectedWithPLC)
                return;

            if (Item.InletAirFreq < 2 && Item.OutletAirFreq < 2)//没有工作!!!!
                return;

            FlyData_IBCCtrl f = new FlyData_IBCCtrl();
            f.Time = DateTime.Now;
            f.FilmWidth = Item.FilmWidth;
            f.InletAirFreq = Item.InletAirFreq;
            f.OutletAirFreq = Item.OutletAirFreq;
            
            CtrlList.Add(f);
        }

        #region 报警
        Dictionary<string, ERRNO> error_property;
        void InitError()
        {
            error_property = new Dictionary<string, ERRNO>();
            error_property.Add("IsInletAirMotorError", ERRNOs.ERRNO_INLETAIR_MOTOR);
            error_property.Add("IsOutletAirMotorError", ERRNOs.ERRNO_OUTLETAIR_MOTOR);
            error_property.Add("IsInletAirCommError", ERRNOs.ERRNO_INLETAIR_COMM);
            error_property.Add("IsOutletAirCommError", ERRNOs.ERRNO_OUTLETAIR_COMM);

            Item.PropertyChanged += Item_PropertyChanged_ForError;


        }
        void Item_PropertyChanged_ForError(object sender, PropertyChangedEventArgs e)
        {
            if (error_property.ContainsKey(e.PropertyName))
            {
                bool b = (bool)Misc.PropertiesManager.GetValue(sender, e.PropertyName);
            
                ERR_STATE state = b? ERR_STATE.ON:ERR_STATE.OFF;
                ERRNO errno = error_property[e.PropertyName];
                byte errcode = errno.Code;
                string description = errno.Descrption;
                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("Item", Item);


            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,
                    Item,
                    var.PropertyName);
                if (dr != null)
                    drs.Add(dr);
            }
        }

        public void Save()
        {
            Misc.SaveToXmlHepler.Save("ibcsystem.xml", this);
        }
        public void Load()
        {
            Misc.SaveToXmlHepler.Load("ibcsystem.xml", this);
        }
        #region ISaveToXml 成员

        public string[] GetSavePropertyNames()
        {
            return new string[]{
                "CtrlListData"
            };
        }

        #endregion
    }
}