// Stub comunication to EM of the Integrade
//
// author: Marcelo de Castro Cardoso

/* c library
 */
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

/* Oil libray
 */
#include <OilOrb.h>
#include <NameServiceStub.h>
#include <LuaUtils.h>

/* Lua library
 */
#include <lua.h>

/* Local library
 */
#include "EMConnOil.h"
#include "ig_pmiutils.h"

/* variables
 */
static char * configFile = "asct.conf";
static OIL_ORB nsOrbOil = NULL;
static char * nsProxyName = "nameServiceProxy"; 

/* prototipes
 */
int instantiateOrb(OIL_ORB * connOrbOil);

/* Create proxy to the object
 * 
 * Input param:
 * obj - object name
 * 
 * Output param:
 * ior - ior to remote object
 *
 * Return param:
 * code error
 */
int connCreateProxy(char * objName, char * ior)
{
	int oil_err = OIL_SUCCESS;
	int conn_err = CONN_SUCCESS;
	
	if (nsOrbOil == NULL) 
	{
		conn_err = instantiateOrb(&nsOrbOil);
		if (conn_err != CONN_SUCCESS)
			goto fail;
	}
	
	oil_err = nspResolve(nsOrbOil, nsProxyName, objName, ior);
	if (oil_err != OIL_SUCCESS)
		goto fail;
	
	oil_err = oilCreateProxy(nsOrbOil, ior, "IDL:clusterManagement/ExecutionManager:1.0", objName);
	if (oil_err != OIL_SUCCESS)
		goto fail;
	
 exit:
 	return conn_err;

 fail:
    conn_err = CONN_ERROR;
    goto exit;
}

/* Send data to ExecutionManager of the Integrade
 * 
 * Input param:
 * name - remote object of destine
 * rank - number of the process rank mpi
 * name_process - unique name of process 
 * kvs - map key/value of process
 * app_id - id of application
 * 
 * Output param:
 * conns - array of maps key/value
 * connCount - size array maps
 * 
 * Return param:
 * code error
 */
int connRegisterNode(char * name, int rank, char * name_process, char * kvs, char * app_id, CONN_t * conns, unsigned int * connCount)
{
	unsigned int i;
	struct lua_State * clientSideState;
	int initialStackSize;

	if (nsOrbOil == NULL)
		return CONN_ERROR;
		
	clientSideState = oilLuaState(nsOrbOil);
	
	initialStackSize = lua_gettop(clientSideState);

	lua_getglobal(clientSideState, name);
	lua_pushstring(clientSideState, "registerMpiProcess");
	lua_gettable(clientSideState, -2);
	lua_getglobal(clientSideState, name);
	lua_newtable(clientSideState);
	luaSetFieldOnTable(clientSideState, "requestId", app_id, -1);
	luaSetFieldOnTable(clientSideState, "processId", name_process, -1);
	lua_pushstring(clientSideState, kvs);
	lua_pushnumber(clientSideState, rank);  

	if (lua_pcall(clientSideState, 4, 1, 0) != 0)
	{
		fprintf(stderr, "COMMUNICATION ERROR: don't register mpi process in EM!!\n");
		lua_pop(clientSideState, 1);
		return CONN_ERROR;
	}

	*connCount = luaGetIntFromTable(clientSideState, "n");
	*conns = (CONN_t) malloc(sizeof(CONN) * (*connCount));

	for(i = 1; i <= *connCount; i++)
	{
		lua_rawgeti(clientSideState, -1, i);
		(*conns)[i - 1].value = luaGetStringFromTable(clientSideState, "kvs");
		(*conns)[i - 1].key = luaGetStringFromTable(clientSideState, "processId");
		lua_pop(clientSideState, 1); //removes FileStruct
	}

	lua_pop(clientSideState, 2);
	assert(initialStackSize == lua_gettop(clientSideState));
	return CONN_SUCCESS;
}

/* Create a new orb
 * 
 * Output param:
 * connOrb - the orb
 * 
 * Return param:
 * code error
 */
int instantiateOrb(OIL_ORB * connOrb)
{
	int oil_err = OIL_SUCCESS;
	int conn_err = CONN_SUCCESS;

	char * varValue;
	
	oil_err = oilLoadOrb("serverMpi", connOrb);
	if (oil_err != OIL_SUCCESS)
		goto fail;

	if(PMIU_loadConfig(configFile, "resourceManagementIdlPath", &varValue) == UTILS_FAIL)
		goto fail;

	oil_err = oilLoadIdl(*connOrb, varValue);
	if (oil_err != OIL_SUCCESS)
		goto fail;
		
	free(varValue);

	if(PMIU_loadConfig(configFile, "cosNamingIdlPath", &varValue) == UTILS_FAIL)
		goto fail;
		
	oil_err = oilLoadIdl(*connOrb, varValue);
	if (oil_err != OIL_SUCCESS)
		goto fail;

	free(varValue);

	if(PMIU_loadConfig(configFile, "serverNameRef", &varValue) == UTILS_FAIL)
		goto fail;

	oil_err = oilCreateProxy(*connOrb, varValue, "IDL:omg.org/CosNaming/NamingContextExt:1.0", nsProxyName);
	if (oil_err != OIL_SUCCESS)
		goto fail;

	free(varValue);

 exit:
 	return conn_err;

 fail:
	conn_err = CONN_ERROR;
	goto exit;
}

