
//..
//..Gold Module - Example template ..
//..developed by GTS..
//..
//..Intel(R) Corporation (C) 2016
//..

//..includes
#include "Include/Main.h"

//..defines
#ifdef __WIN_OS__
#include <Windows.h>
#endif
#ifdef __LIN_OS__
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>
#endif

//..Read String Parts routine
bool bReadStringParts(string sDetected, string sExpected)
{
	//..clear vectors and string list before each compare
	vsBrandStringElements.clear();
	vsStringPartElements.clear();
	vsComparedStringElements.clear();
	vsNotComparedStringElements.clear();
	sComparedStringList = "";

	//..sDetected is BrandString retrieved from Processor
	SplitString(sDetected, vsBrandStringElements, cDelimiterSpace);
	//..sExpected is expected BrandString elements based upon *StringParts section in local config file
	SplitString(sExpected, vsStringPartElements, cDelimiterPipe);

	//..start vector compare loop of elements
	for (size_t i = 0; i < vsBrandStringElements.size(); i++)
	{
		for (size_t j = 0; j < vsStringPartElements.size(); j++)
		{
			if ((vsStringPartElements[j].compare(vsBrandStringElements[i]) == 0))
			{
				vsComparedStringElements.push_back(vsStringPartElements[j]);
				sComparedStringList += vsStringPartElements[j];
				sComparedStringList += " ";
			}
			else
			{
				vsNotComparedStringElements.push_back(vsStringPartElements[j]);
			}
		}
	}

	if (vsComparedStringElements.size() == vsStringPartElements.size())
	{
		if(iDebug == 1)
		{
			cout << "..vector sizes matched..!!.." << endl;
		}
		bCheckBrandString = true;		
	}
	else
	{
		if (iDebug == 1)
		{
			cout << "..vector sizes mis-matched..!!.." << endl;
		}
		bCheckBrandString = false;
	}

	if (iDebug == 1)
	{
		//..output vector lists & bool value of bCheckBrandString
		cout << endl << "..IN DEBUG.." << endl;
		cout << "..Output of vector vsBrandStringElements.." << endl;
		PrintVector(vsBrandStringElements);

		cout << "..Output of vector vsStringPartElements.." << endl;
		PrintVector(vsStringPartElements);

		cout << "..Output of vector vsComparedStringElements.." << endl;
		PrintVector(vsComparedStringElements);

		cout << "..Output of vector vsNOTComparedStringElements.." << endl;
		PrintVector(vsNotComparedStringElements);

		cout << endl << "..value of bCheckBrandString -> " << bCheckBrandString << endl;
	}
	return bCheckBrandString;	
}

