using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Timers;
using Microsoft.Win32;
using QC.QSPRAutomation.Internal;
using QC.QTMInterface;

namespace QC.QSPRAutomationInterface;

[ComVisible(true)]
[ProgId("QSPR3.Application")]
[ComSourceInterfaces(typeof(IQSPRApplicationEvents))]
[ClassInterface(ClassInterfaceType.None)]
public class Application : IQSPRApplication
{
	[ComVisible(false)]
	public delegate void EventQsprStarted();

	[ComVisible(false)]
	public delegate void EventQsprExited(int exitCode);

	[ComVisible(false)]
	public delegate void EventQsprHidden(bool hiddenOkay);

	[ComVisible(false)]
	public delegate void EventQsprShown(bool shownOkay);

	[ComVisible(false)]
	public delegate void EventGlobalVariableModified(string globalVariableName, string globalVariableValue);

	[ComVisible(false)]
	public delegate void EventDebugMessage(string windowName, string debugText, int traceLevel);

	[ComVisible(false)]
	public delegate void TestMessageReceivedDelegate(object message);

	[ComVisible(false)]
	public delegate void EventTMSPluginInitialized();

	private const string QSPRID = "QSPR_1";

	private int minimumApp = 1;

	private int enableRegex = 1;

	private int securityLevel;

	private XTTDocument xttDocument;

	private int receiveQSPRDebugMessages;

	private StreamWriter localLogStream;

	private string lastError = "";

	private QSPRInstance qsprInstance;

	private Random randNum = new Random();

	private int portNumber = 2113;

	private bool portSpecified;

	private int qsprInstanceNoOfTries = 3;

	private string lastCallInfo = "";

	private TcpListener tcpListener;

	private Timer timer1;

	private string localLogPath = "c:\\qualcomm\\qspr\\temp";

	public int MinimizeApp
	{
		get
		{
			lastCallInfo = "MinimizeApp";
			return minimumApp;
		}
		set
		{
			lastCallInfo = "MinimizeApp = " + value;
			minimumApp = value;
			if (minimumApp == 1)
			{
				qsprInstance.HideWindow();
			}
			else
			{
				qsprInstance.ShowWindow();
			}
		}
	}

	public int ReceiveQSPRDebugMessages
	{
		get
		{
			lastCallInfo = "ReceiveQSPRDebugMessages";
			return receiveQSPRDebugMessages;
		}
		set
		{
			lastCallInfo = "ReceiveQSPRDebugMessages = " + value;
			receiveQSPRDebugMessages = value;
			if (receiveQSPRDebugMessages == 1)
			{
				Log("Send Qspr Debug messages");
				qsprInstance.SendQSPRDebugMessages();
			}
			else
			{
				Log("Stop sending Qspr Debug messages");
				qsprInstance.StopSendingQSPRDebugMessages();
			}
		}
	}

	public int IsQsprProcessAlive
	{
		get
		{
			lastCallInfo = "IsQsprProcessAlive";
			if (qsprInstance != null)
			{
				if (!qsprInstance.IsQsprInstanceAlive)
				{
					return 0;
				}
				return 1;
			}
			return 0;
		}
	}

	public int CloseHidesWindow
	{
		get
		{
			lastCallInfo = "CloseHidesWindow";
			if (qsprInstance.CloseHidesUI)
			{
				return 1;
			}
			return 0;
		}
		set
		{
			if (value == 1)
			{
				qsprInstance.CloseHidesUI = true;
			}
			else
			{
				qsprInstance.CloseHidesUI = false;
			}
		}
	}

	public XTTDocument ActiveDocument
	{
		get
		{
			lastCallInfo = "ActiveDocument";
			return xttDocument;
		}
	}

