using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Threading;
using QC.QsprShared.Trace;

namespace QC.QTMScriptKernel;

public class ScriptKernel
{
	private class OnScriptSimulationData
	{
		public ScriptData Test;

		public Timer timer;
	}

	public const int iException = 2;

	public const int iFailed = 0;

	public const int iPassed = 1;

	private string standardOutput = "";

	private string standardError = "";

	private Process pScript = new Process();

	private Thread readStandardOutputThread;

	private Thread readStandardErrorThread;

	public static Mutex mutTest = new Mutex(initiallyOwned: false);

	private ArrayList parameters = new ArrayList();

	private Properties properties = new Properties();

	private string scriptFile = "";

	private string Arguments
	{
		get
		{
			string text = "";
			try
			{
				text = scriptFile + " ";
				foreach (Parameter parameter in parameters)
				{
					if (parameter.IOType == "Input")
					{
						text = text + parameter.Value + " ";
					}
				}
			}
			catch
			{
			}
			return text;
		}
	}

	public event ScriptDoneEventHandler OnScriptDone;

	public event ScriptTextOutEventHandler OnScriptTextOut;

	public bool RunTest(string scriptFullName, ref object objParameters, ref object scriptProperties)
	{
		TraceMessage.Write(ToString(), "ENTER: ScriptKernel.RunTest()", TraceMessageType.Trace);
		try
		{
			ParameterHandler.CreateParameters(objParameters, out parameters);
			CreateProperties(scriptProperties);
			if (!File.Exists(scriptFullName))
			{
				throw new Exception();
			}
			ScriptData scriptData = default(ScriptData);
			scriptData.ScriptFullName = scriptFullName;
			scriptData.ScriptProperties = properties;
			ThreadPool.QueueUserWorkItem(RunScriptTest, scriptData);
			return true;
		}
		catch (Exception ex)
		{
			TraceMessage.Write(ToString(), "EXCEPTION: ScriptKernel.RunScriptTest() " + ex.ToString(), TraceMessageType.Trace);
			throw new Exception("Test couldn't be started");
		}
	}

	internal void RunScriptTest(object stateInfo)
	{
		TraceMessage.Write(ToString(), "ENTER: ScriptKernel.RunScriptTest()", TraceMessageType.Trace);
		try
		{
			mutTest.WaitOne();
			scriptFile = "";
			ScriptData test = (ScriptData)stateInfo;
			pScript = new Process();
			standardError = "";
			standardOutput = "";
			pScript.StartInfo.FileName = test.ScriptFullName;
			pScript.StartInfo.RedirectStandardOutput = test.ScriptProperties.RedirectStandardOutput;
			pScript.StartInfo.RedirectStandardError = test.ScriptProperties.RedirectStandardOutput;
			pScript.StartInfo.CreateNoWindow = test.ScriptProperties.CreateNoWindow;
			if (test.ScriptProperties.Verb.Trim().Length > 0)
			{
				if (test.ScriptProperties.Verb.Trim().ToUpper().Contains(".EXE"))
				{
					pScript.StartInfo.FileName = test.ScriptProperties.Verb.Trim();
					scriptFile = test.ScriptFullName;
				}
				else
				{
					pScript.StartInfo.Verb = test.ScriptProperties.Verb;
				}
			}
			if (test.ScriptProperties.WorkingDirectory.Trim().Length > 0)
			{
				pScript.StartInfo.WorkingDirectory = test.ScriptProperties.WorkingDirectory;
			}
			pScript.StartInfo.UseShellExecute = test.ScriptProperties.UseShellExecute;
			pScript.StartInfo.Arguments = Arguments;
			pScript.EnableRaisingEvents = true;
			if (!test.ScriptProperties.ExitAfterStart)
			{
				pScript.Exited += script_Exited;
			}
			ScriptTextOut(properties.DebugWindowName, "CommandLine :" + test.ScriptFullName + " " + Arguments);
			try
			{
				pScript.Start();
			}
			catch (Win32Exception ex)
			{
				if (ex.Message == "The system cannot find the file specified")
				{
					throw new FileNotFoundException("The script test could not run because the file couldn't be found:\n" + pScript.StartInfo.FileName);
				}
				throw ex;
			}
			if (pScript.StartInfo.RedirectStandardOutput)
			{
				readStandardOutputThread = new Thread(ReadStandardOutput);
				readStandardErrorThread = new Thread(ReadStandardError);
				readStandardOutputThread.Start();
				readStandardErrorThread.Start();
			}
			mutTest.ReleaseMutex();
			if (test.ScriptProperties.ExitAfterStart)
			{
				OnScriptSimulationData onScriptSimulationData = new OnScriptSimulationData();
				TimerCallback callback = TimerDone;
				Timer timer = new Timer(callback, onScriptSimulationData, 300, 1000);
				onScriptSimulationData.timer = timer;
				onScriptSimulationData.Test = test;
			}
		}
		catch (Exception ex2)
		{
			TraceMessage.Write(ToString(), "EXCEPTION: ScriptKernel.RunScriptTest() " + ex2.ToString(), TraceMessageType.Trace);
			mutTest.ReleaseMutex();
			ScriptDone(properties.DescriptiveName, 2, ex2);
		}
		TraceMessage.Write(ToString(), "EXIT: ScriptKernel.RunScriptTest()", TraceMessageType.Trace);
	}

