
// Utility.cpp

// #include "Includes.h"
#include "Utility.h"
// #include <TextUtils.h>

// #include <uchar.h>
// char16_t asd;

static long plg_ErrorCallbackMethodId = 0; // static long?

/*
http://sources.4d.com/svn_public/4d_keisuke/SOURCES/Apple%20Push%20Notification/4DPluginAPI_Extensions.c
*/

#if VERSIONWIN
#else
    #include <libkern/OSAtomic.h>  
#endif

void ReadWriteMemoryBarrier(void){
  #if VERSIONWIN
    MemoryBarrier(); //_ReadWriteBarrier();
#else
    // see: https://bitbucket.org/olivierg/jackbeat/src/6c89a76e3131/src/core/pa_ringbuffer.c
    OSMemoryBarrier();//_ReadWriteBarrier();

    //__sync_synchronize();

    // asm volatile("mfence":::"memory");

    // int32_t dummy = 0;
    // OSAtomicIncrement32Barrier( &dummy ); // OSMemoryBarrier();
  #endif
}

int isCompiled = -1;
long plg_SetBlobParameter( PA_PluginParameters params, short index, char* data, long dataLen ) {
  // will cause memory leak: PA_SetBlobParameter( params, index, blob, blobSize );
  long returnValue;
  PA_Handle returnBlob = PA_NewHandle(dataLen);
  returnValue = PA_GetLastError();
  if ( returnValue == kNoErr ) {
    char* returnPtr = PA_LockHandle(returnBlob);
    PA_MoveBlock( data, returnPtr, dataLen );
    returnValue = PA_GetLastError();
    if ( returnValue == kNoErr ) {
      PA_Handle paramBlob = PA_GetBlobHandleParameter( params, index );
      PA_SetBlobHandleParameter(params, index, returnBlob);
      returnValue = PA_GetLastError();
      if ( paramBlob != NULL ) {
        if ( isCompiled == -1 ){
          isCompiled = PA_IsCompiled(1);
        }
        if( isCompiled ){ // uncompiled will dispose handle, compiled will consume memory hugely
          PA_DisposeHandle(paramBlob);
        }
        if( returnValue == kNoErr ){
          returnValue = PA_GetLastError();
        }
      }
    }
    PA_UnlockHandle(returnBlob);
  }
  if ( returnValue != kNoErr ){
    returnValue = 12;
  }
  return returnValue;
  /*
	PA_Handle pBlob = PA_GetBlobHandleParameter( params, index );
	if( hblob == pBlob )	// no need to do anything if the handles are the same.
		return; 
	if( pBlob ) { 
		long size = PA_GetHandleSize( hblob ); 
		PA_SetHandleSize( pBlob, size ); 
		if( size > 0 ) { 
			PA_MoveBlock( *hblob, *pBlob, size ); 
			PA_DisposeHandle( hblob ); 
		} 
	} 
	else { 
		PA_SetBlobHandleParameter( params, index, hblob ); 
	} 
   */
} 

long plg_ErrorCallbackMethodNameSet( wstring errMeth )
{
	PA_Unichar callback4DMethodName[256];
	// plg_WstringToUnichar( L"MA_ON_ERROR_CALLBACK", callback4DMethodName );
	plg_WstringToUnichar( errMeth, callback4DMethodName, sizeof(callback4DMethodName) );
	
	plg_ErrorCallbackMethodId = PA_GetMethodID( callback4DMethodName );
	
	if( plg_ErrorCallbackMethodId == 0 ){
		if( errMeth == L"" ){
			return kNoErr; // "" == remove callback
		} else {
			return -1;
		}
	} else {
		return kNoErr;
	}

}

