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

namespace QCRPG.Framework;

public class PacketDataReceiver : IObserver<IncomingPacketData>
{
	private Thread receiveThread;

	private Queue<IncomingPacketData> receiveQueue = new Queue<IncomingPacketData>();

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

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

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

	private bool running;

	public void Startup()
	{
		if (!running)
		{
			receiveThread = new Thread(ReceiveThread);
			receiveThread.Name = "PacketDataReceiver-Receive";
			receiveThread.IsBackground = true;
			receiveThread.Start();
			running = true;
		}
	}

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

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

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

	public void NotifyObserver(IncomingPacketData packetData)
	{
		lock (receiveQueue)
		{
			receiveQueue.Enqueue(packetData);
			receiveDataQueuedEvent.Set();
		}
	}

	private void ReceiveThread()
	{
		ManualResetEvent[] array = new ManualResetEvent[2] { receiveDataQueuedEvent, shuttingDownEvent };
		while (true)
		{
			int num = WaitHandle.WaitAny(array);
			if (array[num] == receiveDataQueuedEvent)
			{
				Queue<IncomingPacketData> queue = new Queue<IncomingPacketData>();
				lock (receiveQueue)
				{
					while (receiveQueue.Count > 0)
					{
						queue.Enqueue(receiveQueue.Dequeue());
					}
					receiveDataQueuedEvent.Reset();
				}
				while (queue.Count > 0)
				{
					receiveDataNotifier.NotifyObservers(queue.Dequeue());
				}
			}
			else if (array[num] == shuttingDownEvent)
			{
				break;
			}
		}
	}
}
