
//..
//..Cache Module ..
//..developed by GTS..
//..
//..Intel(R) Corporation (C) 2015
//..

//..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


void Run_Cache()
{
	// - Tolerance set to .0005 - Tolerance needs to be a very small number for Cache Size 
	// or any other Cache Size as Detected Size is Expected S ize.

	std::cout << std::endl << " --- Reading Cache Size --- " << std::endl << std::endl;
	strPFOut.append("\n --- Reading Cache Size ---  \n\n");
	unsigned long L[8] = { 0, 0, 0, 0, 1, 1, 1, 0xAA }; //=0xAA if cache is not supported.

	Cachetest(L);					//load array. - if unsupported, all will remain 0

	//std::cout << std::endl << "Cachetest(L)" << std::endl << std::endl;
	//std::cout << std::endl << "L[0] --> " << L[0] << std::endl;
	//std::cout << std::endl << "L[1] --> " << L[1] << std::endl;
	//std::cout << std::endl << "L[2] --> " << L[2] << std::endl;
	//std::cout << std::endl << "L[3] --> " << L[3] << std::endl;
	//std::cout << std::endl << "L[4] --> " << L[4] << std::endl;
	//std::cout << std::endl << "L[5] --> " << L[5] << std::endl;
	//std::cout << std::endl << "L[6] --> " << L[6] << std::endl;
	//std::cout << std::endl << "L[7] --> " << L[7] << std::endl;

	unsigned long dwExpectedL2;
	unsigned long dwExpectedL3;
	//unsigned long L2cache = L[2] * L[5];
	//unsigned long L3cache = L[3] * L[6];   //total cache amount = size x Multiplier.
	unsigned long L2cache = L[2];
	unsigned long L3cache = L[3];   //total cache amount = size x Multiplier.
	dwExpectedL3 = L3cache;
	dwExpectedL2 = L2cache;

	//printf ("L[7] = %X\n", L[7]);
	if (L[7] != 0xAA) //AA = unsupported, anything else = supported
	{

		//std::cout << " - Detected L1 Data Cache Size --> " << L[4] << " x " << L[0] << "\n";   //display L1 cache info.
		//std::cout << " - Detected L1 Inst Cache Size --> " << L[4] << " x " << L[1] << "\n";
		std::cout << " - Detected L1 Data Cache Size --> " << L[0] << "\n";   //display L1 cache info.
		std::cout << " - Detected L1 Inst Cache Size --> " << L[1] << "\n";
		//Add L1 data to .txt file.
		//strPFOut.append("- Detected L1 Data Cache Size --> " + UtilConvert((int)L[4]) + " x " + UtilConvert((int)L[0]) + "\n");
		//strPFOut.append("- Detected L1 Inst Cache Size --> " + UtilConvert((int)L[4]) + " x " + UtilConvert((int)L[1]) + "\n\n");
		strPFOut.append("- Detected L1 Data Cache Size --> " + UtilConvert((int)L[0]) + "\n");
		strPFOut.append("- Detected L1 Inst Cache Size --> " + UtilConvert((int)L[1]) + "\n\n");

		if (L[2] == 0){
			std::cout << " - Detected L2 Cache Size --> Not detected.\n";
			strPFOut.append("- Detected L2 Cache Size --> Not detected.\n");
		}
		else
		{
			std::cout << " - Detected L2 Cache Size --> " << L2cache << std::endl;
			strPFOut.append("- Detected L2 Cache Size --> " + UtilConvert((int)L2cache) + "\n");
		}

		if (L[3] == 0){
			std::cout << " - Detected L3 Cache Size --> Not detected.\n";
			strPFOut.append("- Detected L3 Cache Size --> Not Detected.\n");
		}
		else
		{
			std::cout << " - Detected L3 Cache Size --> " << L3cache << std::endl;
			strPFOut.append("- Detected L3 Cache Size --> " + UtilConvert((int)L3cache) + "\n");
		}


		if ((L3cache == dwExpectedL3) && (L2cache == dwExpectedL2))   //.
		{
			//PrintColorMsg("Cache Size Test Passed!!!", TextColor::Green);

			//std::cout << std::endl << "Cache Size Test Passed!!!" << std::endl << std::endl;
			strPFOut.append("\nCache Size Test Passed!!!\n");
			igPassFailStatus = 0;
		}
		else
		{
			//PrintColorMsg("Cache Size Test Failed!!!", TextColor::Red);
			//std::cout << std::endl << "Cache Size Test Failed!!!" << std::endl << std::endl;
			strPFOut.append("\nCache Size Test Failed!!!\n");
			igPassFailStatus = 1;
		}

	}
	else {
		PrintColorMsg("Cache test not supported on this model processor", TextColor::Yellow);
		//std::cout << "Cache test not supported on this model processor.\n";
		strPFOut.append("Cache Test not supported on this model processor.\n");
		igPassFailStatus = 0;
	}


}

