//..
//..Frequency Module ..
//..developed by GTS..
//..
//..Intel(R) Corporation (C) 2019
//..

//..includes..
#include "..\include\main.h"


std::string::size_type sz;
bool bHelpMessage = false;

BrandString brandstring;
MeasureFrequency measurefrequency;


//..Capture Signal Function
void SignalFun(int iSigNum)
{
	// If you want to print out the signal, do the following
	std::cout << "Signal is:" << iSigNum << std::endl;
	
	// 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;
	std::string sTemp = "Error is: " + ConvertInt2String(igPassFailStatus) + " Indeterminate..!!..";
	PrintColorMsg(sTemp, TextColor::Yellow);
	exit(igPassFailStatus);
}

//..Init
void Init()
{
	tStartTimer = std::time(nullptr);
	iRun = 1;
}

//..Validate Command Line Arguments
void ValidateArgs(int argc, char *argv[])
{
	std::string sLowTol = "";
	bool bCheckLowTol = false;
	std::vector <std::string> sArgs_v;
	sArgs_v.push_back("-h");
	sArgs_v.push_back("-info");
	sArgs_v.push_back("-resultName");
	sArgs_v.push_back("-c");
	sArgs_v.push_back("-nc");
	sArgs_v.push_back("-lt");

	if (argc > 1)
	{
		for (int iArg = 1; iArg < argc; iArg++)
		{
			for (int iVec = 0; iVec < (int)sArgs_v.size(); iVec++)
			{
				if (argv[iArg] == sArgs_v[iVec])
				{
					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 < (int)sArgs_v.size(); iVec++)
			{
				if (argv[iArg] == sArgs_v[iVec])
				{
					iOptionValid = 1;

					if (sArgs_v[iVec] == std::string("-h"))
					{
						if (iPrintVersionFlag != 0)
						{
							OutputVersion();
						}
						iRun = 0;
						iSuccessFlag = 0;
						bHelpMessage = true;
						HelpMessage();
					}
					if (sArgs_v[iVec] == std::string("-info"))
					{
						iRun = 0;
						//iPrintVersionFlag = 0;
						iSuccessFlag = 0;
						std::cout << "\"parallel:yes|socket:yes|core:yes\"" << std::endl;
					}
					if (sArgs_v[iVec] == std::string("-resultName"))
					{
						if(argv[iArg + 1] == NULL)
						{
							iRun = 0;
							iSuccessFlag = 0;
							HelpMessage();
							WriteResultsFile(4);
							break;
						}
						else
						{
							sModuleResultsFile = argv[iArg + 1];
						}
						iArg++;
					}
					if (sArgs_v[iVec] == std::string("-nc"))
					{
						iNoCompare = 1;
					}
					if (sArgs_v[iVec] == std::string("-lt"))
					{
						iLT = 1;
						if (argv[iArg + 1] == NULL)
						{
							iRun = 0;
							iSuccessFlag = 0;
							break;
						}
						else
						{
							sLowTol = argv[iArg + 1];
						}
						iArg++;
						bCheckLowTol = CheckString(sLowTol, ".");
						if (bCheckLowTol)
						{
							fLowTolArg = std::stof(sLowTol, &sz);
						}
						else
						{
							iRun = 0;
							iSuccessFlag = 0;
							std::cout << ".." << std::endl << "..Input format for argument '-lt' is [x.xx].. e.g. 0.10" << std::endl << "..";
						}
					}
					sArgs_v.erase(sArgs_v.begin() + (iVec));
				}
			}//..end of iVec for loop
			if (iOptionValid == 0)
			{
				break;
			}
		}//..end of iArg for loop
		if (iOptionValid == 0)
		{
			std::string sArgTemp = argv[iArgIndex];
			std::string sTempMsg = "Option " + sArgTemp + " invalid!";
			PrintColorMsg(sTempMsg, TextColor::Red);
			iRun = 0;
			igPassFailStatus = ReturnValueDef::InvalidArgs;
			HelpMessage();
		}
	}
	else
	{
		//..place holder
	}
}

//..Command Line Help Message
void HelpMessage()
{
	std::cout << "Test Information:" << std::endl;
	std::cout << "..FrequencyCheck.exe compares the value between expected and measured CPU frequency," << std::endl;
	std::cout << "..Options are as follows - " << std::endl << std::endl;
	std::cout << " -h	\t = Help or Usage (this message)" << std::endl;
	std::cout << "\t\t   Example:" << std::endl;
	std::cout << "\t\t   FrequencyCheck.exe -h" << std::endl << std::endl;
	std::cout << " -info\t\t = Information switch publishes parallel information" << std::endl;
	std::cout << "\t\t   using the following scheme:" << std::endl;
	std::cout << "\t\t   \"parallel:yes/no|socket:yes/no|core:yes/no\"" << std::endl;
	std::cout << "\t\t   Example:" << std::endl;
	std::cout << "\t\t   FrequencyCheck.exe -info" << std::endl << std::endl;
	std::cout << " -resultName\t = This option provides a way to rename the results file" << std::endl;
	std::cout << "\t\t   This is for the convenience of the control program. " << std::endl;
	std::cout << "\t\t   Example:" << std::endl;
	std::cout << "\t\t   FrequencyCheck.exe -resultName FrequencyCheck_results_01.txt " << std::endl << std::endl;
	std::cout << " -c\t\t = If present, this option will display text in various colors" << std::endl;
	std::cout << "\t\t   Example:" << std::endl;
	std::cout << "\t\t   FrequencyCheck.exe -c" << std::endl << std::endl;
	std::cout << " -nc\t\t = Skip the comparison test between expected and detected CPU frequency" << std::endl;
	std::cout << "\t\t   and will only display measured CPU frequency." << std::endl;
	std::cout << "\t\t   Example:" << std::endl;
	std::cout << "\t\t   FrequencyCheck.exe -nc " << std::endl;
	std::cout << std::endl << "Copyright (C) 2019, Intel Corporation" << std::endl;
}

//..Output Version
void OutputVersion()
{
	std::cout << std::endl << "--- Frequency Check ---" << std::endl << "..." << std::endl << "Version: " << sTestModuleVersion << std::endl << "..." << std::endl;
}

//..Clean Up Log Results File
void CleanUp()
{
	if (!bHelpMessage)
	{
		if (RemoveFile(sModuleResultsFile))
		{
			//std::cout << "..Log File Successfully Removed --> " << std::endl;
		}
		else
		{
			//std::cout << "..Could not delete results file.." << std::endl;
		}
	}
}

//..Output Results
void ResultsStatus()
{
	if (igPassFailStatus == ReturnValueDef::Success)
	{
		if (!bHelpMessage)
		{
			PrintColorMsg("FrequencyCheck Success..!!..", TextColor::Green);
		}
	}
	if (igPassFailStatus == ReturnValueDef::Fail)
	{
		PrintColorMsg("FrequencyCheck Fail..!!..", TextColor::Red);
	}
	if (igPassFailStatus == ReturnValueDef::Indeterminate)
	{
		PrintColorMsg("FrequencyCheck Interrupted..!!..", TextColor::Yellow);
	}
	if (igPassFailStatus == ReturnValueDef::InvalidArgs)
	{
		PrintColorMsg("FrequencyCheck has invalid arguments..!!..", TextColor::Red);
	}
	if (igPassFailStatus != ReturnValueDef::Success)
	{
		std::cout << std::endl << "Return Status = " << igPassFailStatus << std::endl;
	}
}

//..Write Results File
//void WriteResultsFile(int iPassFailStatus, int iResultStatus)
void WriteResultsFile(int iPassFailStatus)
{
	WriteLogFile(sModuleResultsFile, "Frequecy Check");
	WriteLogFile(sModuleResultsFile, "Module Version: " + sTestModuleVersion);
	WriteLogFileNoEndL(sModuleResultsFile, DateTime("Start Time: ", tStartTimer));

	if (iPassFailStatus == 4)
	{
		igPassFailStatus = ReturnValueDef::InvalidArgs;
		WriteLogFile(sModuleResultsFile, "Test Result - INVALID ARGS");
	}

	if (iPassFailStatus == 3)
	{
		igPassFailStatus = ReturnValueDef::NoCompare;
		WriteLogFile(sModuleResultsFile, "Test Result - NO COMPARE OPTION USED");
	}
	
	if (iPassFailStatus == 2)
	{
		igPassFailStatus = ReturnValueDef::Indeterminate;
		WriteLogFile(sModuleResultsFile, "Test Result - INDETERMINATE");
	}
	
	if (iPassFailStatus == 1)
	{
		igPassFailStatus = ReturnValueDef::Fail;
		WriteLogFile(sModuleResultsFile, "Test Result - FAIL");
	}
		   
	if (iPassFailStatus == 0)
	{
		igPassFailStatus = ReturnValueDef::Success;
		WriteLogFile(sModuleResultsFile, "Test Result - PASS");
	}

	if (iPassFailStatus == 0 || iPassFailStatus == 1 || iPassFailStatus == 3)
	{
		WriteLogFile(sModuleResultsFile, "Processor Name: " + sProcessorName);
		WriteLogFile(sModuleResultsFile, "Expected Processor Frequency: " + sExpectedFrequency);
		WriteLogFile(sModuleResultsFile, "Measured Processor Frequency: " + std::to_string(dMeasuredFrequency));

		if (iPassFailStatus == 1)
		{
			WriteLogFile(sModuleResultsFile, "Expected Frequency - The highest frequency at which the processor was manufactured to operate");
			WriteLogFile(sModuleResultsFile, "Measured Frequency - The frequency at which the processor is currently operating");
			WriteLogFile(sModuleResultsFile, "Power management modes can create marginally higher or lower detected frequency");
			WriteLogFile(sModuleResultsFile, "than expected frequency. Small variations in clock frequencies are common.");
		}
	}
	
	tEndTimer = std::time(nullptr);
	WriteLogFileNoEndL(sModuleResultsFile, DateTime("End Time: ", tEndTimer));

	tTotalTime = (tEndTimer - tStartTimer);
	WriteLogFile(sModuleResultsFile, "Total Time: in seconds: " + std::to_string(tTotalTime));
}

//..Compare Frequency
void CheckFrequencyResult()
{
	dMeasuredFrequency = measurefrequency.measuredFrequency();
	sProcessorName = brandstring.getCPUBrandString();
	
	int iBrandStringLength = sProcessorName.length();
	sExpectedFrequency = ParseFrequency(iBrandStringLength, sProcessorName);
	fExpFreq = std::stof(sExpectedFrequency, &sz);

	if (iLT == 1)
	{
		fLowTolerance = fLowTolArg;
	}

	if (sProcessorName.length() < 1)
	{
		iBrandStringNull = 1;
	}

	if(iBrandStringNull == 1)
	{
		PrintColorMsg("Processor Brand String - Null..", TextColor::Yellow);
		WriteResultsFile(2);
	}
	else if(iNoCompare == 1)
	{
		std::cout << ".." << std::endl << "..In No Compare Option.." << std::endl << "..";
		std::cout << std::endl << "..Expected Frequency --> " << sExpectedFrequency;
		std::cout << std::endl << "..Measured frequency --> " << dMeasuredFrequency;
		PrintColorMsg("No Compare Option Used..!!..", TextColor::Yellow);
		WriteResultsFile(3);
	}
	else if((dMeasuredFrequency >= (fExpFreq - (fExpFreq*fLowTolerance))) &&
			((dMeasuredFrequency <= (fExpFreq + (fExpFreq*fHighTolerance)))))
	{
		PrintColorMsg("FrequencyCheck Passed..!!..", TextColor::Green);
		WriteResultsFile(0);
	}
	else if ((dMeasuredFrequency) < (fExpFreq - (fExpFreq*fLowTolerance)))
	{
		PrintColorMsg("FrequencyCheck Failed..!!..", TextColor::Red);
		WriteResultsFile(1);
	}
	else
	{
		PrintColorMsg("FrequencyCheck Passed..!!..", TextColor::Green);
		PrintColorMsg("Expected Frequency - The highest frequency at which the processor was manufactured to operate \nMeasured Frequency - The frequency at which the processor is currently operating \nPower management modes can create marginally higher or lower detected frequency \n than expected frequency. Small variations in clock frequencies are common.", TextColor::Yellow);
		WriteResultsFile(0);
	}
}

//..Main
int main(int argc, char *argv[])
{
#if defined __WIN_32__
	sTestModuleVersion = "1.0.1.32b.W";
#endif
#if defined __WIN_64__
	sTestModuleVersion = "1.0.1.64b.W";
#endif

	signal(SIGINT, SignalFun);

	Init();

	ValidateArgs(argc, argv);

	CleanUp();

	if (iRun)
	{
		if (iPrintVersionFlag != 0)
		{
			OutputVersion();
		}

		CheckFrequencyResult();
	}

	if (iSuccessFlag != 0)
	{
		ResultsStatus();
	}

	return igPassFailStatus;
}


