using HslCommunication;
using HslCommunication.ModBus;
using System.Net.NetworkInformation;
using WIDESEA_Comm.LogInfo;

namespace WIDESEA_WCS.WCSClient
{
    /// <summary>
    /// ModelBus协议PLC
    /// </summary>
    public class ModelBusClient : PLCClient
    {
        private readonly object _lockWrite = new object();
        public ModbusTcpNet modbusTcp { get; set; }

        public ModelBusClient()
        {
            modbusTcp = new ModbusTcpNet();
            base.modbusTcpNet = this.modbusTcpNet;
        }

        /// <summary>
        /// 连接PLC,长链接
        /// </summary>
        /// <returns></returns>
        public override string Connect()
        {
            var res = new Ping().Send(Ip, 1000);
            if (res.Status != IPStatus.Success)
            {
                string msg = $"{PLCName},{Ip}网络异常。";
                WriteLog.Write_Log(PLCName, $"{PLCName}_CoonInfo", msg);
                return msg;
            }

            modbusTcp.IpAddress = Ip;
            modbusTcp.Port = Port;
            modbusTcp.ConnectTimeOut = 1000 * 3;//è¶…æ—¶æ—¶é—´
            modbusTcp.ConnectClose();
            var coonRes = modbusTcp.ConnectServer();
            IsConnected = coonRes.IsSuccess;

            //日志记录
            string coonMsg = string.Empty;
            if (coonRes.IsSuccess)
            {
                coonMsg = PLCName + "连接成功";
            }
            else
            {
                coonMsg = PLCName + "连接失败," + coonRes.Message;
            }
            Console.WriteLine(coonMsg);
            WriteLog.Write_Log(PLCName, $"{PLCName}_CoonInfo", coonMsg);
            return coonMsg;
        }

        /// <summary>
        /// 断开PLC长链接
        /// </summary>
        /// <returns></returns>
        public override bool DisConnect()
        {
            var res = modbusTcp.ConnectClose();
            IsConnected = false;
            if (res.IsSuccess)
            {
                WriteLog.Write_Log(PLCName, $"{PLCName}_CoonInfo", PLCName + "断开连接成功!");
            }
            else
            {
                WriteLog.Write_Log(PLCName, $"{PLCName}_CoonInfo", PLCName + "断开连接失败," + res.Message);
            }
            return res.IsSuccess;
        }

        /// <summary>
        /// 读取数据,直接写地址
        /// </summary>
        /// <typeparam name="DataType">数据类型</typeparam>
        /// <param name="dbAddress">DB地址</param>
        /// <param name="len">读取场地</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public override DataType Read<DataType>(string dbAddress, int len = 1)
        {
            if (typeof(DataType) == typeof(int))//4字节,有符号类型
            {
                return (DataType)GetContent(modbusTcp.ReadInt32(dbAddress), dbAddress);
            }
            else if (typeof(DataType) == typeof(uint))//4字节,无符号类型
            {
                return (DataType)GetContent(modbusTcp.ReadUInt32(dbAddress), dbAddress);
            }
            else if (typeof(DataType) == typeof(short))//2字节,有符号类型,最常用
            {
                return (DataType)GetContent(modbusTcp.ReadInt16(dbAddress), dbAddress);
            }
            else if (typeof(DataType) == typeof(ushort))//2字节,无符号类型
            {
                return (DataType)GetContent(modbusTcp.ReadUInt16(dbAddress), dbAddress);
            }
            else if (typeof(DataType) == typeof(float))//浮点型
            {
                return (DataType)GetContent(modbusTcp.ReadFloat(dbAddress), dbAddress);
            }
            else if (typeof(DataType) == typeof(bool))
            {
                return (DataType)GetContent(modbusTcp.ReadBool(dbAddress), dbAddress);
            }
            else if (typeof(DataType) == typeof(byte[]))//字节数组
            {
                return (DataType)GetContent(modbusTcp.Read(dbAddress, (ushort)len), dbAddress);
            }
            else if (typeof(DataType) == typeof(string))//字符串
            {
                var str = GetContent(modbusTcp.ReadString(dbAddress, (ushort)len), dbAddress).ToString();
                str = str.Replace("\0", "");
                return (DataType)(str as object);
            }
            else
            {
                throw new Exception($"【{PLCName}】,DB地址{dbAddress},未定义数据类型{typeof(DataType).Name}");
            }
        }

        /// <summary>
        /// 读取数据,根据数据库指令来
        /// </summary>
        /// <param name="orderName">IO点名称</param>
        /// <returns></returns>
        public override DataType ReadByOrder<DataType>(string orderName, string Method = null)
        {
            var item = itemGroups.Where(t => t.name.Equals(orderName)).FirstOrDefault();
            if (item == null)
            {
                throw new Exception($"PLC{PLCName},未定义指令{orderName}");
            }

            if (typeof(DataType) == typeof(int))//4字节,有符号类型
            {
                return (DataType)GetContent(modbusTcp.ReadInt32(item.dbAddress), item);
            }
            else if (typeof(DataType) == typeof(uint))//4字节,无符号类型
            {
                return (DataType)GetContent(modbusTcp.ReadUInt32(item.dbAddress), item);
            }
            else if (typeof(DataType) == typeof(short))//2字节,有符号类型,最常用
            {
                return (DataType)GetContent(modbusTcp.ReadInt16(item.dbAddress), item);
            }
            else if (typeof(DataType) == typeof(ushort))//2字节,无符号类型
            {
                return (DataType)GetContent(modbusTcp.ReadUInt16(item.dbAddress), item);
            }
            else if (typeof(DataType) == typeof(float))//浮点型
            {
                return (DataType)GetContent(modbusTcp.ReadFloat(item.dbAddress), item);
            }
            else if (typeof(DataType) == typeof(bool))
            {
                return (DataType)GetContent(modbusTcp.ReadBool(item.dbAddress), item);
            }
            else if (typeof(DataType) == typeof(byte[]))//字节数组
            {
                return (DataType)GetContent(modbusTcp.Read(item.dbAddress, (ushort)item.dataLen), item);
            }
            else if (typeof(DataType) == typeof(string))//字符串
            {
                var str = GetContent(modbusTcp.ReadString(item.dbAddress, (ushort)item.dataLen), item).ToString();
                str = str.Replace("\0", "");
                return (DataType)(str as object);
            }
            else
            {
                throw new Exception($"【Error】,指令{orderName},未定义数据类型{typeof(DataType).Name}");
            }
        }


