#include <lua.h>                               
#include <lauxlib.h>                           
#include <lualib.h>
                            
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#include <drmaa.h>

#define RETURN_ON_ERROR if (errnum != DRMAA_ERRNO_SUCCESS) { return errnum; }

#define JD_COMMAND_FILE_KEY "CommandFile"
#define JD_OUTPUT_FILE_KEY "OutputFile"
#define JD_INPUT_FILE_KEY "InputFile"
#define JD_ERROR_FILE_KEY "ErrorFile"
#define JD_ARGUMENTS_KEY "Args"
#define JD_JOBID_KEY "JobId"
#define JD_WORKINGDIRECTORY_KEY "WorkingDirectory"
#define JD_NAME_KEY "Name"
#define JD_JOINFILES_KEY "JoinFiles"
#define JD_ENVIRONMENT_KEY "Env"
#define JD_EMAIL_KEY "Email"
#define JD_BULK_KEY "Bulk"
#define JD_BULK_START_KEY "bulkStart"
#define JD_BULK_END_KEY "bulkEnd"
#define JD_BULK_INCR_KEY "bulkIncr"

#define PS_STR_UNDETERMINED "UNKNOWN"
#define PS_STR_QUEUED_ACTIVE "QUEUED"
#define PS_STR_SYSTEM_ON_HOLD "SYSTEM ON HOLD"
#define PS_STR_USER_ON_HOLD "USER ON HOLD"
#define PS_STR_USER_SYSTEM_ON_HOLD "USER SYSTEM ON HOLD"
#define PS_STR_RUNNING "RUNNING"
#define PS_STR_SYSTEM_SUSPENDED "SUSPENDED"
#define PS_STR_DONE "DONE"
#define PS_STR_FAILED "FAILED"

#define PS_STR_BUFFER 20

#define EXIT_STATUS_EXITED "EXITED"
#define EXIT_STATUS_ABORTED "ABORTED"
#define EXIT_STATUS_SIGNALED "SIGNALED"

#define CONTROL_SIGNAL_SUSPEND "SUSPEND"
#define CONTROL_SIGNAL_RESUME "RESUME"
#define CONTROL_SIGNAL_HOLD "HOLD"
#define CONTROL_SIGNAL_RELEASE "RELEASE"
#define CONTROL_SIGNAL_TERMINATE "TERMINATE"

typedef struct jobDesc {
	const char* commandFile;
	char jobId[DRMAA_JOBNAME_BUFFER];
	const char* outputFile;
	const char* errorFile;
	const char* inputFile;
	const char** arguments;
	const char* workingDirectory;
	const char* name;
	const char* joinFiles;
	const char** jobEnv;
	const char** email;
	drmaa_job_ids_t* bulkIds;
	
} JobDescriptor;

void dump (void *p, int n) {
  unsigned char *p1 = p;
  while (n--) {
    printf("%p - %02x\n", p1, *p1);
    p1++;
  }
}