//..Read Local Configurartion routine
void ReadLocalConfig(void)
{	
	XMLParser localXMLObj;
	try
	{
		//Local config
		int iCFE = td.checkFileExists(sBSLocalConfigFile);
		
		if (iCFE == 1)
		{
			localXMLObj.LoadXMLFile("BrandString_LocalConfig.xml");
		}
		else
		{
			if ((!bCheckBrandString) && (!bStringPartsFound))
			{
				igPassFailStatus = Fail;
				cout << endl << sBSLocalConfigFileMsg << endl;
				cout << sExitMsg << endl;
				WriteResultsFile(igPassFailStatus, sBrandValTrim, sBSLocalConfigFileMsg, sExitMsg);
				exit(1);
			}
		}
		
		if ((sBrandValTrim.length() < 1) || (sBrandValTrim.find(s3Hash) != string::npos))
		{
			igPassFailStatus = 1;
			sMsg = "Expected Production Released Processor";
			sMsg2 = "Possible Early Engineering Sample Processor Detected..!!..";
			WriteResultsFile(igPassFailStatus, sBrandValTrim, sMsg, sMsg2);
		}
		
		// Set up the root element
		localXMLObj.SetRootElem("BrandString_LocalConfig");

		string localStrItem = localXMLObj.ReadNodeKeyAsString("@BrandString_LocalConfig", "");		
		string localStrItemfam = localXMLObj.ReadNodeKeyAsString("@definitions", "");		
		sSampleStringParts = localXMLObj.ReadNodeKeyAsString("@SampleStringParts", "");
		sCoreStringParts = localXMLObj.ReadNodeKeyAsString("@CoreStringParts", "");
		sCoreEvoStringParts = localXMLObj.ReadNodeKeyAsString("@CoreEvoStringParts", "");
		sXeonStringParts = localXMLObj.ReadNodeKeyAsString("@XeonStringParts", "");
		sXeonPhiStringParts = localXMLObj.ReadNodeKeyAsString("@XeonPhiStringParts", "");
		sAtomStringParts = localXMLObj.ReadNodeKeyAsString("@AtomStringParts", "");
		sPentiumStringParts = localXMLObj.ReadNodeKeyAsString("@PentiumStringParts", "");
		sCeleronStringParts = localXMLObj.ReadNodeKeyAsString("@CeleronStringParts", "");
		
		//..Check for Sample String Parts
		bCheckBrandString = bReadStringParts(sBrandValTrim, sSampleStringParts);
		if (bCheckBrandString)
		{
			if (!bNoCompare)
			{
				igPassFailStatus = Fail;
				bStringPartsFound = true;
			}
			else
			{
				igPassFailStatus = NoCompare;
				bStringPartsFound = true;
			}

			sMsg = "Expected: " + sComparedStringList;
			sMsg2 = "Late Engineering Sample or Early QSpec Processor Detected..!!..";			
			
			if (bStringPartsFound)
			{
				WriteResultsFile(igPassFailStatus, sBrandValTrim, sMsg, sMsg2);
			}
		}

		//..Check for Core String Parts
		bCheckBrandString = bReadStringParts(sBrandValTrim, sCoreStringParts);
		if (bCheckBrandString)
		{
			if (!bNoCompare)
			{
				igPassFailStatus = Success;
				sMsg = "Expected: " + sComparedStringList;
				sMsg2 = "Intel(R) Core(TM) processor detected..!!..";
				bStringPartsFound = true;
			}
			else
			{
				igPassFailStatus = NoCompare;
				sMsg = "Expected: ";
				//sMsg2 = "";
				bStringPartsFound = true;
			}

			//sMsg = "Expected: " + sComparedStringList;
			//sMsg2 = "Intel(R) Core(TM) processor detected..!!..";			

			if (bStringPartsFound)
			{
				WriteResultsFile(igPassFailStatus, sBrandValTrim, sMsg, sMsg2);
			}			
		}

		//..Check for Core Evo String Parts
		bCheckBrandString = bReadStringParts(sBrandValTrim, sCoreEvoStringParts);
		if (bCheckBrandString)
		{
			if (!bNoCompare)
			{
				igPassFailStatus = Success;
				sMsg = "Expected: " + sComparedStringList;
				sMsg2 = "Intel(R) Core Evo(TM) processor detected..!!..";
				bStringPartsFound = true;
			}
			else
			{
				igPassFailStatus = NoCompare;
				sMsg = "Expected: ";
				//sMsg2 = "";
				bStringPartsFound = true;
			}

			//sMsg = "Expected: " + sComparedStringList;
			//sMsg2 = "Intel(R) Core Evo(TM) processor detected..!!..";			

			if (bStringPartsFound)
			{
				WriteResultsFile(igPassFailStatus, sBrandValTrim, sMsg, sMsg2);
			}
		}

		//..Check for Xeon String Parts
		bCheckBrandString = bReadStringParts(sBrandValTrim, sXeonStringParts);
		if (bCheckBrandString)
		{
			if (!bNoCompare)
			{
				igPassFailStatus = Success;
				bStringPartsFound = true;
			}
			else
			{
				igPassFailStatus = NoCompare;
				bStringPartsFound = true;
			}

			sMsg = "Expected: " + sComparedStringList;
			sMsg2 = "Intel(R) Xeon(R) processor detected..!!..";

			if (bStringPartsFound)
			{
				WriteResultsFile(igPassFailStatus, sBrandValTrim, sMsg, sMsg2);
			}
		}

		//..Check for Xeon Phi String Parts
		bCheckBrandString = bReadStringParts(sBrandValTrim, sXeonPhiStringParts);
		if (bCheckBrandString)
		{
			if (!bNoCompare)
			{
				igPassFailStatus = Success;
				bStringPartsFound = true;
			}
			else
			{
				igPassFailStatus = NoCompare;
				bStringPartsFound = true;
			}

			sMsg = "Expected: " + sComparedStringList;
			sMsg2 = "Intel(R) Xeon Phi(TM) processor detected..!!..";

			if (bStringPartsFound)
			{
				WriteResultsFile(igPassFailStatus, sBrandValTrim, sMsg, sMsg2);
			}
		}

		//..Check for Atom String Parts
		bCheckBrandString = bReadStringParts(sBrandValTrim, sAtomStringParts);
		if (bCheckBrandString)
		{
			if (!bNoCompare)
			{
				igPassFailStatus = Success;
				bStringPartsFound = true;
			}
			else
			{
				igPassFailStatus = NoCompare;
				bStringPartsFound = true;
			}
			sMsg = "Expected: " + sComparedStringList;
			sMsg2 = "Intel(R) Atom(TM) processor detected..!!..";

			if (bStringPartsFound)
			{
				WriteResultsFile(igPassFailStatus, sBrandValTrim, sMsg, sMsg2);
			}
		}

		//..Check for Pentium String Parts
		bCheckBrandString = bReadStringParts(sBrandValTrim, sPentiumStringParts);
		if (bCheckBrandString)
		{
			if (!bNoCompare)
			{
				igPassFailStatus = Success;
				bStringPartsFound = true;
			}
			else
			{
				igPassFailStatus = NoCompare;
				bStringPartsFound = true;
			}

			sMsg = "Expected: " + sComparedStringList;
			sMsg2 = "Intel(R) Pentium(R) processor detected..!!..";

			if (bStringPartsFound)
			{
				WriteResultsFile(igPassFailStatus, sBrandValTrim, sMsg, sMsg2);
			}
		}

		//..Check for Celeron String Parts
		bCheckBrandString = bReadStringParts(sBrandValTrim, sCeleronStringParts);
		if (bCheckBrandString)
		{
			if (!bNoCompare)
			{
				igPassFailStatus = Success;
				bStringPartsFound = true;
			}
			else
			{
				igPassFailStatus = NoCompare;
				bStringPartsFound = true;
			}

			sMsg = "Expected: " + sComparedStringList;
			sMsg2 = "Intel(R) Celeron(R) processor detected..!!..";

			if (bStringPartsFound)
			{
				WriteResultsFile(igPassFailStatus, sBrandValTrim, sMsg, sMsg2);
			}
		}

		if (!bStringPartsFound)
		{
			igPassFailStatus = Fail;
			sMsg = "..no valid string parts found..";
			sMsg2 = "String part compare error";
			WriteResultsFile(igPassFailStatus, sBrandValTrim, sMsg, sMsg2);
		}
	}
	catch (...)
	{
		std::string sException;
		sException.append("\n-------------------------------\n");
		sException.append("Cannot locate config file: 'BrandString_LocalConfig.xml'! \n");
		sException.append("Application terminated! \n");
		sException.append("\n-------------------------------\n");
		throw(sException);
	}
	return;
}