        /// <summary>
        /// 写入数据
        /// </summary>
        /// <param name="dbAddress"></param>
        /// <param name="value"></param>
        public override bool Write(string dbAddress, object value)
        {
            lock (_lockWrite)
            {
                Type dataType = value.GetType();
                OperateResult result;
                if (dataType == typeof(int))
                {
                    result = modbusTcp.Write(dbAddress, Convert.ToInt32(value));//4字节,有符号
                }
                else if (dataType == typeof(uint))
                {
                    result = modbusTcp.Write(dbAddress, Convert.ToUInt32(value));//4字节,无符号
                }
                else if (dataType == typeof(short))
                {
                    result = modbusTcp.Write(dbAddress, Convert.ToInt16(value));//2字节,有符号,最常用
                }
                else if (dataType == typeof(ushort))
                {
                    result = modbusTcp.Write(dbAddress, Convert.ToUInt16(value));//2字节,无符号,最常用
                }
                else if (dataType == typeof(float))
                {
                    result = modbusTcp.Write(dbAddress, (float)value);//4字节浮点型
                }
                else if (dataType == typeof(bool))
                {
                    result = modbusTcp.Write(dbAddress, Convert.ToBoolean(value));
                }
                else if (dataType == typeof(byte))
                {
                    result = modbusTcp.Write(dbAddress, (byte)value);
                }
                else if (dataType == typeof(byte[]))
                {
                    result = modbusTcp.Write(dbAddress, (byte[])value);
                }
                else if (dataType == typeof(string))
                {
                    result = modbusTcp.Write(dbAddress, (string)value);
                }
                else
                {
                    throw new Exception($"【Error】DB地址{dbAddress},未定义数据类型{dataType.Name}");
                }

                if (!result.IsSuccess)
                {
                    WriteLog.Write_Log(PLCName, $"{PLCName}_Write", $"{dbAddress}写入失败," + result.Message);
                    throw new Exception($"{dbAddress}写入失败," + result.Message);
                }
                return result.IsSuccess;
            }
        }

        /// <summary>
        /// 写入数据,根据数据库指令
        /// </summary>
        /// <param name="orderName"></param>
        /// <exception cref="Exception"></exception>
        public override bool WriteByOrder(string orderName, object value, string Method = null)
        {
            lock (_lockWrite)
            {
                var item = itemGroups.Where(t => t.name.Equals(orderName)).FirstOrDefault();
                if (item == null)
                {
                    throw new Exception($"PLC{PLCName},未定义指令{orderName}");
                }

                Type dataType = value.GetType();
                OperateResult result;

                if (dataType == typeof(int))
                {
                    result = modbusTcp.Write(item.dbAddress, Convert.ToInt32(value));//4字节,有符号
                }
                else if (dataType == typeof(uint))
                {
                    result = modbusTcp.Write(item.dbAddress, Convert.ToUInt32(value));//4字节,无符号
                }
                else if (dataType == typeof(short))
                {
                    result = modbusTcp.Write(item.dbAddress, Convert.ToInt16(value));//2字节,有符号,最常用
                }
                else if (dataType == typeof(ushort))
                {
                    result = modbusTcp.Write(item.dbAddress, Convert.ToUInt16(value));//2字节,无符号,最常用
                }
                else if (dataType == typeof(float))
                {
                    result = modbusTcp.Write(item.dbAddress, (float)value);//4字节浮点型
                }
                else if (dataType == typeof(bool))
                {
                    result = modbusTcp.Write(item.dbAddress, Convert.ToBoolean(value));
                }
                else if (dataType == typeof(byte))
                {
                    result = modbusTcp.Write(item.dbAddress, (byte)value);
                }
                else if (dataType == typeof(byte[]))
                {
                    result = modbusTcp.Write(item.dbAddress, (byte[])value);
                }
                else if (dataType == typeof(string))
                {
                    result = modbusTcp.Write(item.dbAddress, (string)value);
                }
                else
                {
                    throw new Exception($"【Error】指令{item.name},DB地址{item.dbAddress},未定义数据类型{dataType.Name}");
                }

                if (!result.IsSuccess)
                {
                    WriteLog.Write_Log(PLCName, $"{PLCName}_Write", $"{orderName}写入失败," + result.Message, item);
                    throw new Exception($"{PLCName},{orderName}写入失败," + result.Message);
                }
                return result.IsSuccess;
            }
        }
    }
}