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

namespace QC.QMSCT;

public class IUnitProgrammer : IDisposable
{
	public class TimeoutWaitHandleManager
	{
		private int timeout;

		public int Timeout
		{
			get
			{
				return timeout;
			}
			set
			{
				timeout = value;
			}
		}

		public int WaitOnHandles(WaitHandle[] waitHandles)
		{
			return WaitHandle.WaitAny(waitHandles, timeout);
		}
	}

	private TimeoutWaitHandleManager timeoutWaitHandleManager = new TimeoutWaitHandleManager();

	private IUnitProgrammerInterface unitProgrammerInterface;

	public OnTestDone OnDone;

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

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

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

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

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

	private bool lastRunTimedOut;

	private Thread thread;

	public UnitProgrammerGenericSetup GenericSetup => unitProgrammerInterface.GenericSetup;

	public int COMPortAtStart
	{
		get
		{
			return unitProgrammerInterface.COMPortAtStart;
		}
		set
		{
			unitProgrammerInterface.COMPortAtStart = value;
		}
	}

	public int COMPortAfterPowerCycle
	{
		get
		{
			return unitProgrammerInterface.COMPortAfterPowerCycle;
		}
		set
		{
			unitProgrammerInterface.COMPortAfterPowerCycle = value;
		}
	}

	public string SerialNumber
	{
		get
		{
			return unitProgrammerInterface.SerialNumber;
		}
		set
		{
			unitProgrammerInterface.SerialNumber = value;
		}
	}

	public string TestPlanFilePath
	{
		get
		{
			return unitProgrammerInterface.TestPlanFilePath;
		}
		set
		{
			unitProgrammerInterface.TestPlanFilePath = value;
		}
	}

	public int TestTimeoutSeconds
	{
		get
		{
			return unitProgrammerInterface.TestTimeoutSeconds;
		}
		set
		{
			unitProgrammerInterface.TestTimeoutSeconds = value;
		}
	}

	public int TestTimeoutSecondsOffset
	{
		get
		{
			return unitProgrammerInterface.TestTimeoutSecondsOffset;
		}
		set
		{
			unitProgrammerInterface.TestTimeoutSecondsOffset = value;
		}
	}

	public string PanelSpecificGV
	{
		get
		{
			return unitProgrammerInterface.PanelSpecificGV;
		}
		set
		{
			unitProgrammerInterface.PanelSpecificGV = value;
		}
	}

	public string ErrorCode => unitProgrammerInterface.ErrorCode;

	public string SubErrorCode => unitProgrammerInterface.SubErrorCode;

	public Dictionary<string, string> TechnologySpecificGV
	{
		set
		{
			unitProgrammerInterface.TechnologySpecificGV = value;
		}
	}

	public bool IsProcessAlive => unitProgrammerInterface.IsProcessAlive;

	public IUnitProgrammerInterface ActiveInterface => unitProgrammerInterface;

	public int Index
	{
		get
		{
			return unitProgrammerInterface.Index;
		}
		set
		{
			unitProgrammerInterface.Index = value;
		}
	}

	public Color BackGroundColor
	{
		get
		{
			return unitProgrammerInterface.BackGroundColor;
		}
		set
		{
			unitProgrammerInterface.BackGroundColor = value;
		}
	}

	public string EngineName => unitProgrammerInterface.EngineName;

	public event EventHandler<TextEventArgs> OnReceiveSN;

	public event EventHandler<TextEventArgs> OnModifyTestTimeout;

	public event EventHandler OnStarted;

	public event EventHandler OnShown;

	public event EventHandler OnHidden;

	public event EventHandler OnExited;

	public event EventHandler OnTestStarted;

	public event EventHandler OnTestStopped;

	public event EventHandler<TextEventArgs> OnSetStatus;

	public event EventHandler<TextEventArgs> OnDisplayStatus;

	public event EventHandler<TextEventArgs> OnTestItemStarted;

	public event EventHandler<TestResultEventArgs> OnTestItemDone;

	public IUnitProgrammer(IUnitProgrammerInterface upi)
	{
		unitProgrammerInterface = upi;
		unitProgrammerInterface.OnReceiveSN += ProcessReceiveSN;
		unitProgrammerInterface.OnModifyTestTimeout += ProcessModifyTestTimeout;
		unitProgrammerInterface.OnStarted += ProcessStarted;
		unitProgrammerInterface.OnShown += ProcessShown;
		unitProgrammerInterface.OnHidden += ProcessHidden;
		unitProgrammerInterface.OnExited += ProcessExited;
		unitProgrammerInterface.OnDone += ProcessDone;
		unitProgrammerInterface.OnSetStatus += ProcessSetStatus;
		unitProgrammerInterface.OnDisplayStatus += ProcessDisplayStatus;
		unitProgrammerInterface.OnTestItemStarted += ProcessTestItemStarted;
		unitProgrammerInterface.OnTestItemDone += ProcessTestItemDone;
	}

