using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FLY.Simulation.Blowing
{
    public class PlcLink : IPlcLink 
    {
        public event PropertyChangedEventHandler PropertyChanged;


        public string PlcAddr { get; set; } = "127.168.50.60:502";

        //D200	4x201 通道数量
        //D201	4x202 设置值 更新
        //D202	4x203 当前值 更新 //不用
        //D400	4x401 设置值 160个
        //D600	4x601 当前值 160个 //不用
        //M3	0x4	风环开关
        //M4	0x5	检测电流

        public FLY.Modbus.WithThread.ServerTCP mserver;

        public Blowing.AirRing mAirRing;

        public UInt16 HeatUpdate { get; set; }

        /// <summary>
        /// 当前电流 有没?
        /// </summary>
        public bool HasElectricCurrent { get; set; } 


        /// <summary>
        /// 风机是否启动?
        /// </summary>
        public bool HasFan { get; set; } = true;


        public PlcLink()
        {
            if (!Load())
                Save();
        }
        public void Init(Blowing.AirRing mAirRing) 
        {
            this.mAirRing = mAirRing;
            mserver = new Modbus.WithThread.ServerTCP(Misc.StringConverter.ToIPEndPoint(PlcAddr), GetValue, SetValue);
            mserver.Start();
        }


        void GetValue(int addr, object values) 
        {
            if (values is UInt16[])
            {
                var uint16s = values as UInt16[];
                for (int i = 0; i < uint16s.Count(); i++) {
                    uint16s[i] = GetValue_reg(i+addr);
                }
            }
            else if (values is bool[]) 
            {
                var bools = values as bool[];
                for (int i = 0; i < bools.Count(); i++)
                {
                    bools[i] = GetValue_coil(i + addr);
                }
            }
        }
        UInt16 GetValue_reg(int addr) 
        {
            if (addr == 200)
            {
                return (UInt16)mAirRing.ChannelCnt;
            }
            else if (addr == 201)
            {
                return HeatUpdate;
            }
            else if (addr >= 400 && addr < 400 + 160)
            {
                int idx = addr - 400;
                if (idx >= 0 && idx < mAirRing.Heats.Count())
                    return (UInt16)mAirRing.Heats[idx];
                else
                    return 0;
            }
            else {
                return 0;
            }
        }
        bool GetValue_coil(int addr)
        {
            if (addr == 3)
            {
                return HasFan;
            }
            else if (addr == 4)
            {
                return HasElectricCurrent;
            }
            else
            {
                return false;
            }
        }
        void SetValue(int addr, object values) 
        {
            if (values is UInt16[])
            {
                var uint16s = values as UInt16[];
                for (int i = 0; i < uint16s.Count(); i++)
                {
                    SetValue_reg(i + addr, uint16s[i]);
                }
            }
            else if (values is bool[])
            {
                var bools = values as bool[];
                for (int i = 0; i < bools.Count(); i++)
                {
                    SetValue_coil(i + addr, bools[i]);
                }
            }
        }

        void SetValue_reg(int addr, UInt16 reg)
        {
            if (addr == 200)
            {
                mAirRing.SetChannelCnt(reg);
            }
            else if (addr == 201)
            {
                if (HeatUpdate != reg) 
                {
                    HeatUpdate = reg;
                    mAirRing.HeatApply();
                    HasElectricCurrent = mAirRing.HasElectricCurrent;
                }
            }
            else if (addr >= 400 && addr < 400 + 160)
            {
                int idx = addr - 400;
                if (idx >= 0 && idx < mAirRing.Heats.Count())
                {
                    mAirRing.Heats[idx] = reg;
                }
            }
            else
            {

            }
        }
        void SetValue_coil(int addr, bool coil)
        {

        }
        string filePath = "airRingPlc.json";
        bool Load() 
        {
            return PlcLinkJsonDb.Load(filePath, this);
        }
        public bool Save() 
        {
            return PlcLinkJsonDb.Save(filePath, this);
        }
    }
    public class PlcLinkJsonDb 
    {
        public string PlcAddr = "127.168.50.60:502";
        public static bool Save(string filePath, PlcLink plcLink) 
        {
            try
            {
                PlcLinkJsonDb jsondb = new PlcLinkJsonDb()
                {
                    PlcAddr = plcLink.PlcAddr
                };
                string json = Newtonsoft.Json.JsonConvert.SerializeObject(jsondb, Newtonsoft.Json.Formatting.Indented);
                File.WriteAllText(filePath, json);
                return true;
            }
            catch {
                return false;
            }
        }
        public static bool Load(string filePath, PlcLink plcLink)
        {
            try
            {
                if (!File.Exists(filePath))
                    return false;
                string json = File.ReadAllText(filePath);
                var jsonDb = Newtonsoft.Json.JsonConvert.DeserializeObject<PlcLinkJsonDb>(json);
                plcLink.PlcAddr = jsonDb.PlcAddr;
                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}