/*
 *  Json_Plugin.cpp
 *  MA_Plugin_x64
 *
 *  Created by pasi on 11.1.2011.
 *  Copyright 2011 Manage Applications. All rights reserved.
 *
 */

#include "Includes.h"

#ifdef MA_Json // must be after #include "Includes.h"

#include "MA_Plugin_x64.h"

//#include "Json_Plugin.h"

// ---------------------------------------------------------
// globals

static wstring jsonLastGeneralErrorText = L"";
static boost::unordered_map<long, long> jsonRefList;
static boost::unordered_map<long, long>::iterator jsonRefListIterator;
//static unordered_set<long> jsonRefList;
//static unordered_set<long>::iterator jsonRefListIterator;

// void MA_Json_msg_test( PA_PluginParameters params ); // delete later

long MA_Json_PluginMain( long selector, PA_PluginParameters params )
{
  	
	switch( selector )
	{
		case eCMD_MA_Json_GetLastErrorText :
			MA_Json_GetLastErrorText( params );
			break;
			
		case eCMD_MA_Json_GetReferences:
			MA_Json_GetReferences( params );
			break;
			
		case eCMD_MA_Json_Parse :
			MA_Json_Parse( params );
			break;
		case eCMD_MA_Json_Print :
			MA_Json_Print( params );
			break;
		case eCMD_MA_Json_PrintUnformatted :
			MA_Json_PrintUnformatted( params );
			break;
		case eCMD_MA_Json_Delete :
			MA_Json_Delete( params );
			break;
			
		case eCMD_MA_Json_GetArraySize :
			MA_Json_GetArraySize( params );
			break;
		case eCMD_MA_Json_GetArrayItem :
			MA_Json_GetArrayItem( params );
			break;
		case eCMD_MA_Json_GetObjectItem :
			MA_Json_GetObjectItem( params );
			break;

		case eCMD_MA_Json_GetObjectString :
			MA_Json_GetObjectString( params );
			break;
		case eCMD_MA_Json_GetObjectLong :
			MA_Json_GetObjectLong( params );
			break;
		case eCMD_MA_Json_GetObjectReal :
			MA_Json_GetObjectReal( params );
			break;
			
		case eCMD_MA_Json_GetItemName :
			MA_Json_GetItemName( params );
			break;
		case eCMD_MA_Json_GetItemType :
			MA_Json_GetItemType( params );
			break;
      
		case eCMD_MA_Json_GetItemString :
			MA_Json_GetItemString( params );
			break;
		case eCMD_MA_Json_GetItemBoolean :
			MA_Json_GetItemBoolean( params );
			break;
		case eCMD_MA_Json_GetItemLong :
			MA_Json_GetItemLong( params );
			break;
		case eCMD_MA_Json_GetItemReal :
			MA_Json_GetItemReal( params );
			break;
			
		case eCMD_MA_Json_GetItemStringArray :
			MA_Json_GetItemStringArray( params );
			break;
		case eCMD_MA_Json_GetItemLongArray :
			MA_Json_GetItemLongArray( params );
			break;			
		case eCMD_MA_Json_GetItemRealArray :
			MA_Json_GetItemRealArray( params );
			break;
			
			
		// These calls create a c_JSON item of the appropriate type.
		case eCMD_MA_Json_CreateNull :
			MA_Json_CreateNull( params );
			break;
		case eCMD_MA_Json_CreateTrue :
			MA_Json_CreateTrue( params );
			break;
		case eCMD_MA_Json_CreateFalse :
			MA_Json_CreateFalse( params );
			break;
		case eCMD_MA_Json_CreateNumber :
			MA_Json_CreateNumber( params );
			break;
		case eCMD_MA_Json_CreateString :
			MA_Json_CreateString( params );
			break;
		case eCMD_MA_Json_CreateArray :
			MA_Json_CreateArray( params );
			break;
		case eCMD_MA_Json_CreateObject :
			MA_Json_CreateObject( params );
			break;
			
			
			// These utilities create an Array of count items.	
		case eCMD_MA_Json_CreateStringArray :
			MA_Json_CreateStringArray( params );
			break;
		case eCMD_MA_Json_CreateLongArray :
			MA_Json_CreateLongArray( params );
			break;			
		case eCMD_MA_Json_CreateRealArray :
			MA_Json_CreateRealArray( params );
			break;
			
		case eCMD_MA_Json_AddItemToArray :
			MA_Json_AddItemToArray( params );
			break;
		case eCMD_MA_Json_AddItemToObject :
			MA_Json_AddItemToObject( params );
			break;			
		case eCMD_MA_Json_AddItemRefToArray :
			MA_Json_AddItemRefToArray( params );
			break;			
		case eCMD_MA_Json_AddItemRefToObject :
			MA_Json_AddItemRefToObject( params );
			break;	
			
			
		case eCMD_MA_Json_DetachItemFromArray :
			MA_Json_DetachItemFromArray( params );
			break;		
		case eCMD_MA_Json_DeleteItemFromArray :
			MA_Json_DeleteItemFromArray( params );
			break;		
		case eCMD_MA_Json_DetachItemFromObject :
			MA_Json_DetachItemFromObject( params );
			break;		
		case eCMD_MA_Json_DeleteItemFromObject :
			MA_Json_DeleteItemFromObject( params );
			break;	
			
		case eCMD_MA_Json_ReplaceItemInArray :
			MA_Json_ReplaceItemInArray( params );
			break;		
		case eCMD_MA_Json_ReplaceItemInObject :
			MA_Json_ReplaceItemInObject( params );
			break;	
			
		case eCMD_MA_Json_AddNullToObject :
			MA_Json_AddNullToObject( params );
			break;		
		case eCMD_MA_Json_AddTrueToObject :
			MA_Json_AddTrueToObject( params );
			break;		
		case eCMD_MA_Json_AddFalseToObject :
			MA_Json_AddFalseToObject( params );
			break;		
		case eCMD_MA_Json_AddNumberToObject :
			MA_Json_AddNumberToObject( params );
			break;		
		case eCMD_MA_Json_AddStringToObject :
			MA_Json_AddStringToObject( params );
			break;	
			
			
		default:
			selector = -1; // was not used
			break;
	
	}
  return selector;
}


// Utility for array list handling.
void suffix_object(c_JSON *prev,c_JSON *item) {prev->next=item;item->prev=prev;}

/* help methods */
c_JSON* ma_json_ref_valid( PA_PluginParameters params, int paramNum ) 
{
	long jsonNum = PA_GetLongParameter( params, paramNum );
	c_JSON *json;
	
	jsonRefListIterator = jsonRefList.find( jsonNum );
  if ( jsonRefListIterator == jsonRefList.end() ) { // not found
		json = NULL;
	} else if ( jsonNum < 1000 ) { // not found
        json = NULL;
	} else {
		json = (c_JSON *)jsonNum;
	}
	return json;
}

long ma_json_ref_add( c_JSON *json )
{
	long jsonNum = (long)json;
	if( jsonNum == 0 ){
		jsonNum = 0;
	} else {
		long prsNum = PA_GetCurrentProcessNumber();
		jsonRefList.insert( std::pair<long, long>(jsonNum, prsNum) ); 
	}
	return jsonNum;
}

long ma_json_ref_delete( c_JSON *json )
{
	long jsonNum = (long)json;
	jsonRefListIterator = jsonRefList.find( jsonNum );
	if ( jsonRefListIterator == jsonRefList.end() ) { // not found
		jsonNum = -10; // error here
	} else {
		jsonRefListIterator = jsonRefList.erase( jsonRefListIterator );
	}
	// Returns:	The iterator following the erased elements - i.e. last.
	return jsonNum;
}