	public int EnableRegexSupport
	{
		get
		{
			lastCallInfo = "EnableRegexSupport";
			return enableRegex;
		}
		set
		{
			lastCallInfo = "EnableRegexSupport = " + value;
			enableRegex = value;
			if (!qsprInstance.EnableRegexSupport(enableRegex))
			{
				lastError = "Unable to set property EnableRegexSupport";
				qsprInstance.SetErrorsExist(1);
			}
		}
	}

	public int SecurityLevel
	{
		get
		{
			lastCallInfo = "SecurityLevel";
			return securityLevel;
		}
		set
		{
			lastCallInfo = "SecurityLevel = " + value;
			if (!qsprInstance.SetSecurityLevel(value))
			{
				lastError = "Unable to set property SecurityLevel";
				qsprInstance.SetErrorsExist(1);
			}
			else
			{
				securityLevel = value;
			}
		}
	}

	public int ErrorsExist
	{
		get
		{
			lastCallInfo = "ErrorsExist";
			if (qsprInstance.ErrorsExist())
			{
				return 1;
			}
			return 0;
		}
		set
		{
			lastCallInfo = "ErrorsExist = " + value;
			if (!qsprInstance.SetErrorsExist(value))
			{
				lastError = "Unable to set ErrorsExist property";
			}
		}
	}

	public event EventQsprStarted QsprStarted;

	public event EventQsprExited QsprExited;

	public event EventQsprHidden QsprHidden;

	public event EventQsprShown QsprShown;

	public event EventGlobalVariableModified GlobalVariableModified;

	public event EventDebugMessage DebugMessage;

	public event TestMessageReceivedDelegate TestMessageReceived;

	public event EventTMSPluginInitialized QSPRTMSPluginInitialized;

	public Application()
		: this(hideQSPRWindow: false)
	{
	}

	public Application(bool hideQSPRWindow)
		: this(hideQSPRWindow, null, null, -1, null)
	{
	}

	public Application(bool hideQSPRWindow, string initialTreeFilePath, string backgroundColor, int port, string qsprExecutablePath)
	{
		if (port > 0)
		{
			portSpecified = true;
		}
		try
		{
			for (int i = 1; i <= qsprInstanceNoOfTries; i++)
			{
				Log("Creating new QSPR instance. Attempt # " + i);
				qsprInstance = new QSPRInstance();
				Log("New QSPR instance created");
				string text = QsprExecutablePath();
				if (!string.IsNullOrEmpty(qsprExecutablePath))
				{
					Log("Overriding executable path. New Qspr path = " + qsprExecutablePath);
					text = qsprExecutablePath;
				}
				Log("Got executable path " + text);
				if (!string.IsNullOrEmpty(text))
				{
					qsprInstance.QSPRExecutablePath = text;
				}
				if (port > 0 && portSpecified)
				{
					qsprInstance.PortNumber = port;
				}
				else
				{
					portNumber = randNum.Next(2000, 4000);
					qsprInstance.PortNumber = FindFreePort(portNumber);
				}
				Log("Assigned port number " + qsprInstance.PortNumber);
				qsprInstance.InstanceIdentifier = "QSPR_1" + GetRandomNumber();
				Log("QSPR instance identifier " + qsprInstance.InstanceIdentifier);
				Log("Registering Channel");
				Channel.Register(0);
				Log("Registering Channel successfull");
				BindToQsprEvents();
				Log("Hide Qspr window :" + hideQSPRWindow);
				if (qsprInstance.StartQSPR(hideQSPRWindow, withoutTestTree: true, backgroundColor))
				{
					Log("QSPR instance started with server in attempt " + i);
					if (!string.IsNullOrEmpty(initialTreeFilePath))
					{
						Log("Opening tree file: " + initialTreeFilePath);
						xttDocument = OpenXTT(initialTreeFilePath);
						if (xttDocument == null)
						{
							Log("Failed to open tree: " + initialTreeFilePath);
						}
					}
					break;
				}
				Log("Unable to start QSPR instance with Server for attempt " + i);
			}
		}
		catch (Exception ex)
		{
			Log("Error in QSPRAutomationInterface constructor: " + ex.ToString());
			throw ex;
		}
	}