void Cachetest(unsigned long *LSIZE)
{

#if defined __WIN_64__ || defined __LIN_64__
	unsigned long long ULEAX = 0;
	unsigned long long ULEBX = 0;
	unsigned long long ULECX = 0;
	unsigned long long ULEDX = 0;
	unsigned long long ULXFRC = 0;
	unsigned long long ULorgEBX = 0;
	unsigned long long ULorgEAX = 0;
	unsigned long long ULorgECX = 0;
	unsigned long long ULLtype = 0;
	unsigned long long ULWASS = 0;
	unsigned long long ULLogIDs = 0;

	unsigned long long ULLS = 0;
	unsigned long long ULcores = 0;
	unsigned long long ULThred = 0;
	unsigned long long ULTYPE = 0;
	unsigned long long ULPLP = 0;
	unsigned long long ULCSIZE = 0;
	unsigned long long Avail = 0;
#endif

#if defined __WIN_32__ || defined __LIN_32__
	unsigned long ULEAX = 0;
	unsigned long ULEBX = 0;
	unsigned long ULECX = 0;
	unsigned long ULEDX = 0;
	unsigned long ULXFRC = 0;
	unsigned long ULorgEBX = 0;
	unsigned long ULorgEAX = 0;
	unsigned long ULorgECX = 0;
	unsigned long ULLtype = 0;
	unsigned long ULWASS = 0;
	unsigned long ULLogIDs = 0;

	unsigned long ULLS = 0;
	unsigned long ULcores = 0;
	unsigned long ULThred = 0;
	unsigned long ULTYPE = 0;
	unsigned long ULPLP = 0;
	unsigned long ULCSIZE = 0;
	unsigned long Avail = 0;
#endif


	//Check if CPUID with eax=04 or > is available, if not, don't bother.
#if defined __WIN_64__ || defined __LIN_64__
	__asm
	{
		//.. updated eax to rax for 64bit support
		mov rax, 0
			CPUID
			mov Avail, rax
	}
#endif

#if defined __WIN_32__ || defined __LIN_32__
	__asm {		//Check if CPUID with eax=04 or > is available, if not, don't bother.
		mov eax, 0
			CPUID
			mov Avail, eax
	}
#endif

	//printf("Max EAX value for CPUID function = %X \n",Avail); //testing	

	if (Avail >= 0x4)
	{
		LSIZE[7] = 0xBB;   //cache is supported so change flag to anything but 0xAA

#if defined __WIN_64__ || defined __LIN_64__
		__asm
		{
			//.. updated registers to support 64bit			
			mov rax, 0x4
				mov rcx, 0
				CPUID
				mov ULorgEAX, rax
				and rax, 0xfc000000
				shr rax, 26
				add rax, 1			//eax+1 = # of cores
				mov ULcores, rax
				mov rax, ULorgEAX
				and rax, 0x03FFC000   //25:14
				shr rax, 14
				add rax, 1				//+1 = result
				mov ULThred, rax
				mov rcx, 0
				mov rax, 0x1
				CPUID
				and rbx, 0xFF0000
				shr rbx, 16
				mov ULLogIDs, rbx
		}
#endif

#if defined __WIN_32__ || defined __LIN_32__
		__asm
		{
			mov eax, 0x4
				mov ecx, 0
				CPUID
				mov ULorgEAX, eax
				and eax, 0xfc000000
				shr eax, 26
				add eax, 1			//eax+1 = # of cores
				mov ULcores, eax
				mov eax, ULorgEAX
				and eax, 0x03FFC000   //25:14
				shr eax, 14
				add eax, 1				//+1 = result
				mov ULThred, eax
				mov ecx, 0
				mov eax, 0x1
				CPUID
				and ebx, 0xFF0000
				shr ebx, 16
				mov ULLogIDs, ebx
		}
#endif


		if ((ULLogIDs == 2) && (ULcores == 1) && (ULThred == 2))   //atom processor 
		{
			LSIZE[4] = 1;
			LSIZE[6] = 1;
			LSIZE[5] = 1;

		}

		if ((ULLogIDs == 2) && (ULcores == 2) && (ULThred == 1))	//Core2Duo & Pentium DC
		{
			LSIZE[4] = 2;
			LSIZE[6] = 1;
			LSIZE[5] = 1;
		}

		if ((ULLogIDs == 4) && (ULcores == 4) && (ULThred == 1))	//Core2Quad
		{
			LSIZE[4] = 4;
			LSIZE[6] = 1;
			LSIZE[5] = 2;
		}

		if ((ULLogIDs == 16) && (ULcores == 8) && (ULThred == 2))	//Core I7
		{
			LSIZE[4] = 4;
			LSIZE[6] = 1;
			LSIZE[5] = 4;  //L2 multiplier
		}

		if ((ULLogIDs == 4) && (ULcores == 2) && (ULThred == 2))	//Pentium EX
		{
			LSIZE[4] = 2;
			LSIZE[6] = 1;
			LSIZE[5] = 2;
		}
		if ((ULLogIDs == 8) && (ULcores == 8) && (ULThred == 1))	//Xeon 7400
		{
			LSIZE[4] = 1; //L1 Multiplier
			LSIZE[6] = 1;  //L3 Multiplier
			LSIZE[5] = 3; //L2 multiplier
		}

		//std::cout << std::endl << "ULLogIDs ---> " << ULLogIDs << std::endl;
		//std::cout << "ULcores ---> " << ULcores << std::endl;
		//std::cout << "ULThred ---> " << ULThred << std::endl;


		ULXFRC = 0;
		ULorgEAX = 1;   //non 0 to start loop

		while (ULorgEAX > 0)
		{
			//ULLtype=CacheI();
			//std::cout << std::endl << ".ULorgEAX --> " << ULorgEAX << std::endl << std::endl;

#if defined __WIN_64__ || defined __LIN_64__
			__asm
			{
				mov rcx, ULXFRC;
				mov rax, 0x4;    //;CPUID 
				CPUID                 //;
					mov ULorgEBX, rbx
					mov ULorgEAX, rax
					mov ULorgECX, rcx

					and rax, 0xE0		//mask bits 7:5 for cache level type.
					shr rax, 5			//shift bits 7:5 over
					mov ULLtype, rax

					and rbx, 0xffc00000  //EBX 31:22 = ways of associativity +1
					shr rbx, 22
					mov ULWASS, rbx

					mov rbx, ULorgEBX
					and rbx, 0x3FF000   //EBX 21:12 = physical line partitions +1
					shr rbx, 12
					mov ULPLP, rbx

					mov rbx, ULorgEBX
					and rbx, 0xfff			//ebx 11:0 = System coherency line size+1
					mov ULLS, rbx

					mov rax, ULorgEAX
					and rax, 0x01F		//mask bits 4:0, unified, instruction, data,...
					mov ULTYPE, rax
			}
#endif

#if defined __WIN_32__ || defined __LIN_32__
			__asm
			{
				mov ecx, ULXFRC;
				mov eax, 0x4;    //;CPUID 
				CPUID                 //;
					mov ULorgEBX, ebx
					mov ULorgEAX, eax
					mov ULorgECX, ecx

					and eax, 0xE0		//mask bits 7:5 for cache level type.
					shr eax, 5			//shift bits 7:5 over
					mov ULLtype, eax

					and ebx, 0xffc00000  //EBX 31:22 = ways of associativity +1
					shr ebx, 22
					mov ULWASS, ebx

					mov ebx, ULorgEBX
					and ebx, 0x3FF000   //EBX 21:12 = physical line partitions +1
					shr ebx, 12
					mov ULPLP, ebx

					mov ebx, ULorgEBX
					and ebx, 0xfff			//ebx 11:0 = System coherency line size+1
					mov ULLS, ebx

					mov eax, ULorgEAX
					and eax, 0x01F		//mask bits 4:0, unified, instruction, data,...
					mov ULTYPE, eax

			}
#endif

			if ((ULLtype == 1) || (ULLtype == 3) || (ULLtype == 2))		//||(ULLtype == 2) || (ULLtype == 1)|| can test individually
			{
				//printf("Cache Type: L%X",ULLtype);
				//if (ULTYPE==1){printf(" Data: ");}
				//if (ULTYPE==2) {printf(" Instr:");}
				//if (ULTYPE==3) {printf(" Unified:");}
				ULCSIZE = ((ULWASS + 1)*(ULPLP + 1)*(ULLS + 1)*(ULorgECX + 1)) / 1024;
				if (ULLtype == 1 && ULTYPE == 1)
				{//printf(" Size = %d X %d\n\n",LSIZE[4],ULCSIZE);
					LSIZE[0] = ULCSIZE;								//LSIZE[0]=L1 Data size
				}
				if (ULLtype == 1 && ULTYPE == 2)
				{//printf(" Size = %d X %d\n\n",LSIZE[4],ULCSIZE);
					LSIZE[1] = ULCSIZE;								//LSIZE[1]=L1 Instr size
				}
				if ((ULLtype == 3) && (LSIZE[6] != 1))
				{//printf(" Size = %d X %d\n\n",LSIZE[6],ULCSIZE);
					LSIZE[3] = ULCSIZE;
				}
				if ((ULLtype == 3) && (LSIZE[6] == 1))
				{//printf(" Size = %d\n\n",ULCSIZE);
					LSIZE[3] = ULCSIZE;
				}
				if ((ULLtype == 2) && (LSIZE[5] != 1))
				{//printf(" Size = %d X %d\n\n",LSIZE[5],ULCSIZE);
					LSIZE[2] = ULCSIZE;
				}
				if ((ULLtype == 2) && (LSIZE[5] == 1))
				{//printf(" Size = %d\n\n",ULCSIZE);
					LSIZE[2] = ULCSIZE;
				}


			}
			ULXFRC++;
		}//while loop
	}//end if (Avail >= 0x4), 
}//end void Cachetest




