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.21
        /// </summary>
        public DeltaSerialOverTcp DeltaInstance1;

        /// <summary>
        /// PLC2 192.168.1.22
        /// </summary>
        public DeltaSerialOverTcp DeltaInstance2;

        /// <summary>
        /// PLC3 192.168.1.23
        /// </summary>
        public DeltaSerialOverTcp DeltaInstance3;

        /// <summary>
        /// PLC4 192.168.1.24
        /// </summary>
        public DeltaSerialOverTcp DeltaInstance4;

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

        public async void InitConnect()
        {
            List<Task<DeltaSerialOverTcp>> tasks = new List<Task<DeltaSerialOverTcp>>
            {
                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)
            };
            
            DeltaInstance1 = tasks[0].GetAwaiter().GetResult();
            DeltaInstance2 = tasks[1].GetAwaiter().GetResult();
            DeltaInstance3 = tasks[2].GetAwaiter().GetResult();
            DeltaInstance4 = tasks[3].GetAwaiter().GetResult();
        }

        /// <summary>
        /// 创建台达PLC连接
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="stationNo"></param>
        /// <returns></returns>
        public async Task<DeltaSerialOverTcp> CreateDeltaConnect(string ip, int port, byte stationNo)
        {
            DeltaSerialOverTcp plc = new DeltaSerialOverTcp(ip, port, stationNo);
            try
            {
                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(DeltaSerialOverTcp connect, string address, object value, DataTypeEnum type)
        {
            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(DeltaSerialOverTcp connect, string address, byte[] data)
        {
            lock (locker1)
            {
                var res = connect.Write(address, data);
                return res;
            }
        }

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

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

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

        /// <summary>
        /// 读取Bool
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public OperateResult<bool> ReadBool(DeltaSerialOverTcp connect, string address)
        {
            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(DeltaSerialOverTcp connect, string address, ushort length)
        {
            lock (locker1)
            {
                var res = connect.Read(address, length);
                return res;
            }
        }


    }
}
