#include "Utils.h"

/*
Start a chronometer.

CHRONO* pChrono : (INOUT) Valid pointer to the structure.

Return : EXIT_SUCCESS or EXIT_FAILURE if there is an error.
*/
int StartChrono(CHRONO* pChrono)
{
	if (!QueryPerformanceFrequency(&pChrono->Frequency))
	{
		printf("StartChrono error.\n");
		return EXIT_FAILURE;
	}

	if (!QueryPerformanceCounter(&pChrono->Start))
	{
		printf("StartChrono error.\n");
		return EXIT_FAILURE;
	}

	pChrono->Finish.QuadPart = 0;
	pChrono->Duration.QuadPart = 0;
	pChrono->Suspended = FALSE;

	return EXIT_SUCCESS;
}

/*
Suspend a chronometer.

CHRONO* pChrono : (INOUT) Valid pointer to the structure.
double* pDuration : (INOUT) Duration (in s).

Return : EXIT_SUCCESS or EXIT_FAILURE if there is an error.
*/
int SuspendChrono(CHRONO* pChrono, double* pDuration)
{
	LARGE_INTEGER temp;

	if (!pChrono->Suspended)
	{
		pChrono->Suspended = TRUE;
		if (!QueryPerformanceCounter(&temp))
		{
			printf("SuspendChrono error.\n");
			return EXIT_FAILURE;
		}

		//pChrono->Duration += pChrono->Finish-pChrono->Start
		pChrono->Finish = temp;
		temp.QuadPart += pChrono->Duration.QuadPart-pChrono->Start.QuadPart;
		pChrono->Duration = temp;
		*pDuration = (double)pChrono->Duration.QuadPart/(double)pChrono->Frequency.QuadPart;
	}
	else
	{
		printf("SuspendChrono error.\n");
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}

/*
Suspend a chronometer.

CHRONO* pChrono : (INOUT) Valid pointer to the structure.

Return : Duration (in s).
*/
double SuspendChronoQuick(CHRONO* pChrono)
{
	LARGE_INTEGER temp;

	if (!pChrono->Suspended)
	{
		pChrono->Suspended = TRUE;
		QueryPerformanceCounter(&temp);

		//pChrono->Duration += pChrono->Finish-pChrono->Start
		pChrono->Finish = temp;
		temp.QuadPart += pChrono->Duration.QuadPart-pChrono->Start.QuadPart;
		pChrono->Duration = temp;
		return (double)pChrono->Duration.QuadPart/(double)pChrono->Frequency.QuadPart;
	}
	else
	{
		printf("SuspendChronoQuick error.\n");
		return -1;
	}
}

/*
Resume a chronometer.

CHRONO* pChrono : (INOUT) Valid pointer to the structure.

Return : EXIT_SUCCESS or EXIT_FAILURE if there is an error.
*/
int ResumeChrono(CHRONO* pChrono)
{
	if (pChrono->Suspended)
	{
		pChrono->Suspended = FALSE;
		if (!QueryPerformanceCounter(&pChrono->Start))
		{
			printf("ResumeChrono error.\n");
			return EXIT_FAILURE;
		}
	}
	else
	{
		printf("ResumeChrono error.\n");
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}

/*
Get the time elapsed of a chronometer.

CHRONO* pChrono : (INOUT) Valid pointer to the structure.
double* pDuration : (INOUT) Duration (in s).

Return : EXIT_SUCCESS or EXIT_FAILURE if there is an error.
*/
int GetTimeElapsedChrono(CHRONO* pChrono, double* pDuration)
{
	LARGE_INTEGER temp;

	if (pChrono->Suspended)
	{
		*pDuration = (double)pChrono->Duration.QuadPart/(double)pChrono->Frequency.QuadPart;
	}
	else
	{
		if (!QueryPerformanceCounter(&temp))
		{
			printf("GetTimeElapsedChrono error.\n");
			return EXIT_FAILURE;
		}

		//*pDuration = pChrono->Duration+temp-pChrono->Start
		temp.QuadPart += pChrono->Duration.QuadPart-pChrono->Start.QuadPart;
		*pDuration = (double)temp.QuadPart/(double)pChrono->Frequency.QuadPart;
	}

	return EXIT_SUCCESS;
}

/*
Get the time elapsed of a chronometer.

CHRONO* pChrono : (INOUT) Valid pointer to the structure.

Return : Duration (in s).
*/
double GetTimeElapsedChronoQuick(CHRONO* pChrono)
{
	LARGE_INTEGER temp;

	if (pChrono->Suspended)
	{
		return (double)pChrono->Duration.QuadPart/(double)pChrono->Frequency.QuadPart;
	}
	else
	{
		QueryPerformanceCounter(&temp);

		//*pDuration = pChrono->Duration+temp-pChrono->Start
		temp.QuadPart += pChrono->Duration.QuadPart-pChrono->Start.QuadPart;
		return (double)temp.QuadPart/(double)pChrono->Frequency.QuadPart;
	}
}

/*
Stop a chronometer.

CHRONO* pChrono : (INOUT) Valid pointer to the structure.
double* pDuration : (INOUT) Duration (in s).

Return : EXIT_SUCCESS or EXIT_FAILURE if there is an error.
*/
int StopChrono(CHRONO* pChrono, double* pDuration)
{
	LARGE_INTEGER temp;

	if (pChrono->Suspended)
	{
		*pDuration = (double)pChrono->Duration.QuadPart/(double)pChrono->Frequency.QuadPart;
	}
	else
	{
		if (!QueryPerformanceCounter(&temp))
		{
			printf("StopChrono error.\n");
			return EXIT_FAILURE;
		}

		//pChrono->Duration += pChrono->Finish-pChrono->Start
		pChrono->Finish = temp;
		temp.QuadPart += pChrono->Duration.QuadPart-pChrono->Start.QuadPart;
		pChrono->Duration = temp;
		*pDuration = (double)pChrono->Duration.QuadPart/(double)pChrono->Frequency.QuadPart;
	}

	return EXIT_SUCCESS;
}

/*
Stop a chronometer.

CHRONO* pChrono : (INOUT) Valid pointer to the structure.

Return : Duration (in s).
*/
double StopChronoQuick(CHRONO* pChrono)
{
	LARGE_INTEGER temp;

	if (pChrono->Suspended)
	{
		return (double)pChrono->Duration.QuadPart/(double)pChrono->Frequency.QuadPart;
	}
	else
	{
		QueryPerformanceCounter(&temp);

		//pChrono->Duration += pChrono->Finish-pChrono->Start
		pChrono->Finish = temp;
		temp.QuadPart += pChrono->Duration.QuadPart-pChrono->Start.QuadPart;
		pChrono->Duration = temp;
		return (double)pChrono->Duration.QuadPart/(double)pChrono->Frequency.QuadPart;
	}
}

/*
Wait some time...

long Milliseconds : (IN) Time to wait in ms.

Return : Nothing.
*/
void mSleep(long Milliseconds)
{
#ifdef _WIN32
	Sleep(Milliseconds);
#else 
	// usleep() is considered as obsolete.
	//usleep(Milliseconds*1000);
	struct timespec req;

	req.tv_sec = Milliseconds/1000; // Seconds.
	req.tv_nsec = (Milliseconds%1000)*1000000; // Additional nanoseconds.
	nanosleep(&req, NULL);
#endif // _WIN32
}

void DecSec2DaysHoursMinSec(double decsec, int* pDays, int* pHours, int* pMin, int* pSec, double* pDeccsec)
{
	int hours = 0, minutes = 0, seconds = 0; 

	seconds = (int)decsec;
	*pSec = seconds%60;
	minutes = seconds/60;
	*pMin = minutes%60;
	hours = minutes/60;
	*pHours = hours%24;
	*pDays = hours/24;

	*pDeccsec = (decsec-seconds)*100.0;
}

char strftime_fns_tmpbuf[32]; // Used to store the string returned by strtime_fns().

/*
Return a string like ctime() but in this format :

Mon_Aug_27_19h28min04sec_2007\0

(without the "\n", ":", " " of ctime() in order to be safely used in file names).
Should not be used in concurrent threads as the string value returned might 
be changed by another thread.

Return : This string.
*/
char* strtime_fns(void)	
{
	time_t t;
	struct tm *timeptr = NULL;

	time(&t);
	timeptr = localtime(&t);

	if (timeptr == NULL)
	{
		return NULL;
	}

	// Use strftime to build a customized time string. 
	if (strftime(
		strftime_fns_tmpbuf,
		32,
		"%a_%b_%d_%Hh%Mmin%Ssec_%Y",
		timeptr
		) <= 0)
	{
		return NULL;
	}

	return strftime_fns_tmpbuf;
}