void plg_DelayCurrentProcess(long delayInTicks)
{
	long   currentProcess = PA_GetCurrentProcessNumber();
	if( currentProcess != 1 )
		if( delayInTicks >= 0 ){
			PA_PutProcessToSleep( currentProcess, delayInTicks );
		} else {
			long i, count = abs( delayInTicks );
			for( i = 0; i < count; i++ ){
				PA_YieldAbsolute(); // PA_Yield();
			}
		}

	else
	{
		/*
		 void wait ( int seconds )
		 {
		 clock_t endwait;
		 endwait = clock () + seconds * CLOCKS_PER_SEC ;
		 while (clock() < endwait) {}
		 }
		 */
		//long   start;
		// GetTheTicks is a routine that returns the ticks count
		// under both Windows and MacOS
		//start = GetTheTicks();
		//while( (GetTheTicks() - start) < delayInTicks )
		PA_YieldAbsolute();
		PA_YieldAbsolute();
		PA_YieldAbsolute();
	}
}


/*
 > Now I'm facing an other problem...  I tried to use the function   
 > strcpy() and 
 > strncpy() to copy the content of a PA_Unichar* into a simple char   
 > array but 
 > for some reasons, only the first character is copied. 
 
 PA_Unichar* is a 16 bit (2 byte) character representation. For most   
 Western languages, the second byte in the character is zero, which is   
 why strcpy() and strncpy() thinks the wstring is only 1 character long. 
 
 On Windows you want to use the wide character functions, since they   
 work with 16 bit Unicode characters. So use wcsncpy_s(). 
 
 Regards, 
 
 Aparajita 
 www.aparajitaworld.com 
 
As Aparajita pointed out, PA_Unichar is an array of unsigned short... in my particular plugin, I did not need nor support unicode, so I used a couple of short methods to do the conversion. I have included the C Char Array -> PA_Unichar, the other direction is very similar.
*/

// ---------------------------------------------------------------------
//  plg_CStringToUnistring Converts a C wstring into a Unicode wstring (no length checking)
// ---------------------------------------------------------------------

/*
void plg_WstringToUnistring(wstring src, PA_Unistring *dest)
{
	long i=0;
	while(src_uchars[i])
	{
		dest[i]=src_uchars[i];
		i++;
	}
	dest[i]=0;
}
 

void plg_CStringToUnistring (wstring sourceCString, PA_Unistring* destinationPAUnistring)
{ 
	PA_Unichar* tempUnichar = PA_GetUnistring(destinationPAUnistring); 
	wchar_t* tempWChar = new wchar_t[sourceCString.length()+1]; 
	
	wcscpy(tempWChar, sourceCString.c_str()); 
	tempUnichar = (PA_Unichar*)tempWChar; 
	
	PA_SetUnistring(destinationPAUnistring, tempUnichar); 
	
	delete [] tempWChar; // Important, otherwise we get a memory leak. 
	
} 

void plg_UnistringToCString (PA_Unistring* sourcePAUnistring, wstring destinationCString)
{ 
	if (PA_GetUnistringLength (sourcePAUnistring)==0){ 
		destinationCString.empty();
	} else { 
		PA_Unichar* tempUnichar = 
		PA_GetUnistring(sourcePAUnistring); 
		wchar_t* tempWChar = new wchar_t[PA_GetUnicharsLength(tempUnichar)+1]; 
		
		wcscpy(tempWChar, (wchar_t*)tempUnichar); 
		destinationCString = tempWChar; 
		
		delete [] tempWChar; // Important, otherwise we get a memory leak. 
	} 
} 
*/

/*
string plg_EncodeNonAsciiCharacters( string value ) {
	StringBuilder sb = new StringBuilder();
	foreach( char c in value ) {
		if( c > 127 ) {
			// This character is too big for ASCII
			string encodedValue = "\\u" + ((int) c).ToString( "x4" );
			sb.Append( encodedValue );
		}
		else {
			sb.Append( c );
		}
	}
	return sb.ToString();
}

string plg_DecodeEncodedNonAsciiCharacters( string value ) {
	return Regex.Replace(
											 value,
											 @"\\u(?<Value>[a-zA-Z0-9]{4})",
											 m => {
												 return ((char) int.Parse( m.Groups["Value"].Value, NumberStyles.HexNumber )).ToString();
        } );
}
*/

