using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Net;
using System.IO;

namespace FLY.Simulation.Casting
{
    public class PlcLink : INotifyPropertyChanged
    {
        //D200	4x201 通道数量
        //D201	4x202 设置值 更新
        //D202	4x203 当前值 更新 //不用
        //D400	4x401 设置值 160个
        //D600	4x601 当前值 160个 //不用
        //M3	0x4	风环开关
        //M4	0x5	检测电流

        const int ADDR_M_HasElectricity = 3;//检测电流
        const int ADDR_M_HasFan = 4;//风环开关

        const int ADDR_D_ChannelCnt = 200;
        const int ADDR_D_HeatUpdate = 201;
        const int ADDR_D_CurrentUpdate = 202;
        const UInt16 ADDR_D_Heats = 400;
        const UInt16 ADDR_D_Currents = 600;

        /// <summary>
        /// 加热通道数
        /// </summary>
        public UInt16 ChannelCnt { get; set; }

        /// <summary>
        /// 加热量更新
        /// </summary>
        public UInt16 HeatUpdate { get; set; }

        /// <summary>
        /// 当前量更新
        /// </summary>
        public UInt16 CurrentUpdate { get; set; }

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

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


        UInt16 heatupdate_last = 1;
        UInt16[] heats;
        bool[] Bads;
        AutoDie mAutoDie;
        FLY.Modbus.WithThread.ServerTCP mbServer;



        public PlcLink()
        {
            heats = new UInt16[160];
            Bads = new bool[160];

            Bads[2] = true;
            Bads[30] = true;
            HeatUpdate = 1;
            heatupdate_last = 1;
            CurrentUpdate = 1;



        }
        public void Init()
        {
            //this.mAutoDie = autoDie;

            PlcLinkJsonDb plcLink = new PlcLinkJsonDb();
            
                ChannelCnt = 100;// (UInt16)mAutoDie.ChannelCnt;
            mbServer = new Modbus.WithThread.ServerTCP(
                Misc.StringConverter.ToIPEndPoint(plcLink.Addr), 
                GetValue, SetValue);
            mbServer.Start();
            this.PropertyChanged += PlcLink_PropertyChanged;

        }

        private void PlcLink_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(ChannelCnt)) {
                //mAutoDie.SetChannelCnt(ChannelCnt);
            }
        }

        void GetValue(int addr, object values)
        {
            if (values is bool[])
                GetValue_M(addr, (bool[])values);
            else
                GetValue_D(addr, (UInt16[])values);
        }

        void SetValue(int addr, object values)
        {
            if (values is bool[])
                SetValue_M(addr, (bool[])values);
            else
                SetValue_D(addr, (UInt16[])values);
        }

        void GetValue_M(int addr, bool[] values)
        {
            for (int i = 0; i < values.Count(); i++)
            {
                int single_addr = addr + i;
                switch (single_addr)
                {
                    case ADDR_M_HasElectricity:
                        {
                            values[i] = HasElectricity;
                        }
                        break;
                    case ADDR_M_HasFan:
                        {
                            values[i] = HasFan;
                        }
                        break;
                }
            }
        }
        void GetValue_D(int addr, UInt16[] values)
        {
            for (int i = 0; i < values.Count(); i++)
            {
                int single_addr = addr + i;

                if (single_addr == ADDR_D_ChannelCnt)
                {
                    values[i] = ChannelCnt;
                }
                else if (single_addr == ADDR_D_HeatUpdate)
                {
                    values[i] = HeatUpdate;
                }
                else if (single_addr == ADDR_D_CurrentUpdate)
                {
                    values[i] = CurrentUpdate;
                }
                else if (single_addr >= ADDR_D_Heats && single_addr < ADDR_D_Heats + 160) 
                {
                    int index = single_addr - ADDR_D_Heats;
                    values[i] = heats[index];

                }
                else if (single_addr >= ADDR_D_Currents && single_addr < ADDR_D_Currents + 160)
                {
                    int index = single_addr - ADDR_D_Currents;
                    values[i] = heats[index];
                    //if (index < mAutoDie.Heats.Count())
                    //{
                    //    values[i] = (UInt16)mAutoDie.Heats[index];
                    //}
                }
            }
        }

        void SetValue_M(int addr, bool[] values)
        {

        }
        void SetValue_D(int addr, UInt16[] values)
        {
            for (int i = 0; i < values.Count(); i++)
            {
                int single_addr = addr + i;

                if (single_addr == ADDR_D_ChannelCnt)
                {
                    ChannelCnt = values[i];
                }
                else if (single_addr == ADDR_D_HeatUpdate)
                {
                    HeatUpdate = values[i];
                    
                    if (HeatUpdate != heatupdate_last) {
                        heatupdate_last = HeatUpdate;
                        //for (int j = 0; j < ChannelCnt; j++) {
                        //    mAutoDie.Heats[j] = heats[j];
                        //}
                        //mAutoDie.HeatApply();

                        if (heats.Take(ChannelCnt).Any(h => h > 0))
                            HasElectricity = true;
                        else
                            HasElectricity = false;
                    }

                    CurrentUpdate++;
                }
                else if (single_addr == ADDR_D_CurrentUpdate)
                {
                    CurrentUpdate = values[i];
                }
                else if (single_addr >= ADDR_D_Heats && single_addr < ADDR_D_Heats + 160)
                {
                    int index = single_addr - ADDR_D_Heats;
                    heats[index] = values[i];
                }
            }
        }


        public event PropertyChangedEventHandler PropertyChanged;
    }

    public class PlcLinkJsonDb 
    {
        public string Addr = "0.0.0.0:502";
        private string filePath = "plclink.json";
        public bool Save() 
        {
            try
            {
                string json = Newtonsoft.Json.JsonConvert.SerializeObject(this);

                File.WriteAllText(filePath, json);

                return true;
            }
            catch {
                return false;
            }
        }
        public bool Load() 
        {
            if (!File.Exists(filePath)) {
                return false;
            }
            try
            {
                string json = File.ReadAllText(filePath);

                Newtonsoft.Json.JsonConvert.PopulateObject(json, this);
                return true;
            }
            catch {
                return false;
            }
        }
    }
}