void ma_json_ref_delete_all( c_JSON *c )
{
	// long jsonNum = (long)c;
	// Delete a c_JSON structure.
	// copied from c_JSON_Delete
	/*
	next=c->next;
	if (!(c->type&c_JSON_IsReference) && c->child) c_JSON_Delete(c->child);
	if (!(c->type&c_JSON_IsReference) && c->valuestring) c_JSON_free(c->valuestring);
	if (c->string) c_JSON_free(c->string);
	c_JSON_free(c);
	c=next;
	*/
	
	c_JSON *next;
	
	long findNum;	// jsonRefListIterator = jsonRefList.find( findNum );
	// if ( jsonRefListIterator != jsonRefList.end() ) 
	// { 
        while ( c ) // c or c->next ??? PM
		{
            findNum = (long)c;
            if( findNum < 1000 )
            {
                // findNum = findNum + 1 - 1; // error here
                c = NULL;
            } else {

                next = c->next;
                if ( !( c->type & c_JSON_IsReference ) && c->child ) {
                    /*
                    long jsonNum = (long)c->child;
                    jsonRefListIterator = jsonRefList.find( jsonNum );
                    if ( jsonRefListIterator == jsonRefList.end() ) { // not found
                        jsonNum = -10; // not found from ref list, do not go down the structure
                    } else {*/
                        ma_json_ref_delete_all( c->child );
                    //}
                }
                
                /* delete child from plugin array (if was found)
                 findNum = (long)c;
                 jsonRefListIterator = jsonRefList.find( findNum );
                 if ( jsonRefListIterator != jsonRefList.end() ) { // was found
                 jsonRefListIterator = jsonRefList.erase( jsonRefListIterator );
                 }
                 */ // end delete child from plugin array
                ma_json_ref_delete( c );
                    
                c = next;
            }
		}
	// }
	
}



void SetLastGeneralErrorText(wstring err, wstring methName, long errNum ) {
	jsonLastGeneralErrorText = err + L" (" + methName + L")"; // + errNum
}


void MA_Json_GetLastErrorText( PA_PluginParameters params )
{
	PA_Unichar returnValue[1024]; // should be dynamic?
	plg_WstringToUnichar( jsonLastGeneralErrorText, returnValue, sizeof( returnValue ) );
	jsonLastGeneralErrorText = L"";
	PA_ReturnString( params, returnValue );
}


void MA_Json_GetReferences( PA_PluginParameters params )
{
	
	long returnValue = kNoErr;
	PA_Variable	arr = PA_GetVariableParameter( params, 1 );
	PA_Variable	arrPrsNum = PA_GetVariableParameter( params, 2 );
	
	if ( arr.fType != eVK_ArrayLongint ) {
		returnValue = -1;
		SetLastGeneralErrorText( L"Parameter 1 is not a longint array" , L"MA_Json_GetReferences", 0);
	} else if ( arrPrsNum.fType != eVK_ArrayLongint ) {
		returnValue = -2;
		SetLastGeneralErrorText( L"Parameter 2 is not a longint array" , L"MA_Json_GetReferences", 0);
	} else {
		long arrSize = PA_GetArrayNbElements( arr );
		long arrSizePrsNum = PA_GetArrayNbElements( arrPrsNum );
		long refCount = jsonRefList.size();
		if ( arrSize < refCount ) {
			PA_ResizeArray( &arr, refCount );
			// A "memory full" error (-108) may be returned if there is not enough room in the heap to allocate the array.
			returnValue = PA_GetLastError();
			// PA_SetVariableParameter( params, 1, arr, 0 );  // later
		}
		if (( returnValue == kNoErr) && ( arrSizePrsNum < refCount )) {
			PA_ResizeArray( &arrPrsNum, refCount );
			// A "memory full" error (-108) may be returned if there is not enough room in the heap to allocate the array.
			returnValue = PA_GetLastError();
			// PA_SetVariableParameter( params, 1, arr, 0 );  // later
		}
		if( returnValue != kNoErr) {	
			SetLastGeneralErrorText( L"Memory full error (-108), there is not enough room in the heap to allocate the array" , L"MA_Json_GetReferences", 0);
			returnValue = -abs( returnValue );
		} else {
			long key, value;
			long i = 0;
			for( jsonRefListIterator = jsonRefList.begin(); jsonRefListIterator != jsonRefList.end(); jsonRefListIterator++ ){
				i++;
				key = jsonRefListIterator->first; // in set: (*jsonRefListIterator);
				value = jsonRefListIterator->second; 
				PA_SetLongintInArray( arr, i, key );
				PA_SetLongintInArray( arrPrsNum, i, value );
				if( i%100 == 99 ){
					PA_Yield();
				}
			}
			if ( arrSize < refCount ) {
				PA_SetVariableParameter( params, 1, arr, 0 );
			} else if ( arrSize > refCount ) {
				for( i = refCount + 1; i <= arrSize; i++ ){
					PA_SetLongintInArray( arr, i, 0 );
					if( i%100 == 99 ){
						PA_Yield();
					}
				}
			}
			
			if ( arrSizePrsNum < refCount ) {
				PA_SetVariableParameter( params, 2, arrPrsNum, 0 );
			} else if ( arrSizePrsNum > refCount ) {
				for( i = refCount + 1; i <= arrSizePrsNum; i++ ){
					PA_SetLongintInArray( arrPrsNum, i, 0 );
					if( i%100 == 99 ){
						PA_Yield();
					}
				}
			}
			
			returnValue = refCount;
		}
	}
	PA_ReturnLong( params, returnValue );
}


void MA_Json_Parse( PA_PluginParameters params ) // c_JSON *c_JSON_Parse(const char *value);
{
	// Supply a block of JSON, and this returns a c_JSON object you can interrogate. Call c_JSON_Delete when finished.
	long returnValue = kNoErr;
	
	PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 1 );
	char* blobStr = PA_LockHandle( paramBlobHandle );
	// long blobSize = PA_GetHandleSize(paramBlobHandle);	// how many bytes will we read
	// blobStr[ blobSize ] = 0;
	
	c_JSON *jsonOut = c_JSON_Parse( blobStr );
	PA_UnlockHandle( paramBlobHandle );
	
	if( !jsonOut ) {
		returnValue = -2;
	} else {
		returnValue = ma_json_ref_add( jsonOut ); // add child item to allowed refs
	}
	
	PA_ReturnLong( params, returnValue );
}


void MA_Json_Print( PA_PluginParameters params ) // char  *c_JSON_Print(c_JSON *item);
{
	// Render a c_JSON entity to text for transfer/storage. Free the char* when finished.
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {		
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_Print", 0);
		returnValue = kJsonNotValid;
	} else {
		char *jsonChar = c_JSON_Print( json );
		returnValue = strlen( jsonChar );
		
		PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
		if ( paramBlobHandle == NULL ) {
			paramBlobHandle = PA_NewHandle( returnValue );
		}
    
		// Note that blob(message_data_ptr) is duplicated in the parameter, so blob(message_data_ptr) still belongs to the plug-in after the call.
    // PA_SetBlobParameter ( params, 2, jsonChar, returnValue );
    plg_SetBlobParameter ( params, 2, jsonChar, returnValue );
    free( jsonChar );  // c_JSON_Free    
	}
	PA_ReturnLong( params, returnValue );
}