inline wchar_t char_to_wchar( const char s )
{
	// simple typecast
	return wchar_t(s);
}

inline char wchar_to_char( const  wchar_t w )
{
// simple typecast
// works because UNICODE incorporates ASCII into itself
	return char(w);
}


wstring plg_StringToWstring( const string &src )
{
	size_t sz = src.length();
	wstring dest( sz , ' ' );
	//dest.resize( sz ); // +1?
	// std::copy(s.begin(), s.end(), ret.begin());
	std::transform(src.begin(), src.end(), dest.begin(), char_to_wchar);
	return dest;
}


string plg_WstringToString( const wstring &src )
{
	size_t sz = src.length();
	string dest( sz, ' ' );
	//dest.resize( sz ); // +1?
	//std::copy(wstr.begin(), wstr.end(), ret.begin());
	std::transform(src.begin(), src.end(), dest.begin(), wchar_to_char);
	return dest;
}


long plg_CharToUnichar(const char *src, PA_Unichar *dest, long destMaxLen )  // returns length
{
	destMaxLen = destMaxLen / 2; // PA_Unichar is 2 bytes long, sizeof(PA_Unichar[1]) == 2
	/*
	 if( destMaxLen > 255 ) { // always in our code PA_Unichar xxx[256];
	 destMaxLen = 255;
	 }
	 */
	
	long i = 0;
	while( ( i < destMaxLen ) && ( src[i] ) )
	{
		dest[i] = (PA_Unichar)src[i]; 
		i++;
	}
	dest[i]=0;
	return i; // returns length
}



void plg_UnicharToWstring( PA_Unichar* src, wstring &dest )
{
	long i = 0;
	long len = 0;
	
	//dest = (wchar_t *) src;	???
	
	len = PA_GetUnicharsLength( src );	
	dest.resize( len + 1 ); // v12 bug needed + 1 for zero terminator
	
	if(len > 0){
		while(src[i])
		{
			dest[i] = (wchar_t)src[i];
			i++;
		}
	}
	
	dest[i]=0;
}


void plg_UnicharToString( PA_Unichar* src, string &dest )
{
	long i = 0;
	long len = 0;
	
	len = PA_GetUnicharsLength( src );	
	dest.resize( len + 1 ); // v12 bug needed + 1 for zero terminator
	
	if(len > 0){
		while(src[i])
		{
			dest[i] = (char)src[i];
			i++;
		}
	}
	
	dest[i]=0;
}


void plg_WstringToUnichar( const wstring src, PA_Unichar *dest, long destMaxLen ) // will copy max destMaxLen chars
{
	long length	 = src.length();
	destMaxLen = destMaxLen / 2; // PA_Unichar is 2 bytes long per one char
	
	// long destlen = PA_GetUnicharsLength( dest ); // = lengt before byte 0, not container length
	/*
	if( destlen > 255 ) { // always in our code PA_Unichar xxx[256];
		destlen = 255;
	}
	*/
	
	if( destMaxLen < length ) { 
		length = destMaxLen;
	}
	
	// wchar_t *
	long i = 0;
	while( i < length )
	{
		dest[i] = (PA_Unichar)src[i]; 
		i++;
	}
	dest[length]=0;
	
	/*
	 //string sourceCstr(length,' '); // MUST be string, not wstring
	 // string sourceCstr((string)src); 
	 //copy(src.begin(), src.end(), sourceCstr.begin());
	 
	 //if( length != sourceCstr.length())
	 //length = length; // should be same!
	 
	 
	 PA_Unichar *src_ptr;
	 src_ptr = (PA_Unichar *) src.c_str();
	 long len2 = sizeof( dest ); // char[256]
	 if( len2 < len )
	 len = len2; 
	 
	 PA_CopyUnichars( src_ptr, dest, len );
	 
	 long len=sizeof( *dest ); // this will only count chart until it finds 0
	 len=PA_GetUnicharsLength(dest); // this will only count chart until it finds 0
	 
	 long i=0;
	 while( ( src[i] != 0 ) && ( i<255 ) ) // PA_Unichar xxx[256] is normal case
	 {
	 dest[i]=src[i];
	 i++;
	 }
	 if ( i == 255 )
	 i = 255; // trace!
	 
	 dest[i]=0;
	 
	 unsigned long len = src.length();
	 unsigned long maxbytesize = 256;
	 unsigned long byteLen = sizeof(PA_Unichar);
	 unsigned long byteLen2 = sizeof(wchar_t);
	 unsigned long byteLen3 = sizeof(char);
	 unsigned long byteLen4 = sizeof(string::value_type);
	 unsigned long byteLen5 = sizeof(wstring::value_type);
	 wchar_t* source;
	 source = (wchar_t *) src.c_str();
	 
	 if (dest)
	 {
	 while ( source && ( *source != 0 ) && ( maxbytesize > byteLen ) )
	 {
	 *dest = *source;
	 source++;
	 dest++;
	 maxbytesize -= byteLen;
	 }
	 
	 *dest = 0;
	 }
	 */
	
}


