using System;
using System.Collections;
using System.Threading;
using QC.QTMDotNetKernelInterface;

namespace QC.QTMToolKit.Tools;

public static class GlobalMutex
{
	private class GlobalMutexInfo
	{
		public volatile Mutex mutex;

		public volatile string mutexName;

		public volatile bool mutexAcquired;

		public volatile bool releaseMutex;

		public volatile bool timedOut;
	}

	private static volatile Hashtable activeMutexList = new Hashtable();

	public static bool LockMutex(string mutexName, int waitTime, int lockTimeout, bool releaseOnStop)
	{
		ArrayList arrayList = new ArrayList();
		arrayList.Add(mutexName);
		arrayList.Add(waitTime);
		arrayList.Add(lockTimeout);
		arrayList.Add(releaseOnStop);
		if (activeMutexList.ContainsKey(mutexName) && ((GlobalMutexInfo)activeMutexList[mutexName]).mutexAcquired)
		{
			return true;
		}
		ThreadPool.QueueUserWorkItem(LockMutex, arrayList);
		return WaitForLock(mutexName);
	}

	public static void UnlockMutex(string mutexName)
	{
		if (activeMutexList.ContainsKey(mutexName))
		{
			((GlobalMutexInfo)activeMutexList[mutexName]).releaseMutex = true;
		}
	}

	private static void LockMutex(object mutexParams)
	{
		try
		{
			ArrayList arrayList = (ArrayList)mutexParams;
			string text = (string)arrayList[0];
			int num = (int)arrayList[1];
			int num2 = (int)arrayList[2];
			bool flag = (bool)arrayList[3];
			bool flag2 = false;
			bool flag3 = false;
			CreateNamedMutex(text, out var _);
			DateTime now = DateTime.Now;
			try
			{
				DebugMessage.Write("Debug", $"Waiting to acquire a lock on Mutex, name={text}, threadID={Thread.CurrentThread.ManagedThreadId}");
				int num3 = num;
				while (num3 != 0 && !flag2)
				{
					if (QTMInfo.CheckForAnyStopAbortMsg)
					{
						DebugMessage.Write("Debug", $"Stop/Abort message received, name={text}, threadID={Thread.CurrentThread.ManagedThreadId}");
						flag3 = true;
						break;
					}
					if (num3 != -1)
					{
						num3 = ((num3 > 100) ? (num3 - 100) : 0);
					}
					flag2 = ((GlobalMutexInfo)activeMutexList[text]).mutex.WaitOne(100);
				}
			}
			catch (AbandonedMutexException)
			{
				flag2 = true;
			}
			if (flag2)
			{
				DebugMessage.Write("Debug", string.Format("Mutex lock has been acquired, waitTime={2}, name={0}, threadID={1}", text, Thread.CurrentThread.ManagedThreadId, (DateTime.Now - now).ToString()));
				((GlobalMutexInfo)activeMutexList[text]).mutexAcquired = true;
				DateTime now2 = DateTime.Now;
				while (num2 != 0 && !((GlobalMutexInfo)activeMutexList[text]).releaseMutex)
				{
					if (flag && QTMInfo.CheckForAnyStopAbortMsg)
					{
						DebugMessage.Write("Debug", $"Stop/Abort message received, name={text}, threadID={Thread.CurrentThread.ManagedThreadId}");
						((GlobalMutexInfo)activeMutexList[text]).releaseMutex = true;
						break;
					}
					Thread.Sleep(100);
					if (num2 != -1)
					{
						num2 = ((num2 > 100) ? (num2 - 100) : 0);
					}
				}
				if (((GlobalMutexInfo)activeMutexList[text]).releaseMutex)
				{
					((GlobalMutexInfo)activeMutexList[text]).releaseMutex = false;
					DebugMessage.Write("Debug", string.Format("Mutex has been released (lock held for {2}), name={0}, threadID={1}", text, Thread.CurrentThread.ManagedThreadId, (DateTime.Now - now2).ToString()));
				}
				else if (num2 <= 0)
				{
					DebugMessage.Write("Debug", string.Format("Mutex lock has expired, LockTimeOut={2}ms, name={0}, threadID={1}", text, Thread.CurrentThread.ManagedThreadId, (int)arrayList[2]));
				}
				try
				{
					((GlobalMutexInfo)activeMutexList[text]).mutex.ReleaseMutex();
				}
				catch (Exception)
				{
				}
				activeMutexList.Remove(text);
			}
			else
			{
				if (flag3)
				{
					DebugMessage.Write("Debug", $"Failed to acquire Mutex, Stop or Abort message was received, name={text}, threadID={Thread.CurrentThread.ManagedThreadId}");
				}
				else
				{
					DebugMessage.Write("Debug", string.Format("Failed to acquire Mutex, WaitTimeOut of {2}ms was exceeded, name={0}, threadID={1}", text, Thread.CurrentThread.ManagedThreadId, num));
				}
				((GlobalMutexInfo)activeMutexList[text]).timedOut = true;
			}
		}
		catch (Exception)
		{
		}
	}

	private static void CreateNamedMutex(string name, out GlobalMutexInfo mutexInfo)
	{
		bool createdNew = false;
		bool flag = false;
		if (!activeMutexList.ContainsKey(name))
		{
			mutexInfo = new GlobalMutexInfo();
			mutexInfo.mutexName = name;
			try
			{
				mutexInfo.mutex = Mutex.OpenExisting(name);
				createdNew = true;
			}
			catch (WaitHandleCannotBeOpenedException)
			{
				flag = true;
			}
			if (flag)
			{
				mutexInfo.mutex = new Mutex(initiallyOwned: false, name, out createdNew);
			}
			activeMutexList.Add(name, mutexInfo);
		}
		else
		{
			mutexInfo = null;
		}
	}

	private static bool WaitForLock(string mutexName)
	{
		while (!activeMutexList.ContainsKey(mutexName))
		{
			if (QTMInfo.CheckForAnyStopAbortMsg)
			{
				return false;
			}
			Thread.Sleep(100);
		}
		while (!((GlobalMutexInfo)activeMutexList[mutexName]).mutexAcquired)
		{
			if (((GlobalMutexInfo)activeMutexList[mutexName]).timedOut)
			{
				activeMutexList.Remove(mutexName);
				return false;
			}
			Thread.Sleep(100);
		}
		return true;
	}
}
