/*******************************************************************************
 * Copyright (c) 2005, 2009 Intel Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Guru Nagarajan,Intel - Initial API and implementation
 *
 * $Id: BaseAgentJNI.cpp,v 1.19 2009/09/10 21:17:40 jcayne Exp $ 
 *******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

#include "JBaseAgentImpl.h"
#include "tptp/agents/BaseAgentImpl.h"
#include "tptp/agents/EventProviderImpl.h"
#include "tptp/agents/DataProviderImpl.h"
#include "BaseAgentJNI.h"
using namespace std ;

#define INIT_VECTOR_CAPACITY 10
#define DATA_PROVIDER		"DATA_PROVIDER"
#define EVENT_PROVIDER		"EVENT_PROVIDER"
#define DEFAULT_PROVIDER	"DEFAULT_PROVIDER"

JBaseAgentImpl* baseAgentImpl = NULL;
/* Global reference to the JVM. */
static JavaVM		*_agent_vm;

/*Store gobal references here*/
static jobject global_thisObj;

jthrowable javaException = NULL;
static jmethodID global_mid;

/**
 * Native method for initializing the agent with the given name and type
 * Class:     org_eclipse_tptp_platform_execution_datacollection_BaseAgent
 * Method:    initializeEngine0
 * Signature: (Ljava/lang/String;Ljava/lang/String;)V
*/
JNIEXPORT jint JNICALL Java_org_eclipse_tptp_platform_execution_datacollection_BaseAgent_initializeEngine0(JNIEnv *env, jobject thisObj, jstring name)
{
   jint returnValue= -1;
  try
	{
	/* Set the global objects */
	global_thisObj = thisObj;

	env->GetJavaVM(&_agent_vm);

	/* Get the global ref for usage later */
	jclass cls = env->GetObjectClass(thisObj);
	if(!cls) return returnValue;
	
	global_thisObj = env->NewGlobalRef(thisObj);

	global_mid = env->GetMethodID(cls, "processCommand", "(Lorg/eclipse/tptp/platform/execution/util/ICommandFragment;)V");
	if(global_mid == 0)
	{
		//TODO:Log cannot find the method
		return returnValue;
	}
	
	/* Convert the Unicode Strings into UTF-8 ones */
	const char *asciiName = env->GetStringUTFChars(name,NULL);
	if(asciiName)
	{
		/* Create a baseAgentImpl object with the given name and type */
		baseAgentImpl = new JBaseAgentImpl((char *)asciiName);
		
		if(!baseAgentImpl)
		{
			return returnValue;
		}
	}
	/* Release the allocated memory buffers */
	env->ReleaseStringUTFChars(name, asciiName);
	returnValue = 0;
	return returnValue;
  }
  catch(...)
  {
  	javaException = env->ExceptionOccurred();
	if(javaException)
	{
		env->ExceptionDescribe();
		//TODO:Logging pending
		env->ExceptionClear();
	}
	return returnValue;
  }
}


/*
 * Class:     org_eclipse_tptp_platform_execution_datacollection_BaseAgent
 * Method:    deregister0
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_org_eclipse_tptp_platform_execution_datacollection_BaseAgent_deregister0(JNIEnv *env, jobject thisObj)
{
	jint returnValue = baseAgentImpl->deRegisterAgent();

	env->DeleteGlobalRef(global_thisObj);
	javaException = env->ExceptionOccurred();
	if(javaException)
	{
		env->ExceptionDescribe();
		//TODO:Logging pending
		env->ExceptionClear();
	}
	return returnValue;

}
/*
 * Class:     org_eclipse_tptp_platform_execution_datacollection_BaseAgent
 * Method:    register0
 * Signature: (Ljava/lang/String;Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_org_eclipse_tptp_platform_execution_datacollection_BaseAgent_register0(JNIEnv *env, jobject thisObj, jstring name)
{
	jint returnValue = -1;
	/* Convert the Unicode Strings into UTF-8 ones */
	const char *asciiName = env->GetStringUTFChars(name,NULL);
	
	/* Register the agent */
	returnValue = baseAgentImpl->registerAgent();
	if(returnValue != 0)
	{
		//TODO:Replace with the TPTP Logging macro
		return returnValue;	
	}
	/* Release the allocated memory buffers */
	if(asciiName) env->ReleaseStringUTFChars(name, asciiName);
	
	/* Return the status of invoking the 'registerAgent' function */
	return returnValue;
}