void plg_StringToUnichar( const string src, PA_Unichar *dest, long destMaxLen ) // will copy max first 255 chars
{
	long length	 = src.length();
	destMaxLen = destMaxLen / 2; // PA_Unichar is 2 bytes long per one char
	
	// long destlen = PA_GetUnicharsLength( dest ); // = lengt before byte 0, not container length
	/*
	 if( destlen > 255 ) { // always in our code PA_Unichar xxx[256];
	 destlen = 255;
	 }
	 */
	
	if( destMaxLen < length ) { 
		length = destMaxLen;
	}
		
	// wchar_t *
	long i = 0;
	while( i < length )
	{
		dest[i] = (PA_Unichar)src[i]; 
		i++;
	}
	dest[length]=0;
}


void plg_UnistringToWstring(PA_Unistring* src, wstring &dest)
{
	PA_Unichar* src_uchars;
	src_uchars = PA_GetUnistring( src );
	
	plg_UnicharToWstring( src_uchars , dest );
}


void plg_UnistringToString(PA_Unistring* src, string &dest)
{
	PA_Unichar* src_uchars;
	src_uchars = PA_GetUnistring( src );
	
	plg_UnicharToString( src_uchars , dest );
}



/*
void plg_CharToPA_Unichar(char* src, PA_Unichar* dest)
{
	// Convert to a wchar_t*
	size_t origsize = strlen(src) + 1;
	size_t convertedChars = 0;
	mbstowcs_s(&convertedChars, (wchar_t*)dest, origsize, src, _TRUNCATE);
}


void plg_PA_UnicharToChar(PA_Unichar* src, char* dest)
{
	// Convert to a char*
	size_t origsize = wcslen((wchar_t*)src) + 1;
	size_t convertedChars = 0;
	wcstombs_s(&convertedChars, dest, origsize, (wchar_t*)src, _TRUNCATE);
}
*/


/*
 
void plg_CStringToUnistring(char *src, PA_Unichar* dest)
 {
 long i=0;
 while(src[i])
 {
 dest[i]=src[i];
 i++;
 }
 dest[i]=0;
}
 
*/



char* plg_CreateUtf8CharFromUnistring( PA_Unistring *unistr )
{
	//PA_Unistring *Param1 = PA_GetStringParameter(params, 1);
	long len = ( unistr->fLength * 4 ) + 1;
	char *utf8Char = (char *)malloc( len );

	if( utf8Char )
	{
		memset(utf8Char,0x00,len);
		if( len > 1 ){ // no need to convert zero size string, len=1=0x00 at the end of the string
			PA_ConvertCharsetToCharset((char *)unistr->fString,unistr->fLength*2,eVTC_UTF_16,(char *)utf8Char,len,eVTC_UTF_8);
		}	
			// free( utf8Char ); this MUST be called in receiving method
	}
	return utf8Char;
}