	private void ReadStandardOutput()
	{
		standardOutput = pScript.StandardOutput.ReadToEnd();
	}

	private void ReadStandardError()
	{
		standardError = pScript.StandardError.ReadToEnd();
	}

	private void script_Exited(object sender, EventArgs e)
	{
		TraceMessage.Write(ToString(), "ENTER: ScriptKernel.script_Exited()", TraceMessageType.Trace);
		try
		{
			mutTest.WaitOne();
			if (readStandardOutputThread != null)
			{
				readStandardOutputThread.Join(2000);
			}
			if (readStandardErrorThread != null)
			{
				readStandardErrorThread.Join(2000);
			}
			ScriptParser scriptParser = new ScriptParser();
			scriptParser.InputString = standardOutput;
			if (scriptParser.Parse())
			{
				UpdateParameters(scriptParser.ParameterList);
				standardOutput = scriptParser.OutputString;
			}
			object parameterObject = ParameterHandler.GetParameterObject(parameters);
			ScriptTextOut(properties.DebugWindowName, standardOutput);
			ScriptTextOut(properties.DebugWindowName + " - ERROR", standardError);
			ScriptDone(properties.DescriptiveName, ExitCode(pScript.ExitCode), parameterObject);
			mutTest.ReleaseMutex();
		}
		catch (Exception ex)
		{
			TraceMessage.Write(ToString(), "EXCEPTION: ScriptKernel.script_Exited() " + ex.ToString(), TraceMessageType.Trace);
			mutTest.ReleaseMutex();
		}
		TraceMessage.Write(ToString(), "EXIT: ScriptKernel.script_Exited()", TraceMessageType.Trace);
	}

	public void TimerDone(object state)
	{
		OnScriptSimulationData onScriptSimulationData = null;
		try
		{
			onScriptSimulationData = (OnScriptSimulationData)state;
			onScriptSimulationData.timer.Dispose();
			onScriptSimulationData.timer = null;
		}
		catch
		{
		}
		finally
		{
			if (onScriptSimulationData != null)
			{
				string testFullPath = onScriptSimulationData.Test.ScriptFullName;
				if (onScriptSimulationData.Test.ScriptProperties.DescriptiveName != "")
				{
					testFullPath = onScriptSimulationData.Test.ScriptProperties.DescriptiveName.Trim();
				}
				ScriptDone(testFullPath, 1, null);
			}
		}
	}

	private int ExitCode(int code)
	{
		if (code == -1)
		{
			return 2;
		}
		if (code < 0)
		{
			return 0;
		}
		return 1;
	}

	protected virtual void ScriptDone(string testFullPath, int testResult, object parameters)
	{
		TraceMessage.Write(ToString(), "ENTER: ScriptKernel.ScriptDone(" + testFullPath + ")", TraceMessageType.Trace);
		if (this.OnScriptDone != null)
		{
			this.OnScriptDone(testFullPath, testResult, parameters);
		}
		TraceMessage.Write(ToString(), "EXIT: ScriptKernel.ScriptDone(" + testFullPath + ")", TraceMessageType.Trace);
	}

	protected virtual void ScriptTextOut(string windowName, string windowText)
	{
		if (this.OnScriptTextOut != null && windowText.Trim() != "")
		{
			this.OnScriptTextOut(windowName, windowText);
		}
	}

	internal void CreateProperties(object objProperties)
	{
		try
		{
			properties = new Properties();
			object[] array = (object[])objProperties;
			properties.DescriptiveName = array[0].ToString();
			properties.TargetName = array[1].ToString();
			properties.RedirectStandardOutput = Convert.ToBoolean(array[2].ToString());
			properties.CreateNoWindow = Convert.ToBoolean(array[3].ToString());
			properties.UseShellExecute = Convert.ToBoolean(array[4].ToString());
			properties.Verb = array[5].ToString();
			properties.WorkingDirectory = array[6].ToString();
			properties.DebugWindowName = array[7].ToString();
			properties.ExitAfterStart = Convert.ToBoolean(array[8].ToString());
		}
		catch
		{
		}
	}

	private void UpdateParameters(Hashtable parameterTable)
	{
		foreach (Parameter parameter in parameters)
		{
			if (parameter.IOType == "Output" && parameterTable.ContainsKey(parameter.Name.ToUpper()))
			{
				parameter.Value = (string)parameterTable[parameter.Name.ToUpper()];
			}
		}
	}

	public bool LoadTestDLL(string testDLL, ref string listOfTests)
	{
		FileInfo fileInfo = new FileInfo(testDLL);
		listOfTests = fileInfo.Name + ",";
		return true;
	}

	public bool UnloadTestDLL(string TestDLL)
	{
		return true;
	}

	public bool CloseKernel()
	{
		try
		{
			pScript.Kill();
		}
		catch
		{
		}
		return true;
	}

	public static string GetNameFromFullPath(string fullPath)
	{
		string text = fullPath;
		try
		{
			string[] array = fullPath.Split('\\');
			string[] array2 = fullPath.Split('/');
			if (array.Length > 1)
			{
				text = array[array.Length - 1];
			}
			else if (array.Length == 1 && array2.Length == 1)
			{
				text = array[0];
			}
			else if (array2.Length > 1)
			{
				text = array2[array2.Length - 1];
			}
		}
		catch
		{
		}
		return text.Trim();
	}
}