/*
 * Class:     org_eclipse_tptp_platform_execution_datacollection_BaseAgent
 * Method:    getAgentID0
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_org_eclipse_tptp_platform_execution_datacollection_BaseAgent_getAgentID0(JNIEnv *env, jobject thisobj)
{
	jint returnValue = -1;
	if(baseAgentImpl)
	{
		returnValue = baseAgentImpl->getAgentID();
	}
	
	return returnValue;
}

/*
 * Class:     org_eclipse_tptp_platform_execution_datacollection_BaseAgent
 * Method:    sendData0
 * Signature: (I[CI)I
 */
JNIEXPORT jint JNICALL Java_org_eclipse_tptp_platform_execution_datacollection_BaseAgent_sendData0(JNIEnv *env, jobject thisObj, jint targetInstanceId, jcharArray buffer, jint bufferLength)
{
	jint returnValue = -1;
	
	jsize	len =0;
	jchar*	bytearr = NULL;
	
	len = (jsize)(env->GetArrayLength(buffer));

	if(len !=0)
	{ 
		bytearr = env->GetCharArrayElements(buffer, 0);
	}
	
	returnValue = baseAgentImpl->sendData(targetInstanceId, (char *)bytearr, len*sizeof(jchar));

	//Release
	if(bytearr)
	{
		if(len !=0)env->ReleaseCharArrayElements(buffer, bytearr, 0);
	}
	
	return returnValue;
}

/*
 * Class:     org_eclipse_tptp_platform_execution_datacollection_BaseAgent
 * Method:    sendData1
 * Signature: (I[BII)I
 */
JNIEXPORT jint JNICALL Java_org_eclipse_tptp_platform_execution_datacollection_BaseAgent_sendData1
	(JNIEnv *env, jobject thisObj, jint targetInstanceId, jbyteArray buffer, jint offset, jint length)
{
	jsize bufLen = env->GetArrayLength(buffer);
	if (bufLen <= 0) return 0;
	
	jbyte* bytearr = env->GetByteArrayElements(buffer, NULL) + offset;
	jint returnValue = baseAgentImpl->sendData(targetInstanceId, (char*) bytearr, length);
	
	// Release
	if (bytearr)
		env->ReleaseByteArrayElements(buffer, bytearr, 0);
	
	return returnValue;
}

/*
 * Class:     org_eclipse_tptp_platform_execution_datacollection_BaseAgent
 * Method:    sendCommand0
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_org_eclipse_tptp_platform_execution_datacollection_BaseAgent_sendCommand0(JNIEnv *env, jobject thisObj, jstring command)
{
	jint returnValue = -1;
	
	/* Convert the Unicode Strings into UTF-8 ones */
	const char *nativecmd = env->GetStringUTFChars(command,NULL);
	if(baseAgentImpl)
	{
		returnValue = baseAgentImpl->sendCommand((char *)nativecmd);
	}
	env->ReleaseStringUTFChars(command,nativecmd);

	return returnValue;
}
/*
 * Class:     org_eclipse_tptp_platform_execution_datacollection_BaseAgent
 * Method:    addClientCallBk 
 * Signature: (ILorg/eclipse/tptp/platform/execution/util/TPTPAgentAccess;)V
 */
void addClientCallBk(int clientID, int accessLevel)
{
	if (baseAgentImpl != NULL)
	{
		/* Attach the current thread to the JVM */
		JNIEnv	*env;
		jint	result = _agent_vm->AttachCurrentThread((void**)&env, NULL); 
		if(result == JNI_ERR)
		{
			//TODO:Log here
			//
			return;
		}
		
		//TODO: I am doing this since I have not figured out how to access the typesafe enums - WIll have to modify that - Guru
		jclass		cls = env->FindClass("org/eclipse/tptp/platform/execution/datacollection/BaseAgent");
		if(cls)	
		{
			jmethodID	mid = env->GetMethodID(cls, "addClient", "(II)V");
			if(mid == 0)
			{
				//TODO:Log cannot find the method
				return;
			}
			env->CallVoidMethod(global_thisObj, mid,clientID, accessLevel);
			javaException = env->ExceptionOccurred();
			if(javaException)
			{
				env->ExceptionDescribe();
				env->ExceptionClear();
			}
		}
		/* Detach the current thread */
		_agent_vm->DetachCurrentThread();
	}
	else
	{
		//TODO: Log if the baseAgent* is NULL 
	}
}
/*
 * Class:     org_eclipse_tptp_platform_execution_datacollection_BaseAgent
 * Method:    removeClient0
 * Signature: (I)V
 */
