using ProjectManagementSystem.Device.Function;
using RRQMCore.ByteManager;
using RRQMSocket;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace ProjectManagementSystem.Device.CasunBox
{
    public class BoxCommunicationUDP : BoxCommunicationBase
    {
        private string ipHost;
        private string defaultRemotePoint;
        private SimpleUdpSession udpSession;

        private List<EndPoint> endPoints = new List<EndPoint>();

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="ipAddress">监听的IP</param>
        /// <param name="port">监听的端口</param>
        /// <param name="remoteIpAddress">默认发送数据的IP</param>
        /// <param name="remotePort">默认发送数据的端口</param>
        public BoxCommunicationUDP(string ipAddress, int port, string remoteIpAddress = null, int remotePort = 0)
        {
            ipHost = $"{ipAddress}:{port}";

            if (string.IsNullOrEmpty(remoteIpAddress)
                || remotePort <= 0)
            {
                //默认终结点为广播地址
                if (ipAddress == IPAddress.Any.ToString())
                {
                    defaultRemotePoint = $"{IPAddress.Loopback}:{port}";
                }
                else
                {
                    string ipStr = ipAddress.Substring(0, ipAddress.LastIndexOf('.') + 1);
                    defaultRemotePoint = $"{ipStr}255:{port}";
                }
            }
            else
            {
                defaultRemotePoint = $"{remoteIpAddress}:{remotePort}";
            }
        }

        public override void Start()
        {
            udpSession = new SimpleUdpSession();
            udpSession.Received += OnReceived;
            var config = new UdpSessionConfig();//UDP配置

            config.SetValue(UdpSessionConfig.DefaultRemotePointProperty, new IPHost(defaultRemotePoint).EndPoint)//设置默认终结点，用于发送
                .SetValue(UdpSessionConfig.LoggerProperty, new LogerBox(this.LogMsg))//设置内部日志记录器
                .SetValue(UdpSessionConfig.UseBindProperty, true)//是否执行绑定，一般作为接收端时需要绑定
                .SetValue(UdpSessionConfig.ListenIPHostsProperty, new IPHost[] { new IPHost(ipHost) })//绑定的IPHost，udp只能绑定一个地址。
                .SetValue(UdpSessionConfig.BufferLengthProperty, 2048)//设置缓存
                .SetValue(UdpSessionConfig.ServerNameProperty, "RRQMUdpServer");//设置服务名称

            udpSession.Setup(config);//加载配置

            try
            {
                //启动
                udpSession.Start();//启动
                LogMsg($"UDP服务端{ipHost}已启动");

                var address = Dns.GetHostAddresses(Dns.GetHostName()).FirstOrDefault(d => ipHost.Contains(d.ToString()));
                if (address == null)
                {
                    LogMsg($"注意：UDP监听IP不属于本机IP");
                }
                base.Start();
            }
            catch (Exception ex)
            {
                LogMsg($"UDP服务端启动异常", ex);
            }

        }

        private void OnReceived(EndPoint client, ByteBlock byteBlock)
        {
            string endPointString = client.ToString();
            //过滤自身发出的数据
            if (endPointString == defaultRemotePoint
                || endPointString == ipHost)
            {
                return;
            }

            int index = endPoints.FindIndex(d => d.ToString() == endPointString);
            if (index < 0)
            {
                endPoints.Add(client);
            }

            byte[] data = new byte[byteBlock.Length];
            Buffer.BlockCopy(byteBlock.Buffer, 0, data, 0, data.Length);

            RecivedData(data, d =>
            {
                d.Name = endPointString;
                LogMsg($"终结点{client}: UDP接收数据: {Tools.Byte2HexString(data)} 校验{d.CheckXOR}");
            });
        }

        private List<EndPoint> GetEndPoint(int route)
        {
            var clientNames = m_boxInfoDict.Values
                .Where(d => d.Route == route)
                .Select(d => d.Name)
                .ToArray();

            var clientList = clientNames.Length > 0 ?
                endPoints.Where(d => clientNames.Contains(d.ToString())).ToList() :
                new List<EndPoint>() { udpSession.DefaultRemotePoint };

            return clientList;
        }

        public override void SendCommand(BoxCommandBase command)
        {
            var clientList = GetEndPoint(command.Route);
            byte[] data = command.Serialization();
            foreach (EndPoint client in clientList)
            {
                try
                {
                    udpSession.SendTo(data, 0, data.Length, client);
                    LogMsg($"终结点{client}: UDP发送数据: {Tools.Byte2HexString(data)}");
                }
                catch (Exception ex)
                {
                    LogMsg($"终结点{client}: UDP发送数据异常: {Tools.Byte2HexString(data)}", ex);
                }
            }
        }

        public override void Stop()
        {
            if (udpSession != null)
            {
                udpSession.Stop();
            }
        }
    }
}

