using NModbus;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Team.Utility;

namespace Team.Communicate.Modbus
{

    public class ModbusTcpSlaverService : IModbusTcpSlaverService
    {
        private IModbusSlave _modbusSlave;
        private TcpListener slaveTcpListener;
        public event EventHandler<StorageEventArgs<bool>> CoilDiscretesHandler;
        public event EventHandler<StorageEventArgs<ushort>> InputRegistersHandler;
        public event EventHandler<StorageEventArgs<ushort>> HoldeRegistersHandler;

        private CancellationTokenSource _cancellationTokenSource;
        public ModbusTcpSlaverService()
        {
            _cancellationTokenSource = new CancellationTokenSource();
        }
        /// <summary>
        /// create and start the TCP slave
        /// 默认创建所有监听所有网卡ip地址和localhost
        /// 默认端口号为502
        /// 默认slaveId为1
        /// </summary>
        public void CreateModbusTcpSlave(string ip = default, byte slaveId = 1, int port = 502)
        {
            IPAddress address;
            if (ip == default)
            {
                address = IPAddress.Any;
            }
            else
            {
                var ret = IPAddress.TryParse(ip, out address);
                if (!ret)
                {
                    throw new ArgumentException("ip 参数错误");
                }
            }
            slaveTcpListener = new TcpListener(address, port);
            slaveTcpListener.Start();
            var factory = new ModbusFactory();
            var network = factory.CreateSlaveNetwork(slaveTcpListener);
            var slaveStorage = new SlaveStorage();
            slaveStorage.InputRegisters.StorageOperationOccurred += InputRegisters_StorageOperationOccurred;
            slaveStorage.HoldingRegisters.StorageOperationOccurred += HoldingRegisters_StorageOperationOccurred;
            slaveStorage.CoilInputs.StorageOperationOccurred += CoilInputs_StorageOperationOccurred;
            slaveStorage.CoilDiscretes.StorageOperationOccurred += CoilDiscretes_StorageOperationOccurred; ;
            var slave = factory.CreateSlave(slaveId, slaveStorage);
            network.AddSlave(slave);
            var listenTask = network.ListenAsync(_cancellationTokenSource.Token);
            _modbusSlave = slave;
          
        }

        private void CoilDiscretes_StorageOperationOccurred(object sender, StorageEventArgs<bool> args)
        {
            //LogUtil.WriteInfo($"DANFOSS CoilDiscretes: {args.Operation} starting at {args.StartingAddress},count {args.Points.Length}");
            CoilDiscretesHandler?.Invoke(this, args );
        }

        private void CoilInputs_StorageOperationOccurred(object sender, StorageEventArgs<bool> args)
        {
            //LogUtil.WriteInfo($"DANFOSS CoilInputs: {args.Operation} starting at {args.StartingAddress},count {args.Points.Length}");
        }

        private void HoldingRegisters_StorageOperationOccurred(object sender, StorageEventArgs<ushort> args)
        {
            //HoldeRegistersHandler?.Invoke(this, args);
            //var x=args.Points[32];
        }

        private void InputRegisters_StorageOperationOccurred(object sender, StorageEventArgs<ushort> args)
        {
            //LogUtil.WriteInfo($"DANFOSS Input registers: {args.Operation} starting at {args.StartingAddress},count {args.Points.Length}");
            InputRegistersHandler?.Invoke(this, args);
        }

        public IModbusSlave GetModbusSlaveByIp()
        {
            return _modbusSlave;
        }

        /// <summary>
        /// 写入32位整数
        /// </summary>
        /// <param name="startAddress"></param>
        /// <param name="value"></param>
        public void WriteParameter(ushort startAddress,int value)
        {
            if (_modbusSlave==null)
            {
                throw new Exception("没有创建modbus slave");
            }
            var bytes=BitConverter.GetBytes(value);
            var first = BitConverter.ToUInt16(new[] {bytes[0], bytes[1]},0);
            var second = BitConverter.ToUInt16(new[] { bytes[2], bytes[3] }, 0);
            _modbusSlave.DataStore.HoldingRegisters.WritePoints(startAddress, new []{ first, second });
        }

        public void WriteCoilParameter(ushort startAddress, bool value)
        {
            if (_modbusSlave == null)
            {
                throw new Exception("没有创建modbus slave");
            }
           
            _modbusSlave.DataStore.CoilInputs.WritePoints(startAddress,new bool[] {value});
        }


        /// <summary>
        /// 写入32位正整数
        /// </summary>
        /// <param name="startAddress"></param>
        /// <param name="value"></param>
        public void WriteParameter(ushort startAddress, uint value)
        {
            if (_modbusSlave == null)
            {
                throw new Exception("没有创建modbus slave");
            }
            var bytes = BitConverter.GetBytes(value);
            var first = BitConverter.ToUInt16(new[] { bytes[0], bytes[1] }, 0);
            var second = BitConverter.ToUInt16(new[] { bytes[2], bytes[3] }, 0);
            _modbusSlave.DataStore.HoldingRegisters.WritePoints(startAddress, new[] { first, second });
        }

        /// <summary>
        /// 写入16位正整数
        /// </summary>
        /// <param name="startAddress"></param>
        /// <param name="value"></param>
        public void WriteParameter(ushort startAddress, ushort value)
        {
            if (_modbusSlave == null)
            {
                throw new Exception("没有创建modbus slave");
            }
            var bytes = BitConverter.GetBytes(value);
            var first = BitConverter.ToUInt16(new[] { bytes[0], bytes[1] }, 0);
            _modbusSlave.DataStore.HoldingRegisters.WritePoints(startAddress, new[] { first});
        }

        /// <summary>
        /// 写入16位整数
        /// </summary>
        /// <param name="startAddress"></param>
        /// <param name="value"></param>
        public void WriteParameter(ushort startAddress, short value)
        {
            if (_modbusSlave == null)
            {
                throw new Exception("没有创建modbus slave");
            }
            var bytes = BitConverter.GetBytes(value);
            var first = BitConverter.ToUInt16(new[] { bytes[0], bytes[1] }, 0);
            _modbusSlave.DataStore.HoldingRegisters.WritePoints(startAddress, new[] { first });
        }

        public void Dispose()
        {
            slaveTcpListener.Stop();
            _cancellationTokenSource.Cancel();
        }
    }
}