int __lua_wrapper_drmaa_create_template(JobDescriptor* jd, drmaa_job_template_t** jtp, char* error)
{
	int errnum = DRMAA_ERRNO_SUCCESS;
	errnum = drmaa_allocate_job_template(jtp, error, DRMAA_ERROR_STRING_BUFFER);
	RETURN_ON_ERROR
	drmaa_job_template_t* jt = *jtp;
    errnum = drmaa_set_attribute(jt, DRMAA_REMOTE_COMMAND, jd->commandFile, error, DRMAA_ERROR_STRING_BUFFER);
    RETURN_ON_ERROR

    if (jd->outputFile)
    {
	errnum = drmaa_set_attribute(jt, DRMAA_OUTPUT_PATH, jd->outputFile, error, DRMAA_ERROR_STRING_BUFFER);
    	RETURN_ON_ERROR
    }

    if (jd->inputFile)
    {
	errnum = drmaa_set_attribute(jt, DRMAA_INPUT_PATH, jd->inputFile, error, DRMAA_ERROR_STRING_BUFFER);
    	RETURN_ON_ERROR
    }

    if (jd->errorFile)
    {
	errnum = drmaa_set_attribute(jt, DRMAA_ERROR_PATH, jd->errorFile, error, DRMAA_ERROR_STRING_BUFFER);
    	RETURN_ON_ERROR
    }

    if (jd->arguments)
    {
	errnum = drmaa_set_vector_attribute(jt, DRMAA_V_ARGV, jd->arguments, error, DRMAA_ERROR_STRING_BUFFER);
    	RETURN_ON_ERROR
    }

    if (jd->workingDirectory)
    {
	errnum = drmaa_set_attribute(jt, DRMAA_WD, jd->workingDirectory, error, DRMAA_ERROR_STRING_BUFFER);
    	RETURN_ON_ERROR
    }

    if (jd->name)
    {
	errnum = drmaa_set_attribute(jt, DRMAA_JOB_NAME, jd->name, error, DRMAA_ERROR_STRING_BUFFER);
    	RETURN_ON_ERROR
    }

    if (jd->joinFiles)
    {
	errnum = drmaa_set_attribute(jt, DRMAA_JOIN_FILES, jd->joinFiles, error, DRMAA_ERROR_STRING_BUFFER);
    	RETURN_ON_ERROR
    }
	
    if (jd->jobEnv)
    {
	errnum = drmaa_set_vector_attribute(jt, DRMAA_V_ENV, jd->jobEnv, error, DRMAA_ERROR_STRING_BUFFER);
    	RETURN_ON_ERROR
    }

    if (jd->email)
    {
	errnum = drmaa_set_vector_attribute(jt, DRMAA_V_EMAIL, jd->email, error, DRMAA_ERROR_STRING_BUFFER);
    	RETURN_ON_ERROR
    }
    return errnum;
}

int __lua_wrapper_drmaa_fill_exit (int status, char* exitStatus, int* code, char* signal, char* error)
{
	int exited, aborted, signaled;	
	int errnum = DRMAA_ERRNO_SUCCESS;
	errnum = drmaa_wifexited(&exited, status, error, DRMAA_ERROR_STRING_BUFFER);
	RETURN_ON_ERROR
	if (exited)
	{
		strcpy(exitStatus, EXIT_STATUS_EXITED);
		errnum = drmaa_wexitstatus(code, status, error, DRMAA_ERROR_STRING_BUFFER);
		RETURN_ON_ERROR
		return errnum;
	}
	
	errnum = drmaa_wifaborted(&aborted, status, error, DRMAA_ERROR_STRING_BUFFER);
	RETURN_ON_ERROR
	
	if (aborted)
	{
		strcpy(exitStatus, EXIT_STATUS_ABORTED);
		*code = -1;
		return errnum;
	}

	errnum = drmaa_wifsignaled(&signaled, status, error, DRMAA_ERROR_STRING_BUFFER);
	RETURN_ON_ERROR

	if (signaled)
	{
		strcpy(exitStatus, EXIT_STATUS_SIGNALED);
		errnum = drmaa_wtermsig(signal, DRMAA_SIGNAL_BUFFER, status, error, DRMAA_ERROR_STRING_BUFFER);
		RETURN_ON_ERROR
		return errnum;
	}
}

int __lua_wrapper_drmaa_run_job (JobDescriptor* jd, char* error) 
{
	int errnum = DRMAA_ERRNO_SUCCESS;
    drmaa_job_template_t *jt = NULL;
    errnum = __lua_wrapper_drmaa_create_template(jd, &jt, error);
    RETURN_ON_ERROR
    errnum = drmaa_run_job(jd->jobId, DRMAA_JOBNAME_BUFFER, jt, error, DRMAA_ERROR_STRING_BUFFER); 
    RETURN_ON_ERROR
    errnum = drmaa_delete_job_template(jt, error, DRMAA_ERROR_STRING_BUFFER);
    RETURN_ON_ERROR
    return errnum;

}

