using System;
using HslCommunication;
using HslCommunication.Profinet.Melsec;
using SlnMesnac.Common;

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

        private MelsecMcNet melsec_net = null;

        public MelsecBinaryFactory(StringChange stringChange)
        {
            _stringChange = stringChange;

            this.melsec_net = new MelsecMcNet();
            this.melsec_net.ConnectTimeOut = 2000;
        }
        
        public override bool IsConnected { get; set; }

        /// <summary>
        /// 建立连接
        /// </summary>
        /// <param name="iP"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public override bool Connect(string iP, int port)
        {
            try
            {
                melsec_net.IpAddress = iP;
                melsec_net.Port = port;
                OperateResult connect = melsec_net.ConnectServer();
                this.IsConnected = connect.IsSuccess;
                if (!connect.IsSuccess)
                {
                    return false;
                }

                return connect.IsSuccess;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public override bool DisConnect()
        {
            try
            {
                OperateResult disConnect = melsec_net.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 = melsec_net.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 = melsec_net.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>
        /// 根据地址读取int32数据
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public override int readInt32ByAddress(string address)
        {
            try
            {
                OperateResult<int> read = melsec_net.ReadInt32(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 = melsec_net.Write(address, Convert.ToInt16(value));
                if (!operateResult.IsSuccess)
                {
                    throw new InvalidOperationException($"根据地址:{address};写入int16数据失败：{operateResult.Message}");
                }
                return operateResult.IsSuccess;
            }
            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 writeInt32ByAddress(string address, int value)
        {
            try
            {
                OperateResult operateResult = melsec_net.Write(address, value);
                if (!operateResult.IsSuccess)
                {
                    throw new InvalidOperationException($"根据地址:{address};写入int32数据失败：{operateResult.Message}");
                }
                return operateResult.IsSuccess;
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"根据地址:{address};写入int32数据异常：{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 = melsec_net.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 = melsec_net.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 = melsec_net.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地址读取心跳结果
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public override bool readHeartByAddress(string address)
        {
            try
            {
                OperateResult<bool> read = melsec_net.ReadBool(address);
                if (!read.IsSuccess)
                {
                    return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <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 = melsec_net.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 = melsec_net.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}");
            }
        }
    }
}