int removeClientCallBk(int clientID)
{
	jint ret = -1;
	JNIEnv *env;
	jint result =_agent_vm->AttachCurrentThread((void**)&env, NULL);
	
	if(result == JNI_ERR)
	{
		return ret;
	}

	jclass cls = env->GetObjectClass(global_thisObj);
	if(cls)
	{
		jmethodID mid = env->GetMethodID(cls, "removeClient", "(I)V");
		if(mid == 0)
		{
			//TODO:Log cannot find the method
			return ret;
		}
	
		env->CallVoidMethod(global_thisObj, mid, clientID);

		javaException = env->ExceptionOccurred();
		if(javaException)
		{
			env->ExceptionDescribe();
			env->ExceptionClear();
			return ret;
		}
		ret = 0;
	}
	
	return ret;
}

JNIEXPORT jint JNICALL Java_org_eclipse_tptp_platform_execution_datacollection_BaseAgent_processCommand0(JNIEnv *env, jobject thisObj, jobject cmd)
{
	jint returnValue = -1;
	/* Convert the java command to a native command */
	CmdBlock* nativeCommand = new CmdBlock();

	/* Stores the class of the 'cmd' object */
	jclass cls = env->GetObjectClass(cmd);    
	if(!cls)
	{
		//TODO:Log error here
		return returnValue;
	}
	
	jmethodID mid; /* Used to store the ID of the methods that we'll be calling */
	
	/* Get the source ID */
	mid = env->GetMethodID(cls, "getSourceID", "()J");
	if(mid == 0)
	{
		//TODO:Log cannot find the method
		return returnValue;
	}
	
	jint sourceID = env->CallIntMethod(cmd, mid);
	javaException = env->ExceptionOccurred();
	if(javaException)
	{
		env->ExceptionDescribe();
		env->ExceptionClear();
		return returnValue;
	}
	/* Get the destination ID */
	mid = env->GetMethodID(cls, "getDestinationID", "()J");
	if(mid == 0)
	{
		//TODO:Log cannot find the method
		return returnValue;
	}

	jint destinationID = env->CallIntMethod(cmd, mid);
	javaException = env->ExceptionOccurred();
	if(javaException)
	{
		env->ExceptionDescribe();
		env->ExceptionClear();
		return returnValue;
	}
	/* Get the context ID */
	mid = env->GetMethodID(cls, "getContextID", "()J");
	if(mid == 0)
	{
		//TODO:Log cannot find the method
		return returnValue;
	}

	jint contextID = env->CallIntMethod(cmd, mid);
	javaException = env->ExceptionOccurred();
	if(javaException)
	{
		env->ExceptionDescribe();
		env->ExceptionClear();
		return returnValue;
	}
	/* Get the IID */
	mid = env->GetMethodID(cls, "getInterfaceID", "()Ljava/lang/String;");
	if(mid == 0)
	{
		//TODO:Log cannot find the method
		return returnValue;
	}

	jobject iid = env->CallObjectMethod(cmd, mid);
	javaException = env->ExceptionOccurred();
	if(javaException)
	{
		env->ExceptionDescribe();
		env->ExceptionClear();
		return returnValue;
	}
	jstring stringIID = (jstring)iid;
	const char *asciiIID = env->GetStringUTFChars(stringIID,NULL);

	/* Get the command name */
	mid = env->GetMethodID(cls, "getCommandName", "()Ljava/lang/String;");
	if(mid == 0)
	{
		//TODO:Log cannot find the method
		return returnValue;
	}

	jobject commandName = env->CallObjectMethod(cmd, mid);
	javaException = env->ExceptionOccurred();
	if(javaException)
	{
		env->ExceptionDescribe();
		env->ExceptionClear();
		return returnValue;
	}
	jstring stringCommandName = (jstring)commandName;
	const char *asciiCommandName = env->GetStringUTFChars(stringCommandName,NULL);

	/* Build the native command */
	nativeCommand->setSourceID((int)sourceID);
	nativeCommand->setDestID((int)destinationID);
	nativeCommand->setContextID((int)contextID);
	nativeCommand->setIID((char *)asciiIID);
	nativeCommand->setCommandName((char *)asciiCommandName);

	/* Send the command to BaseAgentImpl */
	if(baseAgentImpl) returnValue = baseAgentImpl->processCommand(nativeCommand);
	else 
	{ 
		//TODO: Log
		return returnValue;
	}

	/* Release the allocated memory buffers */
	env->ReleaseStringUTFChars(stringIID, asciiIID);
	env->ReleaseStringUTFChars(stringCommandName, asciiCommandName);

	return returnValue;
}
 