void Init(void)
{
	tStartTime = std::time(nullptr);
	if (iDebugFlag)
	{
		std::string sTemp = std::asctime(std::localtime(&tStartTime));
		std::cout << "tStartTime = " << sTemp << std::endl;
	}
	// xd.LoadXMLFile("GlobalConfig.xml");	

	// Logic needs to be done to determine if this test is a pass or fail.  
	//If indeterminate, it means that the test was interrupted
	igPassFailStatus = ReturnValueDef::Success;  // Success
	//igPassFailStatus = 1;  // Fail
	//igPassFailStatus = 2;  // Indeterminate 
	iColorText = 0;
	iSec = 0;
	iMin = 0;
	iHour = 0;
	iOptionValid = 0;
	iRun = 1;
	iArgIndex = 0;
	iPrintVersionFlag = 1;
	iPrintSuccessFlag = 1;
}

void PrintVersion(void)
{
	if (iPrintVersionFlag == 1)
	{
		std::cout << std::endl << "--- Brand String Test ---" << std::endl << "..." << std::endl << "Version: " << sgGoldModuleVersion << std::endl << "..." << std::endl << std::endl;
	}
}

void SignalFun(int iSigNum)
{
	// If you want to print out the signal, do the following
	cout << "Signal is:" << iSigNum << endl;

	// Depending on your routine, you may want to have some sort of exit message ... however you may also want to comment these out
	cout << endl << "Do the soft clean up here" << endl;
	
	// Do cleanup and close up stuff here 
	CleanUp();

	// Exit the program with one of the accepted error levels. 
	//0 = Success
	//1 = Fail
	//2 = Indeterminate 
	igPassFailStatus = ReturnValueDef::Indeterminate;

    // if you get to this logic, most likely your answer should always be a 2
	std::string sTemp = "Error: " + UtilConvert(igPassFailStatus) + " Indeterminate!";
	PrintColorMsg(sTemp, TextColor::Yellow);
	exit(igPassFailStatus);
}