// ---------------------------------------------------------------------------
//  PopulateData -- A routine to populate configuration variables
// ---------------------------------------------------------------------------


void Init(void)
{

	tStartTime = std::time(nullptr);
	if (iDebugFlag)
	{
		std::string sTemp = std::asctime(std::localtime(&tStartTime));
		std::cout << "tStartTime = " << sTemp << std::endl;
	}


	// 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)
{
	std::cout << std::endl << "..." << std::endl << "Version: " << sgGoldModuleVersion << 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)
{

	// pass fail logic using iPassFailStatus  with 0=pass, 1=fail, 2=indeterminate

	// Write Results File
	td.WriteToFile(sgGoldModuleResultsFile, "Cache Test");
	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 == 0)
	{
		igPassFailStatus = 0;  // Success
		td.WriteToFile(sgGoldModuleResultsFile, "Test Result - PASS");

	}
	else if (iPassFailStatus == 1) //Fail
	{
		igPassFailStatus = 1;  // Fail
		td.WriteToFile(sgGoldModuleResultsFile, "Test Result - FAIL");
	}

	else if (iPassFailStatus == 2) //Indeterminate
	{
		igPassFailStatus = 2;  // Indeterminate 
		td.WriteToFile(sgGoldModuleResultsFile, "Test Result - INDETERMINATE");
	}

	td.WriteToFile(sgGoldModuleResultsFile, strPFOut);

	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 << "Help or Usage ... version info ... copyright info ..." << std::endl;
	std::cout << std::endl << "Test Information:" << std::endl;
	std::cout << " The purpose of CPU Cache test is to display the size of the" << std::endl;
	std::cout << " L1, L2, and L3 Cache, whichever is present." << std::endl;
	std::cout << " The CPUID instruction is used to read the general purpose " << std::endl;
	std::cout << " EAX, EBX, ECX, and EDX registers." << std::endl;
	std::cout << " The test retrieves the L1, L2, and L3 Cache size information" << std::endl;
	std::cout << " " << 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;
#ifdef __WIN_OS__
	std::cout << "                cache.exe -h" << std::endl << std::endl;
#endif
#ifdef __LIN_OS__
	std::cout << "                ./cache -h" << std::endl << std::endl;
#endif
	std::cout << " -info        = Information switch that 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;
#ifdef __WIN_OS__
	std::cout << "                cache.exe -info" << std::endl << std::endl;
#endif
#ifdef __LIN_OS__
	std::cout << "                ./cache -info" << std::endl << std::endl;
#endif
	std::cout << " -resultName  = The resultName switch provides a way to name " << std::endl;
	std::cout << "                the results file as desired." << std::endl;
	std::cout << "                Example :" << std::endl;
#ifdef __WIN_OS__
	std::cout << "                cache.exe -resultName cache_results_0001.txt " << std::endl << std::endl;
#endif
#ifdef __LIN_OS__
	std::cout << "                ./cache -resultName cache_results_0001.txt " << std::endl << std::endl;
#endif
	std::cout << " -pa          = pause app option" << std::endl;
	std::cout << "                Example:" << std::endl;
#ifdef __WIN_OS__
	std::cout << "                cache.exe -pa" << std::endl << std::endl;
#endif
#ifdef __LIN_OS__
	std::cout << "                ./cache -pa" << std::endl << std::endl;
#endif
	std::cout << " -c           = This option will display text in various colors" << std::endl;
	std::cout << "                Example:" << std::endl;
#ifdef __WIN_OS__
	std::cout << "                cache.exe -c" << std::endl << std::endl;
#endif
#ifdef __LIN_OS__
	std::cout << "                ./cache -c" << std::endl << std::endl;
#endif
	std::cout << std::endl << " Copyright (C) 2015, Intel Corporation" << std::endl;
}
void PauseWQuit(void)
{
	// Pause code
	std::cout << "Please press 'q' <ENTER> to quit: ";
	std::string PauseStr;
	std::cin >> PauseStr;
}

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]+"));
}

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;
}

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("-hrs");
	//sArgs_v.push_back("-m");
	//sArgs_v.push_back("-s");
	//sArgs_v.push_back("-d");
	//sArgs_v.push_back("-p");
	//sArgs_v.push_back("-plx");
	//sArgs_v.push_back("-plt");
	sArgs_v.push_back("-pa");
	sArgs_v.push_back("-c");
	//sArgs_v.push_back("-r");

	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;
						std::cout << std::endl << " --- Cache Test --- ";
						PrintVersion();
						HelpUseage();
						iPrintVersionFlag = 0;
						iPrintSuccessFlag = 0;
					}
					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("-hrs"))
					{
						// Hours
						if (isOptionValid(iArg, argc, argv, VarType::vtINT))
						{
							iHour = CustomAsciiToInteger(argv[++iArg]);
						}
						else
						{
							iRun = 0;
							iOptionValid = 0;
						}

					}
					if (sArgs_v[iVec] == std::string("-m"))
					{
						// Minutes
						if (isOptionValid(iArg, argc, argv, VarType::vtINT))
						{
							iMin = CustomAsciiToInteger(argv[++iArg]);
						}
						else
						{
							iRun = 0;
							iOptionValid = 0;
						}
					}
					if (sArgs_v[iVec] == std::string("-s"))
					{
						// Seconds
						if (isOptionValid(iArg, argc, argv, VarType::vtINT))
						{
							iSec = CustomAsciiToInteger(argv[++iArg]);
						}
						else
						{
							iRun = 0;
							iOptionValid = 0;
						}
					}
					if (sArgs_v[iVec] == std::string("-d"))
					{
						// debug
						iDebugFlag = 1;
					}
					if (sArgs_v[iVec] == std::string("-p"))
					{
						std::cout << std::endl << "Entering print opt" << std::endl;
						igPrintConfig = 1;
					}
					if (sArgs_v[iVec] == std::string("-pa"))
					{
						std::cout << std::endl << "Entering pause app opt" << std::endl;
						igPauseApp = 1;
					}
					if (sArgs_v[iVec] == std::string("-c"))
					{
						std::cout << std::endl << "Entering color text opt" << std::endl;
#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
					}


					// Erase current vector so the option doesn't repeat
					sArgs_v.erase(sArgs_v.begin() + (iVec));
				}

			}
			if (iDebugFlag)
			{
				std::cout << std::endl << "iOptionValid = " << iOptionValid << std::endl;
			}
			if (iOptionValid == 0)
			{
				break;
			}
		}
		if (iOptionValid == 0)
		{
			std::string sArgTemp = argv[iArgIndex];
			std::string sTempMsg = "Option " + sArgTemp + " invalid!";
			PrintColorMsg(sTempMsg, TextColor::Red);
			iRun = 0;
			igPassFailStatus = ReturnValueDef::InvalidArgs;
			HelpUseage();

		}
	}
	else
	{
		// Default message if no arguments are used  ... it may be the usage message or it may be OK that no args are used
		//std::cout << "No args used!!" << std::endl;
	}

}