PA_Unistring plg_CreateUnistringFromUtf8Char( const char* utf8Char )
{
	/*
	 void plg_CStringToUnistring (wstring sourceCString, PA_Unistring* destinationPAUnistring)
	 { 
	 PA_Unichar* tempUnichar = PA_GetUnistring(destinationPAUnistring); 
	 wchar_t* tempWChar = new wchar_t[sourceCString.length()+1]; 
	 
	 wcscpy(tempWChar, sourceCString.c_str()); 
	 tempUnichar = (PA_Unichar*)tempWChar; 
	 
	 PA_SetUnistring(destinationPAUnistring, tempUnichar); 
	 
	 delete [] tempWChar; // Important, otherwise we get a memory leak. 
	 
	 } 
	 */
	PA_Unistring ustr;
	if( utf8Char ) 
	{
			long len = strlen( utf8Char ); // utf 8
			if( len == 0 ){
				ustr = PA_CreateUnistring( (PA_Unichar *)L"" ); // return null string
				return ustr;
			}
			long value_len = ( len * 4 ) + 2; // utf 16 max len + 0x00,0x00 for zero byte at the end
			char *value_buffer = (char *)malloc( value_len );
			
			if( value_buffer )
			{
				memset( value_buffer, 0x00, value_len );
				PA_ConvertCharsetToCharset( (char *)utf8Char, len, eVTC_UTF_8, value_buffer, value_len, eVTC_UTF_16);	
				
				ustr = PA_CreateUnistring( (PA_Unichar *)value_buffer );
				free( value_buffer );
				
				return ustr;
			}		
	}
	ustr = PA_CreateUnistring( (PA_Unichar *)L"" ); // return null string
	return ustr;
}


// ------------------------------------ utility methods -----------------------------------
long plg_GetCharParameter( PA_PluginParameters params, long paramNum, char* paramChar, long maxCharLen )
{
	long i=0;
	PA_Unichar* Arg_uchars = NULL;
	PA_Unistring* Arg = NULL;
	
	// maxCharLen = maxCharLen / 1; // char is 1 bytes long per 1 character
	
	Arg = PA_GetStringParameter( params, (short)paramNum );
	Arg_uchars = PA_GetUnistring( Arg );
	long length = PA_GetUnistringLength( Arg );
	
	// plg_UnicharToChar( Arg_uchars, paramChar );
	
	if ( maxCharLen < length ) { //( ( maxCharLen > 0 ) && ( maxCharLen < length ) )
		length = maxCharLen;
	}
	
	while( ( i < length ) && ( Arg_uchars[i] ) )
	{
		paramChar[i] = (char)Arg_uchars[i];
		i++;
	}
	
	paramChar[i]=0;
	return i; // char len
	
}

void plg_GetStringParameter( PA_PluginParameters params, long paramNum, string &paramString )
{
	PA_Unichar* Arg_uchars;
	PA_Unistring* Arg;
	
	Arg = PA_GetStringParameter( params, (short)paramNum );
	Arg_uchars = PA_GetUnistring( Arg );
	
	plg_UnicharToString( Arg_uchars, paramString );
	
}

void plg_GetWstringParameter( PA_PluginParameters params, long paramNum, wstring &paramWstring )
{
	PA_Unichar* Arg_uchars;
	PA_Unistring* Arg;
	
	Arg = PA_GetStringParameter( params, (short)paramNum );
	Arg_uchars = PA_GetUnistring( Arg );
	
	plg_UnicharToWstring( Arg_uchars, paramWstring );
	
}

void plg_Alert( wstring errtxt )
{
	PA_Unichar err[256];
	PA_WindowRef ref=0;
	
	plg_WstringToUnichar( errtxt, err, sizeof(err) );
	PA_Alert ( err, ref );
}