void CleanUp()
{
	td.RemoveFile(sgGoldModuleResultsFile);
}

void WriteResultsFile(int iPassFailStatus, string sBV, string sMessage, string sMessage2)
{
	// pass fail logic using iPassFailStatus  with 0=pass, 1=fail, 2=indeterminate

	// Write Results File
	//cout << "sExpectedString here is: " << sExpectedString << endl;
	td.WriteToFile(sgGoldModuleResultsFile, "CPU Brand String Test");	//test module name
	std::string sTemp = "Module Version: " + sgGoldModuleVersion;
	td.WriteToFile(sgGoldModuleResultsFile, sTemp);
	sTemp = "Start Time: ";
	sTemp.append(std::asctime(std::localtime(&tStartTime)));
	td.WriteToFileNoEndL(sgGoldModuleResultsFile, sTemp);

	if (iPassFailStatus == Success)
	{
		td.WriteToFile(sgGoldModuleResultsFile, "Test Result - PASS ");	//pass
		//td.WriteToFile(sgGoldModuleResultsFile, "Expected String Parts: " + sExpectedString);
		//td.WriteToFile(sgGoldModuleResultsFile, "Expected String Parts: As Defined in BrandString_LocalConfig.xml" );
		td.WriteToFile(sgGoldModuleResultsFile, sMessage);
		td.WriteToFile(sgGoldModuleResultsFile, "Detected: " + sBV);
		td.WriteToFile(sgGoldModuleResultsFile, sMessage2);
	}

	if (iPassFailStatus == Fail)
	{
		td.WriteToFile(sgGoldModuleResultsFile, "Test Result - FAIL");	//fail
		//td.WriteToFile(sgGoldModuleResultsFile, "Expected String Parts: " + sExpectedString);
		//td.WriteToFile(sgGoldModuleResultsFile, "Expected String Parts: As Defined in BrandString_LocalConfig.xml");
		td.WriteToFile(sgGoldModuleResultsFile, sMessage);
		td.WriteToFile(sgGoldModuleResultsFile, "Detected: " + sBV);
		td.WriteToFile(sgGoldModuleResultsFile, sMessage2);		
	}

	if (iPassFailStatus == Indeterminate)
	{
		td.WriteToFile(sgGoldModuleResultsFile, "Test Result - Indeterminate"); //aborted
	}

	if (iPassFailStatus == NoCompare)
	{
		td.WriteToFile(sgGoldModuleResultsFile, "Test Result - NO COMPARE"); //-nc option used
		td.WriteToFile(sgGoldModuleResultsFile, sMessage);
		td.WriteToFile(sgGoldModuleResultsFile, "Detected: " + sBV);
		//td.WriteToFile(sgGoldModuleResultsFile, sMessage2); //..not needed if NoCompare is used.. adds an exta line to results file
	}

	if (igPauseApp)
	{
		PauseWQuit();
	}

	tEndTime = std::time(nullptr);
	sTemp = "End Time: ";
	sTemp.append(std::asctime(std::localtime(&tEndTime)));
	td.WriteToFileNoEndL(sgGoldModuleResultsFile, sTemp);

	double seconds = difftime(tEndTime, tStartTime);
	sTemp = "Total Time: ";
	sTemp.append(" seconds: ");
	sTemp.append(UtilConvert(seconds));
	
	td.WriteToFileNoEndL(sgGoldModuleResultsFile, sTemp);
}

