/** SGX

The   sss    gggg x   x   
     s      g      x x    Engine
      sss   g  gg   x
         s  g   g  x x          Copyright 1995-2009.
     ssss    gggg x   x         Steven Goodwin. All Rights Reserved.
    
This version has been released under the GNU Public License v2.0.

Please see the license files for details.

File: sgx/src/sgx/core/sgxlib/string.cpp

*/

#define _CRT_SECURE_NO_WARNINGS

#include "sgx/core/types/types.hpp"
#include "sgx/core/stl/stl.hpp"
#include "sgx/core/sgxlib/string.hpp"
#include "sgx/core/helpers/memwatch.hpp"

#include <string.h>
#include <stdlib.h>
#include <cstdarg>
#include <stdio.h>
/**
The SGX-compliant abstraction for the standard string methods, such as
copy, concatenate, and compare. The input arguments and results must be
identical to their standard C equivalents.

Passing a NULL ptr is undetermined across platforms, so we err on the
side of caution and act as if it were a string of ""
*/

//
// C string wrappers
//
tSIZET sgxStrlen(const tCHAR *pString)
{	
	if (!pString) {
		return 0;
	}
    return strlen((const char *)pString);
}

tCHAR *sgxStrcpy(tCHAR *pDest, const tCHAR *pSrc)
{	
    sgxCheckForOverwrites(pDest, sgxStrlen(pSrc));
    if (!pDest || !pSrc)	return pDest;
    return (tCHAR *)strcpy((char *)pDest, (const char *)pSrc);
}

tCHAR * sgxStrncpy(tCHAR *pDest, const tCHAR *pSrc, tMEM_SIZE maxChars)
{	
    sgxCheckForOverwrites(pDest, sgxStrlen(pSrc));
    if (!pDest || !pSrc)	return pDest;
    return (tCHAR *)strncpy((char *)pDest, (const char *)pSrc, maxChars);
}

tCHAR *sgxStrcat(tCHAR *pDest, const tCHAR *pSrc)
{	
    sgxCheckForOverwrites(pDest, sgxStrlen(pSrc));
    if (!pDest || !pSrc)	return pDest;
    return (tCHAR *)strcat((char *)pDest, (const char *)pSrc);
}

int sgxStrcmp(const tCHAR *pSrc1, const tCHAR *pSrc2)
{	
	if (pSrc1 == pSrc2)	return 0;	// covers identical pointers - whether both NULL, or real
	if (!pSrc1)			return 1;
	if (!pSrc2)			return -1;

    return strcmp((const char *)pSrc1, (const char *)pSrc2);
}

int sgxStrncmp(const tCHAR *pSrc1, const tCHAR *pSrc2, const tMEM_SIZE iMaxCount)
{	
	if (pSrc1 == pSrc2)	return 0;	// covers identical pointers - whether both NULL, or real
	if (!pSrc1)			return 1;
	if (!pSrc2)			return -1;

    return strncmp((const char *)pSrc1, (const char *)pSrc2, iMaxCount);
}

tCHAR sgxLower(tCHAR c) {
	if (c>='A' && c<='Z') {
		return (c-'A')+'a';
	}
	return c;
}

tCHAR sgxUpper(tCHAR c) {
	if (c>='a' && c<='z') {
		return (c-'a')+'A';
	}
	return c;
}

tCHAR *sgxStrdup(tCHAR *pStr) {
	return pStr;
}

tCHAR *sgxStrupr(tCHAR *pStr) {
	if (!pStr)	return NULL;

	tCHAR *p = pStr;
	do {
		*p = sgxUpper(*p);
	} while(*++p);
	return pStr;
}

tCHAR *sgxStrlwr(tCHAR *pStr) {
	if (!pStr)	return NULL;

	tCHAR *p = pStr;
	do {
		*p = sgxLower(*p);
	} while(*++p);
	return pStr;
}

tCHAR * sgxStrreplace(tCHAR *pStr, const tCHAR original, const tCHAR replacement) {
	if (!pStr)	return NULL;

	tCHAR *p = pStr;
	do {
		*p = *p == original ? replacement : *p;
	} while(*++p);
	return pStr;
}


int sgxStricmp(const tCHAR *pSrc1, const tCHAR *pSrc2)
{	
	const tCHAR *p1 = pSrc1;
	const tCHAR *p2 = pSrc2;

	if (p1 == p2)	return 0;	// covers identical pointers - whether both NULL, or real
	if (!p1)		return 1;
	if (!p2)		return -1;

	do {
		if (sgxLower(*p1) < sgxLower(*p2)) {
			return -1;
		} else if (sgxLower(*p1) > sgxLower(*p2)) {
			return 1;
		}
		++p1;
		++p2;
	} while(*p1 && *p2);

	// Any letters left?
	if (*p2) {
		return -1;
	} else if (*p1) {
		return 1;
	}

    return 0;
}

tCHAR *sgxStrchr(const tCHAR *pStr, int c)
{
	if (!pStr)	return NULL;
	return (tCHAR *)strchr((const char *)pStr, c);
}

tINT32 	sgxAtoi(const tCHAR *pStr) {
	if (!pStr)	return 0;
	return atoi((const char *)pStr);
}

tLONG 	sgxAtol(const tCHAR *pStr){
	if (!pStr)	return 0;
	return atol((const char *)pStr);
}


tREAL32	sgxAtof(const tCHAR *pStr){
	if (!pStr)	return 0;
	return (tREAL32)atof((const char *)pStr);
}