	public void StartTestThread(string serialnumber)
	{
		SerialNumber = serialnumber;
		try
		{
			if (thread != null)
			{
				thread.Abort();
			}
		}
		catch
		{
		}
		thread = new Thread(ProgramUnit);
		thread.Name = Index.ToString();
		thread.Start();
	}

	private void ProgramUnit()
	{
		try
		{
			StartUnitProgrammer();
			if (!unitProgrammerInterface.IsTestTreeValid)
			{
				string text = "Test tree is not valid!";
				AppendToLog(text);
				Done(SerialNumber, TestResult.Failed, text);
				return;
			}
			testPassed.Reset();
			testFailed.Reset();
			testAborted.Reset();
			Exited.Reset();
			List<WaitHandle> list = new List<WaitHandle>();
			list.Add(testPassed);
			list.Add(testFailed);
			list.Add(testAborted);
			list.Add(Exited);
			list.Add(disposingObject);
			WaitHandle[] waitHandles = list.ToArray();
			unitProgrammerInterface.RunTest();
			ProcessTestStarted();
			timeoutWaitHandleManager.Timeout = TestTimeoutSeconds * 1000;
			int eventIndex = timeoutWaitHandleManager.WaitOnHandles(waitHandles);
			ProcessTestStopped();
			Determine_EventType(waitHandles, eventIndex);
		}
		catch (Exception ex)
		{
			AppendToLog("Caught exception.\r\nSource: " + ex.Source + "\r\nMessage: " + ex.Message);
			string text = "Exception: " + ex.Message;
			Done(SerialNumber, TestResult.Exception, text);
		}
	}

	public bool EnableShow()
	{
		return unitProgrammerInterface.EnableShow();
	}

	public bool ShowUnitProgrammer()
	{
		if (EnableShow())
		{
			return unitProgrammerInterface.Show();
		}
		return false;
	}

	public bool EnableHide()
	{
		return unitProgrammerInterface.EnableHide();
	}

	public bool HideUnitProgrammer()
	{
		if (EnableHide())
		{
			return unitProgrammerInterface.Hide();
		}
		return false;
	}

	public bool EnableAbort()
	{
		return unitProgrammerInterface.EnableAbort();
	}

	public bool AbortUnitProgrammer()
	{
		if (EnableAbort())
		{
			return unitProgrammerInterface.Abort();
		}
		return false;
	}

	public bool EnableStop()
	{
		return unitProgrammerInterface.EnableStop();
	}

	public bool StopUnitProgrammer()
	{
		if (EnableStop())
		{
			return unitProgrammerInterface.Stop();
		}
		return false;
	}

	public void StartUnitProgrammer()
	{
		if (lastRunTimedOut)
		{
			CloseUnitProgrammer();
			lastRunTimedOut = false;
		}
		if (GenericSetup.ShowStartStopMessages)
		{
			AppendToLog("Start UnitProgrammer");
		}
		unitProgrammerInterface.Start();
	}

	public void CloseUnitProgrammer()
	{
		if (GenericSetup.ShowStartStopMessages)
		{
			AppendToLog("Closing...");
		}
		Exited.Set();
		unitProgrammerInterface.Close();
	}

	private void Determine_EventType(WaitHandle[] waitHandles, int eventIndex)
	{
		int num = 0;
		int num2 = 0;
		switch (eventIndex)
		{
		case 258:
		{
			if (num > 0)
			{
				timeoutWaitHandleManager.Timeout = num * 1000;
				eventIndex = timeoutWaitHandleManager.WaitOnHandles(waitHandles);
				num = 0;
				Determine_EventType(waitHandles, eventIndex);
				break;
			}
			string resultMessage = "Test timed out after " + (num2 + timeoutWaitHandleManager.Timeout) + " seconds";
			Done(SerialNumber, TestResult.Failed, resultMessage);
			lastRunTimedOut = true;
			if (GenericSetup.KillImmediatelyAfterTimeout)
			{
				AppendToLog("");
				AppendToLog("Timed out while running the TestTree.  Shutting down QSPR");
				AppendToLog("Please disconnect and reconnect the device to restart the test.");
				unitProgrammerInterface.Close();
			}
			break;
		}
		case 0:
			Done(SerialNumber, TestResult.Passed, "");
			break;
		case 1:
		{
			string resultMessage = ErrorCode + "\t" + SubErrorCode;
			Done(SerialNumber, TestResult.Failed, resultMessage);
			break;
		}
		case 2:
		{
			string resultMessage = "Testing aborted";
			Done(SerialNumber, TestResult.Exception, resultMessage);
			break;
		}
		case 3:
		{
			string resultMessage = "QSPR Application exited";
			Done(SerialNumber, TestResult.Exception, resultMessage);
			break;
		}
		case 4:
		{
			string resultMessage = "GoNoGo Did not start";
			Done(SerialNumber, TestResult.Exception, resultMessage);
			break;
		}
		case 5:
		{
			AppendToLog("Event index is " + eventIndex + ", disposing");
			string resultMessage = "Disposing unit programmer";
			Done(SerialNumber, TestResult.Exception, resultMessage);
			break;
		}
		default:
		{
			AppendToLog("Event index is " + eventIndex + ", unknown");
			string resultMessage = "Unknown event index of " + eventIndex;
			Done(SerialNumber, TestResult.Exception, resultMessage);
			break;
		}
		}
	}