/*
 * Callback
 */
void waitForTerminationCallBk()
{
	
	return;
}


int receiveDataCallBk(int sourceID, char buffer[], int bytesRead, DIME_HEADER_PTR_T dimeHeader)
{
	jint returnValue = -1;
	JNIEnv *env;
	jint result =_agent_vm->AttachCurrentThread((void**)&env, NULL);
	if(result == JNI_ERR)
	{
		//TODO:Log
		return result;
	}
	
	jclass cls = env->GetObjectClass(global_thisObj);
	if(!cls)
	{
		//TODO:Log 
		return returnValue;
	}

	jmethodID mid = env->GetMethodID(cls, "receiveData", "(I[BI)I");
	if(mid == 0)
	{
		//TODO:Log cannot find the method
		return returnValue;
	}
	
	jbyteArray jbuffer = env->NewByteArray(bytesRead);
	env->SetByteArrayRegion(jbuffer, 0, bytesRead, (jbyte*) buffer);

	returnValue = env->CallIntMethod(global_thisObj, mid, sourceID, jbuffer, bytesRead);
	javaException = env->ExceptionOccurred();
	if(javaException)
	{
		env->ExceptionDescribe();
		env->ExceptionClear();
		return returnValue;
	}
	
	/* Detach the current thread */
	_agent_vm->DetachCurrentThread();	

	return returnValue;
}

/*
 * Class:     org_eclipse_tptp_platform_execution_datacollection_BaseAgent
 * Method:    sendEventNotifications0
 * Signature: (Lorg/eclipse/tptp/platform/execution/util/ICommandFragment;)V
 */
