using System;
using System.Collections.Generic;
using System.Threading;
using QCRPG.Framework;
using QCRPG.TSL.BT.Packets;

namespace QCRPG.TSL.BT;

public class ISODataQueue
{
	private Queue<SynchronousData> isoDataQueue = new Queue<SynchronousData>();

	private bool running;

	private Thread isoDataThread;

	private BTAPI btAPI;

	private int maxAvailable;

	private ushort transInterval;

	public bool abort;

	private int currentAvailable;

	private bool flowControl;

	private SynchronousData isoDataTemp;

	private SpecificPacketNotifier specificPacketNotifier;

	private ManualResetEvent parentShutdownEvent;

	private List<uint> connectionHandles = new List<uint>();

	public int CurrentAvailable => currentAvailable;

	public SpecificPacketNotifier.PacketNotifier UpdateISOInfo => ISODataQueue_UpdateISOInfo;

	public bool FlowControl => flowControl;

	public ISODataQueue(int connectionHandle, SpecificPacketNotifier specificPacketNotifier, BTAPI btAPI, ManualResetEvent parentShutdownEvent = null)
	{
		if (connectionHandle >= 0)
		{
			connectionHandles.Add((uint)connectionHandle);
		}
		this.specificPacketNotifier = specificPacketNotifier;
		this.btAPI = btAPI;
		this.parentShutdownEvent = parentShutdownEvent;
		specificPacketNotifier.AddPacketNotification(typeof(NumberOfCompletedPacketsEvent), ISODataQueue_UpdateISOInfo);
	}

	private void ISODataQueue_UpdateISOInfo(PacketBase packet)
	{
		if (!(packet is NumberOfCompletedPacketsEvent))
		{
			return;
		}
		NumberOfCompletedPacketsEvent numberOfCompletedPacketsEvent = (NumberOfCompletedPacketsEvent)packet;
		if (connectionHandles.Contains(numberOfCompletedPacketsEvent.UserFields.ConnectionHandle))
		{
			currentAvailable += (int)numberOfCompletedPacketsEvent.UserFields.HcNumOfCompletedPackets;
			if (currentAvailable > maxAvailable)
			{
				currentAvailable = maxAvailable;
			}
		}
	}

	public void SetBufferSize(int freeISODataBuffer)
	{
		maxAvailable = freeISODataBuffer;
		currentAvailable = freeISODataBuffer;
	}

	public void AddConnection(uint connectionHandle)
	{
		connectionHandles.Add(connectionHandle);
	}

	public void SetFlowControl(bool flowCtrl)
	{
		flowControl = flowCtrl;
	}

	public void SetTransInterval(ushort interval)
	{
		transInterval = interval;
	}

	public bool IsQueueEmpty()
	{
		if (isoDataQueue.Count <= 0)
		{
			return true;
		}
		return false;
	}

	public void Startup()
	{
		if (!running)
		{
			running = true;
			isoDataThread = new Thread(ISODataThread);
			isoDataThread.Name = "ISODataQueue";
			isoDataThread.IsBackground = true;
			isoDataThread.Start();
		}
	}

	public void Shutdown()
	{
		if (!running)
		{
			return;
		}
		while (running)
		{
			if (abort)
			{
				running = false;
				abort = false;
			}
			lock (isoDataQueue)
			{
				if (isoDataQueue.Count == 0)
				{
					break;
				}
			}
			Thread.Sleep(100);
		}
		running = false;
		isoDataThread.Join();
	}

	public bool Enqueue(SynchronousData isoDataPacket)
	{
		while (running && (parentShutdownEvent == null || !parentShutdownEvent.WaitOne(0)))
		{
			lock (isoDataQueue)
			{
				if (isoDataQueue.Count < maxAvailable)
				{
					isoDataQueue.Enqueue(isoDataPacket);
					return true;
				}
			}
			Thread.Sleep(0);
		}
		return false;
	}

	public void Clear()
	{
		if (!running)
		{
			return;
		}
		lock (isoDataQueue)
		{
			isoDataQueue.Clear();
		}
	}

	private void ISODataThread()
	{
		while (running)
		{
			bool flag = false;
			lock (isoDataQueue)
			{
				if (isoDataQueue.Count > 0 && currentAvailable > 0)
				{
					isoDataTemp = isoDataQueue.Dequeue();
					flag = true;
					if (flowControl)
					{
						currentAvailable--;
						if (currentAvailable < 0)
						{
							currentAvailable = 0;
						}
					}
					else
					{
						Thread.Sleep(transInterval);
					}
				}
			}
			if (flag)
			{
				try
				{
					btAPI.Send(isoDataTemp);
				}
				catch (Exception)
				{
					running = false;
					lock (isoDataQueue)
					{
						isoDataQueue.Clear();
					}
				}
			}
			Thread.Sleep(0);
		}
	}
}