void plg_ErrMessage( wstring errtxt, wstring methodName )
{
	wstring err = errtxt + L" (" + methodName + L")";
	if( methodName.length() < 1 ) { // show alert preference -here / callback set
		err = errtxt + L" (Method name missing from the call)";
	} 
	
	if( plg_ErrorCallbackMethodId == 0 ){
		 wstring startChar = methodName.substr(0,1);
		 if( startChar != L"-" ) { // show alert preference -here / callback set
			 plg_Alert ( err );
		 }
		return; // method does not exist
		
	} else {
		
		// instead of PA_Alert we call 4D callback
		PA_Variable params[2];
		PA_Variable dummyVar;
		PA_Unistring err_ustr;
		PA_Unistring methodName_ustr;
		PA_Unichar err_uchar[1024];
		PA_Unichar methodName_uchar[256];
		
		plg_WstringToUnichar( errtxt, err_uchar, sizeof(err_uchar) );
		plg_WstringToUnichar( methodName, methodName_uchar, sizeof(methodName_uchar) );
		
		err_ustr = PA_CreateUnistring( err_uchar );
		methodName_ustr = PA_CreateUnistring( methodName_uchar );
		
		// Set first parameter
		PA_SetStringVariable( &params[0], &err_ustr ); // area reference
		// Set the second parameter
		PA_SetStringVariable( &params[1], &methodName_ustr );
		// Now, we can execute the method
		dummyVar = PA_ExecuteMethodByID( plg_ErrorCallbackMethodId, params, 2);
		
		/*
		 Once you give the variable to 4D by calling PA_SetVariable, 4D will be the owner of the variable and you should not dispose it. This is true if you get the variable by calling PA_GetVariable or if you create it by calling PA_CreateVariable. 

		PA_DisposeUnistring( err_ustr );
		PA_DisposeUnistring( methodName_ustr );
		*/
		
		PA_ClearVariable( &dummyVar );
		PA_ClearVariable( params );
	}
	return;
	
}

// help functions -----------------------------------------

long  BoyerMooreSearch(char* sourceText, char* whatToFind, long txtLen, long findLen)
{
	long i;
	if ( findLen < 1 )
		return -1; // nothing to find, return -1
		
	if ( findLen == 1 ) { // what to find is of size 1 optimization
		for ( i = 0; i < findLen - 1; i++) {
			if ( sourceText[i] == whatToFind[1] )
				return i; // return first found
		}
		return -1; // nothing found
	}
	
	long startPos = 0;
	unsigned char charBuffer = 0; // must absolutely be unsigned char!!!

	if ( ( (txtLen-startPos) >= findLen ) && ( startPos >- 1 ) && ( startPos < txtLen )) {
		unsigned char skipTable[256];

		for(i=0; i<256; i++)
			skipTable[i] = (unsigned char)findLen;

		for(i=0; i < findLen-1; i++)
			skipTable[ (unsigned char) whatToFind[i] ] = (unsigned char) (findLen-i-1);

		while (startPos < (txtLen-findLen)) {
			i = startPos+findLen-1;
			charBuffer = sourceText[i];
			if (whatToFind[ findLen-1 ] == charBuffer) {
			  i = 1;
			  while ( (i<findLen) && (whatToFind[i-1] == sourceText[i+startPos-1]) )
			    i++;
			  if (i == findLen)
			    return startPos; // succesfull find
			}
			startPos = startPos + skipTable[charBuffer];
		}
	}
	return -1; // nothing found
}

