using System;
using System.Collections.Generic;

namespace SSWMS.Server
{
    class ModbusSocket : ClientSocket
    {
        public ModbusSocket(string ip, int port) : base(ip, port)
        {
        }

        private byte[] Reverse(byte[] data)
        {
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(data);
            }
            return data;
        }

        private readonly object lockobjModbus = new object();
        private ushort _sendID = ushort.MaxValue;
        public ushort GetSendID()
        {
            lock (lockobjModbus)
            {
                if (_sendID == ushort.MaxValue)
                {
                    _sendID = 0;
                }
                else
                {
                    ++_sendID;
                }
                return _sendID;
            }
        }

        // 03 Read Holding Registers
        public void Read(ushort sendID, ushort sSlaveID, ushort sAddress, ushort sQuantity)
        {
            try
            {
                List<byte> list = new List<byte>();
                list.AddRange(Reverse(BitConverter.GetBytes(sendID)));
                list.AddRange(new byte[] { 0x00, 0x00 });
                list.AddRange(Reverse(BitConverter.GetBytes((short)6)));
                list.Add(Convert.ToByte(sSlaveID));
                list.Add(Convert.ToByte((short)3));
                list.AddRange(Reverse(BitConverter.GetBytes(sAddress)));
                list.AddRange(Reverse(BitConverter.GetBytes(sQuantity)));
                Send(list.ToArray());
            }
            catch
            {
            }
        }

        // 06 Write Single Register
        public void Write(ushort sendID, ushort slaveID, ushort address, ushort value)
        {
            try
            {
                List<byte> list = new List<byte>();
                list.AddRange(Reverse(BitConverter.GetBytes(sendID)));
                list.AddRange(new byte[] { 0x00, 0x00 });
                list.AddRange(Reverse(BitConverter.GetBytes((ushort)6)));
                list.Add(Convert.ToByte(slaveID));
                list.Add(Convert.ToByte((ushort)6));
                list.AddRange(Reverse(BitConverter.GetBytes(address)));
                list.AddRange(Reverse(BitConverter.GetBytes(value)));
                Send(list.ToArray());
            }
            catch
            {
            }
        }

        // 16 (0x10) Write Multiple Registers
        public void Write(ushort sendID, ushort slaveID, ushort address, ushort[] values)
        {
            try
            {
                List<byte> list = new List<byte>();
                list.AddRange(Reverse(BitConverter.GetBytes(sendID)));
                list.AddRange(new byte[] { 0x00, 0x00 });
                list.AddRange(Reverse(BitConverter.GetBytes((ushort)(7 + values.Length * 2))));
                list.Add(Convert.ToByte(slaveID));
                list.Add(Convert.ToByte(16));
                list.AddRange(Reverse(BitConverter.GetBytes(address)));
                list.AddRange(Reverse(BitConverter.GetBytes(Convert.ToUInt16(values.Length))));
                list.Add(Convert.ToByte(values.Length * 2));
                foreach (ushort value in values)
                {
                    list.AddRange(Reverse(BitConverter.GetBytes(value)));
                }
                Send(list.ToArray());
            }
            catch
            {
            }
        }
    }
}