tBOOL sgxIsTrue(const tCHAR *pStr){
	if (!pStr)									return false;
	if (sgxStricmp(pStr, (tCHAR *)"true") == 0)	return true;
	if (sgxStricmp(pStr, (tCHAR *)"on") == 0)	return true;
	if (sgxStricmp(pStr, (tCHAR *)"yes") == 0)	return true;
	if (sgxStricmp(pStr, (tCHAR *)"1") == 0)		return true;
	return false;
}

tBOOL sgxIsFalse(const tCHAR *pStr){
	if (!pStr)										return false;
	if (sgxStricmp(pStr, (tCHAR *)"false") == 0)	return true;
	if (sgxStricmp(pStr, (tCHAR *)"off") == 0)		return true;
	if (sgxStricmp(pStr, (tCHAR *)"no") == 0)		return true;
	if (sgxStricmp(pStr, (tCHAR *)"0") == 0)		return true;
	return false;
}

tBOOL sgxBoolean(const tCHAR *pStr){
	return sgxIsTrue(pStr);
}



//
// C++ STL equivalents
//
tSIZET  sgxStrlen(const sgxString &str) {
	return str.length();
}

void	sgxStrcpy(sgxString &dest, const sgxString &src) {
	dest = src;
}

void	sgxStrcat(sgxString &dest, const sgxString &src) {
	dest += src;
}

int     sgxStrcmp(const sgxString &str1, const sgxString &str2) {
	return sgxStrcmp((tCHAR *)str1.c_str(), (tCHAR *)str2.c_str());
}

int     sgxStrncmp(const sgxString &str1, const sgxString &str2, const tMEM_SIZE iMaxCount) {
	return sgxStrncmp((tCHAR *)str1.c_str(), (tCHAR *)str2.c_str(), iMaxCount);
}

int     sgxStricmp(const sgxString &str1, const sgxString &str2) {
	return sgxStricmp((tCHAR *)str1.c_str(), (tCHAR *)str2.c_str());
}

sgxString sgxStrupr(const sgxString &str) {
	sgxString outString("");
	const char *p = str.c_str();
	do {
		outString += sgxUpper(*p);
	} while(*++p);
	return outString;
}

sgxString sgxStrlwr(const sgxString &str) {
	sgxString outString("");
	const char *p = str.c_str();
	do {
		outString += sgxLower(*p);
	} while(*++p);
	return outString;
}

sgxString sgxStrreplace(const sgxString &str, const tCHAR original, const tCHAR replacement) {
	sgxString outString("");
	const char *p = str.c_str();
	do {
		if (*p == original) {
			outString += replacement;
		} else {
			outString += *p;
		}
	} while(*++p);
	return outString;
}

tCHAR * sgxStrchr(const sgxString &str, int c) {
	return (tCHAR *)strchr(str.c_str(), c);
}

tINT32 	sgxAtoi(const sgxString &str) {
	return atoi(str.c_str());
}

tLONG 	sgxAtol(const sgxString &str) {
	return atol(str.c_str());
}

tREAL32	sgxAtof(const sgxString &str) {
	return (tREAL32)atof(str.c_str());
}


tBOOL sgxBoolean(const sgxString &str){
	return sgxBoolean((const tCHAR *)str.c_str());
}

tBOOL 	sgxIsTrue(const sgxString &str){
	return sgxIsTrue((const tCHAR *)str.c_str());
}

tBOOL 	sgxIsFalse(const sgxString &str){
	return sgxIsFalse((const tCHAR *)str.c_str());
}


//
//
//
void	sgxFormatStringTime(sgxString &str, const tUINT32 secs, tTimeFormat fmt) {
	sgxString sz;
	SGX_UNUSED(fmt);
	
	tUINT32 s = secs;
	str = "";
	// hrs
	if (s >= 60*60) {
		sgxStringFormat(sz, "%d:", s/(60*60));
		str += sz;
		s /= 60*60;
	}
	// mins
	sgxStringFormat(sz, "%2d:%2d", s/60, s%60);
	str += sz;
}

void	sgxFormatStringTime(sgxString &str, const tUINT32 mins, const tUINT32 secs, const tTimeFormat fmt) {
	sgxFormatStringTime(str, mins*60 + secs, fmt);
}

void	sgxFormatStringTime(sgxString &str, const tUINT32 hrs, const tUINT32 mins, const tUINT32 secs, const tTimeFormat fmt) {
	sgxFormatStringTime(str, hrs*60*24 + mins*60 + secs, fmt);
}

void
sgxStringFormat(sgxString &result, const char *pText, ...) {
    result = "";

	if (pText == NULL) {
		return;
	}
    va_list va;
    static char buffer[1024];

	// TODO: This is not thread-safe
    va_start(va, pText);
	vsprintf(buffer, pText, va);
    va_end(va);

	result = buffer;
}

void
sgxStringSplit(sgxVector<sgxString> &list, const sgxString &string, const char delimiter) {
	sgxStringSplit(list, string.c_str(), delimiter);
}

void
sgxStringSplit(sgxVector<sgxString> &list, const char *pString, const char delimiter) {
	sgxString tmpString("");
	const char *p = pString;
	do {
		if (*p == delimiter) {
			list.push_back(tmpString);
			tmpString = "";
		} else {
			tmpString += *p;
		}
	} while(*++p);
	//
	if (tmpString != "") {
		list.push_back(tmpString);
	}
}