wstring String(double d, wstring format)
{
	
	wstring str;
	
	// str = wprintf( L"%f", d  ); // remove later
	try {
		unsigned long len = format.length();
		unsigned long pos = format.rfind(L",");
		
		if( pos == string::npos ) { // string::npos = maximum value of characters that a string can store + 1 = not found
			str = boost::str( boost::wformat( L"%.0f" ) % d ); // L"%.2f" = 120.33 L"%.4f" = 120.3345
		} else if ( pos == len-2 ) {
			str = boost::str( boost::wformat( L"%.1f" ) % d ); // L"%.2f" = 120.33 L"%.4f" = 120.3345
		} else if ( pos == len-3 ) {
			str = boost::str( boost::wformat( L"%.2f" ) % d ); // L"%.2f" = 120.33 L"%.4f" = 120.3345
		} else if ( pos == len-4 ) {
			str = boost::str( boost::wformat( L"%.3f" ) % d ); // L"%.2f" = 120.33 L"%.4f" = 120.3345
		} else {
			str = boost::str( boost::wformat( L"%.1f" ) % d ); // L"%.2f" = 120.33 L"%.4f" = 120.3345
		}
		//string cstr = boost::str( boost::format( "%.1f" ) % d ); 
		//str = plg_StringToWstring( cstr );
	}
	catch (unsigned char newexcept) {
		str = L"err: ";
    str += newexcept;
	};
	//str = wprintf( format.c_str(), "%f", d );
	
	
	/*
	// %d = integer, %f =float
	ios::precision(2);
	swprintf_s( str, "%f", d );
	
	PA_Unichar buffer[256];
	PA_Unichar format_uchars[256];
	plg_WstringToUnichar( format, format_uchars );
	PA_FormatReal( d, format_uchars, buffer );
	plg_UnicharToWstring( buffer, str );
	*/
	return str;
}

wstring String(int i, wstring format)
{
	return String( (long) i, format );
}

wstring String( long i, wstring format)
{
	wstring str;
  // using namespace boost::format;
	
	// str = wprintf( L"%i", i ); // remove later
	try {
		str = boost::str( boost::wformat( L"%d") % i );
	}
	catch (unsigned char newexcept) {
		str = L"err: ";
    str += newexcept;
	};
	
	/*
	 PA_Unichar buffer[256];
	 PA_Unichar format_uchars[256];
	 
	plg_WstringToUnichar( format, format_uchars );
	PA_FormatLongint( i, format_uchars, buffer );
	plg_UnicharToWstring( buffer, str );
	*/
	
	
	/*
	// above command does not work in design mode, it returns format string
	// PA_FormatReal does not work either in design mode

	if ( str == format )
	{
		
		#if VERSIONWIN
			// _itow( i, str, 10 );
			wchar_t buf[20];
			_itow_s(i, buf, 20, 10);
			str = buf;
		#else
			Str255 theString;
			NumToString( i, theString );
			// Line Location Utility.cpp:315: warning: 'NumToString' is deprecated 
			// (declared at /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers/NumberFormatting.h:170)
			str = (wchar_t *) theString;
		#endif
		
	}
	*/

	return str;
}

string NarrowString( long i, string format)
{
	string str;
  // using namespace boost::format;
	
	// str = wprintf( L"%i", i ); // remove later
	try {
		str = boost::str( boost::format( "%d") % i );
	}
	catch (unsigned char newexcept) {
		str = "err: ";
    str += newexcept;
	};
	return str;
}

long Trunc( double in )
{
	return (long)in;
}

long Round( double in )
{
	return (long)Round( in, 0 );
}

double Round( double in, int decimals )
{

	double result, decimalPart, multiplier;
	multiplier = pow(10.0, decimals);
	result = in * multiplier;
	decimalPart = result - (long)result;
	if ( decimalPart >= 0.5 ) 
		result = (long)result + 1;
	else
		result = (long)result;
	result = result / multiplier;

	return result;
}

/*
double Abs( double in )
{
	if ( in < 0 ) 
		return -in;
	else
		return in;
}
*/



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


wstring StringToLower(wstring strToConvert)
{  //change each element of the wstring to lower case
   for(unsigned int i=0;i<strToConvert.length();i++)
   {
      strToConvert[i] = tolower(strToConvert[i]);
   }
   return strToConvert;  //return the converted wstring
} 