void MA_Json_PrintUnformatted( PA_PluginParameters params ) // char  *c_JSON_PrintUnformatted(c_JSON *item);
{
	// Render a c_JSON entity to text for transfer/storage without any formatting. Free the char* when finished.
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {		
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_PrintUnformatted", 0);
		returnValue = kJsonNotValid;
	} else {
		char *jsonChar = c_JSON_PrintUnformatted( json );
		returnValue = strlen( jsonChar );
		
		PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
		if ( paramBlobHandle == NULL ) {
			paramBlobHandle = PA_NewHandle( returnValue );
		}
		// Note that blob(message_data_ptr) is duplicated in the parameter, so blob(message_data_ptr) still belongs to the plug-in after the call.
    // PA_SetBlobParameter ( params, 2, jsonChar, returnValue );
    plg_SetBlobParameter ( params, 2, jsonChar, returnValue );
    free( jsonChar ); // c_JSON_Free
	}
	PA_ReturnLong( params, returnValue );
}
	
void MA_Json_Delete( PA_PluginParameters params ) // void   c_JSON_Delete(c_JSON *c);
{
	// Delete a c_JSON entity and all subentities.
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {		
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_Delete", 0);
		returnValue = kJsonNotValid;
	} else {
		ma_json_ref_delete_all( json );
		c_JSON_Delete( json );
	}
	PA_ReturnLong( params, returnValue );
}


void MA_Json_GetArraySize( PA_PluginParameters params ) // int	  c_JSON_GetArraySize(c_JSON *array);
{
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {		
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_GetArraySize", 0);
		returnValue = kJsonNotValid;
	} else {
		returnValue = c_JSON_GetArraySize( json );
	}
	PA_ReturnLong( params, returnValue );
}

void MA_Json_GetArrayItem( PA_PluginParameters params ) // c_JSON *c_JSON_GetArrayItem(c_JSON *array,int item);
{
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {		
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_GetArrayItem", 0);
		returnValue = kJsonNotValid;
	} else {
		long item = PA_GetLongParameter( params, 2 );
		c_JSON *jsonOut = c_JSON_GetArrayItem( json, item-1 ); // index -1 for c++
		
		if( !jsonOut ) {
			SetLastGeneralErrorText( L"Json object was not found" , L"MA_Json_GetArrayItem", 0);
			returnValue = kJsonNotFound;
		} else {
			returnValue = ma_json_ref_add( jsonOut ); // add child item to allowed refs
		}
		
	}
	PA_ReturnLong( params, returnValue );
}


void MA_Json_GetObjectItem( PA_PluginParameters params ) // c_JSON *c_JSON_GetObjectItem(c_JSON *object,const char *string);
{
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {		
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_GetObjectItem", 0);
		returnValue = kJsonNotValid;
	} else {
		PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
		char* blobStr = PA_LockHandle( paramBlobHandle );
  	// long blobSize = PA_GetHandleSize(paramBlobHandle);	// how many bytes will we read
		// blobStr[ blobSize ] = 0;
	
		c_JSON *jsonOut = c_JSON_GetObjectItem( json, blobStr );
		PA_UnlockHandle( paramBlobHandle );
		
		if( !jsonOut ) {
			SetLastGeneralErrorText( L"Json object was not found" , L"MA_Json_GetObjectItem", 0);
			returnValue = kJsonNotFound;
		} else {
			returnValue = ma_json_ref_add( jsonOut ); // add child item to allowed refs
		}
		
	}
	PA_ReturnLong( params, returnValue );
}

void MA_Json_GetObjectString( PA_PluginParameters params ) // "MA_Json_GetObjectReal(&L;&O;&8):L",
{
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {		
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_GetObjectString", 0);
		returnValue = kJsonNotValid;
	} else {
		PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
		char* blobStr = PA_LockHandle( paramBlobHandle );
  	// long blobSize = PA_GetHandleSize(paramBlobHandle);	// how many bytes will we read
		// blobStr[ blobSize ] = 0;
		
		c_JSON *jsonOut = c_JSON_GetObjectItem( json, blobStr );
		PA_UnlockHandle( paramBlobHandle );
		
		if( !jsonOut ) {
			SetLastGeneralErrorText( L"Json object was not found" , L"MA_Json_GetObjectString", 0);
			returnValue = kJsonNotFound;
		} else if ( ((jsonOut->type)&255) != c_JSON_String ) {
			SetLastGeneralErrorText( L"Json type is not a string" , L"MA_Json_GetObjectString", 0);
			returnValue = kJsonWrongType;
		} else {
			returnValue = strlen( jsonOut->valuestring );
			
			PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 3 );
			if ( paramBlobHandle == NULL ) {
				paramBlobHandle = PA_NewHandle( returnValue );
			}
			// Note that blob(message_data_ptr) is duplicated in the parameter, so blob(message_data_ptr) still belongs to the plug-in after the call.
      // PA_SetBlobParameter( params, 3, jsonOut->valuestring, returnValue );
      plg_SetBlobParameter ( params, 3, jsonOut->valuestring, returnValue );
		}
		// returnValue = ma_json_ref_add( jsonOut ); // add child item to allowed refs
	}
	PA_ReturnLong( params, returnValue );
}

void MA_Json_GetObjectLong( PA_PluginParameters params ) // "MA_Json_GetObjectLong(&L;&O;&L):L",
{
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {		
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_GetObjectLong", 0);
		returnValue = kJsonNotValid;
	} else {
		PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
		char* blobStr = PA_LockHandle( paramBlobHandle );
  	// long blobSize = PA_GetHandleSize(paramBlobHandle);	// how many bytes will we read
		// blobStr[ blobSize ] = 0;
		
		c_JSON *jsonOut = c_JSON_GetObjectItem( json, blobStr );
		PA_UnlockHandle( paramBlobHandle );
		
		if( !jsonOut ) {
			SetLastGeneralErrorText( L"Json object was not found" , L"MA_Json_GetObjectLong", 0);
			returnValue = kJsonNotFound;
		} else if ( ((jsonOut->type)&255) != c_JSON_Number ) {
			SetLastGeneralErrorText( L"Json type is not a number" , L"MA_Json_GetObjectLong", 0);
			returnValue = kJsonWrongType;
		} else {
			PA_SetLongParameter( params, 3, jsonOut->valueint );
		}
		// returnValue = ma_json_ref_add( jsonOut ); // add child item to allowed refs
	}
	PA_ReturnLong( params, returnValue );
}

void MA_Json_GetObjectReal( PA_PluginParameters params ) // "MA_Json_GetObjectReal(&L;&O;&8):L",
{
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {		
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_GetObjectReal", 0);
		returnValue = kJsonNotValid;
	} else {
		PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
		char* blobStr = PA_LockHandle( paramBlobHandle );
  	// long blobSize = PA_GetHandleSize(paramBlobHandle);	// how many bytes will we read
		// blobStr[ blobSize ] = 0;
		
		c_JSON *jsonOut = c_JSON_GetObjectItem( json, blobStr );
		PA_UnlockHandle( paramBlobHandle );
		
		if( !jsonOut ) {
			SetLastGeneralErrorText( L"Json object was not found" , L"MA_Json_GetObjectReal", 0);
			returnValue = kJsonNotFound;
		} else if ( ((jsonOut->type)&255) != c_JSON_Number ) {
			SetLastGeneralErrorText( L"Json type is not a number" , L"MA_Json_GetObjectReal", 0);
			returnValue = kJsonWrongType;
		} else {
			PA_SetDoubleParameter( params, 3, jsonOut->valuedouble );
		}

		// returnValue = ma_json_ref_add( jsonOut ); // add child item to allowed refs
	}
	PA_ReturnLong( params, returnValue );
}


