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

//..includes
#include "Include/Main.h"
#include <iomanip>

//..defines
#ifdef __WIN_OS__
#include <Windows.h>
#include <VersionHelpers.h>
typedef BOOL(WINAPI *PGNSI)(PULONGLONG);
#include <ctime>

#endif
#ifdef __LIN_OS__
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/sysinfo.h>
#include <sys/mman.h>
#endif

#define CHECK(X) if (!(X)) return false;

string sFamilyCfg, sModelCfg, sCPUnameCfg;
int argExpMemory = 0;
int argMemorySizeTolerance = 0;
int skipMemorySizeTest = 0;
int skipMemoryStressTest = 0;
float fArgMemorySizeTolerance = 0;
string sArgExpMemory;
int displayOnly = 0;  //nc
string sIMCDisplayResult[50];
int iIMCDisplayResult = 0;

std::string displayExpectedMemorySizeStr1, displayDetectedMemorySizeStr1;


void WriteResultsFile(int iPassFailStatus, int IMCResultStatus)
{
	//..clean up result files ... Clean file before another one is written
	//CleanUp();
	// pass fail logic using iPassFailStatus  with 0=pass, 1=fail, 2=indeterminate
	// CPUFreqResultStatus 0=within lower and higher tolerance, 1=lower that lower tolerance, 2=higher than higher tolerance, 3=DisplayOnly
	// Write Results File

	td.WriteToFile(sgGoldModuleResultsFile, "IMC Test");
	std::string sTemp = "Module Version: " + sgTestModuleVersion;
	td.WriteToFile(sgGoldModuleResultsFile, sTemp);
	sTemp = "Start Time: ";
	sTemp.append(std::asctime(std::localtime(&tStartTime)));
	td.WriteToFileNoEndL(sgGoldModuleResultsFile, sTemp);


	//td.WriteToFile(sgGoldModuleResultsFile, "SubTest 1: PASS");

	/*if (igPauseApp)
	{
	PauseWQuit();
	}
	*/

	//
	if (iPassFailStatus == 0)
	{

		if (displayOnly) //No Compare Option from argument -nc
		{
			igPassFailStatus = ReturnValueDef::NoCompare;
			td.WriteToFile(sgGoldModuleResultsFile, "Test Result - No Compare Option Used");
			for (int i = 1; i <= iIMCDisplayResult; i++)
			{
				td.WriteToFile(sgGoldModuleResultsFile, sIMCDisplayResult[i]);
			}
		}
		else if (IMCResultStatus==5)
		{
			igPassFailStatus = ReturnValueDef::ConfigMismatch;
			td.WriteToFile(sgGoldModuleResultsFile, "Test Result - Config Mismatch");
			for (int i = 1; i <= iIMCDisplayResult; i++)
			{
				td.WriteToFile(sgGoldModuleResultsFile, sIMCDisplayResult[i]);
			}
			td.WriteToFile(sgGoldModuleResultsFile, "Configuration Mismatch in IMC_LocalConfig.xml file.");
			td.WriteToFile(sgGoldModuleResultsFile, "Skipping IMC Test.");
		}
		else
		{
			igPassFailStatus = ReturnValueDef::Success;
			td.WriteToFile(sgGoldModuleResultsFile, "Test Result - PASS");
			for (int i = 1; i <= iIMCDisplayResult; i++)
			{
				td.WriteToFile(sgGoldModuleResultsFile, sIMCDisplayResult[i]);
			}
		}

	}

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

		for (int i = 1; i <= iIMCDisplayResult; i++)
		{
			td.WriteToFile(sgGoldModuleResultsFile, sIMCDisplayResult[i]);
		}
	}
	else if (iPassFailStatus == 2) //Indeterminate
	{
		//igPassFailStatus = 0;  // Success
		//igPassFailStatus = 1;  // Fail
		igPassFailStatus = ReturnValueDef::Indeterminate;  // Indeterminate 

		td.WriteToFile(sgGoldModuleResultsFile, "Test Result - INDETERMINATE");
	}

	

	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 WinRing0Fun(void)
//{
//#ifdef __WIN_OS__
//	int iFD = 99;
//	InitializeOls();
//	iFD = GetDllStatus();
//#endif
//#ifdef __LIN_OS__
//	int iFD = 0;
//	off_t offT = 0;
//	ssize_t sszT = 0;
//	unsigned long long int iMSR = 0;
//	iFD = open("/dev/cpu/0/msr", O_RDONLY);
//#endif
//
//#ifdef __WIN_OS__
//	if (0 == iFD)
//#endif
//#ifdef __LIN_OS__
//		if (iFD)
//#endif
//		{
//
//#ifdef __WIN_64__
//			//std::cout << std::endl << "..loaded WinRing0x64 driver successfully.." << std::endl;
//#endif
//#ifdef __WIN_32__
//			//std::cout << std::endl << "..loaded WinRing0 driver successfully.." << std::endl;
//#endif
//#ifdef __LIN_OS__
//			//std::cout << std::endl << "../dev/cpu/0/msr accessible.." << std::endl;
//#endif
//		}
//		else
//		{
//#ifdef __WIN_OS__
//			PrintColorMsg("..WinRing0 encountered a problem loading windows driver..\n..ensure app is executed with administrator privileges..", TextColor::Yellow);
//			WriteResultsFile(2,5);
//			exit(1);
//#endif
//#ifdef __LIN_OS__
//			std::cout << ".." << std::endl << "..could not open '/dev/cpu/0/msr' .." << std::endl
//				<< "..ensure app is executed with root privileges.." << std::endl << ".." << std::endl << std::endl;
//#endif
//		}
//
//	
//#ifdef __WIN_OS__
//		Rdmsr(0x17, &ulRetEAX, &ulRetEDX);
//		DeinitializeOls();
//#endif
//#ifdef __LIN_OS__
//		offT = lseek(iFD, 0x17, SEEK_SET);
//		sszT = read(iFD, &iMSR, sizeof(iMSR));
//		close(iFD);
//		ulRetEAX = iMSR & 0xFFFFFFFF;
//		ulRetEDX = iMSR >> 32;
//#endif
//	
//		
//		std::cout << "..ulRetEAX dec contents --> " << ulRetEAX << std::endl;
//		std::cout << "..ulRetEDX dec contents --> " << ulRetEDX << std::endl;
//		std::cout << "..ulRetEAX hex contents --> " << std::hex << ulRetEAX << std::endl;
//		std::cout << "..ulRetEDX hex contents --> " << std::hex << ulRetEDX << std::endl;
//
//
//}

