using FLY.OBJComponents.IService;
using FLY.OBJComponents.Server;
using FLY.Weight2.Common;
using FLY.Weight2.IService;
using FLY.Weight2.Server.Model;
using FObjBase;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using FLY.Modbus;


namespace FLY.Weight2.Server
{
    public class WeightSystem : IWeightSystemService, IPropertyOpt
    {

        #region IWeightSystemService 接口

        public ObservableCollection<WeighterC> Items { get; } = new ObservableCollection<WeighterC>();


        public WeighterAccessory Accessory { get; } = new WeighterAccessory();

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

        private int flowInterval = 10;
        /// <summary>
        /// 流量记录周期,单位s, 最小值为5
        /// </summary>
        public int FlowInterval
        {
            get { return flowInterval; }
            set
            {
                if (value < 5)
                    value = 5;
                if (flowInterval != value)
                {
                    flowInterval = value;
                }
            }
        }

        /// <summary>
        /// 层数
        /// </summary>
        public int ItemsCnt { get; private set; } = 3;

        #endregion

        string[] NumberNames;
        /// <summary>
        /// 报警系统
        /// </summary>
        WarningSystem warning;
        /// <summary>
        /// 记录到数据库
        /// </summary>
        HistoryDb historyDb;
        /// <summary>
        /// 报警配置
        /// </summary>
        ErrorConf errorConf;
        /// <summary>
        /// 周期保存Ibc数据
        /// </summary>
        PeriodicallySaveData<Lc_Flow> psdFlow;
        public WeightSystem()
        {
            if (!LoadNumberNames())
                SaveNumberNames();
            Load();

            //--------------------------------------------------------------------------------
            //step 1 加载PLC寄存器 文件
            AddConfigFile();



        }

        public void Init(HistoryDb historyDb, WarningSystem warning)
        {
            this.historyDb = historyDb;
            this.warning = warning;

            //--------------------------------------------------------------------------------
            //step 2 报警配置
            errorConf = new ErrorConf(PLCos, this.warning, "称重");
            errorConf.AddErrorAction(Accessory);
            for (int i = 0; i < Items.Count(); i++)
            {
                errorConf.AddErrorAction(
                    Items[i],
                        (ref string description, object state) => {
                            int idx = (int)state;
                            description = Items[idx].Number + "层 " + description;
                        },
                        i);
            }
            errorConf.InitError();

            //报警使能
            Misc.BindingOperations.SetBinding(Accessory, nameof(Accessory.AlarmIsOn), () =>
            {
                this.warning.Enable = !Accessory.AlarmIsOn;
            });


            Misc.BindingOperations.SetBinding(this.warning, nameof(this.warning.Enable), () =>
            {
                Accessory.AlarmIsOn = !this.warning.Enable;
            });

            //报警复位呢?

            //Misc.BindingOperations.SetBinding(this.warning, "IsRinging", () =>
            //{
            //    if (!this.warning.IsRinging)
            //    {
            //        for (int i = 0; i < ItemsCnt; i++)
            //        {
            //            Items[i].IsAlarmReseted = false;
            //        }
            //    }
            //});

            //--------------------------------------------------------------------------------
            this.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == nameof(FlowInterval))
                {
                    Save();
                }
            };


            //step 3 历史数据记录


            //添加任务
            for (int i = 0; i < Items.Count(); i++)
            {
                List<string> props = new List<string>
                {
                    nameof(WeighterC.CurrentFlow),
                    nameof(WeighterC.ScrewPDisp),
                    nameof(WeighterC.ScrewMotorFreq)
                };
                PLCos.SetPlan($"{nameof(Items)}[{i}]", props, 0);
            }
            PLCos.SetPlan(nameof(Accessory), new string[] { nameof(Accessory.TotalFlow) }, 0);

