 /* --------------------------------------------------------------------------------
 #
 #	MA_Plugin_x64.cpp (4DPlugin.c)
 #	source generated by 4D Plugin Wizard
 #	Project : FineLoad
 #	author : Pasi
 #	29.10.2001
 #
 # --------------------------------------------------------------------------------*/

/*
See:
http://sources.4d.com/trac/4d_4dpluginapi
 http://sources.4d.com/trac/4d_4dpluginapi/wiki/Implementations.htm
 drawing:
http://sources.4d.com/trac/4d_4dpluginapi/wiki/CMU84478.HTM
http://sources.4d.com/trac/4d_4dpluginapi/wiki/CMU84339.HTM
 
 void PA_CharAlert		   ( const char* message, PA_WindowRef ref );
 PA_ConvertCharsetToCharset
 PA_SetPluginAreaClipMode
 
*/


	// in win put to project properties / Genereal / Additional include directories:
	// 4D Tcp API,ppc_h,Sources,./include,./apr/apr/include,./apr/apr-util/include
	// maybe also? :Sources\Matrix;Sources\FineLoad;Sources\Tree

//#include <boost/lambda/lambda.hpp>
//#include "boost/date_time/gregorian/gregorian.hpp" //include all types plus i/o
//or

//#include "boost/date_time/gregorian/gregorian_types.hpp" //no i/o just types

#include "MA_Plugin_x64.h"

// these variables will be referenced as extern from:

/*
 int mblen ( const char * pmb, size_t max );
 Get length of multibyte character
 
 The size of the multibyte character pointed by pmb is determined, examining at most max bytes.
 mblen has its own internal shift state, which is altered as necessary only by calls to this function.
 
 Parameters
 
 pmb
 Pointer to the first byte of a multibyte character.
 Alternativelly, the function may be called with a null pointer, in which case the function resets its internal shift state to the initial value and returns whether multibyte characters have state-dependent encodings or not.
 max
 Maximum number of bytes to be checked for character length. No more than MB_CUR_MAX characters are examined in any case.
 
 
 Return Value
 
 If the argument passed as pmb is not a null pointer, the size in bytes of the character pointed by pmb is returned when it forms a valid multibyte character and is not the terminating null character. If it is the terminating null character, the function returns zero, and in the case they do not form a valid multibyte character, -1 is returned.
 If the argument passed as pmb is a null pointer, the function returns a nonzero value if multibyte character encodings are state-dependent, and zero otherwise.
 
 See also
 
 mbtowc	 Convert multibyte character to wide character (function)
 wctomb	 Convert wide character to multibyte character (function)
 mbstowcs	 Convert multibyte string to wide-character string (function)
 wcstombs	 Convert wide-character string to multibyte string (function)
 */

void plg_Test()
{
	int runTest = 0;
	
	if( runTest ){
		/*
	unsigned long maxbytesize = 256;
	unsigned long byteLen = sizeof(PA_Unichar); //mac=2
	unsigned long byteLen2 = sizeof(wchar_t);   //mac=4
	unsigned long byteLen3 = sizeof(char);			//mac=1
	unsigned long byteLen4 = sizeof(string::value_type);	//mac=1
	unsigned long byteLen5 = sizeof(wstring::value_type);	//mac=4
	
		wchar_t c = 'A';
		wchar_t b[255];
		wchar_t *sd = &b[0];
		char *a = "a b c d e f g";
		mbstowcs(sd, a , strlen(a));
		std::wstring s = L"wide string";
		std::wstring *ps = &s;
		
		
	// write test code here...
	wchar_t* wtest = L"testiää!";
	wstring out = L"Run!";
	//plg_Alert(out);
	
	PA_Unichar name[256] = {'#','#','#','#','#','#','#','#','#','#',0}; 
	PA_GetUserName( name ); // works
	
	plg_UnicharToWstring( name, out );
	//plg_Alert(out);
	
	
	out = L"out?";
	//plg_Alert(out);
	
	out = L"out2?";
	// plg_Alert(out);
	
	
	wstring format = L"###### ### ###";
	PA_Unichar format_uchars[] = {'#','#','#','#','#','#','#','#','#','#',0};
	
	plg_UnicharToWstring( format_uchars, out );
	//plg_Alert(out);
	
	PA_Unichar result[256];
	
	long day = 1827; // = days between 1.1.2000 - 1.1.3195 
	PA_FormatLongint( day, format_uchars, result);
	
	double dbl = 12345.6;
	PA_FormatReal( dbl, format_uchars, result );
	
	short d,m,y;
	d=3;
	m=12;
	y=2009;
	
	// PA_EvalDate ( str_uchars, &d, &m, &y ); 
  long formatNum=2;
	//PA_FormatDate (d, m, y, (short)formatNum, result ); // d, m, y are short, can not be more than 32767
	
	
	plg_WstringToUnichar( format, format_uchars );
	plg_UnicharToWstring( format_uchars, out );
	
	day = 1827; // = days between 1.1.2000 - 1.1.3195 
	//PA_FormatLongint( day, format_uchars, result);
	
		*/
	}
	
}