//void ReadLocalTextConfig(void)
//{
//	TextData tdLocal;
//	std::list<std::string> lLineArr;
//	tdLocal.ReadFile("local_text_cfg.txt", lLineArr);
//	for (std::list<string>::iterator li = lLineArr.begin(); li != lLineArr.end(); ++li)
//	{
//		std::cout << ' ' << *li << endl;
//	}
//
//}

//void ReadLocalConfig(void)
//{
//	RapidXMLData localXMLObj;
//	try
//	{
//		
//		//Local config
//		localXMLObj.LoadXMLFile("LocalConfig.xml");
//
//		// Set up the root element
//		localXMLObj.SetRootElem("LocalModuleConfig");
//
//		string localStrItem = localXMLObj.ReadNodeKeyAsString("@LocalConfigItem", "");
//		cout << "LocalConfigItem = " << localStrItem << endl;
//		
//	}
//	catch (...)
//	{
//		std::string sException;
//		sException.append("\n-------------------------------\n");
//		sException.append("Cannot locate config file: 'LocalConfig.xml'! \n");
//		sException.append("Application terminated! \n");
//		sException.append("\n-------------------------------\n");
//		throw(sException);
//	}
//	return;
//}

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

void PopulateDataLocalConfig(XMLParser& xdLocal, LocalConfig& localConfig)
{
	try
	{
		//Global config
		// Set up the root element
		xdLocal.SetRootElem("LocalModuleConfig");

		localConfig.setFMS_family(xdLocal.ReadNodeKeyAsString("@Family", ""));
		localConfig.setFMS_model(xdLocal.ReadNodeKeyAsString("@Model", ""));

		sFamilyCfg = localConfig.getFMS_family();
		sModelCfg = localConfig.getFMS_model();
	}
	catch (...)
	{
		std::string sException;
		sException.append("\n-------------------------------\n");
		sException.append("Cannot locate config file: 'IMC_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");
	///xdLocal.LoadXMLFile("IMC_LocalConfig.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;
	iOptionValid = 0;
	iRun = 1;
	iArgIndex = 0;

}

void PrintVersion(void)
{
	std::cout << std::endl << "--- Integrated Memory Controller Test ---" << std::endl << "..." << std::endl << "Version: " << sgTestModuleVersion << 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 = 2;

    // if you get to this logic, most likely your answer should always be a 2
	cout << "Error is: " << igPassFailStatus << " Indeterminate!" << endl;
	exit(igPassFailStatus);

}

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

void HelpUseage(void)
{
	//std::cout << "Help or Useage ... version info ... copyright info ..." << std::endl;
	std::cout << "Test Information:" << std::endl;
	std::cout << " IMC.exe displays or compares the value between expected and detected memory," << std::endl;
	std::cout << " performs simple memory patterns test." << std::endl;
	std::cout << " IMC.exe has memory size subtest and memory stress subtest." << 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 << "                IMC.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/no|socket:yes/no|core:yes/no\"" << std::endl;
	std::cout << "                Example:" << std::endl;
	std::cout << "                IMCreq.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 << "                IMC.exe -resultName IMC_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 << "                IMC.exe -c" << std::endl << std::endl;
	std::cout << " -nc          = Skip the result, will display only."<< std::endl;
	std::cout << "                Example:" << std::endl;
	std::cout << "                IMC.exe -nc " << std::endl << std::endl;
	std::cout << " -skipsize    = Skip memory size test." << std::endl;
	std::cout << "                Example:" << std::endl;
	std::cout << "                IMC.exe -skipsize " << std::endl << std::endl;
	std::cout << " -skipstress  = Skip memory stress test." << std::endl;
	std::cout << "                Example:" << std::endl;
	std::cout << "                IMC.exe -skipstress " << std::endl << std::endl;
	std::cout << " -expsize [d.d][kB|MB|GB] "<< std::endl;
	std::cout << "                Define expected memory size available." << std::endl;
	std::cout << "                Default is not tested, will only display" << std::endl;
	std::cout << "                detected memory size available." << std::endl;
	std::cout << "                If define, it will compare the expected and" << std::endl;
	std::cout << "                detected memory size with tolerance of 10%" << std::endl;
	std::cout << "                Example:" << std::endl;
	std::cout << "                IMC.exe -expsize 3.5gb " << std::endl << std::endl;
	std::cout << " -sizetol [d.d] " << std::endl;
	std::cout << "                Define Tolerance accepted if '-expsize' is defined." << std::endl;
	std::cout << "                Default is 10%.(0.1)" << std::endl;
	std::cout << "                Example:" << std::endl;
	std::cout << "                IMC.exe -expsize 3.5gb -sizetol 0.3 " << std::endl;
	std::cout << "                IMC.exe -expsize 4gb -sizetol 0.2 -skipstress -nc -c " << std::endl << std::endl;
	std::cout << " -d           = Debug option" << std::endl;
	std::cout << "                Example:" << std::endl;
	std::cout << "                IMC.exe -d" << std::endl << std::endl;

	std::cout << "Dependencies:" << std::endl;
	std::cout << "               IMC_LocalConfig.xml" << std::endl;
	std::cout << std::endl << 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
		}

	}
}

