using System;
using System.Threading.Tasks;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;

namespace Plane.Communication
{
    public class UdpConnection : UdpConnectionBase
    {
        private HostName _remoteHostName;

        private string _remoteServiceName;

        private DatagramSocket _socket;

        public UdpConnection(string remoteHostName, int remotePort = 5250)
        {
            _remoteHostName = new HostName(remoteHostName);
            _remoteServiceName = remotePort.ToString();
        }

        public event EventHandler MessageReceived;

        public override void Close()
        {
            if (IsOpen)
            {
                IsOpen = false;
                _socket?.Dispose();
            }
        }

        public override Task OpenAsync()
        {
            if (!IsOpen)
            {
                IsOpen = true;
                _socket = new DatagramSocket();
                _socket.MessageReceived += _socket_MessageReceived;
            }
            return TaskUtils.CompletedTask;
        }

        protected override async Task SendAsync(byte[] datagram, int bytes)
        {
            if (datagram.Length != bytes)
            {
                Array.Resize(ref datagram, bytes);
            }
            try
            {
                var outputStream = await _socket.GetOutputStreamAsync(_remoteHostName, _remoteServiceName);
                var writer = new DataWriter(outputStream);
                writer.WriteBytes(datagram);
                await writer.StoreAsync();
            }
            catch (Exception ex)
            {
                RaiseExceptionThrown(ex);
            }
        }

        private void _socket_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
        {
            try
            {
                var reader = args.GetDataReader();
                var data = new byte[reader.UnconsumedBufferLength];
                reader.ReadBytes(data);
                EnqueueDatagram(data);
                MessageReceived?.Invoke(this, EventArgs.Empty);
            }
            catch (Exception ex)
            {
                RaiseExceptionThrown(ex);
            }
        }
    }
}