	internal void Log(string message)
	{
		Log(string.Empty, message);
	}

	internal void Log(string qsprInstanceIdentifier, string message)
	{
		if (localLogStream != null)
		{
			localLogStream.WriteLine(DateTime.Now.ToString("MM_dd_yyyy_HH_mm_ss_ffff") + ">" + message);
		}
	}

	private void InitializeLocalLogStream()
	{
		try
		{
			DirectoryInfo directoryInfo = new DirectoryInfo(localLogPath);
			if (!directoryInfo.Exists)
			{
				directoryInfo.Create();
			}
			if (localLogStream == null)
			{
				string text = DateTime.Now.ToString("MM_dd_yyyy_HH_mm_ss_ffff");
				string path = Path.Combine(directoryInfo.FullName, Process.GetCurrentProcess().Id + "_QSPRAutomationSharedLog_" + text + ".log");
				localLogStream = new StreamWriter(path, append: false);
				localLogStream.AutoFlush = true;
			}
		}
		catch
		{
		}
	}

	private int FindFreePort(int portNumber)
	{
		if (IsPortFree(portNumber))
		{
			return portNumber;
		}
		portNumber++;
		if (portNumber > 65535)
		{
			throw new Exception("Max port limit reached. No TCP port available to connect");
		}
		return FindFreePort(portNumber);
	}

	private bool IsPortFree(int portNumber)
	{
		bool result = true;
		IPGlobalProperties iPGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
		List<IPEndPoint> list = new List<IPEndPoint>();
		list.AddRange(iPGlobalProperties.GetActiveTcpListeners());
		TcpConnectionInformation[] activeTcpConnections = iPGlobalProperties.GetActiveTcpConnections();
		foreach (TcpConnectionInformation tcpConnectionInformation in activeTcpConnections)
		{
			list.Add(tcpConnectionInformation.LocalEndPoint);
		}
		foreach (IPEndPoint item in list)
		{
			if (item.Port == portNumber)
			{
				result = false;
				break;
			}
		}
		return result;
	}

	private string GetRandomNumber()
	{
		Random random = new Random();
		return random.Next(10000).ToString();
	}

	private string QsprExecutablePath()
	{
		try
		{
			string location = GetType().Assembly.Location;
			string fullName = Directory.GetParent(location).FullName;
			string text = Path.Combine(fullName, "qspr.exe");
			if (File.Exists(text))
			{
				return text;
			}
			RegistryKey classesRoot = Registry.ClassesRoot;
			RegistryKey registryKey = classesRoot.OpenSubKey("QSPR3.Application\\CLSID");
			string text2 = registryKey.GetValue("").ToString();
			RegistryKey registryKey2 = classesRoot.OpenSubKey("Wow6432Node\\CLSID\\" + text2 + "\\InprocServer32");
			if (registryKey2 == null)
			{
				registryKey2 = classesRoot.OpenSubKey("CLSID\\" + text2 + "\\InprocServer32");
			}
			string uriString = registryKey2.GetValue("CodeBase").ToString();
			Uri uri = new Uri(uriString);
			fullName = Directory.GetParent(uri.LocalPath).FullName;
			text = Path.Combine(fullName, "qspr.exe");
			if (File.Exists(text))
			{
				return text;
			}
			return "";
		}
		catch
		{
			return "";
		}
	}

	private void BindToQsprEvents()
	{
		try
		{
			Log("Binding to QSPR events");
			qsprInstance.qsprExitedDelegate = ProcessQsprExited;
			qsprInstance.qsprHiddenDelegate = ProcessQsprHidden;
			qsprInstance.qsprShownDelegate = ProcessQsprShown;
			qsprInstance.qsprStartedDelegate = ProcessQsprStarted;
			qsprInstance.processReceivedQSPRDebugMessageDelegate = ProcessQsprDebugMessage;
			qsprInstance.processGlobalVariablesModifiedDelegate = ProcessGlobalVariableModified;
			qsprInstance.TestMessageReceived = ProcessTestMessageReceived;
		}
		catch (Exception ex)
		{
			Log("Error binding QsprEvents : " + ex.ToString());
		}
	}