void HelpUseage(void)
{
	std::cout << "Test Information:" << std::endl;
	std::cout << " BrandString.exe reads the brand string parts from the CPU" << std::endl;
	std::cout << " and compares them against parts defined in the configuration" << std::endl;
	std::cout << " file \"BrandString_LocalConfig.xml\".  If all expected parts" << std::endl;
	std::cout << " from the configuration file are found in the parts read from " << std::endl;
	std::cout << " the CPU, the test will pass." << std::endl << std::endl;
	std::cout << "Possible options are as follows:" << std::endl;
	std::cout << " -h          = Help or Usage (this message)" << std::endl;
	std::cout << "               Example:" << std::endl;
	std::cout << "               BrandString.exe -h" << std::endl << std::endl;
	std::cout << " -info       = Information switch publishes parallel information" << std::endl;
	std::cout << "               using the following scheme:" << std::endl;
	std::cout << "               \"parallel:yes|socket:yes|core:yes\"" << std::endl;
	std::cout << "               Example:" << std::endl;
	std::cout << "               BrandString.exe -info" << std::endl << std::endl;
	std::cout << " -resultName = The resultName switch provides a way to name " << std::endl;
	std::cout << "               the results file as desired." << std::endl;
	std::cout << "               This is for the convenience of the control program. " << std::endl;	
	std::cout << "               Example:" << std::endl;
	std::cout << "               BrandString.exe -resultName BrandString_results_01.txt " << std::endl << std::endl;
	std::cout << " -c          = If present, this option will display text in various colors" << std::endl;
	std::cout << "               Example:" << std::endl;
	std::cout << "               BrandString.exe -c" << std::endl << std::endl;

	std::cout << "Dependencies:" << std::endl;
	std::cout << "               BrandString_LocalConfig.xml" << std::endl << std::endl;
	std::cout << std::endl << "Copyright (C) 2016, Intel Corporation" << std::endl;
}

void PauseWQuit(void)
{
	// Pause code
	std::cout << "Please press 'q' <ENTER> to quit: ";
	std::string PauseStr;
	std::cin >> PauseStr;
}

