using HslCommunication;
using HslCommunication.Profinet.Delta;
using Sln.Iot.Serilog;
using System;
using System.Drawing;

namespace Sln.Iot.PLC
{
    public class PLCConnect
    {
        private static readonly Lazy<PLCConnect> lazy = new Lazy<PLCConnect>(() => new PLCConnect());

        public static PLCConnect Instance
        {
            get
            {
                return lazy.Value;
            }
        }

        private readonly SerilogHelper _log = SerilogHelper.Instance;

        /// <summary>
        /// PLC1 192.168.1.20 烤箱
        /// </summary>
        public DeltaTcpNet PLC20;

        /// <summary>
        /// PLC1 192.168.1.21 胶机
        /// </summary>
        public DeltaTcpNet PLC21;

        /// <summary>
        /// PLC2 192.168.1.22 真空箱
        /// </summary>
        public DeltaTcpNet PLC22;

        /// <summary>
        /// PLC3 192.168.1.23 接驳台1
        /// </summary>
        public DeltaTcpNet PLC23;

        /// <summary>
        /// PLC4 192.168.1.24 接驳台2
        /// </summary>
        public DeltaTcpNet PLC24;

        /// <summary>
        /// 锁对象1
        /// </summary>
        private static readonly object locker1 = new object();

        public async void InitConnect()
        {
            List<Task<DeltaTcpNet>> tasks = new List<Task<DeltaTcpNet>>
            {
                CreateDeltaConnect("192.168.1.20", 502, 1),
                CreateDeltaConnect("192.168.1.21", 502, 1),
                CreateDeltaConnect("192.168.1.22", 502, 1),
                CreateDeltaConnect("192.168.1.23", 502, 1),
                CreateDeltaConnect("192.168.1.24", 502, 1)
            };

            await Task.WhenAll(tasks);

            PLC20 = tasks[0].GetAwaiter().GetResult();
            _log.Info($"PLC连接成功: {PLC20.IpAddress}");
            PLC21 = tasks[1].GetAwaiter().GetResult();
            _log.Info($"PLC连接成功: {PLC21.IpAddress}");
            PLC22 = tasks[2].GetAwaiter().GetResult();
            _log.Info($"PLC连接成功: {PLC22.IpAddress}");
            PLC23 = tasks[3].GetAwaiter().GetResult();
            _log.Info($"PLC连接成功: {PLC23.IpAddress}");
            PLC24 = tasks[4].GetAwaiter().GetResult();
            _log.Info($"PLC连接成功: {PLC24.IpAddress}");

            _log.Info("PLC连接全部成功");
        }

        /// <summary>
        /// 创建台达PLC连接
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="stationNo"></param>
        /// <returns></returns>
        public async Task<DeltaTcpNet> CreateDeltaConnect(string ip, int port, byte stationNo)
        {
            DeltaTcpNet plc = new DeltaTcpNet(ip, port, stationNo);
            try
            {
                plc.Series = DeltaSeries.AS;
                OperateResult res = new OperateResult();
                res.IsSuccess = true;
                int count = 0;
                do
                {
                    if (res.IsSuccess == false)
                    {
                        count++;
                        _log.Error($"PLC[{ip}]连接失败，正在进行第[{count}]次重连...");
                    }
                    res = await plc.ConnectServerAsync();
                }
                while (!res.IsSuccess);

            }
            catch (Exception ex)
            {
                _log.Error($"连接PLC[{ip}]失败", ex);
            }

            return plc;
        }

        /// <summary>
        /// PLC写入数据
        /// </summary>
        /// <param name="address">地址</param>
        /// <param name="value">值</param>
        /// <param name="type">数据类型</param>
        /// <returns></returns>
        public OperateResult PlcWrite(DeltaTcpNet connect, string address, object value, DataTypeEnum type)
        {
            if (connect == null) return new OperateResult() { IsSuccess = false };
            var result = new OperateResult() { IsSuccess = false };

            lock (locker1)
            {
                switch (type)
                {
                    case DataTypeEnum.Bool:
                        result = connect.Write(address, Convert.ToBoolean(value));
                        break;
                    case DataTypeEnum.Byte:
                        result = connect.Write(address, Convert.ToByte(value));
                        break;
                    case DataTypeEnum.Int16:
                        result = connect.Write(address, Convert.ToInt16(value));
                        break;
                    case DataTypeEnum.UInt16:
                        result = connect.Write(address, Convert.ToUInt16(value));
                        break;
                    case DataTypeEnum.Int32:
                        result = connect.Write(address, Convert.ToInt32(value));
                        break;
                    case DataTypeEnum.UInt32:
                        result = connect.Write(address, Convert.ToUInt32(value));
                        break;
                    case DataTypeEnum.Int64:
                        result = connect.Write(address, Convert.ToInt64(value));
                        break;
                    case DataTypeEnum.UInt64:
                        result = connect.Write(address, Convert.ToUInt64(value));
                        break;
                    case DataTypeEnum.Float:
                        result = connect.Write(address, Convert.ToSingle(value));
                        break;
                    case DataTypeEnum.Double:
                        result = connect.Write(address, Convert.ToDouble(value));
                        break;
                    case DataTypeEnum.String:
                        result = connect.Write(address, Convert.ToString(value));
                        break;
                    default:
                        throw new ArgumentException($"Unsupported data type: {type}");
                }
            }
            return result;
        }

        /// <summary>
        /// 写入byte数组
        /// </summary>
        /// <param name="address"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public OperateResult PlcWriteBytes(DeltaTcpNet connect, string address, byte[] data)
        {
            if (connect == null) return new OperateResult() { IsSuccess = false };
            lock (locker1)
            {
                var res = connect.Write(address, data);
                return res;
            }
        }

        /// <summary>
        /// 读取int32
        /// </summary>
        /// <returns></returns>
        public OperateResult<int> ReadInt32(DeltaTcpNet connect, string address)
        {
            if (connect == null) return new OperateResult<int>() { IsSuccess = false };
            lock (locker1)
            {
                var res = connect.ReadInt32(address);
                return res;
            }
        }

        /// <summary>
        /// 读取int16
        /// </summary>
        /// <returns></returns>
        public OperateResult<short> ReadInt16(DeltaTcpNet connect, string address)
        {
            if (connect == null) return new OperateResult<short>() { IsSuccess = false };
            lock (locker1)
            {
                var res = connect.ReadInt16(address);
                return res;
            }
        }

        /// <summary>
        /// 读取float
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public OperateResult<float> ReadFloat(DeltaTcpNet connect, string address)
        {
            if (connect == null) return new OperateResult<float>() { IsSuccess = false };
            lock (locker1)
            {
                var res = connect.ReadFloat(address);
                return res;
            }
        }

        /// <summary>
        /// 读取Bool
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public OperateResult<bool> ReadBool(DeltaTcpNet connect, string address)
        {
            if (connect == null) return new OperateResult<bool>() { IsSuccess = false };
            lock (locker1)
            {
                var res = connect.ReadBool(address);
                return res;
            }
        }

        /// <summary>
        /// 读取字节数组
        /// </summary>
        /// <param name="address"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public OperateResult<byte[]> ReadBytes(DeltaTcpNet connect, string address, ushort length)
        {
            if (connect == null) return new OperateResult<byte[]>() { IsSuccess = false };
            lock (locker1)
            {
                var res = connect.Read(address, length);
                return res;
            }
        }


    }
}