JNIEXPORT jint JNICALL Java_org_eclipse_tptp_platform_execution_datacollection_BaseAgent_sendEventNotifications0(JNIEnv *env, jobject thisObj, jobject cmd)
{
	jint returnValue = -1;
	
	/* Convert the java command to a native command */
	CmdBlock* nativeCommand = new CmdBlock();

	/* Stores the class of the 'cmd' object */
	jclass cls = env->GetObjectClass(cmd);    
	if(!cls)
	{
		//TODO:Log error here
		return returnValue;
	}
	
	jmethodID mid; /* Used to store the ID of the methods that we'll be calling */
	
	/* Get the source ID */
	mid = env->GetMethodID(cls, "getSourceID", "()J");
	if(mid == 0)
	{
		//TODO:Log cannot find the method
		return returnValue;
	}
	
	jint sourceID = env->CallIntMethod(cmd, mid);

	javaException = env->ExceptionOccurred();
	if(javaException)
	{
		env->ExceptionDescribe();
		env->ExceptionClear();
		return returnValue;
	}
	/* Get the destination ID */
	mid = env->GetMethodID(cls, "getDestinationID", "()J");
	if(mid == 0)
	{
		//TODO:Log cannot find the method
		return returnValue;
	}

	jint destinationID = env->CallIntMethod(cmd, mid);
	javaException = env->ExceptionOccurred();
	if(javaException)
	{
		env->ExceptionDescribe();
		env->ExceptionClear();
		return returnValue;
	}
	/* Get the context ID */
	mid = env->GetMethodID(cls, "getContextID", "()J");
	if(mid == 0)
	{
		//TODO:Log cannot find the method
		return returnValue;
	}

	jint contextID = env->CallIntMethod(cmd, mid);
	javaException = env->ExceptionOccurred();
	if(javaException)
	{
		env->ExceptionDescribe();
		env->ExceptionClear();
		return returnValue;
	}
	/* Get the IID */
	mid = env->GetMethodID(cls, "getInterfaceID", "()Ljava/lang/String;");
	if(mid == 0)
	{
		//TODO:Log cannot find the method
		return returnValue;
	}

	jobject iid = env->CallObjectMethod(cmd, mid);
	javaException = env->ExceptionOccurred();
	if(javaException)
	{
		env->ExceptionDescribe();
		env->ExceptionClear();
		return returnValue;
	}
	jstring stringIID = (jstring)iid;
	const char *asciiIID = env->GetStringUTFChars(stringIID,NULL);

	/* Get the command name */
	mid = env->GetMethodID(cls, "getCommandName", "()Ljava/lang/String;");
	if(mid == 0)
	{
		//TODO:Log cannot find the method
		return returnValue;
	}

	jobject commandName = env->CallObjectMethod(cmd, mid);
	javaException = env->ExceptionOccurred();
	if(javaException)
	{
		env->ExceptionDescribe();
		env->ExceptionClear();
		return returnValue;
	}
	jstring stringCommandName = (jstring)commandName;
	const char *asciiCommandName = env->GetStringUTFChars(stringCommandName,NULL);

	//TODO: Build parmList from Vector
	/* Get the ParmList as Vector */
	//mid = env->GetMethodID(cls, "getElemList", "()Ljava/util/Vector;");
	//jobject veclist = env->CallObjectMethod(cmd, mid);
	


	/* Build the native command */
	nativeCommand->setSourceID((int)sourceID);
	nativeCommand->setDestID((int)destinationID);
	nativeCommand->setContextID((int)contextID);
	nativeCommand->setIID((char *)asciiIID);
	nativeCommand->setCommandName((char *)asciiCommandName);

	/* Send the command to BaseAgentImpl */
	if(baseAgentImpl) { baseAgentImpl->sendEventNotifications(nativeCommand);}
	else 
	{ 
		//TODO: Log
		return returnValue;
	}

	/* Release the allocated memory buffers */
	env->ReleaseStringUTFChars(stringIID, asciiIID);
	env->ReleaseStringUTFChars(stringCommandName, asciiCommandName);

	return returnValue;
}

