using HslCommunication;
using HslCommunication.Profinet.Inovance;
using SlnMesnac.Common;
using System;
using System.Threading.Tasks;

#region << 版 本 注 释 >>

/*--------------------------------------------------------------------
* 版权所有 (c) 2024 WenJY 保留所有权利。
* CLR版本：4.0.30319.42000
* 机器名称：LAPTOP-E0N2L34V
* 命名空间：SlnMesnac.Plc.Factory
* 唯一标识：496f8d2b-70e3-4a05-ae18-a9b0fcd06b82
*
* 创建者：WenJY
* 电子邮箱：wenjy@mesnac.com
* 创建时间：2024-03-27 21:58:35
* 版本：V1.0.0
* 描述：
*
*--------------------------------------------------------------------
* 修改人：
* 时间：
* 修改说明：
*
* 版本：V1.0.0
*--------------------------------------------------------------------*/

#endregion << 版 本 注 释 >>

namespace SlnMesnac.Plc.Factory
{
    public class InovanceFactory : PlcAbsractFactory
    {
        private StringChange _stringChange;

        private InovanceTcpNet inovanceTcp = null;

        public InovanceFactory(StringChange stringChange)
        {
            _stringChange = stringChange;

            this.inovanceTcp = new InovanceTcpNet();
            this.inovanceTcp.ConnectTimeOut = 2000;
        }

        public override bool IsConnected { get; set; }