	private void ProcessQsprExited(string instanceIdentifer, int exitCode)
	{
		if (this.QsprExited != null)
		{
			this.QsprExited(exitCode);
		}
	}

	private void ProcessQsprHidden(bool hiddenOkay)
	{
		if (this.QsprHidden != null)
		{
			this.QsprHidden(hiddenOkay);
		}
	}

	private void ProcessQsprShown(bool shownOkay)
	{
		if (this.QsprShown != null)
		{
			this.QsprShown(shownOkay);
		}
	}

	private void ProcessQsprStarted()
	{
		if (this.QsprStarted != null)
		{
			this.QsprStarted();
		}
	}

	private void ProcessQsprDebugMessage(string instanceIdentifer, string windowName, string text, int traceLevel)
	{
		if (this.DebugMessage != null)
		{
			Log("DebugMessage: " + windowName + " : " + text);
			this.DebugMessage(windowName, text, traceLevel);
		}
	}

	private void ProcessGlobalVariableModified(string instanceIdentifier, string globalvariableName, string globalVariableValue)
	{
		if (this.GlobalVariableModified != null)
		{
			Log(globalvariableName + " : " + globalVariableValue);
			this.GlobalVariableModified(globalvariableName, globalVariableValue);
		}
	}

	private void ProcessTestMessageReceived(object message)
	{
		if ((TestMsgType)message == TestMsgType.TMSPluginInitialized)
		{
			this.QSPRTMSPluginInitialized();
		}
		else if (this.TestMessageReceived != null)
		{
			this.TestMessageReceived(message);
		}
	}

	public string LastCallInfo()
	{
		return lastCallInfo;
	}

	public string GetLastError()
	{
		return lastError;
	}

	public int GetProcessID()
	{
		return qsprInstance.GetQsprProcessID();
	}

	public XTTDocument OpenXTT(string treeFilePath)
	{
		if (!string.IsNullOrEmpty(treeFilePath))
		{
			lastCallInfo = "OpenXTT(" + treeFilePath + ")";
			xttDocument = new XTTDocument();
			if (qsprInstance.OpenXTT(treeFilePath))
			{
				xttDocument.SetAutomationObject(qsprInstance);
				return xttDocument;
			}
			xttDocument.SetAutomationObject(null);
			lastError = "Failed to open the Tree";
			qsprInstance.SetErrorsExist(1);
			return null;
		}
		lastCallInfo = "OpenXTT was called with null or empty treeFilePath";
		lastError = "OpenXTT failed, treeFilePath is null or empty";
		qsprInstance.SetErrorsExist(1);
		return null;
	}

	public XTTDocument NewXTT()
	{
		lastCallInfo = "NewXTT()";
		xttDocument = new XTTDocument();
		if (qsprInstance.NewXTT())
		{
			xttDocument.SetAutomationObject(qsprInstance);
			return xttDocument;
		}
		xttDocument.SetAutomationObject(null);
		lastError = "Failed to open a new Tree";
		qsprInstance.SetErrorsExist(1);
		return null;
	}

	public int SetUUTId(int phoneIndex, string uutID)
	{
		if (uutID != null)
		{
			lastCallInfo = "SetUUTId(" + phoneIndex + ", " + uutID + ")";
			if (xttDocument != null)
			{
				if (xttDocument.SetUUTId(phoneIndex, uutID) != 0)
				{
					return 1;
				}
				lastError = xttDocument.GetLastError();
				qsprInstance.SetErrorsExist(1);
			}
			else
			{
				lastError = "Failed to set UUTId, the xtt document is null";
				qsprInstance.SetErrorsExist(1);
			}
			return 0;
		}
		lastCallInfo = "SetUUTId was called with null uutid value";
		lastError = "SetUUTId failed, uutid was null";
		qsprInstance.SetErrorsExist(1);
		return 0;
	}