long Position( wstring txtToFind, wstring source ) 
{
	return source.find( txtToFind ) + 1;
}

wstring Substring( wstring source, long fromWhere ) 
{
	return Substring( source, fromWhere, source.length() );
}

wstring Substring( wstring source, long fromWhere, long countChars ) 
{
	wstring result = L"";
	
	if( source.c_str()[0] != 0 )
		result = source.substr( fromWhere - 1, countChars );
	
	return result;
}

wstring Replace( wstring source, wstring fromWhat, wstring toWhat )
{
    int pos ;
    do
    {
        pos = source.find(fromWhat);
        if (pos!=-1)
					source.replace(pos, fromWhat.length(), toWhat);
    }
    while (pos!=-1);
    return source;
}

long StringToNum( wstring source )
{
	/*
	 
	 std::wstring value = “123.456″;
	 float f = boost::lexical_cast(value);
	 
	 The additional benefit is that when you use stringstream to convert an incorrect number (e.g if the wstring is “abc.def” and you try to convert it to number), you will get a wrong result.
	 
	 boost::lexical_cast throws a boost::bad_lexical_cast exception when the conversion may not succeed.
	 
	 http://www.boost.org/doc/libs/1_36_0/libs/conversion/lexical_cast.htm
	
	 
	 */
	
	int num = -1;
	
	try
	{
		num = boost::lexical_cast<int>(source);
		// error for ex. 123.456 will go to catch stringstream part
	}
	catch( boost::bad_lexical_cast & )	{
		wstringstream SStream(source);
		num = 0;
		SStream >> num;
	}
	
	/*
	const char* str_int = source.c_str();
	
#if VERSIONWIN
	if( EOF == sscanf_s( str_int, "%d", &num) )
	{
		num = num; //error
	}
#else
	if( EOF == sscanf( str_int, "%d", &num) )
	{
		num = num; //error
	}	
#endif
 */
	
	/*
	long num = -1;
	char ch[1];
	if( source.length() == 0 )
		return num;
	
	strncpy_s( ch, (const char *)source[0], 1 );
	num = (long) ch;
	*/
	return num;
}

wstring Parse( wstring source, wstring divider, long num ) 
{
	long i = 0, k = 0;
	wstring result = L"";
	
	do{
	  i = i+1;
	  k = Position( divider, source );
	  if (i >= num) {
	    
	    if (k<=0)
	    	k = source.length() + 1;
	    
	    result = Substring( source, 1, k-1 );
	    
	  } else { 
	    
	    if (k<=0)
	      i = num;
	    else 
	      source = Substring( source, k + divider.length() );
	    
	  }
	} while (i < num);
	return result;
}

void SmallerFirstSwap( long &var1, long &var2 ) 
{
	if( var2 < var1 ) {
		long temp = var2;
		var2 = var1;
		var1 = temp;
	}
}

long ColorDarknessChange( long color, double darknessPercentage )		
{
	long partColorR, partColorG, partColorB;
	double change = 100.0 / ( 100 + darknessPercentage ); // clBlack = 0x00000000 and clWhite = 0x00FFFFFF

	partColorR = (color & 0x00FF0000) >> 16; // red
	partColorG = (color & 0x0000FF00) >> 8; // green
	partColorB = color & 0x000000FF; // blue
	
	partColorR = Round( partColorR * change);
	if( partColorR > 255 ) // 0x000000FF = 255
		partColorR = 255;
	else if( partColorR < 0 )
		partColorR = 0;

	partColorG = Round( partColorG  * change);
	if( partColorG > 255 )
		partColorG = 255;
	else if( partColorG < 0 )
		partColorG = 0;

	partColorB = Round( partColorB * change);
	if( partColorB > 255 )
		partColorB = 255;
	else if( partColorB < 0 )
		partColorB = 0;

	color = (partColorR << 16) + (partColorG << 8) + partColorB;
	return color;
}