// begin of assembly code
std::string getCPUBrandString()
{
	__asm
	{
		//Get First Part of the Brand String
		mov EAX, 0x80000002
			CPUID

			//Get all byte stored in EAX
			mov sCPUname[0], al
			mov sCPUname[1], ah
			shr EAX, 16
			mov sCPUname[2], al
			mov sCPUname[3], ah

			//Get all byte stored in EBX
			mov sCPUname[4], bl
			mov sCPUname[5], bh
			shr EBX, 16
			mov sCPUname[6], bl
			mov sCPUname[7], bh

			//Get all byte stored in ECX
			mov sCPUname[8], cl
			mov sCPUname[9], ch
			shr ECX, 16
			mov sCPUname[10], cl
			mov sCPUname[11], ch

			//Get all byte stored in EDX
			mov sCPUname[12], dl
			mov sCPUname[13], dh
			shr EDX, 16
			mov sCPUname[14], dl
			mov sCPUname[15], dh

			//Get Second Part of the Brand String
			mov EAX, 0x80000003
			CPUID

			//Get all byte stored in EAX
			mov sCPUname[16], al
			mov sCPUname[17], ah
			shr EAX, 16
			mov sCPUname[18], al
			mov sCPUname[19], ah

			//Get all byte stored in EBX
			mov sCPUname[20], bl
			mov sCPUname[21], bh
			shr EBX, 16
			mov sCPUname[22], bl
			mov sCPUname[23], bh

			//Get all byte stored in ECX
			mov sCPUname[24], cl
			mov sCPUname[25], ch
			shr ECX, 16
			mov sCPUname[26], cl
			mov sCPUname[27], ch

			//Get all byte stored in EDX
			mov sCPUname[28], dl
			mov sCPUname[29], dh
			shr EDX, 16
			mov sCPUname[30], dl
			mov sCPUname[31], dh

			//Get Third Part of the Brand String
			mov EAX, 0x80000004
			CPUID

			//Get all byte stored in EAX
			mov sCPUname[32], al
			mov sCPUname[33], ah
			shr EAX, 16
			mov sCPUname[34], al
			mov sCPUname[35], ah

			//Get all byte stored in EBX
			mov sCPUname[36], bl
			mov sCPUname[37], bh
			shr EBX, 16
			mov sCPUname[38], bl
			mov sCPUname[39], bh

			//Get all byte stored in ECX
			mov sCPUname[40], cl
			mov sCPUname[41], ch
			shr ECX, 16
			mov sCPUname[42], cl
			mov sCPUname[43], ch

			//Get all byte stored in EDX
			mov sCPUname[44], dl
			mov sCPUname[45], dh
			shr EDX, 16
			mov sCPUname[46], dl
			mov sCPUname[47], dh
	}
	sBS.assign(sCPUname);
	//sBS = "Genuine Intel(R) CPU 0000 @ 0.00GHz";
	//sBS = "###";
	return sBS;
}
// end of assembly code

//..Print Vector routine
void PrintVector(vector<string> & vs)
{
	//cout << endl << "..in Print Vector .." << endl;
	for (size_t i = 0; i<vs.size(); i++)
	{
		cout << vs[i] << endl;
	}
	cout << endl;
}

//..Print Color Message routine
void PrintColorMsg(std::string sMsg, TextColor iColor)
{
	if (iColorText == 0)
	{
		std::cout << std::endl << sMsg << std::endl;
	}
	else
	{
		if (iColor == TextColor::Red)
		{
#ifdef __WIN_OS__
			HANDLE hCommandWindowTextColor = GetStdHandle(STD_OUTPUT_HANDLE);
			SetConsoleTextAttribute(hCommandWindowTextColor, (FOREGROUND_RED | FOREGROUND_INTENSITY));
			std::cout << std::endl << sMsg << std::endl;
			SetConsoleTextAttribute(hCommandWindowTextColor, (FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN));
#endif
#ifdef __LIN_OS__
			std::cout << "\033[0;31m";
			std::cout << std::endl << sMsg << std::endl;
			std::cout << "\033[0m";
#endif
		}
		if (iColor == TextColor::Green)
		{

#ifdef __WIN_OS__
			HANDLE hCommandWindowTextColor = GetStdHandle(STD_OUTPUT_HANDLE);
			SetConsoleTextAttribute(hCommandWindowTextColor, (FOREGROUND_GREEN | FOREGROUND_INTENSITY));
			std::cout << std::endl << sMsg << std::endl;
			SetConsoleTextAttribute(hCommandWindowTextColor, (FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN));
#endif
#ifdef __LIN_OS__
			std::cout << "\033[0;32m";
			std::cout << std::endl << sMsg << std::endl;
			std::cout << "\033[0m";
#endif
		}
		if (iColor == TextColor::Yellow)
		{
#ifdef __WIN_OS__
			HANDLE hCommandWindowTextColor = GetStdHandle(STD_OUTPUT_HANDLE);
			SetConsoleTextAttribute(hCommandWindowTextColor, (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY));
			std::cout << std::endl << sMsg << std::endl;
			SetConsoleTextAttribute(hCommandWindowTextColor, (FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN));
#endif
#ifdef __LIN_OS__
			std::cout << "\033[0;33m";
			std::cout << std::endl << sMsg << std::endl;
			std::cout << "\033[0m";
#endif
		}
	}
}

