﻿using System;
using DarkRift;
using DarkRift.Client;
using Dissonance.Datastructures;
using Dissonance.Networking;

namespace Dissonance.Integrations.DarkRift2
{
    public class DarkRift2Client
        : BaseClient<DarkRift2Server, DarkRift2Client, DarkRift2Peer>
    {
        private readonly DarkRift2CommsNetwork _comms;

        private readonly ConcurrentPool<byte[]> _byteBuffers = new ConcurrentPool<byte[]>(3, () => new byte[4096]);

        public DarkRift2Client([NotNull] DarkRift2CommsNetwork comms)
            : base(comms)
        {
            _comms = comms;
        }

        public override void Connect()
        {
            _comms.DarkRiftClient.MessageReceived += OnEvent;

            Connected();
        }

        public override void Disconnect()
        {
            _comms.DarkRiftClient.MessageReceived -= OnEvent;

            base.Disconnect();
        }

        #region receive
        protected override void ReadMessages()
        {
            //Messages are received in an event handler, so we don't need to do any work to read events
        }

        private void OnEvent(object sender, [NotNull] MessageReceivedEventArgs e)
        {
            //Get a temporary buffer to read the data into
            var buffer = _byteBuffers.Get();

            //Read the message and process it in Dissonance
            using (var message = e.GetMessage())
            {
                var read = DarkRift2Helpers.ReadPacket(message, buffer);
                if (read.HasValue)
                    NetworkReceivedPacket(read.Value);
            }

            //Return the buffer now that we're finished with it
            _byteBuffers.Put(buffer);
        }
        #endregion

        #region send
        private void Send(ArraySegment<byte> packet, SendMode mode)
        {
            using (var writer = DarkRift2Helpers.WritePacket(packet))
            using (var msg = Message.Create(DarkRift2Helpers.DissonanceMessageTag, writer))
                _comms.DarkRiftClient.SendMessage(msg, mode);
        }

        protected override void SendReliable(ArraySegment<byte> packet)
        {
            Send(packet, SendMode.Reliable);
        }

        protected override void SendUnreliable(ArraySegment<byte> packet)
        {
            Send(packet, SendMode.Unreliable);
        }
        #endregion
    }
}