static long plgRegistered = -1;

void PluginMain( long selector, PA_PluginParameters params )
{
	// --- External commands
	long retVal = -1; // command taken by switch

	switch( selector )
	{
	/*
	case eCMD_MA_SharedMemory : // must be fastest in switch case
      retVal = MA_SharedMemoryPluginMain( selector, params );
			break;
    */  
    case eCMD_MA_Microseconds:
    case eCMD_MA_Milliseconds:
    case eCMD_MA_Seconds:
		case eCMD_MA_Markdown :
		case eCMD_MA_LuaText :
		case eCMD_MA_LuaBlob :
      retVal = MA_UtilityPluginMain( selector, params );
			break;
      			      // --- MA_Plugin_x64 register
		case eCMD_MA_v12_Register :
			
			MA_v12_Register( params );
			/*
			if( kFalse ) {
				cjson_test_main();
			}
#ifdef MA_Sql
			database_Test();
#endif
			plg_Test();
			*/
			
			
			retVal = 1;
			break;
			
		case eCMD_MA_v12_IsRegistered :
			MA_v12_IsRegistered( params );
			
			retVal = 1;
			break;
			
			// --- MA_Plugin_x64 error callback
		case eCMD_MA_v12_SetErrorCallback :
			MA_v12_SetErrorCallback( params );
			
			retVal = 1;
			break;
			
			
		case eCMD_MA_Util_Sha2 :
			MA_Util_Sha2( params );
			
			retVal = 1;
			break;
			
      // --- Initialisation
		case kInitPlugin : // -1 start 4D
			
			plgRegistered = kFalse;
			InitPlugin();
			InitTcp();
			// InitSharedMemory(); // after Tcp because of apr init in InitTcp();
			InitUtility();
      
#ifdef MA_Zmq
			MA_Zmq_InitMessage();
#endif
#ifdef MA_Sql
			InitSql();
#endif
			retVal = 1;
			break;
      
      // --- Deinitialisation
		case kDeinitPlugin : // -2 exit 4D
      
			DeInitUtility(); 
			// DeInitSharedMemory(); // before Tcp because of apr deinit in DeInitTcp();
			DeInitTcp();
#ifdef MA_Zmq
			MA_Zmq_DeInitMessage();
#endif
#ifdef MA_Sql
			DeInitSql();
#endif
			DeinitPlugin();
			
			retVal = 1;
			break;
			
		case kCreateProcess :	// -3 called each time a process is created
			//test=1;
			
			retVal = 1;
			break;
			
		case kCloseProcess :	// -4 called each time a process is removed
			//test=2;
			
			CloseProcessUtility();
			retVal = 1;
			break;
			
			/*
       !!!!!!! eAE_LoadRecord and eAE_SaveRecord MUST NOT BE in this case, actually any positive 4D case is NOT allowed !!!!!!!
       // --- Load Record event
       case eAE_LoadRecord :
       
       retVal = 1;
       break;
       
       // --- Save Record event
       case eAE_SaveRecord :
       
       retVal = 1;
			 break;
			 !!!!!!! eAE_LoadRecord and eAE_SaveRecord MUST NOT BE in this case, actually any positive 4D case is NOT allowed !!!!!!!
			 */


		default:  // be sure to have break in every other item before
			
			if( plgRegistered == kTrue ) 
			{
				
#ifdef MA_Json 
				if ( retVal < 0) { // could be first and last enum commands here
					retVal = MA_Json_PluginMain( selector, params );
				}
#endif
				if ( retVal < 0) { // could be first and last enum commands here
					retVal = MA_SocketPluginMain( selector, params );
				}
        
#ifdef MA_Zmq 
				if ( retVal < 0) { // could be first and last enum commands here
					retVal = MA_Zmq_PluginMain( selector, params );
				}
#endif

				
#ifdef MA_Sql
				if ( retVal < 0) { // could be first and last enum commands here
					retVal = SqlPluginMain( selector, params );
				}
#endif
				
				if ( retVal < 0) {
					retVal = -3; // error here !!!
				}
				
			} // end if( plgRegistered == kTrue )
			
		} // end switch case
	
	
} // end PluginMain