bool is_integer(const std::string & s)
{
	return std::regex_match(s, std::regex("[0-9]+"));
}

//..Validate Options routine
bool isOptionValid(int iArgLocal, int argcLocal, char *argvLocal[], VarType vt)
{
	// Start out as Valid
	bool iRetVal = true;
	//std::string sMsg = "";
	std::string sTemp = argvLocal[iArgLocal];

	if (((iArgLocal + 1) < argcLocal) && strlen(argvLocal[iArgLocal + 1]) > 0)
	{
		if (vt == VarType::vtINT)
		{
			if (!is_integer(argvLocal[iArgLocal + 1]))
			{
				iRetVal = false;
				sMsg = "Wrong argument type format for argument: '" + sTemp + "'!";
			}
		}
	}
	else
	{
		// invalid
		iRetVal = false;
		sMsg = "No argument for '" + sTemp + "' detected!";
	}

	// if there was an invalid argument
	if (iRetVal == false)
	{
		PrintColorMsg(sMsg, TextColor::Red);
	}
	return iRetVal;
}

//..Parse the arguments
void handleArgs(int argc, char *argv[])
{
	// Optional args
	// Make sure the options can only be run one time
	// Load up all the possible args
	std::vector <string> sArgs_v;
	sArgs_v.push_back("-h");
	sArgs_v.push_back("-info");
	sArgs_v.push_back("-resultName");
	sArgs_v.push_back("-c");
	//..option -nc & -d not to be published in any documentation..
	sArgs_v.push_back("-nc");
	sArgs_v.push_back("-d");
	
	if (argc > 1)
	{
		for (int iArg = 1; iArg < argc; iArg++)
		{
			for (int iVec = 0; iVec < sArgs_v.size(); iVec++)
			{
				if (argv[iArg] == sArgs_v[iVec])
				{
					// Only the options that need to be processed before all the other ones need to be in this list
					if (sArgs_v[iVec] == std::string("-c"))
					{
						iColorText = 1;
					}
				}
			}
		}
		for (int iArg = 1; iArg < argc; iArg++)
		{
			iArgIndex = iArg;
			iOptionValid = 0;
			for (int iVec = 0; iVec < sArgs_v.size(); iVec++)
			{
				if (argv[iArg] == sArgs_v[iVec])
				{
					iOptionValid = 1;

					if (sArgs_v[iVec] == std::string("-h"))
					{
						iRun = 0;
						HelpUseage();
					}

					if (sArgs_v[iVec] == std::string("-info"))
					{
						iRun = 0;
						iPrintVersionFlag = 0;
						iPrintSuccessFlag = 0;
						std::cout << "\"parallel:yes|socket:yes|core:yes\"" << std::endl;
					}

					if (sArgs_v[iVec] == std::string("-resultName"))
					{
						sgGoldModuleResultsFile = argv[++iArg];
					}					
										
					if (sArgs_v[iVec] == std::string("-nc"))
					{
						bNoCompare = true;
						igPassFailStatus = 3; //pass
						std::cout << sMsg << endl;
					}

					if (sArgs_v[iVec] == std::string("-d"))
					{
						iDebug = 1;
					}
					
					if (sArgs_v[iVec] == std::string("-c"))
					{
						//std::cout << std::endl << "Entering color text opt" << std::endl;
						//PrintVersion();
					#ifdef __WIN_OS__
						HANDLE hCommandWindowTextColor = GetStdHandle(STD_OUTPUT_HANDLE);
						SetConsoleTextAttribute(hCommandWindowTextColor, (FOREGROUND_GREEN | FOREGROUND_INTENSITY));
						//std::cout << "Some green text ..." << std::endl << std::endl;
						SetConsoleTextAttribute(hCommandWindowTextColor, (FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN));
					#endif
					#ifdef __LIN_OS__
						std::cout << "\033[1;32m";
						//std::cout << std::endl << ".." << std::endl << "Some green text ..." << std::endl << std::endl;
						std::cout << "\033[0m";
					#endif

						if (igPassFailStatus == 0)
						{
							sMsg = "Brand String Test Passed!!!";
						}
						else
						{
							sMsg = "Brand String Test Failed!!!";
						}
					}

					// Erase current vector so the option doesn't repeat
					sArgs_v.erase(sArgs_v.begin() + (iVec));
				}
			}
			
			if (iOptionValid == 0)
			{
				break;
			}
		}

		if (iOptionValid == 0)
		{
			std::string sArgTemp = argv[iArgIndex];
			std::string sTempMsg = "Option " + sArgTemp + " invalid!\n";
			PrintColorMsg(sTempMsg, TextColor::Red);
			iRun = 0;
			igPassFailStatus = ReturnValueDef::InvalidArgs;
			HelpUseage();
		}
	}
	//else
	//{
		// Default message if no arguments are used  ... it may be the useage message or it may be OK that no args are used
		//std::cout << "No args used!!" << std::endl;
		//PrintVersion();
	//}
}