int __lua_wrapper_drmaa_job_ps (const char* jobId, char* status, char* error)
{
	int errnum = DRMAA_ERRNO_SUCCESS;
	int remote_ps;
	errnum = drmaa_job_ps(jobId, &remote_ps, error, DRMAA_ERROR_STRING_BUFFER);
	RETURN_ON_ERROR
	switch (remote_ps)
	{
		case DRMAA_PS_UNDETERMINED:
			strcpy(status, PS_STR_UNDETERMINED);
			break;
		case DRMAA_PS_QUEUED_ACTIVE:
			strcpy(status, PS_STR_QUEUED_ACTIVE);
			break;
		case DRMAA_PS_SYSTEM_ON_HOLD:
			strcpy(status, PS_STR_SYSTEM_ON_HOLD);
			break;
		case DRMAA_PS_USER_ON_HOLD:
			strcpy(status, PS_STR_USER_ON_HOLD);
			break;
		case DRMAA_PS_USER_SYSTEM_ON_HOLD:
			strcpy(status, PS_STR_USER_SYSTEM_ON_HOLD);
			break;
		case DRMAA_PS_RUNNING:
			strcpy(status, PS_STR_RUNNING);
			break;
		case DRMAA_PS_SYSTEM_SUSPENDED:
			strcpy(status, PS_STR_SYSTEM_SUSPENDED);
			break;
		case DRMAA_PS_DONE:
			strcpy(status, PS_STR_DONE);
			break;
		case DRMAA_PS_FAILED:
			strcpy(status, PS_STR_FAILED);
			break;
	}
	return errnum;
}

int __lua_wrapper_drmaa_wait (const char* jobId, int timeout, char* exitStatus, int* exitCode, char* signalCode, char* error, char*** attr, int* num_attr)
{
	int errnum = DRMAA_ERRNO_SUCCESS;
	int status;
	drmaa_attr_values_t *rusage;
	char jobIdCopy[DRMAA_JOBNAME_BUFFER];
	errnum = drmaa_wait(jobId, jobIdCopy, DRMAA_JOBNAME_BUFFER, &status, timeout, &rusage, error, DRMAA_ERROR_STRING_BUFFER);
	RETURN_ON_ERROR
	{
		int i;
		int bufsize = 100;
		size_t num;
		errnum = drmaa_get_num_attr_values(rusage, &num);
		RETURN_ON_ERROR
		*num_attr = num;
		*attr = (char**)malloc((*num_attr)*sizeof(char*));
		char** attrs = *attr;
		for (i=0; i<(*num_attr); i++)
		{
			(attrs[i]) = (char*)malloc(bufsize*sizeof(char));
			drmaa_get_next_attr_value(rusage, attrs[i], bufsize);
		}
		drmaa_release_attr_values(rusage);
	}
	
	errnum = __lua_wrapper_drmaa_fill_exit (status, exitStatus, exitCode, signalCode, error);
	RETURN_ON_ERROR
	return errnum;
}

int __lua_wrapper_drmaa_control (const char* jobId, const char* action, char* error)
{
	int errnum = DRMAA_ERRNO_SUCCESS;
	int drmaa_action = -1;
	if (strcmp(action, CONTROL_SIGNAL_SUSPEND) == 0)
		drmaa_action = DRMAA_CONTROL_SUSPEND;
	else if (strcmp(action, CONTROL_SIGNAL_RESUME) == 0)
		drmaa_action = DRMAA_CONTROL_RESUME;
	else if (strcmp(action, CONTROL_SIGNAL_HOLD) == 0)
		drmaa_action = DRMAA_CONTROL_HOLD;
	else if (strcmp(action, CONTROL_SIGNAL_RELEASE) == 0)
		drmaa_action = DRMAA_CONTROL_RELEASE;
	else if (strcmp(action, CONTROL_SIGNAL_TERMINATE) == 0)
		drmaa_action = DRMAA_CONTROL_TERMINATE;
	else
		fprintf(stderr,"Ação inválida %s!!!", action);
	
	errnum = drmaa_control(jobId, drmaa_action, error, DRMAA_ERROR_STRING_BUFFER);
	RETURN_ON_ERROR
	return errnum;
}

