/** SGX

The   sss    gggg x   x   
     s      g      x x    Engine
      sss   g  gg   x
         s  g   g  x x          Copyright 1995-2008.
     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: src/sgx/core/text/sgxtext.cpp

*/

#include "sgx/core/core.hpp"
#include "sgx/filesystem/filesystem.hpp"

sgxHashMap<tUINT32, SGXStringEntry *> *SGXText::byHash;
sgxHashMap<tUINT32, SGXStringEntry *> *SGXText::byID;

void
SGXText::initialize() {
	SGXText::byHash = new sgxHashMap<tUINT32, SGXStringEntry *>;
	SGXText::byID = new sgxHashMap<tUINT32, SGXStringEntry *>;
}

tBOOL SGXText :: loadResource(const sgxString &filename) {
CSGXFile file(filename);

	 if (!file.open()) {
		 return FALSE;
	}

	 sgxString str;
	 SGXStringEntry *pCurrent = NULL;
	 tBOOL lateHashBinding = FALSE;
	 tINT32 lastID = 0;
	 
	 while(!file.isEOF()) {
		 file.readLine(str);
		 sgxString midstr = str.substr(str.find(':') + 1);
		 //sgxTrace("read %s, mid=%s", str.c_str(), midstr.c_str());

		 switch(str[0]) {
			 case ':':
				 pCurrent = new SGXStringEntry();	// we fill in the id/hash later
				 lateHashBinding = TRUE;
				 break;
			 case 'I':
			 case 'i':
				 pCurrent = new SGXStringEntry();
				 lastID = sgxAtoi(midstr);
				 (*byID)[lastID] = pCurrent;
				 lateHashBinding = FALSE;
				 break;
			 case 'H':
			 case 'h':
				 pCurrent = new SGXStringEntry();
				 pCurrent->vSingle = midstr;
				 (*byHash)[sgxGetCRC32(midstr)] = pCurrent;
				 lateHashBinding = FALSE;
				 break;
			 case '+':	// fill in existing entry, and post-increment
				 pCurrent->vSingle = midstr;
				 pCurrent = new SGXStringEntry();
				 (*byID)[++lastID] = pCurrent;
				 lateHashBinding = FALSE;
				 break;
			 case 'S':
			 case 's':
				 pCurrent->vSingle = midstr;
				 if (lateHashBinding) {
					 (*byHash)[sgxGetCRC32(midstr)] = pCurrent;
				 }
				 break;
			 case 'P':
			 case 'p':
				 pCurrent->vPlural = midstr;
				 break;
			 default:
				 pCurrent->vOthers[sgxAtoi(str)] = midstr;
				 break;
		}
	}
#if 0
	// enumerate
	sgxHashMap<tUINT32, SGXStringEntry *>::iterator it = (*byID).begin();
	for(;it!=(*byID).end();++it) {
		sgxTrace("%ld : %s\n", (*it).first, (*it).second->vSingle.c_str());
	}
#endif
	return TRUE;
}

tBOOL SGXText::eraseStrings(const tUINT32 fromStringID, const tUINT32 toStringIDExclusive) {
	for(tUINT32 i=fromStringID;i<toStringIDExclusive;++i) {
		delete (*byID)[i];
		(*byID)[i] = NULL;
	}
	return TRUE;
}


//
// Variant retrieval methods
//
const char *SGXText::getText(const char *textString, const tINT32 number /*= 0*/) {
	 tINT32 hash = sgxGetCRC32(textString);
	 SGXStringEntry *pEntry = (*byHash)[hash];
	 if (pEntry) {
		 return (const char *)getText(pEntry, number).c_str();
	}
	 return textString;
}

const sgxString &SGXText::getText(const tUINT32 keyID, const tINT32 number /*= 0*/) {
	SGXStringEntry *pEntry = (*byID)[keyID];

	if (pEntry) {
		return getText(pEntry, number);
	}

#ifdef SGX_DEBUG
	 static sgxString empty("*No String*");
#else
	 static sgxString empty;
#endif
	 return empty;
}

const char *SGXText::getTextString(const tUINT32 keyID, const tINT32 number /*= 0*/) {
	return getText(keyID, number).c_str();
}

const sgxString &SGXText::getText(const SGXStringEntry *pEntry, const tINT32 number /* = 0 */) {
	sgxAssert(pEntry);

	sgxHashMap<tINT32, sgxString>::const_iterator cit = pEntry->vOthers.find(number);

	if (cit != pEntry->vOthers.end()) {
		// We have a specific numeral for this string, so use it
		return (*cit).second;
	} else if (number == 1 || pEntry->vPlural == "") {
		// Use the singular version when there's no plural, or it's obviously a single (i.e. 1)
		return pEntry->vSingle;
	} else {
		return pEntry->vPlural;
	}

	sgxAssert(0);
#ifdef SGX_DEBUG
	 static sgxString empty("*No String*");
#else
	 static sgxString empty;
#endif
	 return empty;
}




