using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using QC.CTDS.DM.ApplicationsManager;
using QC.CTDS.DM.DataStructures.InputDataStructure;
using QC.QTMInterface;

namespace QC.DataminerController;

public class QsprOutputToDataminerInputDataBuilder : IDataminerInputDataBuilder
{
	private InputData inputDataGenerator;

	private Dictionary<string, QC.CTDS.DM.DataStructures.InputDataStructure.ParamInfo> parameterDict = new Dictionary<string, QC.CTDS.DM.DataStructures.InputDataStructure.ParamInfo>();

	private string currentTestName = "";

	private TestRunInfo currentTestRunInfo;

	private QC.CTDS.DM.DataStructures.InputDataStructure.TestInfo currentTestInfo;

	private string currentLoopString;

	private ConcurrentQueue<object> qsprMessageQueue = new ConcurrentQueue<object>();

	private Mutex _mutMessageQueue = new Mutex(initiallyOwned: false);

	private bool inInSuiteMode;

	private Dictionary<string, string> testNameMapper = new Dictionary<string, string>();

	private int runId;

	private string serialNumber = "";

	private bool initializedForRun;

	private int currentRunId;

	public bool IsInSuiteMode
	{
		get
		{
			return inInSuiteMode;
		}
		set
		{
			inInSuiteMode = value;
		}
	}

	public Dictionary<string, string> TestNameMapper
	{
		get
		{
			return testNameMapper;
		}
		set
		{
			testNameMapper = value;
		}
	}

	public void PopulateDMDataFromQSPRMessage(MsgData msgData)
	{
		qsprMessageQueue.Enqueue(msgData);
		DequeueQsprMessage();
	}

	private void DequeueQsprMessage()
	{
		_mutMessageQueue.WaitOne();
		if (qsprMessageQueue.Count > 0)
		{
			object result = null;
			if (qsprMessageQueue.TryDequeue(out result) && result != null)
			{
				if (result is MsgData)
				{
					ProcessQsprMessageData((MsgData)result);
				}
				else
				{
					Tuple<string, string, string, string, string, string, string> tuple = result as Tuple<string, string, string, string, string, string, string>;
					ProcessQsprGenericMessage(tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, tuple.Item5, tuple.Item6, tuple.Item7);
				}
			}
		}
		_mutMessageQueue.ReleaseMutex();
		if (qsprMessageQueue.Count > 0)
		{
			DequeueQsprMessage();
		}
	}

	private void ProcessQsprMessageData(MsgData msgData)
	{
		switch (msgData.msgType)
		{
		case TestMsgType.OnUnitStart:
			if (!initializedForRun)
			{
				InitializeInputData(msgData.TestFullPath);
			}
			break;
		case TestMsgType.OnStartOfDebugTesting:
			if (!initializedForRun)
			{
				InitializeInputData(msgData.TestFullPath);
			}
			break;
		case TestMsgType.OnUnitEnd:
			initializedForRun = false;
			break;
		case TestMsgType.OnEndOfDebugTesting:
			initializedForRun = false;
			break;
		case TestMsgType.OnAbort:
			initializedForRun = false;
			break;
		case TestMsgType.OnTestStart:
			if (!initializedForRun)
			{
				InitializeInputData();
			}
			if (!string.IsNullOrEmpty(msgData.ErrorCode))
			{
				currentTestName = msgData.ErrorCode;
			}
			currentLoopString = msgData.LoopDetails;
			break;
		case TestMsgType.OnTestResult:
		{
			if (msgData.ParamResult == null)
			{
				break;
			}
			ArrayList arrayList = (ArrayList)msgData.ParamResult;
			foreach (ParamValue item in arrayList)
			{
				for (int i = 0; i < item.Value.Count; i++)
				{
					if ((bool)item.EnabledDataLogging[i])
					{
						string paramName = ((item.Value.Count <= 1) ? item.ParamName : (item.ParamName + "_" + i));
						string lowerLimit = item.LL[i].ToString();
						string value = item.Value[i].ToString();
						string upperLimit = item.UL[i].ToString();
						string unit = item.Unit;
						if (item.IOType == IOType.Input)
						{
							AddInputParamToList(paramName, value, unit);
						}
						else if (item.IOType == IOType.Output)
						{
							AddOutputParamToList(paramName, value, lowerLimit, upperLimit, unit);
						}
					}
				}
			}
			if (!IsInSuiteMode && parameterDict.Count > 0)
			{
				AddLoopDetailsAsInputParams(currentLoopString);
				AddTestRun();
			}
			break;
		}
		}
	}