JobDescriptor* __lua_wrapper_drmaa_createEmptyJobDescriptor()
{
	JobDescriptor* jd = (JobDescriptor*)malloc(sizeof(JobDescriptor));
	if (jd==NULL)
		return NULL;
	jd->commandFile      = NULL;
	jd->outputFile       = NULL;
	jd->inputFile        = NULL;
	jd->errorFile        = NULL;
	jd->arguments        = NULL;
	jd->workingDirectory = NULL;
	jd->name             = NULL;
	jd->joinFiles        = NULL;
	jd->jobEnv           = NULL;
	jd->bulkIds          = NULL;
	jd->email            = NULL;
	return jd;
}

void __lua_wrapper_drmaa_destroyJobDescriptor(JobDescriptor* jd)
{
	if (jd)
	{
		if (jd->arguments)
			free(jd->arguments);
		if (jd->jobEnv)
			free(jd->jobEnv);
		if (jd->bulkIds)
			free(jd->bulkIds);
		free(jd);
	}
}

void __lua_wrapper_drmaa_fillArray (lua_State *L, int index, const char*** array)
{
	size_t size = lua_objlen(L, index);
	*array = (const char**)malloc((size+1)*sizeof(const char*));
	(*array)[size] = NULL;
	int n;
	for (n=0; n<size; n++) {
		lua_rawgeti(L, index, n+1);
		(*array)[n] = lua_tostring(L, -1);
		lua_pop(L, 1);
	}
}

void __lua_wrapper_drmaa_updateJobDescriptor(lua_State *L, int index, JobDescriptor* jd)
{
	lua_pushnil(L);  
	while (lua_next(L, index)) {
		const char *key = lua_tostring(L, -2);
		//printf("key = %s\n", key);
		if (strcmp(key, JD_COMMAND_FILE_KEY)==0) {  
			jd->commandFile = lua_tostring(L, -1); 
		}
		else if (strcmp(key, JD_OUTPUT_FILE_KEY)==0) { 
			jd->outputFile = lua_tostring(L, -1); 
		}
		else if (strcmp(key, JD_INPUT_FILE_KEY)==0) { 
			jd->outputFile = lua_tostring(L, -1); 
		}
		else if (strcmp(key, JD_ERROR_FILE_KEY)==0) { 
			jd->errorFile = lua_tostring(L, -1); 
		}
		else if (strcmp(key, JD_ARGUMENTS_KEY)==0) {
			__lua_wrapper_drmaa_fillArray(L, -1, &(jd->arguments));
		}
		else if (strcmp(key, JD_WORKINGDIRECTORY_KEY)==0) {
			jd->workingDirectory = lua_tostring(L, -1);
		}
		else if (strcmp(key, JD_NAME_KEY)==0) {
			jd->name = lua_tostring(L, -1);
		}
		else if (strcmp(key, JD_JOINFILES_KEY)==0) {
			if(lua_toboolean(L, -1))
				jd->joinFiles = "y";
			else
				jd->joinFiles = "n";
		}
		else if (strcmp(key, JD_ENVIRONMENT_KEY)==0) {
			__lua_wrapper_drmaa_fillArray(L, -1, &(jd->jobEnv));
		}
		else if (strcmp(key, JD_EMAIL_KEY)==0) {
			__lua_wrapper_drmaa_fillArray(L, -1, &(jd->email));
		}
		else { printf("Unknown value for key: %s\n", key); }
		lua_pop(L, 1);
	}
}