        /// <summary>
        /// 建立连接
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        public override bool Connect(string ip, int port)
        {
            try
            {
                inovanceTcp?.ConnectClose();
                if (inovanceTcp != null)
                {
                    inovanceTcp.IpAddress = ip;
                    inovanceTcp.Port = port;
                    inovanceTcp.DataFormat = HslCommunication.Core.DataFormat.CDAB;

                    OperateResult connect = inovanceTcp.ConnectServer();
                    this.IsConnected = connect.IsSuccess;
                    if (!connect.IsSuccess)
                    {
                        throw new InvalidOperationException($"汇川PLC连接失败:{connect.Message}");
                    }

                    return connect.IsSuccess;
                }
                else
                {
                    throw new ArgumentException($"汇川PLC实例inovanceTcp为null");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"汇川PLC连接异常：{ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        public override bool DisConnect()
        {
            try
            {
                OperateResult disConnect = inovanceTcp.ConnectClose();
                this.IsConnected = false;
                if (!disConnect.IsSuccess)
                {
                    throw new InvalidOperationException($"汇川PLC断开连接失败:{disConnect.Message}");
                }
                return disConnect.IsSuccess;
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"汇川PLC断开连接异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 根据地址读取指定长度数据
        /// </summary>
        /// <param name="address"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public override byte[] readValueByAddress(string address, int len)
        {
            try
            {
                OperateResult<byte[]> read = inovanceTcp.Read(address, (ushort)(len));
                if (!read.IsSuccess)
                {
                    throw new InvalidOperationException($"根据地址:{address};读取指定长度数据失败：{read.Message}");
                }
                return _stringChange.ConvertFloatToINt(read.Content);
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"根据地址:{address};读取指定长度数据异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 根据地址读取int16数据
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public override int readInt16ByAddress(string address)
        {
            try
            {
                OperateResult<short> read = inovanceTcp.ReadInt16(address);
                if (!read.IsSuccess)
                {
                    throw new InvalidOperationException($"根据地址:{address};读取int16数据失败：{read.Content}");
                }
                return read.Content;
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"根据地址:{address};读取int16数据异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 根据地址写入int16数据
        /// </summary>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public override bool writeInt16ByAddress(string address, int value)
        {
            try
            {
                OperateResult operateResult = new OperateResult();
                int s = 0;
                string[] strArry = address.Split('.');

                //先读取整个块的内容
                var info = inovanceTcp.ReadInt16(strArry[0]);
                if (info.Content == 0)
                {
                    int length = _stringChange.ParseToInt(strArry[1]) + 1;
                    string[] array = new string[length];
                    for (int i = 0; i < length; i++)
                    {
                        if (i == _stringChange.ParseToInt(strArry[1]))
                        {
                            array[i] = value.ToString();
                        }
                        else
                        {
                            array[i] = "0";
                        }
                    }
                    //反转
                    Array.Reverse(array);
                    byte[] buffer = new byte[array.Length];
                    string result = "";
                    for (int i = 0; i < array.Length; i++)
                    {
                        result += (byte)Convert.ToInt32(array[i], 16);
                    }
                    s = Convert.ToInt32(result.Trim(), 2);
                    operateResult = inovanceTcp.Write(strArry[0], (ushort)s);
                }
                else
                {
                    var inf2 = Convert.ToString(info.Content, 2);
                    string[] infoArray = new string[inf2.Length];
                    for (int i = 0; i < inf2.Length; i++)
                    {
                        infoArray[i] = inf2.Substring(i, 1);
                    }
                    Array.Reverse(infoArray);
                    infoArray[_stringChange.ParseToInt(strArry[1])] = value.ToString();
                    string result = "";
                    foreach (var item in infoArray)
                    {
                        result = result + item;
                    }
                    s = Convert.ToInt32(result.Trim(), 10);
                    operateResult = inovanceTcp.Write(strArry[0], s);
                }
                if (!operateResult.IsSuccess)
                {
                    throw new InvalidOperationException($"根据地址:{address};写入int16数据失败：{operateResult.Message}");
                }
                return operateResult.IsSuccess;
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"根据地址:{address};写入int16数据异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 通过PLC地址读取string类型数据
        /// </summary>
        /// <param name="address"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public override string readStringByAddress(string address, ushort length)
        {
            try
            {
                OperateResult<String> read = inovanceTcp.ReadString(address, length);
                if (!read.IsSuccess)
                {
                    throw new InvalidOperationException($"根据地址:{address};读取string数据失败：{read.Content}");
                }
                return read.Content;
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"根据地址:{address};读取string数据异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 通过PLC地址写入String类型数据
        /// </summary>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public override bool writeStringByAddress(string address, string value)
        {
            try
            {
                OperateResult operateResult = inovanceTcp.Write(address, value);
                if (!operateResult.IsSuccess)
                {
                    throw new InvalidOperationException($"根据地址:{address};写入string数据失败：{operateResult.Message}");
                }
                return operateResult.IsSuccess;
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"根据地址:{address};写入string数据异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 通过PLC地址读取Bool类型数据
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public override bool readBoolByAddress(string address)
        {
            try
            {
                OperateResult<bool> read = inovanceTcp.ReadBool(address);
                if (!read.IsSuccess)
                {
                    throw new InvalidOperationException($"根据地址:{address};读取bool数据失败：{read.Content}");
                }
                return read.Content;
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"根据地址:{address};读取bool数据异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 通过PLC地址写入Bool类型数据
        /// </summary>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public override bool writeBoolByAddress(string address, bool value)
        {
            try
            {
                OperateResult operateResult = inovanceTcp.Write(address, short.Parse(_stringChange.ParseToInt(value ? "1" : "0").ToString()));
                if (!operateResult.IsSuccess)
                {
                    throw new InvalidOperationException($"根据地址:{address};写入bool数据失败：{operateResult.Message}");
                }
                return operateResult.IsSuccess;
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"根据地址:{address};写入bool数据异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 通过PLC地址写入Double类型数据
        /// </summary>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public override bool writeDoubleByAddress(string address, int value)
        {
            try
            {
                OperateResult operateResult = inovanceTcp.Write(address, Convert.ToDouble(value));
                if (!operateResult.IsSuccess)
                {
                    throw new InvalidOperationException($"根据地址:{address};写入double数据失败：{operateResult.Message}");
                }
                return operateResult.IsSuccess;
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"根据地址:{address};写入double数据异常：{ex.Message}");
            }
        }

        public override bool readHeartByAddress(string address)
        {
            throw new NotImplementedException();
        }

        public override Task<bool> ConnectAsync(string ip, int port)
        {
            throw new NotImplementedException();
        }

        public override bool writeStringByAddress(string address, string value, int length)
        {
            throw new NotImplementedException();
        }
    }
}