void MA_Json_GetItemName( PA_PluginParameters params ) // "MA_Json_GetItemName(&L;&O):L",
{
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_GetItemName", 0);
		returnValue = kJsonNotValid;
	} else if ( !json->string ) {
    SetLastGeneralErrorText( L"Json object name does not exist" , L"MA_Json_GetItemName", 0);
		returnValue = kJsonWrongType;
  } else {
    returnValue = strlen( json->string );
    
    PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
    if ( paramBlobHandle == NULL ) {
      paramBlobHandle = PA_NewHandle( returnValue );
    }
    // Note that blob(message_data_ptr) is duplicated in the parameter, so blob(message_data_ptr) still belongs to the plug-in after the call.
    // PA_SetBlobParameter( params, 2, json->string, returnValue );
    plg_SetBlobParameter ( params, 2, json->string, returnValue );
	}
	PA_ReturnLong( params, returnValue );
}

void MA_Json_GetItemType( PA_PluginParameters params ) // "MA_Json_GetItemType(&L):L",
{
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_GetItemType", 0);
		returnValue = kJsonNotValid;
	} else {
    returnValue = (json->type)&255;
    /*
     #define c_JSON_False 0
     #define c_JSON_True 1
     #define c_JSON_NULL 2
     #define c_JSON_Number 3
     #define c_JSON_String 4
     #define c_JSON_Array 5
     #define c_JSON_Object 6
     */
  }
  PA_ReturnLong( params, returnValue );
}


void MA_Json_GetItemString( PA_PluginParameters params ) // "MA_Json_GetObjectLong(&L;&O;&L):L",
{
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {		
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_GetItemString", 0);
		returnValue = kJsonNotValid;
	} else if ( ((json->type)&255) != c_JSON_String ) {
		SetLastGeneralErrorText( L"Json type is not a number" , L"MA_Json_GetItemString", 0);
		returnValue = kJsonWrongType;
	} else {
		returnValue = strlen( json->valuestring );
		
		PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
		if ( paramBlobHandle == NULL ) {
			paramBlobHandle = PA_NewHandle( returnValue );
		}
		// Note that blob(message_data_ptr) is duplicated in the parameter, so blob(message_data_ptr) still belongs to the plug-in after the call.
    // PA_SetBlobParameter ( params, 2, json->valuestring, returnValue );
    plg_SetBlobParameter ( params, 2, json->valuestring, returnValue );
  }
  // returnValue = ma_json_ref_add( jsonOut ); // add child item to allowed refs
	
	PA_ReturnLong( params, returnValue );
}


void MA_Json_GetItemBoolean( PA_PluginParameters params ) // "MA_Json_GetObjectLong(&L;&O;&L):L",
{
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_GetItemBoolean", 0);
		returnValue = kJsonNotValid;
	} else if ( ( ((json->type)&255) != c_JSON_True ) || ( ((json->type)&255) != c_JSON_False ) ) {
		SetLastGeneralErrorText( L"Json type is not a boolean" , L"MA_Json_GetItemBoolean", 0);
		returnValue = kJsonWrongType;
	} else {
		PA_SetLongParameter( params, 2, json->valueint );
	}
  // returnValue = ma_json_ref_add( jsonOut ); // add child item to allowed refs
  
	PA_ReturnLong( params, returnValue );
}

void MA_Json_GetItemLong( PA_PluginParameters params ) // "MA_Json_GetObjectLong(&L;&O;&L):L",
{
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {		
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_GetItemLong", 0);
		returnValue = kJsonNotValid;
	} else if ( ((json->type)&255) != c_JSON_Number ) {
		SetLastGeneralErrorText( L"Json type is not a number" , L"MA_Json_GetItemLong", 0);
		returnValue = kJsonWrongType;
	} else {
		PA_SetLongParameter( params, 2, json->valueint );
	}
		// returnValue = ma_json_ref_add( jsonOut ); // add child item to allowed refs
		
	PA_ReturnLong( params, returnValue );
}

void MA_Json_GetItemReal( PA_PluginParameters params ) // "MA_Json_GetObjectLong(&L;&O;&L):L",
{
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {		
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_GetItemReal", 0);
		returnValue = kJsonNotValid;
	} else if ( ((json->type)&255) != c_JSON_Number ) {
		SetLastGeneralErrorText( L"Json type is not a number" , L"MA_Json_GetItemReal", 0);
		returnValue = kJsonWrongType;
	} else {
		PA_SetDoubleParameter( params, 2, json->valuedouble) ;
	}
		// returnValue = ma_json_ref_add( jsonOut ); // add child item to allowed refs

	PA_ReturnLong( params, returnValue );
}


void MA_Json_GetItemStringArray( PA_PluginParameters params ) // c_JSON *c_JSON_CreateStringArray(const char **strings,int count);
{
	
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {		
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_GetItemStringArray", 0);
		returnValue = kJsonNotValid;
	} else if ( ((json->type)&255) != c_JSON_Array ) {
		SetLastGeneralErrorText( L"Json item type is not an array" , L"MA_Json_GetItemStringArray", 0);
		returnValue = kJsonWrongType;
	} else {
		
		PA_Variable	arr = PA_GetVariableParameter( params, 2 );
		// long arrFrom = PA_GetLongParameter( params, 3 );
		// long arrTo = PA_GetLongParameter( params, 4 );
		
		if ( arr.fType != eVK_ArrayUnicode ) {
			returnValue = -1;
			SetLastGeneralErrorText( L"Parameter 2 is not a text array" , L"MA_Json_GetItemStringArray", 0);
		} else {
			
			long refCount = c_JSON_GetArraySize( json );
			long arrSize = PA_GetArrayNbElements( arr );
			/*
			 if( arrFrom < 0) {
			 arrFrom = 0;
			 }
			 if( arrTo < 0) {
			 arrTo = arrSize;
			 }
			 if( arrTo > arrSize) {
			 arrTo = arrSize;
			 }
			 long count = arrTo - arrFrom + 1;
			 */
			
			if ( arrSize != refCount ) {
				PA_ResizeArray( &arr, refCount );
				// A "memory full" error (-108) may be returned if there is not enough room in the heap to allocate the array.
				returnValue = PA_GetLastError();
				// PA_SetVariableParameter( params, 1, arr, 0 );  // later
			}
			
			if( returnValue != kNoErr) {	
				SetLastGeneralErrorText( L"Memory full error (-108), there is not enough room in the heap to allocate the array" , L"MA_Json_GetItemStringArray", 0);
				returnValue = -abs( returnValue );
			} else {
				
				long i = 0;
				
				c_JSON *c = json->child;  
				while ( c ) {
					i++;
					PA_Unistring unistr;
					unistr = plg_CreateUnistringFromUtf8Char( c->valuestring );
					PA_SetStringInArray( arr, i, &unistr );
					
					// usually we would dispose unistr: PA_ClearVariable( &unistr ); 
					/*
					 * When you call PA_SetStringInArray, PA_SetPictureInArray, the given   
					 object will now belongs to the array. Any previous object in the array   
					 will be disposed. 
					 
					 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. 
					*/
					
					
					if( i%100 == 99 ){
						PA_Yield();
					}
					c = c->next;
				}
				
				if ( arrSize != refCount ) {
					PA_SetVariableParameter( params, 2, arr, 0 );
				}
				
				returnValue = refCount;
			}
		}
	}
	
	PA_ReturnLong( params, returnValue );
}