int processCmdCallBkWCtxt(CmdBlock *command, char* context)
{
	jint returnValue = -1;	
    if (baseAgentImpl != NULL)
	{
		/* Attach the current thread to the JVM */
		JNIEnv *env;
		returnValue =_agent_vm->AttachCurrentThread((void**)&env, NULL); 
		if(returnValue == JNI_ERR)
		{
			//TODO:Log
			return returnValue;
		}
		
		/* Use the native command to build the java command.
		 * First extract the information from the native command */
		jint sourceID = command->getSourceID();
		jint destinationID = command->getDestID();
		jint contextID = command->getContextID();
		jstring commandName = env->NewStringUTF(command->getCommandName());
		jstring interfaceID = env->NewStringUTF(command->getIID());
		
		/* Build an ICommandElement object */
		jclass commandFragmentClass = env->FindClass("org/eclipse/tptp/platform/execution/util/internal/CommandFragment");
		if(!commandFragmentClass)
		{
			//TODO:Log 
			return returnValue;
		}
		jmethodID commandFragmentConstructor = env->GetMethodID(commandFragmentClass, "<init>", "()V");
		if(commandFragmentConstructor == 0)
		{
			//TODO:Log cannot find the method
			return returnValue;
		}

		jobject javaCommand = env->NewObject(commandFragmentClass, commandFragmentConstructor);

		javaException = env->ExceptionOccurred();
		if(javaException)
		{
			env->ExceptionDescribe();
			env->ExceptionClear();
			return returnValue;
		}

		/* Set source ID */
		jmethodID mid = env->GetMethodID(commandFragmentClass, "setSource", "(I)V");
		if(mid == 0)
		{
			//TODO:Log cannot find the method
			return returnValue;
		}

		env->CallVoidMethod(javaCommand, mid, sourceID);
		javaException = env->ExceptionOccurred();
		if(javaException)
		{
			env->ExceptionDescribe();
			env->ExceptionClear();
			return returnValue;
		}

		/* Set destination ID */
		mid = env->GetMethodID(commandFragmentClass, "setDestination", "(I)V");
		if(mid == 0)
		{
			//TODO:Log cannot find the method
			return returnValue;
		}
		env->CallVoidMethod(javaCommand, mid, destinationID);
		javaException = env->ExceptionOccurred();
		if(javaException)
		{
			env->ExceptionDescribe();
			env->ExceptionClear();
			return returnValue;
		}
				
		mid = env->GetMethodID(commandFragmentClass, "setContext", "(I)V");
		if(mid == 0)
		{
			//TODO:Log cannot find the method
			return returnValue;
		}
		env->CallVoidMethod(javaCommand, mid, contextID);
		javaException = env->ExceptionOccurred();
		if(javaException)
		{
			env->ExceptionDescribe();
			env->ExceptionClear();
			return returnValue;
		}
		
		/* Set command name */
		mid = env->GetMethodID(commandFragmentClass, "setCommandName", "(Ljava/lang/String;)V");
		if(mid == 0)
		{
			//TODO:Log cannot find the method
			return returnValue;
		}
		
		env->CallVoidMethod(javaCommand, mid, commandName);
		javaException = env->ExceptionOccurred();
		if(javaException)
		{
			env->ExceptionDescribe();
			env->ExceptionClear();
			return returnValue;
		}
		/* Set interface ID */
		mid = env->GetMethodID(commandFragmentClass, "setInterfaceID", "(Ljava/lang/String;)V");
		if(mid == 0)
		{
			//TODO:Log cannot find the method
			return returnValue;
		}
		
		env->CallVoidMethod(javaCommand, mid, interfaceID);
		javaException = env->ExceptionOccurred();
		if(javaException)
		{
			env->ExceptionDescribe();
			env->ExceptionClear();
			return returnValue;
		}
		
		jclass vectorClass = env->FindClass("Ljava/util/Vector;");
		if(!vectorClass)
		{
			//TODO:Log 
			return returnValue;
		}
		
		jmethodID vector_mid = env->GetMethodID(vectorClass, "<init>", "(I)V");
		if(mid == 0)
		{
			//TODO:Log cannot find the method
			return returnValue;
		}
		
		//Initialize
		jobject vecobj = env->NewObject(vectorClass, vector_mid, 5);

		javaException = env->ExceptionOccurred();
		if(javaException)
		{
			env->ExceptionDescribe();
			env->ExceptionClear();
			return returnValue;
		}
		/*
		env->CallVoidMethod(vecobj, mid);
		javaException = env->ExceptionOccurred();
		if(javaException)
		{
			env->ExceptionDescribe();
			env->ExceptionClear();
			return returnValue;
		}
		*/
		jmethodID add_elem_mid = env->GetMethodID(vectorClass, "addElement", "(Ljava/lang/Object;)V");
		if(mid == 0)
		{
			//TODO:Log cannot find the method
			return returnValue;
		}		
		jclass variableClass = env->FindClass("org/eclipse/tptp/platform/execution/util/Variable");
		if(!variableClass)
		{
			//TODO:Log 
			return returnValue;
		}
		
		jmethodID var_mid = env->GetMethodID(variableClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;)V");

		javaException = env->ExceptionOccurred();
		if(javaException)
		{
			env->ExceptionDescribe();
			env->ExceptionClear();
			return returnValue;
		}
		
		tptp_node_t* node;
		tptp_param_t* param;
		
		for (node = command->getParamList()->head; node != 0; node = node->next)
		{
			param = (tptp_param_t*)node->data;
			if(param) 
			{
				jstring name = env->NewStringUTF(param->name);
				jstring value = env->NewStringUTF(param->value);
				jobject vecelem = env->NewObject(variableClass, var_mid, name, value);
		
				javaException = env->ExceptionOccurred();
				if(javaException)
				{
					env->ExceptionDescribe();
					env->ExceptionClear();
					return returnValue;
				}				
				//Add to the Vector object
				env->CallVoidMethod(vecobj, add_elem_mid, vecelem);

				javaException = env->ExceptionOccurred();
				if(javaException)
				{
					env->ExceptionDescribe();
					env->ExceptionClear();
					return returnValue;
				}
			}
		}
		/* Set the ParmList as vector of Obj(variable) */
		mid = env->GetMethodID(commandFragmentClass, "setElemList", "(Ljava/util/Vector;)V");
		if(mid == 0)
		{
			//TODO:Log cannot find the method
			return returnValue;
		}
		
		env->CallVoidMethod(javaCommand, mid, vecobj);

		javaException = env->ExceptionOccurred();
		if(javaException)
		{
			env->ExceptionDescribe();
			env->ExceptionClear();
			return returnValue;
		}
		
		if(strcmp(context, DATA_PROVIDER) == 0)
		{
			jclass cls = env->GetObjectClass(global_thisObj);
			jmethodID data_mid = env->GetMethodID(cls, "processDataProviderCommands", "(Lorg/eclipse/tptp/platform/execution/util/ICommandFragment;)I");
			if(data_mid == 0)
			{
				//TODO:Log cannot find the method
				return returnValue;
			}
			env->CallIntMethod(global_thisObj, data_mid,javaCommand);
			javaException = env->ExceptionOccurred();
			if(javaException)
			{
				env->ExceptionDescribe();
				env->ExceptionClear();
				return returnValue;
			}
		}
		if(strcmp(context, EVENT_PROVIDER) == 0)
		{
			jclass cls = env->GetObjectClass(global_thisObj);
			jmethodID event_mid = env->GetMethodID(cls, "processEventProviderCommands", "(Lorg/eclipse/tptp/platform/execution/util/ICommandFragment;)I");
			if(event_mid == 0)
			{
				//TODO:Log cannot find the method
				return returnValue;
			}
			env->CallIntMethod(global_thisObj, event_mid,javaCommand);
			javaException = env->ExceptionOccurred();
			if(javaException)
			{
				env->ExceptionDescribe();
				env->ExceptionClear();
				return returnValue;
			}
		}
		if(strcmp(context, DEFAULT_PROVIDER) == 0)
		{
			env->CallVoidMethod(global_thisObj, global_mid,javaCommand);
			javaException = env->ExceptionOccurred();
			if(javaException)
			{
				env->ExceptionDescribe();
				env->ExceptionClear();
				return returnValue;
			}
		}
		
		/* Detach the current thread */
		_agent_vm->DetachCurrentThread();
		returnValue = 0;	
	}
	return returnValue;
}