            psdFlow = new PeriodicallySaveData<Lc_Flow>();
            psdFlow.Init(
                FlowInterval,
                this.historyDb.AddFlowRange,
                () => {
                    if (!PLCos.IsConnectedWithPLC)
                        return null;
                    var v = Items[0].BinWeight;
                    var v1 = Items[1].BinWeight;
                    var v2 = Items[2].BinWeight;

                    if (Accessory.TotalFlow < 5)//没有生产
                        return null;

                    //记录数据
                    Lc_Flow lc_Flow = new Lc_Flow
                    {
                        Time = DateTime.Now,
                        Total = Math.Round(Accessory.TotalFlow, 4),
                        Items = new Lc_FlowItem[Items.Count]
                    };
                    for (int i = 0; i < Items.Count; i++)
                    {
                        lc_Flow.Items[i] = new Lc_FlowItem
                        {
                            Flow = Math.Round(Items[i].CurrentFlow, 4),
                            ScrewPDisp = Math.Round(Items[i].ScrewPDisp, 2),
                            ScrewMotorFreq = Math.Round(Items[i].ScrewMotorFreq, 1)
                        };
                    }
                    return lc_Flow;
                });

            //--------------------------------------------------------------------------------
            //last step  PLC 更新计划服务初始化
            plcos.Init();
        }

        string GetNumber(int index)
        {
            string number;

            if (NumberNames != null
                && index < NumberNames.Count()
                && !string.IsNullOrEmpty(NumberNames[index]))
            {
                number = NumberNames[index];
            }
            else
            {
                number = ((char)('A' + index)).ToString();
            }
            return number;
        }
        void AddConfigFile()
        {
            plcos.AddConfigFile("plcgroup.json", (plcgroup) =>
            {
                //从plcgroup 分析出 有多少层,每层的仓数
                int itemsCnt = 0;
                Regex r = new Regex(@"Items\[([0-9])\]");

                foreach (PLCGroup.PLCVariable var in plcgroup.Variables)
                {
                    Match m = r.Match(var.OwnerName);
                    if (m.Success)
                    {
                        int weighter_idx = int.Parse(m.Groups[1].Value);
                        if (itemsCnt <= weighter_idx)//记录最大值
                            itemsCnt = weighter_idx + 1;
                    }
                }
                ItemsCnt = itemsCnt;

                for (int i = 0; i < ItemsCnt; i++)
                {
                    string number = GetNumber(i);
                    WeighterC w = new WeighterC(number, i);
                    Items.Add(w);
                }


                //objname 转 obj
                Dictionary<string, INotifyPropertyChanged> objnames = new Dictionary<string, INotifyPropertyChanged>();

                objnames.Add(nameof(Accessory), Accessory);
                for (int i = 0; i < ItemsCnt; i++)
                    objnames.Add($"{nameof(Items)}[{i}]", Items[i]);
                return objnames;
            });

            //这个是从测厚仪获取的,每几秒就写一次,不调试!!!!!
            plcos.IgnoreLogProperties.Add(new SenderProperty() { sender = Accessory, propertyName = nameof(Accessory.CurrentVelocitySet) });

        }

        public event PropertyChangedEventHandler PropertyChanged;

        string filepath = "weight2.json";
        void Save()
        {
            WeightSystemJsonDb p = new WeightSystemJsonDb()
            {
                FlowInterval = FlowInterval
            };
            string json = JsonConvert.SerializeObject(p, Newtonsoft.Json.Formatting.Indented);
            File.WriteAllText(filepath, json);
        }
        void Load()
        {
            if (!File.Exists(filepath))
                return;
            try
            {
                string json = File.ReadAllText(filepath);
                JsonConvert.PopulateObject(json, this);
            }
            catch
            {

            }
        }
        string filePath_number = "weight2NumberNames.json";
        bool LoadNumberNames()
        {
            if (!File.Exists(filePath_number))
                return false;
            string json = File.ReadAllText(filePath_number);
            var p = Newtonsoft.Json.JsonConvert.DeserializeObject<NumberNamesJsonDb>(json);
            NumberNames = p.NumberNames;
            return true;
        }
        void SaveNumberNames()
        {
            NumberNamesJsonDb jsonDb = new NumberNamesJsonDb
            {
                NumberNames = NumberNames
            };
            string json = Newtonsoft.Json.JsonConvert.SerializeObject(jsonDb);
            File.WriteAllText(filePath_number, json);
        }

        public string[] GetSyncPropNames()
        {
            return new string[]{
                nameof(FlowInterval),
                nameof(ItemsCnt)
                };
        }

        public string[] GetNoSyncPropNames()
        {
            return null;
        }
    }

    public class WeightSystemJsonDb 
    {
        public int FlowInterval { get; set; }
    }
    public class NumberNamesJsonDb
    {
        public string[] NumberNames;
    }
}