	public int SetUserInput(string sCaption, string sLabel, string sUserInput)
	{
		if (sCaption != null && sLabel != null && sUserInput != null)
		{
			lastCallInfo = "SetUserInput(" + sCaption + ", " + sLabel + ", " + sUserInput + ")";
			if (xttDocument != null)
			{
				if (xttDocument.SetUserInput(sCaption, sLabel, sUserInput) != 0)
				{
					return 1;
				}
				lastError = xttDocument.GetLastError();
				qsprInstance.SetErrorsExist(1);
			}
			else
			{
				lastError = "Failed to Set User Input, the xtt document is null";
				qsprInstance.SetErrorsExist(1);
			}
			return 0;
		}
		lastCallInfo = "SetUserInput was called with one or more null arguments";
		lastError = "SetUserInput failed, one or more arguments were null";
		qsprInstance.SetErrorsExist(1);
		return 0;
	}

	public int SetGlobalVariable(string globalVariableName, string globalVariableValue)
	{
		if (globalVariableName != null && globalVariableValue != null)
		{
			lastCallInfo = "SetGlobalVariable(" + globalVariableName + ", " + globalVariableValue + ")";
			if (qsprInstance.SetGlobalVariable(globalVariableName, globalVariableValue))
			{
				return 1;
			}
			lastError = "Failed to Set Global Variable";
			qsprInstance.SetErrorsExist(1);
			return 0;
		}
		lastCallInfo = "SetGlobalVariable called with one or more null arguments";
		lastError = "SetGlobalVariable failed, one or more arguments were null";
		qsprInstance.SetErrorsExist(1);
		return 0;
	}

	public string GetGlobalVariable(string globalVariableName)
	{
		string value = "";
		if (!string.IsNullOrEmpty(globalVariableName))
		{
			lastCallInfo = "GetGlobalVariable(" + globalVariableName + ")";
			if (!qsprInstance.GetGlobalVariable(globalVariableName, out value))
			{
				lastError = "Failed to Get Global Variable " + globalVariableName;
				qsprInstance.SetErrorsExist(1);
			}
			return value;
		}
		lastCallInfo = "GetGlobalVariable was called with an invalid gvName";
		lastError = "GetGlobalVariable failed, the gvName was null or empty";
		qsprInstance.SetErrorsExist(1);
		return "";
	}

	public int SupressAllMessages(int supress)
	{
		lastCallInfo = "SupressAllMessages(" + supress + ")";
		bool flag = false;
		switch (supress)
		{
		case 1:
			flag = true;
			break;
		case 0:
			flag = false;
			break;
		default:
			lastError = "Incorrect parameter suppress, valid values are 0 or 1.";
			qsprInstance.SetErrorsExist(1);
			return 0;
		}
		if (qsprInstance.SuppressAllMessages(flag))
		{
			return 1;
		}
		lastError = "Failed to suppress messages";
		qsprInstance.SetErrorsExist(1);
		return 0;
	}

	public int Exit()
	{
		lastCallInfo = "Exit()";
		qsprInstance.Exit();
		return 1;
	}

	public int AddDllPath(string dllPath)
	{
		if (string.IsNullOrEmpty(dllPath))
		{
			lastCallInfo = "AddDllPath was called with an empty or null dllPath";
			lastError = "AddDllPath called with invalid argument. DllPath can't be null or empty";
			qsprInstance.SetErrorsExist(1);
			return 0;
		}
		lastCallInfo = "AddDllPath(" + dllPath + ")";
		if (!qsprInstance.AddDllPath(dllPath))
		{
			lastError = "Failed to Add Dll Path";
			qsprInstance.SetErrorsExist(1);
			return 0;
		}
		return 1;
	}