int lua_wrapper_drmaa_job_ps (lua_State *L)
{
	char error[DRMAA_ERROR_STRING_BUFFER];
	int errnum = DRMAA_ERRNO_SUCCESS;
	const char* jobId = lua_tostring(L, 1);
	char status[PS_STR_BUFFER];
	//printf("Called getStatus with arg %s\n", jobId);
	if (__lua_wrapper_drmaa_job_ps(jobId, status, error)==DRMAA_ERRNO_SUCCESS)
	{
		lua_pushstring(L, status);
		return 1;
	}
	lua_pushnil(L);
	lua_pushstring(L, (char*)error);
	return 2;
}
/*
int lua_wrapper_drmaa_wait (lua_State *L)
{
	char error[DRMAA_ERROR_STRING_BUFFER];
	int errnum = DRMAA_ERRNO_SUCCESS;
	const char* jobId = lua_tostring(L, 1);
	int timeout = lua_tonumber(L, 2);
	char exitStatus[20];
	char signalCode[DRMAA_SIGNAL_BUFFER];
	int exitCode;
	char** attr_pt;
	int num_attr = 0;

	if (__lua_wrapper_drmaa_wait(jobId, timeout, exitStatus, &exitCode, signalCode, error, &attr_pt, &num_attr)==DRMAA_ERRNO_SUCCESS)
	{
		lua_pushstring(L, exitStatus);
		if (strcmp(exitStatus, EXIT_STATUS_EXITED)==0)
		{
			lua_pushinteger(L, exitCode);
			if (num_attr!=0)
			{
				lua_createtable(L, num_attr, 0);
				int i;
				for (i=1; i<=num_attr; i++)
				{
					//printf("%d - %s\n", i, attr_pt[i-1]);
					lua_pushstring(L, attr_pt[i-1]);
					// -1 -> the string
					// -2 -> the table
					lua_rawseti(L, -2, i);
					free(attr_pt[i-1]);
				}
				free(attr_pt);
				return 3;
			}
			return 2;
		}
		else if (strcmp(exitStatus, EXIT_STATUS_SIGNALED)==0)
		{
			lua_pushstring(L, signalCode);
			return 2;
		}
		return 1;
	}
	lua_pushnil(L);
	lua_pushstring(L, (char*)error);
	return 2;
}
*/
int lua_wrapper_drmaa_wait (lua_State *L)
{
	char error[DRMAA_ERROR_STRING_BUFFER];
	int errnum = DRMAA_ERRNO_SUCCESS;
	const char* jobId = lua_tostring(L, 1);
	int timeout = lua_tonumber(L, 2);
	char exitStatus[20];
	char signalCode[DRMAA_SIGNAL_BUFFER];
	int exitCode;
	char** attr_pt;
	int num_attr = 0;

	if (__lua_wrapper_drmaa_wait(jobId, timeout, exitStatus, &exitCode, signalCode, error, &attr_pt, &num_attr)==DRMAA_ERRNO_SUCCESS)
	{
		lua_pushstring(L, exitStatus);
		if (strcmp(exitStatus, EXIT_STATUS_EXITED)==0)
		{
			lua_pushinteger(L, exitCode);
			if (num_attr!=0)
			{
				int i;
				for (i=1; i<=num_attr; i++)
				{
					lua_pushstring(L, attr_pt[i-1]);
					free(attr_pt[i-1]);
				}
				free(attr_pt);
				return 2+num_attr;
			}
			return 2;
		}
		else if (strcmp(exitStatus, EXIT_STATUS_SIGNALED)==0)
		{
			lua_pushstring(L, signalCode);
			return 2;
		}
		return 1;
	}
	lua_pushnil(L);
	lua_pushstring(L, (char*)error);
	return 2;
}

