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

namespace QCRPG.Framework;

public sealed class Logger : IObserver<LogMessage>
{
	private Queue<LogMessage> logMessageQueue = new Queue<LogMessage>();

	private List<LogMessage> logMessageNotificationList = new List<LogMessage>();

	private GenericNotifier<LogMessage> logMessageNotifier = new GenericNotifier<LogMessage>();

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

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

	private Thread notificationThread;

	private bool running;

	private string technologyName;

	private string dutName;

	public string TechnologyName
	{
		get
		{
			return technologyName;
		}
		set
		{
			technologyName = value;
		}
	}

	public string DutName
	{
		get
		{
			return dutName;
		}
		set
		{
			dutName = value;
		}
	}

	public Logger(string technologyName, string dutName)
	{
		this.technologyName = technologyName;
		this.dutName = dutName;
	}

	public void Startup()
	{
		if (!running)
		{
			notificationThread = new Thread(NotificationThread);
			notificationThread.Name = $"Logger-Notification ({technologyName}-{dutName})";
			notificationThread.IsBackground = true;
			notificationThread.Start();
			running = true;
		}
	}

	public void Enqueue(LogMessage logMessage)
	{
		if (!running)
		{
			return;
		}
		lock (logMessageQueue)
		{
			logMessage.TechnologyName = technologyName;
			logMessage.DutName = dutName;
			logMessageQueue.Enqueue(logMessage);
			messagesInQueueEvent.Set();
		}
	}

	public void NotifyObserver(LogMessage logMessage)
	{
		Enqueue(logMessage);
	}

	public void RegisterObserver(IObserver<LogMessage> observer)
	{
		logMessageNotifier.RegisterObserver(observer);
	}

	public void UnregisterObserver(IObserver<LogMessage> observer)
	{
		logMessageNotifier.UnregisterObserver(observer);
	}

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

	private void NotificationThread()
	{
		ManualResetEvent[] array = new ManualResetEvent[2] { messagesInQueueEvent, shuttingDownEvent };
		while (true)
		{
			int num = WaitHandle.WaitAny(array);
			if (array[num] == messagesInQueueEvent)
			{
				logMessageNotificationList.Clear();
				lock (logMessageQueue)
				{
					while (logMessageQueue.Count > 0)
					{
						logMessageNotificationList.Add(logMessageQueue.Dequeue());
					}
					messagesInQueueEvent.Reset();
				}
				foreach (LogMessage logMessageNotification in logMessageNotificationList)
				{
					logMessageNotifier.NotifyObservers(logMessageNotification);
				}
			}
			else if (array[num] == shuttingDownEvent)
			{
				break;
			}
		}
	}
}