int processEventProviderCommandsCallBk(CmdBlock* cmd)
{
	return processCmdCallBkWCtxt(cmd, EVENT_PROVIDER);
}

int processDataProviderCommandsCallBk(CmdBlock* cmd)
{
	return processCmdCallBkWCtxt(cmd, DATA_PROVIDER);
}
int processCommandCallBk(CmdBlock* cmd)
{
	return processCmdCallBkWCtxt(cmd, DEFAULT_PROVIDER);
}

/*
 * Class:     org_eclipse_tptp_platform_execution_datacollection_BaseAgent
 * Method:    processCommandLine0
 * Signature: ([Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_org_eclipse_tptp_platform_execution_datacollection_BaseAgent_processCommandLine0
  (JNIEnv *env, jobject obj, jobjectArray args) {
  	
	int len = env->GetArrayLength(args);
	if (len <= 0) return;

	char** argv = (char**) malloc(len*sizeof(char*));
	if (argv == NULL) return;
	
	for (int i=0; i<len; i++) {
	   jstring arg = (jstring) env->GetObjectArrayElement(args, i);
	   char* s = (char*) env->GetStringUTFChars(arg, 0);

	   int slen = strlen(s);
	   argv[i] = (char*) malloc(slen+1);
	   if (argv[i] == NULL) return;
	   
	   strcpy (argv[i], s);

	   env->ReleaseStringUTFChars(arg, s);
	}

    baseAgentImpl->processCommandLine(len, argv);
    
    for (int j=0; j<len; j++) free(argv[j]);
    
    free(argv);
 }