// These utilities create an Array of count items.	
void MA_Json_GetItemLongArray( PA_PluginParameters params ) // c_JSON *c_JSON_CreateIntArray(int *numbers,int count);
{
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {		
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_GetItemLongArray", 0);
		returnValue = kJsonNotValid;
	} else if ( ((json->type)&255) != c_JSON_Array ) {
		SetLastGeneralErrorText( L"Json item type is not an array" , L"MA_Json_GetItemLongArray", 0);
		returnValue = kJsonWrongType;
	} else {
		
		PA_Variable	arr = PA_GetVariableParameter( params, 2 );
		// long arrFrom = PA_GetLongParameter( params, 3 );
		// long arrTo = PA_GetLongParameter( params, 4 );
	
		if ( arr.fType != eVK_ArrayLongint ) {
			returnValue = -1;
			SetLastGeneralErrorText( L"Parameter 2 is not a longint array" , L"MA_Json_GetItemLongArray", 0);
		} else {
			
			long refCount = c_JSON_GetArraySize( json );
			long arrSize = PA_GetArrayNbElements( arr );
			/*
			if( arrFrom < 0) {
				arrFrom = 0;
			}
			if( arrTo < 0) {
				arrTo = arrSize;
			}
			if( arrTo > arrSize) {
				arrTo = arrSize;
			}
			long count = arrTo - arrFrom + 1;
			*/
			
			if ( arrSize != refCount ) {
				PA_ResizeArray( &arr, refCount );
				// A "memory full" error (-108) may be returned if there is not enough room in the heap to allocate the array.
				returnValue = PA_GetLastError();
				// PA_SetVariableParameter( params, 1, arr, 0 );  // later
			}
			
			if( returnValue != kNoErr) {	
				SetLastGeneralErrorText( L"Memory full error (-108), there is not enough room in the heap to allocate the array" , L"MA_Json_GetItemLongArray", 0);
				returnValue = -abs( returnValue );
			} else {
				
				long i = 0;
				
				c_JSON *c = json->child;  
				while ( c ) {
					i++;
					PA_SetLongintInArray( arr, i, c->valueint );
					if( i%100 == 99 ){
						PA_Yield();
					}
					c = c->next;
				}
				
				if ( arrSize != refCount ) {
					PA_SetVariableParameter( params, 2, arr, 0 );
				}
				
				returnValue = refCount;
			}
		}
	}
	
	PA_ReturnLong( params, returnValue );
}

void MA_Json_GetItemRealArray( PA_PluginParameters params ) // c_JSON *c_JSON_CreateDoubleArray(double *numbers,int count);
// (c_JSON *c_JSON_CreateFloatArray(float *numbers,int count);)
{
	long returnValue = kNoErr;
	c_JSON *json;
	
	json = ma_json_ref_valid( params, 1 );
	if ( json == NULL ) {		
		SetLastGeneralErrorText( L"Json parameter is not a valid json reference" , L"MA_Json_GetItemRealArray", 0);
		returnValue = kJsonNotValid;
	} else if ( ((json->type)&255) != c_JSON_Array ) {
		SetLastGeneralErrorText( L"Json item type is not an array" , L"MA_Json_GetItemRealArray", 0);
		returnValue = kJsonWrongType;
	} else {
		
		PA_Variable	arr = PA_GetVariableParameter( params, 2 );
		// long arrFrom = PA_GetLongParameter( params, 3 );
		// long arrTo = PA_GetLongParameter( params, 4 );
		
		if ( arr.fType != eVK_ArrayReal ) {
			returnValue = -1;
			SetLastGeneralErrorText( L"Parameter 2 is not a longint array" , L"MA_Json_GetItemRealArray", 0);
		} else {
			
			long refCount = c_JSON_GetArraySize( json );
			long arrSize = PA_GetArrayNbElements( arr );
			/*
			 if( arrFrom < 0) {
			 arrFrom = 0;
			 }
			 if( arrTo < 0) {
			 arrTo = arrSize;
			 }
			 if( arrTo > arrSize) {
			 arrTo = arrSize;
			 }
			 long count = arrTo - arrFrom + 1;
			 */
			
			if ( arrSize != refCount ) {
				PA_ResizeArray( &arr, refCount );
				// A "memory full" error (-108) may be returned if there is not enough room in the heap to allocate the array.
				returnValue = PA_GetLastError();
				// PA_SetVariableParameter( params, 1, arr, 0 );  // later
			}
			
			if( returnValue != kNoErr) {	
				SetLastGeneralErrorText( L"Memory full error (-108), there is not enough room in the heap to allocate the array" , L"MA_Json_GetItemRealArray", 0);
				returnValue = -abs( returnValue );
			} else {
				
				long i = 0;
				
				c_JSON *c = json->child;  
				while ( c ) {
					i++;
					PA_SetRealInArray( arr, i, c->valuedouble );
					if( i%100 == 99 ){
						PA_Yield();
					}
					c = c->next;
				}
				
				if ( arrSize != refCount ) {
					PA_SetVariableParameter( params, 2, arr, 0 );
				}
				
				returnValue = refCount;
			}
		}
	}
	
	PA_ReturnLong( params, returnValue );
}


void MA_Json_CreateNull( PA_PluginParameters params ) // c_JSON *c_JSON_CreateNull();
{
	long returnValue = kNoErr;
	
	c_JSON *json = c_JSON_CreateNull();
	returnValue = ma_json_ref_add( json );	
	
	PA_ReturnLong( params, returnValue );
}


void MA_Json_CreateTrue( PA_PluginParameters params ) // c_JSON *c_JSON_CreateTrue();
{
	long returnValue = kNoErr;
	
	c_JSON *json = c_JSON_CreateTrue();
	returnValue = ma_json_ref_add( json );	
	
	PA_ReturnLong( params, returnValue );
}


void MA_Json_CreateFalse( PA_PluginParameters params ) // c_JSON *c_JSON_CreateFalse();
{
	long returnValue = kNoErr;
	
	c_JSON *json = c_JSON_CreateFalse();
	returnValue = ma_json_ref_add( json );	
	
	PA_ReturnLong( params, returnValue );
}


void MA_Json_CreateNumber( PA_PluginParameters params ) // c_JSON *c_JSON_CreateNumber(double num);
{
	long returnValue = kNoErr;
	double num = PA_GetDoubleParameter( params, 1 );
	
	c_JSON *json = c_JSON_CreateNumber( num );
	returnValue = ma_json_ref_add( json );	
	
	PA_ReturnLong( params, returnValue );
}


void MA_Json_CreateString( PA_PluginParameters params ) //  c_JSON *c_JSON_CreateString(const char *string);
{
	long returnValue = kNoErr;
	PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 1 );
	char* blobStr = PA_LockHandle( paramBlobHandle );
	// long blobSize = PA_GetHandleSize(paramBlobHandle);	// how many bytes will we read
	// blobStr[ blobSize ] = 0;

	c_JSON *json = c_JSON_CreateString( blobStr );
	PA_UnlockHandle( paramBlobHandle );
	returnValue = ma_json_ref_add( json );	
	
	PA_ReturnLong( params, returnValue );
}


void MA_Json_CreateArray( PA_PluginParameters params ) // c_JSON *c_JSON_CreateArray();
{
	// Delete a c_JSON entity and all subentities.
	long returnValue = kNoErr;
	
	c_JSON *json = c_JSON_CreateArray();
	returnValue = ma_json_ref_add( json );
	
	PA_ReturnLong( params, returnValue );
}