	public int EnableDllSearchPaths(int enable)
	{
		lastCallInfo = "EnableDllSearchPaths(" + enable + ")";
		if (enable < 0 || enable > 1)
		{
			lastError = "EnableDllSearchPaths called with an invalid argument. Enable must be 0 or 1";
			qsprInstance.SetErrorsExist(1);
			return 0;
		}
		if (!qsprInstance.EnableDllSearchPaths(enable))
		{
			lastError = "Failed to enable DLL Search paths";
			qsprInstance.SetErrorsExist(1);
			return 0;
		}
		return 1;
	}

	public string GetVersion()
	{
		lastCallInfo = "GetVersion()";
		return qsprInstance.GetVersion();
	}

	public XTTDocument LoadTestPlan(long id, int versionNumber, string databaseServer, string databaseName)
	{
		if (id > 0)
		{
			lastCallInfo = "LoadTestPlan(" + id + ")";
			xttDocument = new XTTDocument();
			if (databaseServer == null)
			{
				databaseServer = string.Empty;
			}
			if (databaseName == null)
			{
				databaseName = string.Empty;
			}
			if (qsprInstance.OpenTestPlan(id, versionNumber, databaseServer, databaseName))
			{
				xttDocument.SetAutomationObject(qsprInstance);
				return xttDocument;
			}
			xttDocument.SetAutomationObject(null);
			lastError = "Failed to open the Tree";
			qsprInstance.SetErrorsExist(1);
			return null;
		}
		lastCallInfo = "LoadTestPlan was called with invalid Testplan ID";
		lastError = "LoadTestPlan failed, ID is invalid";
		qsprInstance.SetErrorsExist(1);
		return null;
	}

	public XTTDocument LoadTestPlanByName(string name, int versionNumber, string databaseServer, string databaseName)
	{
		if (!string.IsNullOrWhiteSpace(name))
		{
			lastCallInfo = "LoadTestPlan(" + name + ")";
			xttDocument = new XTTDocument();
			if (databaseServer == null)
			{
				databaseServer = string.Empty;
			}
			if (databaseName == null)
			{
				databaseName = string.Empty;
			}
			if (qsprInstance.OpenTestPlan(name, versionNumber, databaseServer, databaseName))
			{
				xttDocument.SetAutomationObject(qsprInstance);
				return xttDocument;
			}
			xttDocument.SetAutomationObject(null);
			lastError = "Failed to open the Tree";
			qsprInstance.SetErrorsExist(1);
			return null;
		}
		lastCallInfo = "LoadTestPlan was called with invalid Testplan Name";
		lastError = "LoadTestPlan failed, Name is invalid";
		qsprInstance.SetErrorsExist(1);
		return null;
	}

	public int SetTesterConfigItem(string name, string value, int addToResults)
	{
		lastCallInfo = "SetTesterConfigItem(" + name + ", " + value + ", " + addToResults + ")";
		if (string.IsNullOrEmpty(name))
		{
			lastError = "SetTesterConfigItem called with an invalid argument. Name cannot be null or empty string.";
			qsprInstance.SetErrorsExist(1);
			return 0;
		}
		if (string.IsNullOrEmpty(value))
		{
			lastError = "SetTesterConfigItem called with an invalid argument. Value cannot be null or empty string.";
			qsprInstance.SetErrorsExist(1);
			return 0;
		}
		if (addToResults < 0 || addToResults > 1)
		{
			lastError = "SetTesterConfigItem called with an invalid argument. AddToResults must be 0 or 1";
			qsprInstance.SetErrorsExist(1);
			return 0;
		}
		if (!qsprInstance.SetConfigInfo(clearPrevious: false, name, value, addToResults == 1))
		{
			lastError = "Failed to set tester config item";
			qsprInstance.SetErrorsExist(1);
			return 0;
		}
		return 1;
	}
}