/*
 #define  kServerDeinitPlugin		-220
 #define  kServerCleanUp				-207
 #define  kWriteOnServer				-206
 #define  kReadOnServer				-205
 #define  kClientDisconnect			-202
 #define  kClientConnect				-201
 #define  kServerInitPlugin			-200
 #define  kPackageGiveMemory			-10
 #define  kClientDeinitPlugin		-2 
 #define  kDeinitPlugin				kClientDeinitPlugin
 #define  kClientInitPlugin			-1
 #define  kInitPlugin				kClientInitPlugin
 */

void InitPlugin()
{
	// write initialisation code here...
  // printf("InitPlugin()");
}

void DeinitPlugin()
{
	// write deinitialisation code here...
}


void MA_v12_Register( PA_PluginParameters params )
{
	long returnValue = kNOT_DONE_YET;
	sha2 myDigest;
	string hashIn;
	long len;
	
	plg_GetStringParameter( params, 1, hashIn );
	
	len = hashIn.length();
	string hash = myDigest.GetHash( sha2::enuSHA512, (const sha_byte *)hashIn.c_str(), len );
	len = hash.length();

	returnValue = -1; // pw not OK
	plgRegistered = kFalse;
	
	string hashEnd = "690456dcb6e1450fd8081bae3cc426ce540563d448aadb5df9174150aec5d5f5";
	if ( hash == ( "ddc1f40229a8afe1b41d16af52707a808218cd51cfe5bd1b6a05646d23a696ec" + hashEnd )) {
		returnValue = kNoErr;
		plgRegistered = kTrue;
	// } else {
		// can't use zmq msg here: Message->SetLastGeneralErrorText( L"Registration failed" , L"MA_v12_Register", returnValue );
	}

	PA_ReturnLong( params, returnValue );
}

void MA_v12_IsRegistered( PA_PluginParameters params )
{
	long returnValue = plgRegistered;
	PA_ReturnLong( params, returnValue );
}

void MA_v12_SetErrorCallback( PA_PluginParameters params )
{
	wstring Arg1_u;
	long returnValue = 0;
	
	//PA_Unistring *hashUString;
	
	//hashUString = PA_GetStringParameter( params, 1 );
	//plg_UnistringToWstring( hashUString, p_word );
	//plg_GetWstringParameter( params, 1, p_word );

	plg_GetWstringParameter( params, 1, Arg1_u );
	// --- write the code of MA_v12_ErrorCallbackSet here...
	returnValue = plg_ErrorCallbackMethodNameSet( Arg1_u );
	
	PA_ReturnLong( params, returnValue );
}


void MA_Util_Sha2( PA_PluginParameters params )
{
	PA_Unichar returnValue[1024]; // should be dynamic?	
	string hashIn;
	long hashTypeNum;
	sha2::SHA_TYPE hashType;
	sha2 myDigest;
	long len;
	
	hashTypeNum = PA_GetLongParameter( params, 1 );
	plg_GetStringParameter( params, 2, hashIn );

	switch (hashTypeNum){
        case 1   : hashType = sha2::enuSHA1;   break;
        case 224 : hashType = sha2::enuSHA224; break;
        case 256 : hashType = sha2::enuSHA256; break;
        case 384 : hashType = sha2::enuSHA384; break;
        case 512 : hashType = sha2::enuSHA512; break;
        default :	 hashType = sha2::enuSHA256;
  }
	
	len = hashIn.length();
	string hash = myDigest.GetHash( hashType, (const sha_byte *)hashIn.c_str(), len );
	// len = hash.length();

	plg_StringToUnichar( hash, returnValue, sizeof(returnValue) ); // hash.c_str()
	PA_ReturnString( params, returnValue );

}

uint32_t luaCallback(char* command, ...){
  // variable arguments: http://www.eskimo.com/~scs/cclass/int/sx11b.html
  //va_list argp;
  //va_start(argp, command);
  
  uint32_t ret = strlen(command);
  // ret = PA_RecordsInSelection(1);
  // ret = PA_GetMethodID((PA_Unichar *)L"_err CRY");
  // PA_Unistring ustr = plg_CreateUnistringFromUtf8Char(command);
  // PA_ExecuteMethod( ustr );
  // PA_ExecuteMethodByID();
  return ret;
}