int lua_wrapper_drmaa_run_job (lua_State *L)
{
	char error[DRMAA_ERROR_STRING_BUFFER];
	int errnum = DRMAA_ERRNO_SUCCESS;
	char jobId[DRMAA_JOBNAME_BUFFER];
	JobDescriptor* jd = __lua_wrapper_drmaa_createEmptyJobDescriptor();
	if (!jd)
	{
		lua_pushnil(L);
		lua_pushstring(L, "Could not allocate job descriptor.");
		return 2;
	}
	__lua_wrapper_drmaa_updateJobDescriptor(L, 1, jd);
	if (__lua_wrapper_drmaa_run_job(jd, error)==DRMAA_ERRNO_SUCCESS)
	{
		lua_pushstring(L, jd->jobId);
		__lua_wrapper_drmaa_destroyJobDescriptor(jd);
		return 1;
	}	
	lua_pushnil(L);
	lua_pushstring(L, (char*)error);
	__lua_wrapper_drmaa_destroyJobDescriptor(jd);
	return 2;
}

int lua_wrapper_drmaa_control (lua_State *L)
{
	char error[DRMAA_ERROR_STRING_BUFFER];
	int errnum = DRMAA_ERRNO_SUCCESS;
	const char* jobId = lua_tostring(L, 1);
	const char* control = lua_tostring(L, 2);
	if (__lua_wrapper_drmaa_control(jobId, control, error)==DRMAA_ERRNO_SUCCESS)
	{
		lua_pushboolean(L, 1);
		return 1;
	}
	lua_pushnil(L);
	lua_pushstring(L, (char*)error);
	return 2;
}

int lua_wrapper_drmaa_init (lua_State *L)
{
	char error[DRMAA_ERROR_STRING_BUFFER];
	int errnum = DRMAA_ERRNO_SUCCESS;
	const char* contact = lua_tostring(L, 1);
	if (drmaa_init(contact, error, DRMAA_ERROR_STRING_BUFFER)==DRMAA_ERRNO_SUCCESS)
	{
		lua_pushboolean(L, 1);
		return 1;
	}
	lua_pushnil(L);
	lua_pushstring(L, (char*)error);
	return 2;	
}

int lua_wrapper_drmaa_exit (lua_State *L)
{
	char error[DRMAA_ERROR_STRING_BUFFER];
	int errnum = DRMAA_ERRNO_SUCCESS;
	if (drmaa_exit(error, DRMAA_ERROR_STRING_BUFFER)==DRMAA_ERRNO_SUCCESS)
	{
		lua_pushboolean(L, 1);
		return 1;
	}
	lua_pushnil(L);
	lua_pushstring(L, (char*)error);
	return 2;	
}

int lua_wrapper_drmaa_get_contact (lua_State *L)
{
	char contact[DRMAA_ERROR_STRING_BUFFER];
	char error[DRMAA_ERROR_STRING_BUFFER];
	int errnum = DRMAA_ERRNO_SUCCESS;
	if (drmaa_get_contact(contact, DRMAA_ERROR_STRING_BUFFER, error, DRMAA_ERROR_STRING_BUFFER)==DRMAA_ERRNO_SUCCESS)
	{
		lua_pushstring(L, contact);
		return 1;
	}
	lua_pushnil(L);
	lua_pushstring(L, (char*)error);
	return 2;
}

int lua_wrapper_drmaa_version (lua_State *L)
{
	char error[DRMAA_ERROR_STRING_BUFFER];
	int errnum = DRMAA_ERRNO_SUCCESS;
	int major, minor;
	if (drmaa_version(&major, &minor, error, DRMAA_ERROR_STRING_BUFFER)==DRMAA_ERRNO_SUCCESS)
	{
		lua_pushnumber(L, major);
		lua_pushnumber(L, minor);
		return 2;
	}
	lua_pushnil(L);
	lua_pushstring(L, (char*)error);
	return 2;
}