void MA_Json_CreateObject( PA_PluginParameters params ) // c_JSON *c_JSON_CreateObject();
{
	// Delete a c_JSON entity and all subentities.
	long returnValue = kNoErr;
	
	c_JSON *json = c_JSON_CreateObject();
	returnValue = ma_json_ref_add( json );
	
	PA_ReturnLong( params, returnValue );
}


void MA_Json_CreateStringArray( PA_PluginParameters params ) // c_JSON *c_JSON_CreateStringArray(const char **strings,int count);
{
	long returnValue = kNoErr;
	PA_Variable	arr = PA_GetVariableParameter( params, 1 );
	long arrFrom = PA_GetLongParameter( params, 2 );
	long arrTo = PA_GetLongParameter( params, 3 );
	
	if ( arr.fType != eVK_ArrayUnicode) {
		returnValue = -1;
		SetLastGeneralErrorText( L"Parameter 1 is not a string array" , L"MA_Json_CreateStringArray", 0);
	} else {
		
		long arrSize = PA_GetArrayNbElements( arr );
		if( arrFrom < 0) {
			arrFrom = 0;
		}
		if( arrTo < 0) {
			arrTo = arrSize;
		}
		if( arrTo > arrSize) {
			arrTo = arrSize;
		}
		long count = arrTo - arrFrom + 1;
		
		if ( count < 1 ) {
			returnValue = -2;
			SetLastGeneralErrorText( L"No array elements to add" , L"MA_Json_CreateStringArray", 0);
		} else {
			
			PA_Unistring value;
			char *utf8Char;
			long i;
			c_JSON *n=0,*p=0,*a=c_JSON_CreateArray();
			for(i=0;i<count;i++){
				if( i%100 == 99 ){
					PA_Yield();
				}
				value = PA_GetStringInArray( arr, i+1 );
				utf8Char = plg_CreateUtf8CharFromUnistring( &value );
				if( !utf8Char ) {
					returnValue = -3;
					SetLastGeneralErrorText( L"Creating string variable failed" , L"MA_Json_CreateStringArray", 0);
					break;
				} else { // crete variable succeeded
					n = c_JSON_CreateString( utf8Char );
					free( utf8Char ); // this MUST be called after plg_CreateUtf8CharFromUnistring
					if(!i)
						a->child=n;
					else 
						suffix_object(p,n);
					p=n;
				}
			}
			returnValue = ma_json_ref_add( a );		
		}
	}
	
	PA_ReturnLong( params, returnValue );
}



// These utilities create an Array of count items.	
void MA_Json_CreateLongArray( PA_PluginParameters params ) // c_JSON *c_JSON_CreateIntArray(int *numbers,int count);
{
	long returnValue = kNoErr;
	PA_Variable	arr = PA_GetVariableParameter( params, 1 );
	long arrFrom = PA_GetLongParameter( params, 2 );
	long arrTo = PA_GetLongParameter( params, 3 );
	
	if ( arr.fType != eVK_ArrayLongint ) {
		returnValue = -1;
		SetLastGeneralErrorText( L"Parameter 1 is not a longint array" , L"MA_Json_CreateLongArray", 0);
	} else {
		/*
		c_JSON *json = c_JSON_CreateIntArray( , count );
		 =
		c_JSON *c_JSON_CreateIntArray(int *numbers,int count)	
		{int i;c_JSON *n=0,*p=0,*a=c_JSON_CreateArray();
			for(i=0;i<count;i++){
				n=c_JSON_CreateNumber(numbers[i]);
				if(!i)a->child=n;
				else suffix_object(p,n);
				p=n;}
			return a;
		}*/
		
		long arrSize = PA_GetArrayNbElements( arr );
		if( arrFrom < 0) {
			arrFrom = 0;
		}
		if( arrTo < 0) {
			arrTo = arrSize;
		}
		if( arrTo > arrSize) {
			arrTo = arrSize;
		}
		long count = arrTo - arrFrom + 1;
		
		if ( count < 1 ) {
			returnValue = -2;
			SetLastGeneralErrorText( L"No array elements to add" , L"MA_Json_CreateLongArray", 0);
		} else {
				
			long value, i;
			c_JSON *n=0,*p=0,*a=c_JSON_CreateArray();
			for(i=0;i<count;i++){
				if( i%100 == 99 ){
					PA_Yield();
				}
				value = PA_GetLongintInArray( arr, i+1 );
				n = c_JSON_CreateNumber( value );
				if(!i)
					a->child=n;
				else 
					suffix_object(p,n);
				p=n;
			} // end for
			returnValue = ma_json_ref_add( a );		
		}
	}
	
	PA_ReturnLong( params, returnValue );
}

void MA_Json_CreateRealArray( PA_PluginParameters params ) // c_JSON *c_JSON_CreateDoubleArray(double *numbers,int count);
// (c_JSON *c_JSON_CreateFloatArray(float *numbers,int count);)
{
	long returnValue = kNoErr;
	PA_Variable	arr = PA_GetVariableParameter( params, 1 );
	long arrFrom = PA_GetLongParameter( params, 2 );
	long arrTo = PA_GetLongParameter( params, 3 );
	
	if ( arr.fType != eVK_ArrayReal ) {
		returnValue = -1;
		SetLastGeneralErrorText( L"Parameter 1 is not a real array" , L"MA_Json_CreateRealArray", 0);
	} else {
		
		long arrSize = PA_GetArrayNbElements( arr );
		if( arrFrom < 0) {
			arrFrom = 0;
		}
		if( arrTo < 0) {
			arrTo = arrSize;
		}
		if( arrTo > arrSize) {
			arrTo = arrSize;
		}
		long count = arrTo - arrFrom + 1;
		
		if ( count < 1 ) {
			returnValue = -2;
			SetLastGeneralErrorText( L"No array elements to add" , L"MA_Json_CreateRealArray", 0);
		} else {
			
			double value;
			long i;
			c_JSON *n=0,*p=0,*a=c_JSON_CreateArray();
			for(i=0;i<count;i++){
				if( i%100 == 99 ){
					PA_Yield();
				}
				value = PA_GetRealInArray( arr, i+1 );
				n=c_JSON_CreateNumber( value );
				if(!i)
					a->child=n;
				else 
					suffix_object(p,n);
				p=n;
			}
			returnValue = ma_json_ref_add( a );
		}
	}
	
	PA_ReturnLong( params, returnValue );
}



void MA_Json_AddItemToArray( PA_PluginParameters params ) // void c_JSON_AddItemToArray(c_JSON *array, c_JSON *item);
{
	// Append item to the specified array/object.
	long returnValue = kNoErr;
	
	c_JSON *jsonArray = ma_json_ref_valid( params, 1 );
	c_JSON *jsonItem = ma_json_ref_valid( params, 2 );
	
	if ( jsonArray == NULL ) {		
		SetLastGeneralErrorText( L"Json array parameter is not a valid json reference" , L"MA_Json_AddItemToArray", 0);
		returnValue = kJsonNotValid;
	} else if ( jsonItem == NULL ) {		
		SetLastGeneralErrorText( L"Json item parameter is not a valid json reference" , L"MA_Json_AddItemToArray", 0);
		returnValue = kJsonNotValid;
	} else {		
		returnValue = ma_json_ref_delete( jsonItem ); // now belongs inside main object
		c_JSON_AddItemToArray( jsonArray, jsonItem );
	}
	PA_ReturnLong( params, returnValue );
}