	private void InitializeInputData(string serialNumber = null)
	{
		if (runId == 0)
		{
			inputDataGenerator = new InputData();
		}
		UnitInformation unitInformation = new UnitInformation();
		if (!string.IsNullOrEmpty(serialNumber))
		{
			unitInformation.SerialNumber = serialNumber;
		}
		else
		{
			unitInformation.SerialNumber = "Unknown";
		}
		serialNumber = unitInformation.SerialNumber;
		unitInformation.UnitDataItemsDict.Add("test", "1");
		currentRunId = runId;
		runId++;
		inputDataGenerator.UnitInfoDict.Add(currentRunId, unitInformation);
		parameterDict.Clear();
		currentLoopString = null;
		initializedForRun = true;
	}

	private void AddLoopDetailsAsInputParams(string loopString)
	{
		Dictionary<string, string> dictionary = ParseLoopString(loopString);
		foreach (KeyValuePair<string, string> item in dictionary)
		{
			AddInputParamToList(item.Key, item.Value);
		}
	}

	private Dictionary<string, string> ParseLoopString(string loopString)
	{
		Dictionary<string, string> dictionary = new Dictionary<string, string>();
		if (!string.IsNullOrEmpty(loopString))
		{
			string[] array = loopString.Split(new string[1] { "_._" }, StringSplitOptions.RemoveEmptyEntries);
			if (array.Length > 0)
			{
				string[] array2 = array;
				foreach (string text in array2)
				{
					string[] array3 = text.Split(new string[1] { "_ _" }, StringSplitOptions.RemoveEmptyEntries);
					string[] array4 = array3;
					foreach (string text2 in array4)
					{
						string[] array5 = text2.Split(new string[1] { "__" }, StringSplitOptions.RemoveEmptyEntries);
						if (array5.Length == 2 && !dictionary.ContainsKey(array5[0]))
						{
							dictionary.Add(array5[0], array5[1]);
						}
					}
				}
			}
		}
		return dictionary;
	}

	private void AddTestRun()
	{
		if (parameterDict.Count > 0)
		{
			if (inputDataGenerator.TestInfoDict == null)
			{
				inputDataGenerator.TestInfoDict = new Dictionary<string, QC.CTDS.DM.DataStructures.InputDataStructure.TestInfo>();
			}
			if (inputDataGenerator.TestInfoDict.ContainsKey(currentTestName))
			{
				currentTestInfo = inputDataGenerator.TestInfoDict[currentTestName];
			}
			else
			{
				currentTestInfo = new QC.CTDS.DM.DataStructures.InputDataStructure.TestInfo();
				currentTestInfo.TestName = currentTestName;
				currentTestInfo.TestRunsList = new List<TestRunInfo>();
				inputDataGenerator.TestInfoDict.Add(currentTestName, currentTestInfo);
			}
			currentTestRunInfo = new TestRunInfo();
			currentTestRunInfo.UnitInfo = inputDataGenerator.UnitInfoDict[currentRunId];
			currentTestInfo.TestRunsList.Add(currentTestRunInfo);
			currentTestRunInfo.TestName = currentTestName;
			currentTestRunInfo.ParamsDict = parameterDict;
			currentTestRunInfo.ParamsDict.Add("RUN_ID", new QC.CTDS.DM.DataStructures.InputDataStructure.ParamInfo
			{
				StrVal = currentRunId.ToString()
			});
			currentTestRunInfo.ParamsDict.Add("UUT_ID", new QC.CTDS.DM.DataStructures.InputDataStructure.ParamInfo
			{
				StrVal = serialNumber
			});
			parameterDict = new Dictionary<string, QC.CTDS.DM.DataStructures.InputDataStructure.ParamInfo>();
		}
	}

