/*
   Copyright (C) 2002-2003 Victor Luchits

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

   See the GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

 */

#include "client.h"
#include "../ui/ui_public.h"

// Structure containing functions exported from user interface DLL
ui_export_t *uie;

mempool_t *ui_mempool;
static void *module_handle;

/*
   ===============
   CL_UIModule_Print
   ===============
 */
static void CL_UIModule_Print( const char *msg )
{
	Com_Printf( "%s", msg );
}

/*
   ===============
   CL_UIModule_Error
   ===============
 */
static void CL_UIModule_Error( const char *msg )
{
	Com_Error( ERR_FATAL, "%s", msg );
}

/*
   ===============
   CL_UIModule_GetConfigString
   ===============
 */
static void CL_UIModule_GetConfigString( int i, char *str, int size )
{
	if( i < 0 || i >= MAX_CONFIGSTRINGS )
		Com_Error( ERR_DROP, "CL_UIModule_GetConfigString: i > MAX_CONFIGSTRINGS" );
	if( !str || size <= 0 )
		Com_Error( ERR_DROP, "CL_UIModule_GetConfigString: NULL string" );
	Q_strncpyz( str, cl.configstrings[i], size );
}

/*
   ===============
   CL_UIModule_MemAlloc
   ===============
 */
static void *CL_UIModule_MemAlloc( size_t size, const char *filename, int fileline )
{
	return _Mem_Alloc( ui_mempool, size, MEMPOOL_USERINTERFACE, 0, filename, fileline );
}

/*
   ===============
   CL_UIModule_MemFree
   ===============
 */
static void CL_UIModule_MemFree( void *data, const char *filename, int fileline )
{
	_Mem_Free( data, MEMPOOL_USERINTERFACE, 0, filename, fileline );
}