void MA_Json_AddItemToObject( PA_PluginParameters params ) 
// void	c_JSON_AddItemToObject(c_JSON *object,const char *string,c_JSON *item);
{
	// Append item to the specified array/object.
	long returnValue = kNoErr;	
	
	c_JSON *jsonObject = ma_json_ref_valid( params, 1 );
	c_JSON *jsonItem = ma_json_ref_valid( params, 3 );
	
	if ( jsonObject == NULL ) {		
		SetLastGeneralErrorText( L"Json object parameter is not a valid json reference" , L"MA_Json_AddItemToObject", 0);
		returnValue = kJsonNotValid;
	} else if ( jsonItem == NULL ) {		
		SetLastGeneralErrorText( L"Json item parameter is not a valid json reference" , L"MA_Json_AddItemToObject", 0);
		returnValue = kJsonNotValid;
	} else {		
		PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
		char* blobStr = PA_LockHandle( paramBlobHandle );
		// long blobSize = PA_GetHandleSize(paramBlobHandle);	// how many bytes will we read
		// blobStr[ blobSize ] = 0;
		
		returnValue = ma_json_ref_delete( jsonItem ); // now belongs inside main object
		c_JSON_AddItemToObject( jsonObject, blobStr, jsonItem );
		PA_UnlockHandle( paramBlobHandle );
    returnValue = (long)jsonItem; // v12.2, not return value from ma_json_ref_delete
	}
	PA_ReturnLong( params, returnValue );
}

void MA_Json_AddItemRefToArray( PA_PluginParameters params ) // void c_JSON_AddItemReferenceToArray(c_JSON *array, c_JSON *item);
{
	// Append reference to item to the specified array/object. Use this when you want to add an existing c_JSON to a new c_JSON, but don't want to corrupt your existing c_JSON.
	long returnValue = kNoErr;	
	
	c_JSON *jsonArray = ma_json_ref_valid( params, 1 );
	c_JSON *jsonItem = ma_json_ref_valid( params, 2 );
	
	if ( jsonArray == NULL ) {		
		SetLastGeneralErrorText( L"Json array parameter is not a valid json reference" , L"MA_Json_AddItemRefToArray", 0);
		returnValue = kJsonNotValid;
	} else if ( jsonItem == NULL ) {		
		SetLastGeneralErrorText( L"Json item parameter is not a valid json reference" , L"MA_Json_AddItemRefToArray", 0);
		returnValue = kJsonNotValid;
	} else {				
		c_JSON_AddItemReferenceToArray( jsonArray, jsonItem );
	}
	PA_ReturnLong( params, returnValue );
}

void MA_Json_AddItemRefToObject( PA_PluginParameters params ) // void	c_JSON_AddItemReferenceToObject(c_JSON *object,const char *string,c_JSON *item);
{
	// Append reference to item to the specified array/object. Use this when you want to add an existing c_JSON to a new c_JSON, but don't want to corrupt your existing c_JSON.
	long returnValue = kNoErr;	
	
	c_JSON *jsonObject = ma_json_ref_valid( params, 1 );
	c_JSON *jsonItem = ma_json_ref_valid( params, 3 );
	
	if ( jsonObject == NULL ) {		
		SetLastGeneralErrorText( L"Json object parameter is not a valid json reference" , L"MA_Json_AddItemRefToObject", 0);
		returnValue = kJsonNotValid;
	} else if ( jsonItem == NULL ) {		
		SetLastGeneralErrorText( L"Json item parameter is not a valid json reference" , L"MA_Json_AddItemRefToObject", 0);
		returnValue = kJsonNotValid;
	} else {		
		PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
		char* blobStr = PA_LockHandle( paramBlobHandle );
		// long blobSize = PA_GetHandleSize(paramBlobHandle);	// how many bytes will we read
		// blobStr[ blobSize ] = 0;
		
		c_JSON_AddItemReferenceToObject( jsonObject, blobStr, jsonItem );
		PA_UnlockHandle( paramBlobHandle );
	}
	PA_ReturnLong( params, returnValue );
}

void MA_Json_DetachItemFromArray( PA_PluginParameters params ) // c_JSON *c_JSON_DetachItemFromArray(c_JSON *array,int which);
{
	long returnValue = kNoErr;
	
	c_JSON *jsonArray = ma_json_ref_valid( params, 1 );
	
	if ( jsonArray == NULL ) {		
		SetLastGeneralErrorText( L"Json array parameter is not a valid json reference" , L"MA_Json_DetachItemFromArray", 0);
		returnValue = kJsonNotValid;
	} else {
		long jsonItemNum = PA_GetLongParameter( params, 2 );
		c_JSON *json = c_JSON_DetachItemFromArray( jsonArray, jsonItemNum );
		returnValue = ma_json_ref_add( json );	
	}
	PA_ReturnLong( params, returnValue );	
}

void MA_Json_DeleteItemFromArray( PA_PluginParameters params ) // void   c_JSON_DeleteItemFromArray(c_JSON *array,int which);
{
	long returnValue = kNoErr;
	
	c_JSON *jsonArray = ma_json_ref_valid( params, 1 );
	
	if ( jsonArray == NULL ) {		
		SetLastGeneralErrorText( L"Json array parameter is not a valid json reference" , L"MA_Json_DeleteItemFromArray", 0);
		returnValue = kJsonNotValid;
	} else {
		long jsonItemNum = PA_GetLongParameter( params, 2 );
		c_JSON_DeleteItemFromArray( jsonArray, jsonItemNum );
	}
	PA_ReturnLong( params, returnValue );		
}

void MA_Json_DetachItemFromObject( PA_PluginParameters params ) // c_JSON *c_JSON_DetachItemFromObject(c_JSON *object,const char *string);
{
	long returnValue = kNoErr;
	
	c_JSON *jsonObject = ma_json_ref_valid( params, 1 );
	
	if ( jsonObject == NULL ) {		
		SetLastGeneralErrorText( L"Json object parameter is not a valid json reference" , L"MA_Json_DetachItemFromObject", 0);
		returnValue = kJsonNotValid;
	} else {	
		PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
		char* blobStr = PA_LockHandle( paramBlobHandle );
		// long blobSize = PA_GetHandleSize(paramBlobHandle);	// how many bytes will we read
		// blobStr[ blobSize ] = 0;
				
		c_JSON *json = c_JSON_DetachItemFromObject( jsonObject, blobStr );
		PA_UnlockHandle( paramBlobHandle );	
		returnValue = ma_json_ref_add( json );	
	}												 
	PA_ReturnLong( params, returnValue );
}

void MA_Json_DeleteItemFromObject( PA_PluginParameters params ) // void   c_JSON_DeleteItemFromObject(c_JSON *object,const char *string);
{
	long returnValue = kNoErr;
	
	c_JSON *jsonObject = ma_json_ref_valid( params, 1 );
	
	if ( jsonObject == NULL ) {		
		SetLastGeneralErrorText( L"Json object parameter is not a valid json reference" , L"MA_Json_DeleteItemFromObject", 0);
		returnValue = kJsonNotValid;
	} else {	
		PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
		char* blobStr = PA_LockHandle( paramBlobHandle );
		// long blobSize = PA_GetHandleSize(paramBlobHandle);	// how many bytes will we read
		// blobStr[ blobSize ] = 0;
		
		c_JSON_DeleteItemFromObject( jsonObject, blobStr );
		PA_UnlockHandle( paramBlobHandle );	
	}
	PA_ReturnLong( params, returnValue );
}