	private void AddInputParamToList(string paramName, string value, string unit = null)
	{
		double result = double.NaN;
		QC.CTDS.DM.DataStructures.InputDataStructure.ParamInfo paramInfo = null;
		Dictionary<string, QC.CTDS.DM.DataStructures.InputDataStructure.ParamInfo> dictionary = parameterDict;
		if (dictionary.ContainsKey(paramName))
		{
			paramInfo = dictionary[paramName];
		}
		else
		{
			paramInfo = new QC.CTDS.DM.DataStructures.InputDataStructure.ParamInfo();
			dictionary.Add(paramName, paramInfo);
		}
		if (double.TryParse(value, out result))
		{
			paramInfo.Val = result;
		}
		else
		{
			paramInfo.StrVal = value;
		}
		if (!string.IsNullOrEmpty(unit))
		{
			paramInfo.ParamUnit = unit;
		}
	}

	private void AddOutputParamToList(string paramName, string value, string lowerLimit, string upperLimit, string unit = null)
	{
		double result = double.NaN;
		double result2 = double.NaN;
		double result3 = double.NaN;
		OutputParamInfo outputParamInfo = null;
		if (parameterDict.ContainsKey(paramName))
		{
			return;
		}
		outputParamInfo = new OutputParamInfo();
		parameterDict.Add(paramName, outputParamInfo);
		if (outputParamInfo != null)
		{
			if (double.TryParse(value, out result))
			{
				outputParamInfo.Val = result;
			}
			else
			{
				outputParamInfo.StrVal = value;
			}
			if (double.TryParse(lowerLimit, out result2))
			{
				outputParamInfo.MinLimit = result2;
			}
			if (double.TryParse(upperLimit, out result3))
			{
				outputParamInfo.MaxLimit = result3;
			}
			if (!string.IsNullOrEmpty(unit))
			{
				outputParamInfo.ParamUnit = unit;
			}
		}
	}

	private void ProcessQsprGenericMessage(string messageType, string id, string name, string value, string units, string lowerLimit, string upperLimit)
	{
		switch (messageType)
		{
		case "StartTest":
			if (!string.IsNullOrEmpty(name))
			{
				if (!string.IsNullOrWhiteSpace(value))
				{
					currentTestName = value;
				}
				else if (TestNameMapper.ContainsKey(name))
				{
					currentTestName = TestNameMapper[name];
				}
				else
				{
					currentTestName = name;
				}
			}
			break;
		case "TestResult":
			if (parameterDict.Count > 0)
			{
				AddLoopDetailsAsInputParams(currentLoopString);
				AddTestRun();
			}
			break;
		case "OutputParam":
			if (!string.IsNullOrEmpty(name))
			{
				if (lowerLimit == "-9999")
				{
					lowerLimit = null;
				}
				if (upperLimit == "9999")
				{
					upperLimit = null;
				}
				if (!parameterDict.ContainsKey(name))
				{
					AddOutputParamToList(name, value, lowerLimit, upperLimit, units);
					break;
				}
				AddLoopDetailsAsInputParams(currentLoopString);
				AddTestRun();
				AddLoopDetailsAsInputParams(currentLoopString);
				AddOutputParamToList(name, value, lowerLimit, upperLimit, units);
			}
			break;
		case "StartLoop":
			if (!string.IsNullOrEmpty(name))
			{
				AddInputParamToList(name, value, units);
			}
			break;
		}
	}

	public void PopulateDMDataFromQSPRGenericMessage(string messageType, string id, string name, string value, string units, string lowerLimit, string upperLimit)
	{
		qsprMessageQueue.Enqueue(new Tuple<string, string, string, string, string, string, string>(messageType, id, name, value, units, lowerLimit, upperLimit));
		DequeueQsprMessage();
	}

	public InputData GetDataminerInputData()
	{
		return inputDataGenerator;
	}

	public void SetReportGenerator(ReportGenerator dataminerReportGenerator)
	{
	}
}