//..Print Success routine
void PrintSuccess(void)
{
	if (iRun)
	{
		if (igPassFailStatus == ReturnValueDef::Success)
		{
			PrintColorMsg("Brand String Module Success..!!..", TextColor::Green);
		}

		if (igPassFailStatus == ReturnValueDef::Fail)
		{
			PrintColorMsg("Brand String Module Fail..!!..", TextColor::Red);
		}

		if (igPassFailStatus == ReturnValueDef::Indeterminate)
		{
			PrintColorMsg("Brand String Module Interrupted..!!..", TextColor::Yellow);
		}

		if (igPassFailStatus == ReturnValueDef::NoCompare)
		{
			PrintColorMsg("Brand String executed with No Compare Option..!!..", TextColor::Yellow);
		}

		if (igPassFailStatus == ReturnValueDef::InvalidArgs)
		{
			PrintColorMsg("Brand String Module has invalid arguments..!!..", TextColor::Red);
		}

		if (igPassFailStatus == ReturnValueDef::ConfigMismatch)
		{
			PrintColorMsg("Brand String Module has a configuration mismatch..!!..", TextColor::Yellow);
		}

		if (iDebug == 1)
		{
			if (igPassFailStatus != ReturnValueDef::Success)
			{
				cout << "Return Status = " << igPassFailStatus << endl;
			}
		}
	}
}

//..main
int main(int argc, char *argv[])
{
	// .W // windows 
#if defined __WIN_64__ 
	sgGoldModuleVersion = "1.0.20.64b.W";
#endif

#if defined __WIN_32__ 
	sgGoldModuleVersion = "1.0.20.32b.W";
#endif

	// .L linux
#if defined __LIN_64__
	sgGoldModuleVersion = "1.0.20.64b.L";
#endif
#if defined __LIN_32__
	sgGoldModuleVersion = "1.0.20.32b.L";
#endif

	// Need to include signal for Softkill functions
	// If this thread is sent a signal SIGINT, we need to send it to the signal function 
	signal(SIGINT, SignalFun);
		
	Init();

	handleArgs(argc, argv);

	// Output version
	if (iPrintVersionFlag != 0)
	{
		PrintVersion();
	}
		
	//..clean up result files ... Clean file before another one is written
	CleanUp();
	
	if (iRun)
	{		
		sBrandVal = getCPUBrandString();
		
		sBrandValTrim = trim(sBrandVal, sDelimiterSpace);
		cout << sBrandValTrim << endl;
		ReadLocalConfig();
	}
	
	if (iPrintSuccessFlag != 0)
	{
		PrintSuccess();
	}
	
	return igPassFailStatus;
}