void PrintSuccess(void)
{
	if (igPassFailStatus == ReturnValueDef::Success)
	{
		PrintColorMsg("Cache Module Success!", TextColor::Green);
	}
	if (igPassFailStatus == ReturnValueDef::Fail)
	{
		PrintColorMsg("Cache Module Fail!", TextColor::Red);
	}
	if (igPassFailStatus == ReturnValueDef::Indeterminate)
	{
		PrintColorMsg("Cache Module Interrupted!", TextColor::Yellow);
	}
	if (igPassFailStatus == ReturnValueDef::InvalidArgs)
	{
		PrintColorMsg("Cache Module has invalid arguments!", TextColor::Red);
	}
	if (igPassFailStatus == ReturnValueDef::ConfigMismatch)
	{
		PrintColorMsg("Cache Module has a configuration mismatch!", TextColor::Yellow);
	}	
	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.16.64b.W";
#endif

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

	// .L linux
#if defined __LIN_64__
	sgGoldModuleVersion = "1.0.16.64b.L";
#endif
#if defined __LIN_32__
	sgGoldModuleVersion = "1.0.16.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);


	// Parse both text local config style and xml style

	Init();
	handleArgs(argc, argv);

	// Print out version
	if (iPrintVersionFlag != 0)
	{
		std::cout << std::endl << " --- Cache Test --- ";
		PrintVersion();
	}


	//..clean up result files ... Clean file before another one is written
	CleanUp();

	if (iRun)
	{
		Run_Cache();
		WriteResultsFile(igPassFailStatus);
	}

	if (iPrintSuccessFlag != 0)
	{
		PrintSuccess();
	}

	if (igPauseApp)
	{
		PauseWQuit();
	}
	return igPassFailStatus;
}