std::string StringToUpper(std::string strToConvert)
{
	//change each element of the string to upper case
	for (unsigned int i = 0; i<strToConvert.length(); i++)
	{
		strToConvert[i] = toupper(strToConvert[i]);
	}
	return strToConvert;//return the converted string
}

bool is_integer(const std::string & s){
	return std::regex_match(s, std::regex("[0-9]+"));
}
bool is_float(const std::string& s)
{
	istringstream iss(s);
	float dummy = 0.0f;
	iss >> skipws >> dummy;
	return (iss && iss.eof());
}

bool isValidMemSizeArg(const std::string& s)
{
	size_t found;
	std::string s2 = StringToUpper(s);
	found = s2.find("GB");
	if (found != std::string::npos) {
		s2.erase(found, 2);
		if (!is_float(s2))
		{
			return false;
		}
	}
	else
	{
		found = s2.find("MB");
		if (found != std::string::npos) {
			s2.erase(found, 2);
			if (!is_float(s2))
			{
				return false;
			}
		}
		else
		{
			found = s2.find("KB");
			if (found != std::string::npos) {				
				s2.erase(found, 2);
				if (!is_float(s2))
				{
					return false;
				}
			}
			else
			{
				found = s2.find("B");
				if (found != std::string::npos) {
					s2.erase(found, 1);
					if (!is_float(s2))
					{
						return false;
					}
				}
				else
				{
					if (!is_float(s2)) {
						return false;
					}
				}
			}
		}
	}	
	return true;
}

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) && !(argvLocal[iArgLocal + 1] == NULL) && !(argvLocal[iArgLocal + 1][0] == '\0'))
	{
		if (vt == VarType::vtINT)
		{
			if (!is_integer(argvLocal[iArgLocal + 1]))
			{
				iRetVal = false;
				sMsg = "Wrong argument type format for argument: '" + sTemp + "'!";
			}
		}
		if (vt == VarType::vtFLOAT)
		{
			if (!is_float(argvLocal[iArgLocal + 1]))
			{
				iRetVal = false;
				sMsg = "Wrong argument type format for argument: '" + sTemp + "'!";
			}
		}
		if (vt == VarType::vtMEMSIZEARG)
		{
			if (!isValidMemSizeArg(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;
}

//Function to Convert Float Value to String
std::string Convert(float number)
{
	std::ostringstream buff;
	buff << number;
	return buff.str();
}

std::string Convert(long number)
{
	std::ostringstream buff;
	buff << number;
	return buff.str();
}

std::string Convert(long long number)
{
	std::ostringstream buff;
	buff << number;
	return buff.str();
}

std::string Convert(unsigned long long number)
{
	std::ostringstream buff;
	buff << number;
	return buff.str();
}

std::string Convert(int number)
{
	std::ostringstream buff;
	buff << number;
	return buff.str();
}

std::string strTrim(std::string& str)
{
	str.erase(0, str.find_first_not_of(' '));       //prefixing spaces
	str.erase(str.find_last_not_of(' ') + 1);         //surfixing spaces
	return str;
}

bool CheckTimeout(long endClock)
{
	if (endClock == -1)
	{
		return false;
	}
#ifdef __WIN_OS__
	if (clock() >= endClock)
	{
		return true;
	}
	return false;
#else	
	struct timespec currentClock;
	clock_gettime(CLOCK_REALTIME, &currentClock);
	if (currentClock.tv_sec >= endClock)
	{
		return true;
	}
	return false;
#endif
}

std::string getCPUBrandString()
{
	std::string sBS;
	char sCPUname[48] = { 0 };

#if defined (__INTEL_COMPILER)

	__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);
	return sBS;

#else
	std::cout << std::endl << "Please compile this program with an Intel C++ Compiler" << std::endl;
#endif
}
void TolkenizeBrandString(std::vector<std::string>& vBS)
{
	std::string _BrandString;
	_BrandString = getCPUBrandString();
	std::vector<std::string> vDelStrList;
	vDelStrList.push_back("\n");
	vDelStrList.push_back("(R)");
	vDelStrList.push_back("(TM)");
	vDelStrList.push_back("@");
	vDelStrList.push_back("CPU");
	vDelStrList.push_back("processor");
	int iDelCnt;
	for (iDelCnt = 0; iDelCnt < vDelStrList.size(); iDelCnt++)
	{
		removeSubStrs(_BrandString, vDelStrList[iDelCnt]);
	}
	Tokenize(_BrandString, vBS);
}
std::string BrandStringSpeed(void)
{
	std::vector<std::string> vBS;
	TolkenizeBrandString(vBS);
	std::string sRet = "";
	if (vBS.size() > 1)
	{
		sRet = vBS[vBS.size() - 1];
	}
	return sRet;
}

extern bool GetMemorySize(long long *result)
{
#ifdef __WIN_OS__
if (IsWindowsXPOrGreater())
	{
		ULONGLONG totalMemoryInKilobytes = 0;
		PGNSI pGNSI;

		pGNSI = (PGNSI)GetProcAddress(
			GetModuleHandle(TEXT("Kernel32.dll")),
			"GetPhysicallyInstalledSystemMemory");
		
		if (NULL != pGNSI)
		{
			if (pGNSI(&totalMemoryInKilobytes))
			{
				*result = totalMemoryInKilobytes * 1024;
				return true;
			}
			else
			{
				return false;
			}
		}
		else
		{
			result = 0;
			return false;
		}
	}
	else
	{
		MEMORYSTATUSEX statex;

		statex.dwLength = sizeof(statex);

		if (GlobalMemoryStatusEx(&statex))
		{
			*result = (long long)statex.ullTotalPhys;
			return true;
		}
		else
		{
			result = 0;
			return false;
		}
	}
#else
	struct sysinfo memInfo;
	if (sysinfo(&memInfo) == 0)
	{
		long long totalPhysMem = memInfo.totalram;
		//Multiply in next statement to avoid int overflow on right hand side...
		totalPhysMem *= memInfo.mem_unit;
		*result = totalPhysMem;
		return true;
	}
	return false;
#endif
}

void IMCTest()
{
	unsigned long long IMCExpectedSpeed;
	unsigned long long IMCDetectedSpeed;
	long long expectedMemorySize;
	long long detectedMemorySize;
	long long stressMemorySize;
	float MemorySizeTolerance = 0.10f;
	int totalMemoryStressPartition = 0;
	bool result = true;
	std::string expectedMemorySizeStr;
	size_t found;

	std::string strCPUName = getCPUBrandString();
	bool memoryAllocated = false;
	int family, model, stepping;
	int familyCfg, modelCfg;
	int StatusFMmatched = 0;

	sIMCDisplayResult[iIMCDisplayResult] = "StartOfString";
	
	sFamilyCfg = strTrim(sFamilyCfg);
	sModelCfg = strTrim(sModelCfg);

	/* if (!sFamilyCfg.empty() && !sModelCfg.empty())
	{
		familyCfg = std::stoi(sFamilyCfg, 0, 16);

		GetProcFamilyModel(&family, &model, &stepping);

		if (iDebugFlag)
		{
			std::cout << std::endl << "Processor Name = " << strCPUName << std::endl;
			std::cout << "family = " << family << std::endl;
			std::cout << "model = " << model << std::endl << std::endl;
			sIMCDisplayResult[iIMCDisplayResult += 1] = "Processor Name = " + strCPUName;
			sIMCDisplayResult[iIMCDisplayResult += 1] = "family = " + Convert(family);
			sIMCDisplayResult[iIMCDisplayResult += 1] = "model = " + Convert(model);
		}
		if (family == familyCfg)
		{
			vector<string> svModelCfg;
			SplitString(sModelCfg, svModelCfg, '|');
			for (int i = 0; i < svModelCfg.size(); i++)
			{
				svModelCfg[i] = strTrim(svModelCfg[i]);
				if (svModelCfg[i].empty())
				{
					std::string sTempMsg = "Cofiguration Mismatch in Model from FamilyModelSkip Node in config file.";
					PrintColorMsg(sTempMsg, TextColor::Yellow);
					sIMCDisplayResult[iIMCDisplayResult += 1] = sTempMsg;
					PrintColorMsg("---  Configuration Mismatch in IMC_LocalConfig.xml file  ---\n..Skipping IMC Test..", TextColor::Yellow);
					WriteResultsFile(0, 5);
					return;
				}
				else
				{

					modelCfg = std::stoi(svModelCfg[i], 0, 16);
					if (model == modelCfg) //FSB
					{
						StatusFMmatched = 1;
						break;
					}
				}
			}
			//if (!StatusFMmatched)
			//{
			//	vector<string> svCPUnameCfg;
			//	SplitString(sCPUnameCfg, svCPUnameCfg, '|');
			//	for (int i = 0; i < svCPUnameCfg.size(); i++)
			//	{
			//		std::string::size_type iCPUname = strCPUName.find(svCPUnameCfg[i]);
			//		if (iCPUname != std::string::npos)
			//		{
			//			StatusFMmatched = 1; 
			//			break;
			//		}
			//	}
			//}
		}
	}
	else if (sFamilyCfg.empty() && !sModelCfg.empty())
	{
		std::string sTempMsg = "Family name in IMC_LocalConfig.xml is empty";
		PrintColorMsg(sTempMsg, TextColor::Yellow);
		sIMCDisplayResult[iIMCDisplayResult += 1] = sTempMsg;
		PrintColorMsg("---  Configuration Mismatch in IMC_LocalConfig.xml file  ---\n..Skipping IMC Test..", TextColor::Yellow);
		WriteResultsFile(0, 5);
		return;
	}
	else if (!sFamilyCfg.empty() && sModelCfg.empty())
	{
		std::string sTempMsg = "Model name in IMC_LocalConfig.xml is empty";
		PrintColorMsg(sTempMsg, TextColor::Yellow);
		sIMCDisplayResult[iIMCDisplayResult += 1] = sTempMsg;
		PrintColorMsg("---  Configuration Mismatch in IMC_LocalConfig.xml file  ---\n..Skipping IMC Test..", TextColor::Yellow);
		WriteResultsFile(0, 5);
		return;
	}
	std::cout << " StatusFMmatched: " << StatusFMmatched<<std::endl;
	if (StatusFMmatched == 0) */

	GetProcFamilyModel(&family, &model, &stepping);

	if (iDebugFlag)
	{
		std::cout << std::endl << "Processor Name = " << strCPUName << std::endl;
		std::cout << "family = " << family << std::endl;
		std::cout << "model = " << model << std::endl << std::endl;
		sIMCDisplayResult[iIMCDisplayResult += 1] = "Processor Name = " + strCPUName;
		sIMCDisplayResult[iIMCDisplayResult += 1] = "family = " + Convert(family);
		sIMCDisplayResult[iIMCDisplayResult += 1] = "model = " + Convert(model);
	}
	
	if ((family == 0x6) && (model == 0x1D) || (family == 0x6) && (model == 0x17) || (family == 0x6) && (model == 0x0F) ||
		(family == 0x6) && (model == 0x0E) || (family == 0x6) && (model == 0x0D) || (family == 0x6) && (model == 0x06) ||
		(family == 0x6) && (model == 0x03) || (family == 0x6) && (model == 0x04) || (family == 0x6) && (model == 0x09))
	{
		std::cout << std::endl << "--- IMC NOT Supported on this Processor ---" << std::endl;
		PrintColorMsg("---  Integrated Memory Controller Test NOT Supported on this Processor  ---\n..Skipping Integrated Memory Controller Test..", TextColor::Yellow);
		sIMCDisplayResult[iIMCDisplayResult += 1] = "---  Integrated Memory Controller Test NOT Supported on this Processor  ---\n..Skipping Integrated Memory Controller Test..";
		WriteResultsFile(0, 2);
	}
	else
	{
		if (displayOnly)
		{
			PrintColorMsg("No Compare Option Used.\n", TextColor::Yellow);
		}
		
		if (skipMemorySizeTest == 0)
		{
			//Memory Size Test
			std::cout << "--- Reading Memory Size --- " << std::endl << std::endl;
			//strPFOut.append("\n--- Reading Memory Size --- \n\n");
			sIMCDisplayResult[iIMCDisplayResult += 1] = "--- Reading Memory Size --- ";

			expectedMemorySizeStr = sArgExpMemory;
			if (expectedMemorySizeStr.compare("") != 0 && argExpMemory != 0)
			{
				expectedMemorySizeStr = StringToUpper(expectedMemorySizeStr);

				if (argMemorySizeTolerance!=0)
				{
					MemorySizeTolerance = fArgMemorySizeTolerance;					
				}

				std::cout << std::endl << "Memory Size Tolerance = " << (MemorySizeTolerance*100) << "%" << std::endl;
				sIMCDisplayResult[iIMCDisplayResult += 1] = "Memory Size Tolerance = " + Convert(MemorySizeTolerance * 100) + "%";
				found = expectedMemorySizeStr.find("GB");
				if (found != std::string::npos)
				{
					expectedMemorySizeStr.erase(found, 2);
					expectedMemorySize = std::stod(expectedMemorySizeStr) * 1024 * 1024 * 1024;
				}
				else
				{

					found = expectedMemorySizeStr.find("MB");
					if (found != std::string::npos)
					{
						expectedMemorySizeStr.erase(found, 2);
						expectedMemorySize = std::stod(expectedMemorySizeStr) * 1024 * 1024;
					}
					else
					{
						found = expectedMemorySizeStr.find("KB");
						if (found != std::string::npos)
						{
							expectedMemorySizeStr.erase(found, 2);
							expectedMemorySize = std::stod(expectedMemorySizeStr) * 1024;
						}
						else
						{
							expectedMemorySize = std::stoll(expectedMemorySizeStr);
						}
					}
				}

				if (expectedMemorySize != -1)
				{
					if (GetMemorySize(&detectedMemorySize))
					{
						double displayExpectedMemorySize = expectedMemorySize;
						double displayDetectedMemorySize = detectedMemorySize;

						std::string unitStr = "B";
						if (expectedMemorySize >= 1 * 1024 * 1024 * 1024)
						{
							unitStr = "GB";
							displayExpectedMemorySize = displayExpectedMemorySize / 1024 / 1024 / 1024;
							displayDetectedMemorySize = displayDetectedMemorySize / 1024 / 1024 / 1024;
						}
						else if (expectedMemorySize >= 1 * 1024 * 1024)
						{
							unitStr = "MB";
							displayExpectedMemorySize = displayExpectedMemorySize / 1024 / 1024;
							displayDetectedMemorySize = displayDetectedMemorySize / 1024 / 1024;
						}
						else if (expectedMemorySize >= 1 * 1024)
						{
							unitStr = "kB";
							displayExpectedMemorySize = displayExpectedMemorySize / 1024;
							displayDetectedMemorySize = displayDetectedMemorySize / 1024;
						}

						char displayExpectedMemorySizeStr[20];
						char displayDetectedMemorySizeStr[20];
						

						if (unitStr == "B")
						{
							snprintf(displayExpectedMemorySizeStr, 20, "%.0f", displayExpectedMemorySize);
							snprintf(displayDetectedMemorySizeStr, 20, "%.0f", displayDetectedMemorySize);
						}
						else
						{

							snprintf(displayExpectedMemorySizeStr, 20, "%.2f", displayExpectedMemorySize);
							snprintf(displayDetectedMemorySizeStr, 20, "%.2f", displayDetectedMemorySize);
						}

						displayExpectedMemorySizeStr1 = displayExpectedMemorySizeStr;
						displayDetectedMemorySizeStr1 = displayDetectedMemorySizeStr;

						std::cout << "Expected Memory Size is --> " << displayExpectedMemorySizeStr1 << unitStr << std::endl;
						sIMCDisplayResult[iIMCDisplayResult += 1] = "Expected Memory Size is --> " + displayExpectedMemorySizeStr1 + unitStr;

						std::cout << "Detected Memory Size is --> " << displayDetectedMemorySizeStr1 << unitStr << std::endl << std::endl;
						sIMCDisplayResult[iIMCDisplayResult += 1] = "Detected Memory Size is --> " + displayDetectedMemorySizeStr1 + unitStr;

						if ((detectedMemorySize <= (1 - MemorySizeTolerance) * expectedMemorySize) ||
							(detectedMemorySize >= (1 + MemorySizeTolerance) * expectedMemorySize))
						{						
							PrintColorMsg("---  Memory Size Test Fail!!!  ---\n", TextColor::Red);
							sIMCDisplayResult[iIMCDisplayResult += 1] = "---  Memory Size Test Fail!!!  ---";
							
							if (!displayOnly)
							{
								result = false;
								WriteResultsFile(1, 0);
								return;
							}
						}
						else
						{
							PrintColorMsg("--- Subtest - Memory Size Test Passed!!!  ---\n", TextColor::Green);
							sIMCDisplayResult[iIMCDisplayResult += 1] = "--- Subtest - Memory Size Test Passed!!!  ---";
							if ((skipMemoryStressTest != 0) || (!IsWindows8OrGreater()))
							{
								if (!displayOnly)
								{
									PrintColorMsg("--- Integrated Memory Controller Test Passed!!! ---", TextColor::Green);
									sIMCDisplayResult[iIMCDisplayResult += 1] = "Integrated Memory Controller Test Passed!!!";
								}								
								WriteResultsFile(0, 0);
								return;
							}
						}
					}
					else
					{
						result = false;
						PrintColorMsg("Unable to retrieve memory size. \n--- Subtest - Memory Size Test Failed!!!  ---\n", TextColor::Red);
						sIMCDisplayResult[iIMCDisplayResult += 1] = "Unable to retrieve memory size. \n--- Subtest - Memory Size Test Failed!!!  ---";
						WriteResultsFile(1, 1);
						return;
					}
				}
			}
			else
			{
				if (GetMemorySize(&detectedMemorySize))
				{


					double displayDetectedMemorySize = detectedMemorySize;
					std::string unitStr = "B";

					if (detectedMemorySize >= 1 * 1024 * 1024 * 1024)
					{
						unitStr = "GB";
						displayDetectedMemorySize = displayDetectedMemorySize / 1024 / 1024 / 1024;
					}
					else if (detectedMemorySize >= 1 * 1024 * 1024)
					{
						unitStr = "MB";
						displayDetectedMemorySize = displayDetectedMemorySize / 1024 / 1024;
					}
					else if (detectedMemorySize >= 1 * 1024)
					{
						unitStr = "kB";
						displayDetectedMemorySize = displayDetectedMemorySize / 1024;
					}

					char displayDetectedMemorySizeStr[20];
					std::string displayDetectedMemorySizeStr1;

					if (unitStr == "B")
					{
						snprintf(displayDetectedMemorySizeStr, 20, "%.0f", displayDetectedMemorySize);
					}
					else
					{
						snprintf(displayDetectedMemorySizeStr, 20, "%.2f", displayDetectedMemorySize);
					}

					displayDetectedMemorySizeStr1 = displayDetectedMemorySizeStr;

					std::cout << "Detected Memory Size is --> " << displayDetectedMemorySizeStr1 << unitStr << std::endl << std::endl;
					//strPFOut.append("\nDetected Memory Size is --> " + displayDetectedMemorySizeStr1 + unitStr + "\n\n");
					sIMCDisplayResult[iIMCDisplayResult += 1] = "Detected Memory Size is --> " + displayDetectedMemorySizeStr1 + unitStr;
					PrintColorMsg("--- Subtest - Memory Size Test Passed!!!  ---\n", TextColor::Green);
					sIMCDisplayResult[iIMCDisplayResult += 1] = "--- Subtest - Memory Size Test Passed!!!  ---";

					if ((skipMemoryStressTest != 0) || (!IsWindows8OrGreater()))
					{
						if (!displayOnly)
						{
							PrintColorMsg("--- Integrated Memory Controller Test Passed!!! ---", TextColor::Green);
							sIMCDisplayResult[iIMCDisplayResult += 1] = "Integrated Memory Controller Test Passed!!!";
						}
						WriteResultsFile(0, 1);
						return;
					}
				}

				else
				{
					result = false;
					PrintColorMsg("Unable to retrieve memory size. \n---  Memory Size Test Fail!!!  ---\n", TextColor::Red);
					sIMCDisplayResult[iIMCDisplayResult += 1] = "Unable to retrieve memory size. \n-- - Memory Size Test Fail!!!-- - ";
					WriteResultsFile(1, 1);
					return;
				}
			}			
		}
		
		if (result && skipMemoryStressTest == 0 && IsWindows8OrGreater())
		{
			bool memoryAllocated = false;
			//Memory Stress Test
			std::cout << std::endl << "--- Integrated Memory Controller Stress Test --- " << std::endl << std::endl;
			sIMCDisplayResult[iIMCDisplayResult += 1] = "--- Integrated Memory Controller Stress Test --- ";
			//strPFOut.append("\n--- Integrated Memory Controller Stress Test --- \n\n");

			//Read stress memory size
			long long availableMemory = (long long)IMCStressTest::GetFreeMemorySize() - 100 * 1024 * 1024;
			//std::cout << "Available Memory = " << availableMemory << std::endl;
			bool enoughMemory = false;
			stressMemorySize = 1 * 1024 * 1024;
			if ((availableMemory - stressMemorySize) >= 0)
			{
				enoughMemory = true;
			}
						
			if (enoughMemory)
			{
				//IMCStressTest* stressTest = NULL;
				
				//test1 = Ones and Zeros Moving Inversions, test2 = 32Bits Sliding Ones, test3 = 32Bits Sliding Zero
				int allocCount = 0, test1WriteCount = 0, test1VerifyCount = 0, test2WriteCount = 0, test2VerifyCount = 0, test3WriteCount = 0, test3VerifyCount = 0, deAllocCount = 0;
								
				std::cout << "Memory to be allocated = " << stressMemorySize << " byte" << std::endl;
				sIMCDisplayResult[iIMCDisplayResult += 1] = "Memory to be allocated = " + std::to_string(stressMemorySize) + " byte";
				int chunkSize = 1 * 1024 * 1024; 
				totalMemoryStressPartition = stressMemorySize / chunkSize;
				//stressTest = new IMCStressTest();
				std::unique_ptr<IMCStressTest> stressTest = std::make_unique<IMCStressTest>();
				IMCStressTest::SetProcessSize((totalMemoryStressPartition + 2) * chunkSize);
				
				if (stressTest->Allocate(chunkSize, totalMemoryStressPartition, true) != 0)
				{
					///delete stressTest;
					result = false;
					PrintColorMsg("Memory Stress Test fail to allocate memory. \n---  Memory Stress Test Fail!!!  ---\n", TextColor::Red);
					sIMCDisplayResult[iIMCDisplayResult += 1] = "Memory Stress Test fail to allocate memory. \n---  Memory Stress Test Fail!!!  ---";
					WriteResultsFile(1, 2);
					return;
				}
				else
				{
					memoryAllocated = true;
					allocCount++;
					std::cout << std::endl << "Memory Allocated." << std::endl;
					sIMCDisplayResult[iIMCDisplayResult += 1] = "Memory Allocated.";
				}

				if (result)
				{
					if (!stressTest->Test1Write())
					{
						///delete stressTest;
						result = false;
						PrintColorMsg("Test 1 Ones and Zeros Moving Inversions write operations - Fail. \n---  Memory Stress Test Fail!!!  ---\n", TextColor::Red);
						sIMCDisplayResult[iIMCDisplayResult += 1] = "Test 1 Ones and Zeros Moving Inversions write operations - Fail. \n---  Memory Stress Test Fail!!!  ---";
						WriteResultsFile(1, 3);
						return;
					}
					else
					{
						PrintColorMsg("Test 1 Ones and Zeros Moving Inversions write operations - Passed", TextColor::Green);
						sIMCDisplayResult[iIMCDisplayResult += 1] = "Test 1 Ones and Zeros Moving Inversions write operations - Passed";
					}
				}

				if (result)
				{
					if (!stressTest->Test1Verify())
					{
						///delete stressTest;
						result = false;
						PrintColorMsg("Test 1 Ones and Zeros Moving Inversions verification operations - Fail.\n---  Memory Stress Test Fail!!!  ---\n", TextColor::Red);
						sIMCDisplayResult[iIMCDisplayResult += 1] = "Test 1 Ones and Zeros Moving Inversions verification operations - Fail.\n---  Memory Stress Test Fail!!!  ---";
						WriteResultsFile(1, 4);
						return;
					}
					else
					{
						PrintColorMsg("Test 1 Ones and Zeros Moving Inversions verification operations - Passed", TextColor::Green);
						sIMCDisplayResult[iIMCDisplayResult += 1] = "Test 1 Ones and Zeros Moving Inversions verification operations - Passed";
					}
				}

				if (result)
				{
					if (!stressTest->Test2Write())
					{
						///delete stressTest;
						result = false;
						PrintColorMsg("Test 2 32Bits Sliding Ones write operations - Fail.\n---  Memory Stress Test Fail!!!  ---\n", TextColor::Red);
						sIMCDisplayResult[iIMCDisplayResult += 1] = "Test 2 32Bits Sliding Ones write operations - Fail.\n---  Memory Stress Test Fail!!!  ---";
						WriteResultsFile(1, 5);
						return;
					}
					else
					{
						PrintColorMsg("Test 2 32Bits Sliding Ones write operations - Passed", TextColor::Green);
						sIMCDisplayResult[iIMCDisplayResult += 1] = "Test 2 32Bits Sliding Ones write operations - Passed";
					}
				}

				if (result)
				{
					if (!stressTest->Test2Verify())
					{
						///delete stressTest;
						result = false;
						PrintColorMsg("Test 2 32Bits Sliding Ones verification operations - Fail.\n---  Memory Stress Test Fail!!!  ---\n", TextColor::Red);
						sIMCDisplayResult[iIMCDisplayResult += 1] = "Test 2 32Bits Sliding Ones verification operations - Fail.\n---  Memory Stress Test Fail!!!  ---";
						WriteResultsFile(1, 6);
						return;
					}
					else
					{
						PrintColorMsg("Test 2 32Bits Sliding Ones verification operations - Passed", TextColor::Green);
						sIMCDisplayResult[iIMCDisplayResult += 1] = "Test 2 32Bits Sliding Ones verification operations - Passed";
					}
				}

				if (result)
				{
					if (!stressTest->Test3Write())
					{
						///delete stressTest;
						result = false;
						PrintColorMsg("Test 3 32Bits Sliding Zero write operations - Fail.\n---  Memory Stress Test Fail!!!  ---\n", TextColor::Red);
						sIMCDisplayResult[iIMCDisplayResult += 1] = "Test 3 32Bits Sliding Zero write operations - Fail.\n---  Memory Stress Test Fail!!!  ---";
						WriteResultsFile(1, 7);
						return;
					}
					else
					{
						PrintColorMsg("Test 3 32Bits Sliding Zero write operations - Passed", TextColor::Green);
						sIMCDisplayResult[iIMCDisplayResult += 1] = "Test 3 32Bits Sliding Zero write operations - Passed";
					}
				}

				if (result)
				{
					if (!stressTest->Test3Verify())
					{
						///delete stressTest;
						result = false;
						PrintColorMsg("Test 3 32Bits Sliding Zero verification operations - Fail.\n---  Memory Stress Test Fail!!!  ---\n", TextColor::Red);
						sIMCDisplayResult[iIMCDisplayResult += 1] = "Test 3 32Bits Sliding Zero verification operations - Fail.\n---  Memory Stress Test Fail!!!  ---";
						WriteResultsFile(1, 8);
						return;
					}
					else
					{
						PrintColorMsg("Test 3 32Bits Sliding Zero verification operations - Passed", TextColor::Green);
						sIMCDisplayResult[iIMCDisplayResult += 1] = "Test 3 32Bits Sliding Zero verification operations - Passed";
					}
				}

				if (memoryAllocated)
				{
					//deAllocCount++;
					stressTest->Release();
					memoryAllocated = false;
					///delete stressTest;
					///if (iDebugFlag)
					///{
					///	std::cout << std::endl << "delete stressTest = " << stressTest << std::endl;
					///}
					std::cout << std::endl << "Memory Deallocated." << std::endl;
					sIMCDisplayResult[iIMCDisplayResult += 1] = "Memory Deallocated.";
				}


				if (memoryAllocated == true)
				{
					stressTest->Release();
				}
				
				///delete stressTest;
				///if (iDebugFlag)
				///{
				///std::cout << std::endl << "delete stressTest..." << std::endl;
				///}

				if (result)
				{
					PrintColorMsg("--- Subtest - Memory Stress Test Passed!!! ---\n", TextColor::Green);
					sIMCDisplayResult[iIMCDisplayResult += 1] = "--- Subtest - Memory Stress Test Passed!!!  ---";

					if (!displayOnly)
					{
						PrintColorMsg("--- Integrated Memory Controller Test Passed!!! ---", TextColor::Green);
						sIMCDisplayResult[iIMCDisplayResult += 1] = "Integrated Memory Controller Test Passed!!!";
					}
					WriteResultsFile(0, 3);
					return;
					//strPFOut.append("\n--- Integrated Memory Controller Stress Test Pass!!! --- \n\n");
				}
			}
			else
			{
				string failMsg = "Not enough free memory to allocate " + Convert(stressMemorySize) + " byte";
				PrintColorMsg(failMsg + "\n--- Subtest - Memory Size Test Failed!!!  ---\n", TextColor::Red);
				sIMCDisplayResult[iIMCDisplayResult += 1] = failMsg + "\n--- Subtest - Memory Size Test Failed!!!  ---";
				WriteResultsFile(1, 9);
				return;
			}
		}
		else
		{
			std::cout << "skipMemoryStressTest " << skipMemoryStressTest << std::endl;

		}
	}

	/*else
	{
		std::cout << std::endl << "--- IMC NOT Supported on this Processor ---" << std::endl;
		PrintColorMsg("---  Integrated Memory Controller Test NOT Supported on this Processor  ---\n..Skipping Integrated Memory Controller Test..", TextColor::Yellow);
		sIMCDisplayResult[iIMCDisplayResult += 1] = "---  Integrated Memory Controller Test NOT Supported on this Processor  ---\n..Skipping Integrated Memory Controller Test..";
		WriteResultsFile(0, 2);
	}*/
}

void handleArgs(int argc, char *argv[])
{
	//int iHelpSelected = 0;
	// 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("-sizetol");
	sArgs_v.push_back("-expsize");
	sArgs_v.push_back("-skipsize");
	sArgs_v.push_back("-d");
	sArgs_v.push_back("-skipstress");
	sArgs_v.push_back("-nc");
	sArgs_v.push_back("-c");


	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"))
					{
						// Print out version
						if (iPrintVersionFlag != 0)
						{
							PrintVersion();
						}
						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("-sizetol"))
					{
						// Memory Size Tolerance
						if (isOptionValid(iArg, argc, argv, VarType::vtFLOAT))
						{
							argMemorySizeTolerance = 1;
							fArgMemorySizeTolerance = std::stof(argv[iArg + 1]);
							iArg++;

						}
						else
						{
							iRun = 0;
							iOptionValid = 0;
						}

					}
					if (sArgs_v[iVec] == std::string("-expsize"))
					{
						// Expected Mem Size
						if (isOptionValid(iArg, argc, argv, VarType::vtMEMSIZEARG))
						{
							argExpMemory = 1;
							sArgExpMemory = argv[iArg + 1];
							iArg++;
						}
						else
						{
							iRun = 0;
							iOptionValid = 0;
						}
					}
					if (sArgs_v[iVec] == std::string("-skipsize"))
					{
						// Skip Memory Size Test 
						skipMemorySizeTest = 1;
					}
					if (sArgs_v[iVec] == std::string("-d"))
					{
						// debug
						iDebugFlag = 1;
					}
					if (sArgs_v[iVec] == std::string("-skipstress"))
					{
						// Skip Memory Stress Test 
						skipMemoryStressTest = 1;
					}
					if (sArgs_v[iVec] == std::string("-nc"))
					{
						// No Compare between expected and detected, display only
						// std::cout << std::endl << "Entering no compare opt" << std::endl;
						displayOnly = 1;
					}

					// 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 useage 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("IMC Success!", TextColor::Green);
	}
	if (igPassFailStatus == ReturnValueDef::Fail)
	{
		PrintColorMsg("IMC Fail!", TextColor::Red);
	}
	if (igPassFailStatus == ReturnValueDef::Indeterminate)
	{
		PrintColorMsg("IMC Interrupted!", TextColor::Yellow);
	}
	if (igPassFailStatus == ReturnValueDef::InvalidArgs)
	{
		PrintColorMsg("IMC has invalid arguments!", TextColor::Red);
	}
	if (igPassFailStatus == ReturnValueDef::ConfigMismatch)
	{
		PrintColorMsg("IMC 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__ 
	sgTestModuleVersion = "1.0.17.64b.W";
#endif

#if defined __WIN_32__ 
	sgTestModuleVersion = "1.0.17.32b.W";
#endif

	// .L linux
#if defined __LIN_64__
	sgTestModuleVersion = "1.0.13.64b.L";
#endif
#if defined __LIN_32__
	sgTestModuleVersion = "1.0.13.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);
	
	// 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 = 0;  // Success
	//igPassFailStatus = 1;  // Fail
	//igPassFailStatus = 2;  // Indeterminate 

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

	//WriteResultsFile(igPassFailStatus);
	if (iRun)
	{
		// Print out version
		if (iPrintVersionFlag != 0)
		{
			PrintVersion();
		}
		//std::cout << " --- Integrated Memory Controller Test  --- " << std::endl << std::endl;
		//PopulateData(xd, gGlobalConfig);
		///PopulateDataLocalConfig(xdLocal, gLocalConfig);
		try
		{
			IMCTest();
		}
		catch (...)
		{
			std::string sTempMsg = "Exception error while running IMC Test.";
			sIMCDisplayResult[iIMCDisplayResult += 1] = sTempMsg;
			PrintColorMsg(" --- Exception error while running IMC Test  ---\n..IMC Test Failed..", TextColor::Red);
			WriteResultsFile(1, 0);
		}
	}
	if (iPrintSuccessFlag != 0)
	{
		PrintSuccess();
	}
		
	/*if (igPauseApp)
	{
	PauseWQuit();
	}*/
	
	// Returns 0=pass, 1=fail, 2=indeterminate 
	//std::cout << "igPassFailStatus  -  " << igPassFailStatus << std::endl;
	return igPassFailStatus;
}