	private void Done(string serialNumber, TestResult testResult, string resultMessage)
	{
		if (OnDone != null)
		{
			OnDone(serialNumber, testResult, resultMessage);
		}
	}

	public void SetPortNo(int comportAtStart, int comportAfterPowerCycle)
	{
		COMPortAtStart = comportAtStart;
		COMPortAfterPowerCycle = comportAfterPowerCycle;
	}

	public void SetSerialNo(string sn)
	{
		SerialNumber = sn;
	}

	private bool IsInTheFilter(string logCategory)
	{
		string text = logCategory.ToUpper();
		foreach (string item in GenericSetup.LogFilter)
		{
			if (text.Equals(item.ToUpper()))
			{
				return true;
			}
		}
		return false;
	}

	protected void AppendToLog(string logMessage)
	{
		SetStatus(this, logMessage);
	}

	protected void SetStatus(object obj, string text)
	{
		if (this.OnSetStatus != null)
		{
			this.OnSetStatus(obj, new TextEventArgs(text));
		}
	}

	protected void ProcessReceiveSN(object obj, TextEventArgs arg)
	{
		if (this.OnReceiveSN != null)
		{
			this.OnReceiveSN(obj, arg);
		}
	}

	protected void ProcessModifyTestTimeout(object obj, TextEventArgs arg)
	{
		if (this.OnModifyTestTimeout != null)
		{
			this.OnModifyTestTimeout(obj, arg);
		}
	}

	protected void ProcessSetStatus(object obj, LogEventArgs arg)
	{
		if (GenericSetup.DisplayDebugMessages && !IsInTheFilter(arg.Window))
		{
			SetStatus(obj, arg.Window + ": " + arg.Text);
		}
	}

	protected void ProcessDisplayStatus(object obj, TextEventArgs arg)
	{
		if (this.OnDisplayStatus != null)
		{
			this.OnDisplayStatus(obj, arg);
		}
	}

	protected void ProcessTestItemStarted(object obj, TextEventArgs arg)
	{
		if (this.OnTestItemStarted != null)
		{
			this.OnTestItemStarted(obj, arg);
		}
	}

	protected void ProcessTestItemDone(object obj, TestResultEventArgs arg)
	{
		if (this.OnTestItemDone != null)
		{
			this.OnTestItemDone(obj, arg);
		}
	}

	protected void ProcessStarted(object obj, EventArgs arg)
	{
		if (this.OnStarted != null)
		{
			this.OnStarted(this, arg);
		}
	}

	protected void ProcessExited(object obj, EventArgs arg)
	{
		if (this.OnExited != null)
		{
			this.OnExited(this, arg);
		}
	}

	protected void ProcessShown(object obj, EventArgs arg)
	{
		if (this.OnShown != null)
		{
			this.OnShown(this, arg);
		}
	}

	protected void ProcessHidden(object obj, EventArgs arg)
	{
		if (this.OnHidden != null)
		{
			this.OnHidden(this, arg);
		}
	}

	protected void ProcessTestStarted()
	{
		if (this.OnTestStarted != null)
		{
			this.OnTestStarted(this, null);
		}
	}

	protected void ProcessTestStopped()
	{
		if (this.OnTestStopped != null)
		{
			this.OnTestStopped(this, null);
		}
	}

	protected void ProcessDone(object obj, TestResultEventArgs arg)
	{
		switch (arg.TestResult)
		{
		case TestResult.Passed:
			testPassed.Set();
			break;
		case TestResult.Failed:
			testFailed.Set();
			break;
		default:
			testAborted.Set();
			break;
		}
	}

	public void Dispose()
	{
		try
		{
			disposingObject.Set();
			this.OnStarted = null;
			this.OnShown = null;
			this.OnHidden = null;
			this.OnExited = null;
			this.OnTestStarted = null;
			this.OnTestStopped = null;
			this.OnSetStatus = null;
			this.OnDisplayStatus = null;
			this.OnTestItemStarted = null;
			this.OnTestItemDone = null;
			unitProgrammerInterface.Dispose();
		}
		catch
		{
		}
	}
}