/*
==============
CL_UIModule_InitImportStruct
==============
*/
#define CL_UIModule_InitImportStruct( import ) \
( \
	import.Error = CL_UIModule_Error, \
	import.Print = CL_UIModule_Print, \
/* dynvars */ \
	import.Dynvar_Create = Dynvar_Create, \
	import.Dynvar_Destroy = Dynvar_Destroy, \
	import.Dynvar_Lookup = Dynvar_Lookup, \
	import.Dynvar_GetName = Dynvar_GetName, \
	import.Dynvar_GetValue = Dynvar_GetValue, \
	import.Dynvar_SetValue = Dynvar_SetValue, \
	import.Dynvar_AddListener = Dynvar_AddListener, \
	import.Dynvar_RemoveListener = Dynvar_RemoveListener, \
\
	import.Cvar_Get = Cvar_Get, \
	import.Cvar_Set = Cvar_Set, \
	import.Cvar_SetValue = Cvar_SetValue, \
	import.Cvar_ForceSet = Cvar_ForceSet, \
	import.Cvar_String = Cvar_String, \
	import.Cvar_Value = Cvar_Value, \
\
	import.Cmd_Argc = Cmd_Argc, \
	import.Cmd_Argv = Cmd_Argv, \
	import.Cmd_Args = Cmd_Args, \
\
	import.Cmd_AddCommand = Cmd_AddCommand, \
	import.Cmd_RemoveCommand = Cmd_RemoveCommand, \
	import.Cmd_ExecuteText = Cbuf_ExecuteText, \
	import.Cmd_Execute = Cbuf_Execute, \
\
	import.FS_FOpenFile = FS_FOpenFile, \
	import.FS_Read = FS_Read, \
	import.FS_Write = FS_Write, \
	import.FS_Print = FS_Print, \
	import.FS_Tell = FS_Tell, \
	import.FS_Seek = FS_Seek, \
	import.FS_Eof = FS_Eof, \
	import.FS_Flush = FS_Flush, \
	import.FS_FCloseFile = FS_FCloseFile, \
	import.FS_RemoveFile = FS_RemoveFile, \
	import.FS_GetFileList = FS_GetFileList, \
	import.FS_GetGameDirectoryList = FS_GetGameDirectoryList, \
	import.FS_FirstExtension = FS_FirstExtension, \
\
	import.CL_Quit = CL_Quit, \
	import.CL_SetKeyDest = CL_SetKeyDest, \
	import.CL_ResetServerCount = CL_ResetServerCount, \
	import.CL_GetClipboardData = CL_GetClipboardData, \
	import.CL_FreeClipboardData = CL_FreeClipboardData, \
\
	import.Key_ClearStates = Key_ClearStates, \
	import.Key_GetBindingBuf = Key_GetBindingBuf, \
	import.Key_KeynumToString = Key_KeynumToString, \
	import.Key_SetBinding = Key_SetBinding, \
	import.Key_IsDown = Key_IsDown, \
\
	import.R_ClearScene = R_ClearScene, \
	import.R_AddEntityToScene = R_AddEntityToScene, \
	import.R_AddLightToScene = R_AddLightToScene, \
	import.R_AddPolyToScene = R_AddPolyToScene, \
	import.R_RenderScene = R_RenderScene, \
	import.R_EndFrame = R_EndFrame, \
	import.R_ModelBounds = R_ModelBounds, \
	import.R_RegisterModel = R_RegisterModel, \
	import.R_RegisterPic = R_RegisterPic, \
	import.R_RegisterSkin = R_RegisterSkin, \
	import.R_RegisterSkinFile = R_RegisterSkinFile, \
	import.R_LerpTag = R_LerpTag, \
	import.R_DrawStretchPic = R_DrawStretchPic, \
	import.R_TransformVectorToScreen = R_TransformVectorToScreen, \
	import.R_SkeletalGetNumBones = R_SkeletalGetNumBones, \
	import.R_SkeletalGetBoneInfo = R_SkeletalGetBoneInfo, \
	import.R_SkeletalGetBonePose = R_SkeletalGetBonePose, \
\
	import.S_RegisterSound = CL_SoundModule_RegisterSound, \
	import.S_StartLocalSound = CL_SoundModule_StartLocalSound, \
	import.S_StartBackgroundTrack = CL_SoundModule_StartBackgroundTrack, \
	import.S_StopBackgroundTrack = CL_SoundModule_StopBackgroundTrack, \
\
	import.SCR_RegisterFont = SCR_RegisterFont, \
	import.SCR_DrawString = SCR_DrawString, \
	import.SCR_DrawStringWidth = SCR_DrawStringWidth, \
	import.SCR_DrawClampString = SCR_DrawClampString, \
	import.SCR_strHeight = SCR_strHeight, \
	import.SCR_strWidth = SCR_strWidth, \
	import.SCR_StrlenForWidth = SCR_StrlenForWidth, \
\
	import.GetConfigString = CL_UIModule_GetConfigString, \
\
	import.Milliseconds = Sys_Milliseconds, \
\
	import.VID_GetModeInfo = VID_GetModeInfo, \
\
	import.Mem_Alloc = CL_UIModule_MemAlloc, \
	import.Mem_Free = CL_UIModule_MemFree, \
\
	import.Auth_CheckUser = Auth_CheckUser, \
\
	import.MM_Join = CL_MM_Join, \
	import.MM_Drop = CL_MM_Drop, \
	import.MM_Chat = CL_MM_Chat, \
\
	import.ML_GetFilename = ML_GetFilename, \
	import.ML_GetFullname = ML_GetFullname, \
	import.ML_GetMapByNum = ML_GetMapByNum \
)

/*
   ==============
   CL_UIModule_Init
   ==============
 */
void CL_UIModule_Init( void )
{
        int apiversion;
        ui_import_t import;

        CL_UIModule_Shutdown();

        ui_mempool = _Mem_AllocPool( NULL, "User Iterface", MEMPOOL_USERINTERFACE, __FILE__, __LINE__ );

        CL_UIModule_InitImportStruct( import );

#ifdef UI_HARD_LINKED
#if defined ( _WIN32 ) && ( _MSC_VER >= 1400 )
#pragma warning( push )
#pragma warning( disable : 4210 )   // nonstandard extension used : function given file scope
#endif

        {
                EXTERN_API_FUNC void *GetUIAPI( void * );
                uie = (ui_export_t *)GetUIAPI( &import );
	}

#if defined ( _WIN32 ) && ( _MSC_VER >= 1400 )
#pragma warning( pop )
#endif
#else
        uie = (ui_export_t *)Com_LoadGameLibrary( "ui", "GetUIAPI", &module_handle, &import, cls.sv_pure );
#endif
        if( !uie )
		Com_Error( ERR_DROP, "Failed to load UI dll" );

        apiversion = uie->API();
        if( apiversion != UI_API_VERSION )
        {
#ifndef UI_HARD_LINKED
                Com_UnloadGameLibrary( &module_handle );
#endif
                Mem_FreePool( &ui_mempool );
                uie = NULL;

                Com_Error( ERR_FATAL, "UI version is %i, not %i", apiversion, UI_API_VERSION );
	}

        uie->Init( viddef.width, viddef.height, APP_PROTOCOL_VERSION );
}