void MA_Json_ReplaceItemInArray( PA_PluginParameters params ) // void c_JSON_ReplaceItemInArray(c_JSON *array,int which,c_JSON *newitem);
{
	long returnValue = kNoErr;
	
	c_JSON *jsonArray = ma_json_ref_valid( params, 1 );
	c_JSON *jsonNewItem = ma_json_ref_valid( params, 2 );
	
	if ( jsonArray == NULL ) {		
		SetLastGeneralErrorText( L"Json array parameter is not a valid json reference" , L"MA_Json_ReplaceItemInArray", 0);
		returnValue = kJsonNotValid;
	} else if ( jsonNewItem == NULL ) {		
		SetLastGeneralErrorText( L"Json new item parameter is not a valid json reference" , L"MA_Json_ReplaceItemInArray", 0);
		returnValue = kJsonNotValid;
	} else {				
		long jsonItemNum = PA_GetLongParameter( params, 2 );	
		c_JSON_ReplaceItemInArray( jsonArray, jsonItemNum, jsonNewItem );
	}
	PA_ReturnLong( params, returnValue );
}

void MA_Json_ReplaceItemInObject( PA_PluginParameters params ) // void c_JSON_ReplaceItemInObject(c_JSON *object,const char *string,c_JSON *newitem);
{
	long returnValue = kNoErr;
	
	c_JSON *jsonObject = ma_json_ref_valid( params, 1 );
	c_JSON *jsonNewItem = ma_json_ref_valid( params, 2 );
	
	if ( jsonObject == NULL ) {		
		SetLastGeneralErrorText( L"Json object parameter is not a valid json reference" , L"MA_Json_ReplaceItemInObject", 0);
		returnValue = kJsonNotValid;
	} else if ( jsonNewItem == NULL ) {		
		SetLastGeneralErrorText( L"Json new item parameter is not a valid json reference" , L"MA_Json_ReplaceItemInObject", 0);
		returnValue = kJsonNotValid;
	} else {				
		PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
		char* blobStr = PA_LockHandle( paramBlobHandle );
		// long blobSize = PA_GetHandleSize(paramBlobHandle);	// how many bytes will we read
		// blobStr[ blobSize ] = 0;
		
		c_JSON_ReplaceItemInObject( jsonObject, blobStr, jsonNewItem );
		PA_UnlockHandle( paramBlobHandle );	
	}
	PA_ReturnLong( params, returnValue );
}

void MA_Json_AddNullToObject( PA_PluginParameters params ) // c_JSON_AddNullToObject(object,name)
{
	long returnValue = kNoErr;
	
	c_JSON *jsonObject = ma_json_ref_valid( params, 1 );
	
	if ( jsonObject == NULL ) {		
		SetLastGeneralErrorText( L"Json object parameter is not a valid json reference" , L"MA_Json_AddNullToObject", 0);
		returnValue = kJsonNotValid;
	} else {				
		PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
		char* blobStr = PA_LockHandle( paramBlobHandle );
		// long blobSize = PA_GetHandleSize(paramBlobHandle);	// how many bytes will we read
		// blobStr[ blobSize ] = 0;
		
		c_JSON_AddNullToObject( jsonObject, blobStr );
		PA_UnlockHandle( paramBlobHandle );	
	}

	PA_ReturnLong( params, returnValue );
}

void MA_Json_AddTrueToObject( PA_PluginParameters params ) // c_JSON_AddTrueToObject(object,name)
{
	long returnValue = kNoErr;
	
	c_JSON *jsonObject = ma_json_ref_valid( params, 1 );
	
	if ( jsonObject == NULL ) {		
		SetLastGeneralErrorText( L"Json object parameter is not a valid json reference" , L"MA_Json_AddTrueToObject", 0);
		returnValue = kJsonNotValid;
	} else {				
		PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
		char* blobStr = PA_LockHandle( paramBlobHandle );
		// long blobSize = PA_GetHandleSize(paramBlobHandle);	// how many bytes will we read
		// blobStr[ blobSize ] = 0;
		
		c_JSON_AddTrueToObject( jsonObject, blobStr );
		PA_UnlockHandle( paramBlobHandle );	
	}
	PA_ReturnLong( params, returnValue );
	
}

void MA_Json_AddFalseToObject( PA_PluginParameters params ) // c_JSON_AddFalseToObject(object,name)
{
	long returnValue = kNoErr;
	
	c_JSON *jsonObject = ma_json_ref_valid( params, 1 );
	
	if ( jsonObject == NULL ) {		
		SetLastGeneralErrorText( L"Json object parameter is not a valid json reference" , L"MA_Json_AddFalseToObject", 0);
		returnValue = kJsonNotValid;
	} else {				
		PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
		char* blobStr = PA_LockHandle( paramBlobHandle );
		// long blobSize = PA_GetHandleSize(paramBlobHandle);	// how many bytes will we read
		// blobStr[ blobSize ] = 0;
		
		c_JSON_AddFalseToObject( jsonObject, blobStr );
		PA_UnlockHandle( paramBlobHandle );	
	}
	PA_ReturnLong( params, returnValue );	
}

void MA_Json_AddNumberToObject( PA_PluginParameters params ) // c_JSON_AddNumberToObject(object,name,n)
{
	long returnValue = kNoErr;
	
	c_JSON *jsonObject = ma_json_ref_valid( params, 1 );
	
	if ( jsonObject == NULL ) {		
		SetLastGeneralErrorText( L"Json object parameter is not a valid json reference" , L"MA_Json_AddNumberToObject", 0);
		returnValue = kJsonNotValid;
	} else {
		PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
		char* blobStr = PA_LockHandle( paramBlobHandle );
		double value = PA_GetDoubleParameter( params, 3 );
		// long blobSize = PA_GetHandleSize(paramBlobHandle);	// how many bytes will we read
		// blobStr[ blobSize ] = 0;
		
		c_JSON_AddNumberToObject( jsonObject, blobStr, value );
		PA_UnlockHandle( paramBlobHandle );	
	}
	PA_ReturnLong( params, returnValue );
	
}

void MA_Json_AddStringToObject( PA_PluginParameters params ) // c_JSON_AddStringToObject(object,name,s)
{
	long returnValue = kNoErr;
	
	c_JSON *jsonObject = ma_json_ref_valid( params, 1 );
	
	if ( jsonObject == NULL ) {		
		SetLastGeneralErrorText( L"Json object parameter is not a valid json reference" , L"MA_Json_AddStringToObject", 0);
		returnValue = kJsonNotValid;
	} else {				
		PA_Handle paramBlobHandle = PA_GetBlobHandleParameter( params, 2 );
		char* blobStr = PA_LockHandle( paramBlobHandle );
		// long blobSize = PA_GetHandleSize(paramBlobHandle);	// how many bytes will we read
		// blobStr[ blobSize ] = 0;
		
		PA_Handle paramBlobHandle2 = PA_GetBlobHandleParameter( params, 3 );
		char* blobStr2 = PA_LockHandle( paramBlobHandle2 );
		long blobSize2 = PA_GetHandleSize(paramBlobHandle2);	// how many bytes will we read
		blobStr2[ blobSize2 ] = 0;
		
		c_JSON_AddStringToObject( jsonObject, blobStr, blobStr2 );
		PA_UnlockHandle( paramBlobHandle );	
		PA_UnlockHandle( paramBlobHandle2 );	
	}
	PA_ReturnLong( params, returnValue );	
}



#endif