int lua_wrapper_drmaa_get_DRM_system (lua_State *L)
{
	char system[DRMAA_ERROR_STRING_BUFFER];
	char error[DRMAA_ERROR_STRING_BUFFER];
	int errnum = DRMAA_ERRNO_SUCCESS;
	if (drmaa_get_DRM_system(system, DRMAA_ERROR_STRING_BUFFER, error, DRMAA_ERROR_STRING_BUFFER)==DRMAA_ERRNO_SUCCESS)
	{
		lua_pushstring(L, system);
		return 1;
	}
	lua_pushnil(L);
	lua_pushstring(L, (char*)error);
	return 2;
}

int lua_wrapper_drmaa_get_DRMAA_implementation (lua_State *L)
{
	char impl[DRMAA_ERROR_STRING_BUFFER];
	char error[DRMAA_ERROR_STRING_BUFFER];
	int errnum = DRMAA_ERRNO_SUCCESS;
	if (drmaa_get_DRMAA_implementation(impl, DRMAA_ERROR_STRING_BUFFER, error, DRMAA_ERROR_STRING_BUFFER)==DRMAA_ERRNO_SUCCESS)
	{
		lua_pushstring(L, impl);
		return 1;
	}
	lua_pushnil(L);
	lua_pushstring(L, (char*)error);
	return 2;
}

int lua_wrapper_get_drmaa_impl_WaitForever (lua_State *L)
{
	char error[DRMAA_ERROR_STRING_BUFFER];
	int errnum = DRMAA_ERRNO_SUCCESS;
        lua_pushnumber(L, DRMAA_TIMEOUT_WAIT_FOREVER);
	return 1;
}

int lua_wrapper_get_drmaa_impl_NoWait (lua_State *L)
{
	char error[DRMAA_ERROR_STRING_BUFFER];
	int errnum = DRMAA_ERRNO_SUCCESS;
        lua_pushnumber(L, DRMAA_TIMEOUT_NO_WAIT);
	return 1;
}

int foo (lua_State *L)
{
	lua_createtable(L, 3, 0);
	int i;
	char* vals[3] = {"Hello", "World", "Lua"};
	for (i=1; i<=3; i++)
	{
		lua_pushstring(L, vals[i-1]);
		// -1 -> the string
		// -2 -> the table
		lua_rawseti(L, -2, i);
	}
	return 1;
}

int luaopen_drmaa(lua_State *L){
	lua_register(L, "lua_wrapper_drmaa_init", lua_wrapper_drmaa_init);
	lua_register(L, "lua_wrapper_drmaa_exit", lua_wrapper_drmaa_exit);
        lua_register(L, "lua_wrapper_drmaa_run_job", lua_wrapper_drmaa_run_job);
	lua_register(L, "lua_wrapper_drmaa_job_ps", lua_wrapper_drmaa_job_ps);
	lua_register(L, "lua_wrapper_drmaa_wait", lua_wrapper_drmaa_wait);
	lua_register(L, "lua_wrapper_drmaa_control", lua_wrapper_drmaa_control);
	lua_register(L, "lua_wrapper_drmaa_get_contact", lua_wrapper_drmaa_get_contact);
	lua_register(L, "lua_wrapper_drmaa_version", lua_wrapper_drmaa_version);
	lua_register(L, "lua_wrapper_drmaa_get_DRM_system", lua_wrapper_drmaa_get_DRM_system);
	lua_register(L, "lua_wrapper_drmaa_get_DRMAA_implementation", lua_wrapper_drmaa_get_DRMAA_implementation);

	lua_register(L, "lua_wrapper_get_drmaa_impl_WaitForever", lua_wrapper_get_drmaa_impl_WaitForever);
	lua_register(L, "lua_wrapper_get_drmaa_impl_NoWait", lua_wrapper_get_drmaa_impl_NoWait);

	lua_register(L, "foo", foo);

	return 0;
}