/*
   ===============
   CL_UIModule_Shutdown
   ===============
 */
void CL_UIModule_Shutdown( void )
{
        if( !uie )
		return;

        uie->Shutdown();
        Mem_FreePool( &ui_mempool );
#ifndef UI_HARD_LINKED
        Com_UnloadGameLibrary( &module_handle );
#endif
        uie = NULL;
}

/*
   ===============
   CL_UIModule_Refresh
   ===============
 */
void CL_UIModule_Refresh( qboolean backGround )
{
	if( uie )
		uie->Refresh( cls.realtime, Com_ClientState(), Com_ServerState(), backGround );
}

/*
   ===============
   CL_UIModule_DrawConnectScreen
   ===============
 */
void CL_UIModule_DrawConnectScreen( qboolean backGround )
{
	if( uie )
        {
                char *p;
                if( cls.download.web )
			p = "(w)";
                else if( cls.download.filenum )
			p = "(s)";
                else
			p = NULL;
                uie->DrawConnectScreen( cls.servername, cls.rejected ? cls.rejectmessage : NULL,
                                        ( cls.download.filenum || cls.download.web ) ?
                                        va( "%s %s %3.1f%c", p, cls.download.name, cls.download.percent * 100.0, '%' ) : NULL,
                                        cls.connect_count, backGround );
	}
}

/*
   ===============
   CL_UIModule_Keydown
   ===============
 */
void CL_UIModule_Keydown( int key )
{
	if( uie )
		uie->Keydown( key );
}

/*
   ===============
   CL_UIModule_Keyup
   ===============
 */
void CL_UIModule_Keyup( int key )
{
	if( uie )
		uie->Keyup( key );
}

/*
   ===============
   CL_UIModule_CharEvent
   ===============
 */
void CL_UIModule_CharEvent( qwchar key )
{
	if( uie )
		uie->CharEvent( key );
}

/*
   ===============
   CL_UIModule_ForceMenuOff
   ===============
 */
void CL_UIModule_ForceMenuOff( void )
{if( uie )
		uie->ForceMenuOff();
}

/*
   ===============
   CL_UIModule_AddToServerList
   ===============
 */
void CL_UIModule_AddToServerList( char *adr, char *info )
{
	if( uie )
		uie->AddToServerList( adr, info );
}

/*
   ===============
   CL_UIModule_MouseMove
   ===============
 */
void CL_UIModule_MouseMove( int dx, int dy )
{
	if( uie )
		uie->MouseMove( dx, dy );
}

/*
   ===============
   CL_UIModule_AuthReply
   ===============
 */
void CL_UIModule_AuthReply( auth_reply_t reply )
{
	if( uie )
		uie->AuthReply( reply );
}

/*
   ===============
   CL_UIModule_MM_UpdateSlot
   ===============
 */
void CL_UIModule_MM_UpdateSlot( int slotno, const char *playername )
{
	if( uie )
		uie->MM_UpdateSlot( slotno, playername );
}

/*
   ===============
   CL_UIModule_MM_UpdateStatus
   ===============
 */
void CL_UIModule_MM_UpdateStatus( const char *status )
{
	if( uie )
		uie->MM_UpdateStatus( status, qtrue );
}

/*
   ===============
   CL_UIModule_MM_UpdateMatchStatus
   ===============
 */
void CL_UIModule_MM_UpdateMatchStatus( qboolean started )
{
	if( uie )
		uie->MM_UpdateMatchStatus( started );
}

void CL_UIModule_MM_AddChatMsg( const char *msg )
{
	if( uie )
		uie->MM_AddChatMsg( msg );
}
