/*
	Example PLUG-IN DLL Source Code for Quake II
	Version 1.01 (last updated Feb 25, 1999)

	Author	: Zarjazz
	Email	: zarjazz@barrysworld.com
	WebPage	: http://www.barrysworld.com/zarjazz
	----
	You will need the original Q2 DLL Source to compile this file.
*/

#include "g_local.h"

#ifdef _WIN32
	#include <windows.h>
#else
	#include <dlfcn.h>
#endif

game_import_t	gi;
game_export_t	globals;

game_import_t	*game_import;
game_export_t	*game_export;


void ClientBegin (edict_t *ent);
void ClientCommand (edict_t *ent);
qboolean ClientConnect (edict_t *ent, char *userinfo);
void ClientDisconnect (edict_t *ent);
void ClientThink (edict_t *ent, usercmd_t *cmd);
void ClientUserinfoChanged (edict_t *ent, char *userinfo);
//void G_RunFrame (void);
void InitGame (void);
void ServerCommand (void);
void ShutdownGame (void);
void SpawnEntities (char *mapname, char *entities, char *spawnpoint);


//===================================================================

#ifdef _WIN32
	HINSTANCE hDLL = NULL;	// Handle to DLL
#else
	void *hDLL = NULL;
#endif

typedef game_export_t * (*LPGETGAMEAPI) (game_import_t *import);

//===================================================================

void LoadGameDLL (void)
{
	LPGETGAMEAPI lpGetGameAPI;

	char gamedir[MAX_OSPATH/2], dllname[MAX_OSPATH/2];
	char gamedll[MAX_OSPATH];

#ifndef _WIN32
	gi.dprintf("\n"); // Cosmetic Fix
#endif

	gi.dprintf("Loading PLUG-IN\n");

	if (hDLL)
	{
		gi.error("PLUG-IN Already Loaded\n");
		return;
	}

	strcpy(gamedir, gi.cvar ("game", "baseq2", CVAR_SERVERINFO)->string);
	if (gamedir[0] == '\0') strcpy(gamedir,"baseq2");

#ifdef _WIN32
	strcpy (dllname,"gamex86.dll");
#else
	strcpy (dllname,"gamei386.so");
#endif

	// Load the game DLL

#ifdef _WIN32
	sprintf(gamedll,"%s\\%s",gamedir,dllname);
	hDLL = LoadLibrary(gamedll);
#else
	sprintf(gamedll,"%s/%s",gamedir,dllname);
	hDLL = dlopen(gamedll, RTLD_LAZY);
#endif

	if (!hDLL)
	{
		gi.error("Unable to load DLL: %s\n", gamedll);
		return;
	}

	gi.dprintf("PLUG-IN Loaded: %s\n", gamedll);

#ifdef _WIN32
	lpGetGameAPI = (LPGETGAMEAPI) GetProcAddress(hDLL, "GetGameAPI");
#else
	lpGetGameAPI = (LPGETGAMEAPI) dlsym(hDLL, "GetGameAPI");
#endif

	if (!lpGetGameAPI)
	{
		// handle the error
#ifdef _WIN32
		FreeLibrary(hDLL);
#else
		dlclose(hDLL);
#endif
		gi.error("Unable to find GetGameAPI()\n");
		return;
	}

	// call the function
	game_export = lpGetGameAPI(game_import);

	if (!game_export) gi.error("Error calling GetGameAPI()\n");

	// -------

	globals = *game_export;

	game_export->ClientBegin			= ClientBegin;
	game_export->ClientCommand			= ClientCommand;
	game_export->ClientConnect			= ClientConnect;
	game_export->ClientDisconnect		= ClientDisconnect;
	game_export->ClientThink			= ClientThink;
	game_export->ClientUserinfoChanged	= ClientUserinfoChanged;
	game_export->Init					= InitGame;
	game_export->ServerCommand			= ServerCommand;
	game_export->Shutdown				= ShutdownGame;
	game_export->SpawnEntities			= SpawnEntities;
}

// ---- Intercepted Calls ---- //

void ClientBegin (edict_t *ent)
{
	globals.ClientBegin(ent);
}

void ClientCommand (edict_t *ent)
{
	globals.ClientCommand(ent);
}

qboolean ClientConnect (edict_t *ent, char *userinfo)
{
	return globals.ClientConnect(ent,userinfo);
}

void ClientDisconnect (edict_t *ent)
{
	globals.ClientDisconnect(ent);
}

void ClientThink (edict_t *ent, usercmd_t *ucmd)
{
	globals.ClientThink(ent, ucmd);
}

void ClientUserinfoChanged (edict_t *ent, char *userinfo)
{
	globals.ClientUserinfoChanged (ent, userinfo);
}

void InitGame (void)
{
	if (!hDLL)
		gi.error("PLUG-IN NOT LOADED\n");

	globals.Init();
}

void ServerCommand (void)
{
	globals.ServerCommand();
}

void ShutdownGame (void)
{
	globals.Shutdown();

#ifdef _WIN32
	FreeLibrary(hDLL);
#else
	dlclose(hDLL);
#endif

	hDLL = NULL;
}

void SpawnEntities (char *mapname, char *entities, char *spawnpoint)
{
	globals.SpawnEntities(mapname, entities, spawnpoint);
}

/*
=================
GetGameAPI

Returns a pointer to the structure with all entry points
and global variables
=================
*/

game_export_t *GetGameAPI (game_import_t *import)
{
	gi = *import;
	game_import = import;

	LoadGameDLL();

	return game_export;
}

