using System;
using Windows.Networking.Sockets;

namespace Plane.Communication
{
    public partial class UdpServerConnectionManager
    {
        private DatagramSocket _socket;

        private UdpServerConnectionManager()
        {
            _socket = new DatagramSocket();
            var temp = _socket.BindServiceNameAsync("5250");
        }

        public void StartReceiving()
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(nameof(UdpServerConnectionManager));
            }
            if (_shouldReceive && _isReceiving)
            {
                return;
            }
            _shouldReceive = true;
            _isReceiving = true;
            _socket.MessageReceived += _socket_MessageReceived;
        }

        public void StopReceiving()
        {
            if (_shouldReceive)
            {
                _shouldReceive = false;
                _socket.MessageReceived -= _socket_MessageReceived;
                _isReceiving = false;
            }
        }

        private async void _socket_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
        {
            try
            {
                var reader = args.GetDataReader();
                var data = new byte[reader.UnconsumedBufferLength];
                reader.ReadBytes(data);
                var remoteAddress = args.RemoteAddress.CanonicalName;
                if (!_connections.ContainsKey(remoteAddress))
                {
                    var connection = new UdpServerConnection(await _socket.GetOutputStreamAsync(args.RemoteAddress, args.RemotePort));
                    _connections.Add(remoteAddress, connection);
                    RaiseConnectionEstablished(connection, remoteAddress);
                }
                else
                {
                    var connection = _connections[remoteAddress];
                    if (connection.NeedNewOutputStream)
                    {
                        connection.SetOutputStream(await _socket.GetOutputStreamAsync(args.RemoteAddress, args.RemotePort));
                    }
                }
                _connections[remoteAddress].EnqueueDatagram(data);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex);
            }
        }

        private void DisposeCore()
        {
            _socket.Dispose();
        }
    }
}
