using System;
using System.Collections.Generic;
using System.Threading;

namespace QCRPG.Framework;

public class PacketDataSender : IObserver<OutgoingPacketData>
{
	private Thread sendAsyncThread;

	private Queue<OutgoingPacketData> sendQueue = new Queue<OutgoingPacketData>();

	private GenericNotifier<OutgoingPacketData> sendDataNotifier = new GenericNotifier<OutgoingPacketData>();

	private GenericNotifier<IncomingPacketData> receiveDataNotifier = new GenericNotifier<IncomingPacketData>();

	private ManualResetEvent sendDataQueuedEvent = new ManualResetEvent(initialState: false);

	private List<OutgoingPacketData> sendDataList = new List<OutgoingPacketData>();

	private ManualResetEvent shuttingDownEvent = new ManualResetEvent(initialState: false);

	private bool running;

	public void Startup()
	{
		if (!running)
		{
			sendAsyncThread = new Thread(SendAsyncThread);
			sendAsyncThread.Name = "PacketDataSender-Send";
			sendAsyncThread.IsBackground = true;
			sendAsyncThread.Start();
			running = true;
		}
	}

	public void Shutdown()
	{
		if (running)
		{
			shuttingDownEvent.Set();
			sendAsyncThread.Join();
			shuttingDownEvent.Reset();
			running = false;
		}
	}

	public void SendAsync(OutgoingPacketData packetData)
	{
		lock (sendQueue)
		{
			sendQueue.Enqueue(packetData.DeepCopy());
			sendDataQueuedEvent.Set();
		}
	}

	public void SendSync(OutgoingPacketData packetData)
	{
		lock (sendDataNotifier)
		{
			sendDataNotifier.NotifyObservers(packetData);
		}
	}

	public void RegisterSendDataObserver(IObserver<OutgoingPacketData> observer)
	{
		sendDataNotifier.RegisterObserver(observer);
	}

	public void UnregisterSendDataObserver(IObserver<OutgoingPacketData> observer)
	{
		sendDataNotifier.UnregisterObserver(observer);
	}

	public void RegisterReceiveDataObserver(IObserver<IncomingPacketData> observer)
	{
		receiveDataNotifier.RegisterObserver(observer);
	}

	public void UnregisterReceiveDataObserver(IObserver<IncomingPacketData> observer)
	{
		receiveDataNotifier.UnregisterObserver(observer);
	}

	public void NotifyObserver(OutgoingPacketData packetData)
	{
		SendAsync(packetData);
	}

	private void SendAsyncThread()
	{
		ManualResetEvent[] array = new ManualResetEvent[2] { sendDataQueuedEvent, shuttingDownEvent };
		while (true)
		{
			int num = WaitHandle.WaitAny(array);
			if (array[num] == sendDataQueuedEvent)
			{
				sendDataList.Clear();
				lock (sendQueue)
				{
					while (sendQueue.Count > 0)
					{
						sendDataList.Add(sendQueue.Dequeue());
					}
					sendDataQueuedEvent.Reset();
				}
				foreach (OutgoingPacketData sendData in sendDataList)
				{
					try
					{
						sendDataNotifier.NotifyObservers(sendData);
					}
					catch (Exception ex)
					{
						receiveDataNotifier.NotifyObservers(new IncomingPacketData(ex));
					}
				}
			}
			else if (array[num] == shuttingDownEvent)
			{
				break;
			}
		}
	}
}
