/*******************************************************************************

	Backgammon.c
	
		The client backgammon game.
		

	Change History (most recent first):
	----------------------------------------------------------------------------
	Rev	 |	Date	 |	Who	 |	What
	----------------------------------------------------------------------------
	0		11/1/96		CHB		Created
	 
*******************************************************************************/

#include <windows.h>
#include <commctrl.h>
#include <mmsystem.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "game.h"
#include "zonecli.h"
#include "zonehelpids.h"


// Defines
#define zGameNameLen	63


// Global variables that don't need to be thread safe
//const TCHAR* gGameRegName = _T("Backgammon");
HWND  gOCXHandle		 = NULL;

#ifndef ZONECLI_DLL

	static HINSTANCE	 ghInstance;
	static TCHAR		 gVillageName[zUserNameLen + 1];
	static TCHAR		 gGameDir[zGameNameLen + 1];
	static TCHAR		 gGameName[zGameNameLen + 1];
	static TCHAR		 gGameDataFile[zGameNameLen + 1];
	static TCHAR		 gGameServerName[zGameNameLen + 1];
	static uint32		 gGameServerPort;
	static ZImage		 gGameIdle;
	static ZImage		 gGaming;
	static TCHAR		 gHelpURL;

#else

	typedef struct
	{
		HINSTANCE	m_ghInstance;
		TCHAR		m_gVillageName[zUserNameLen + 1];
		TCHAR		m_gGameDir[zGameNameLen + 1];
		TCHAR		m_gGameName[zGameNameLen + 1];
		TCHAR		m_gGameDataFile[zGameNameLen + 1];
		TCHAR		m_gGameServerName[zGameNameLen + 1];
		TCHAR		m_gHelpURL[ 128 ];
		uint32		m_gGameServerPort;
		ZImage		m_gGameIdle;
		ZImage		m_gGaming;
	} GameGlobalsType, *GameGlobals;

	#define ghInstance			(pGameGlobals->m_ghInstance)
	#define gVillageName		(pGameGlobals->m_gVillageName)
	#define gGameDir			(pGameGlobals->m_gGameDir)
	#define gGameName			(pGameGlobals->m_gGameName)
	#define gGameDataFile		(pGameGlobals->m_gGameDataFile)
	#define gGameServerName		(pGameGlobals->m_gGameServerName)
	#define gGameServerPort		(pGameGlobals->m_gGameServerPort)
	#define gGameIdle			(pGameGlobals->m_gGameIdle)
	#define gGaming				(pGameGlobals->m_gGaming)
	#define	gHelpURL			(pGameGlobals->m_gHelpURL)

#endif //!ZONECLI_DLL


///////////////////////////////////////////////////////////////////////////////
// Inline Functions
///////////////////////////////////////////////////////////////////////////////

inline BOOL IsValidSeat( int seat )
{
	return ((seat >= 0) && (seat < zNumPlayersPerTable));
}


///////////////////////////////////////////////////////////////////////////////
// EXPORTED ROUTINES
///////////////////////////////////////////////////////////////////////////////

extern "C" static ZBool GetObjectFunc(int16 objectType, int16 modifier, ZImage* image, ZRect* rect)
{
#ifdef ZONECLI_DLL
	GameGlobals	pGameGlobals = (GameGlobals) ZGetGameGlobalPointer();
#endif
/*
	HRSRC hrc;
	ZImageDescriptor* ptr;
	int sz;

	switch (objectType)
	{
		case zRoomObjectGameMarker:
			if (image != NULL)
			{
				if (modifier == zRoomObjectIdle)
				{
					if ( gGameIdle )
						*image = gGameIdle;
					else
					{
						hrc = FindResource( ghInstance, MAKEINTRESOURCE(ID_ZIMAGE_IDLE), _T("ZIMAGE") );
						if ( !hrc )
							return FALSE;
						ptr = (ZImageDescriptor*) new BYTE [ sz = SizeofResource( ghInstance, hrc ) ];
						if ( !ptr )
							return FALSE;
						CopyMemory( ptr, LockResource( LoadResource( ghInstance, hrc ) ), sz );
						ZImageDescriptorEndian( ptr, TRUE, zEndianFromStandard );
						gGameIdle = ZImageNew();
						ZImageInit( gGameIdle, ptr, NULL );
						*image = gGameIdle;
						delete [] ptr;
					}
				}
				else if (modifier == zRoomObjectGaming)
				{
					if ( gGaming )
						*image = gGaming;
					else
					{
						hrc = FindResource( ghInstance, MAKEINTRESOURCE(ID_ZIMAGE_PLAY), _T("ZIMAGE") );
						if ( !hrc )
							return FALSE;
						ptr = (ZImageDescriptor*) new BYTE [ sz = SizeofResource( ghInstance, hrc ) ];
						if ( !ptr )
							return FALSE;
						CopyMemory( ptr, LockResource( LoadResource( ghInstance, hrc ) ), sz );
						ZImageDescriptorEndian( ptr, TRUE, zEndianFromStandard );
						gGaming = ZImageNew();
						ZImageInit( gGaming, ptr, NULL );
						*image = gGaming;
						delete [] ptr;
					}
				}
			}
			return (TRUE);
	}
	*/
	return (TRUE);
}



extern "C" static void DeleteObjectsFunc(void)
{
#ifdef ZONECLI_DLL
	GameGlobals	pGameGlobals = (GameGlobals) ZGetGameGlobalPointer();
#endif
/*
	if ( gGaming )
	{
		ZImageDelete(gGaming);
		gGaming = NULL;
	}
	if ( gGameIdle )
	{
		ZImageDelete(gGameIdle);
		gGameIdle = NULL;
	}
*/
}



extern "C" ZError ZoneGameDllInit(HINSTANCE hLib, GameInfo gameInfo)
{
#ifdef ZONECLI_DLL
	GameGlobals	pGameGlobals = (GameGlobals) ZCalloc(1, sizeof(GameGlobalsType));
	if (pGameGlobals == NULL)
		return (zErrOutOfMemory);
	ZSetGameGlobalPointer(pGameGlobals);
#endif

	// global variables
//	lstrcpyn(gGameDir, gameInfo->game, zGameNameLen);
//	lstrcpyn(gGameName, gameInfo->gameName, zGameNameLen);
//	lstrcpyn(gGameDataFile, gameInfo->gameDataFile, zGameNameLen);
//	lstrcpyn(gGameServerName, gameInfo->gameServerName, zGameNameLen);

	gGameServerPort = gameInfo->gameServerPort;
	ghInstance = hLib;
	gGameIdle = NULL;
	gGaming = NULL;
//	gHelpURL[0] = _T('\0');
	
	// random numbers
    srand(GetTickCount());

	// common controls
	InitCommonControls();
	
	return (zErrNone);
}



extern "C" void ZoneGameDllDelete(void)
{
#ifdef ZONECLI_DLL
	GameGlobals pGameGlobals = (GameGlobals) ZGetGameGlobalPointer();
	if (pGameGlobals != NULL)
	{
		ZSetGameGlobalPointer(NULL);
		ZFree(pGameGlobals);
	}
#endif
}



ZError ZoneClientMain( _TUCHAR *commandLineData, IGameShell *piGameShell )
{
#ifdef ZONECLI_DLL
	GameGlobals	pGameGlobals = (GameGlobals) ZGetGameGlobalPointer();
#endif

	ZError err = zErrNone;
/*
	// Copy Help URL
	lstrcpy( gHelpURL, (TCHAR*) commandLineData );
*/	
	// Initialize room
	err = ZClient2PlayerRoom(
				gGameServerName,
				(uint16) gGameServerPort,
				gGameName,
				GetObjectFunc,
				DeleteObjectsFunc, 
				NULL );
	return (err);
}



extern "C" void ZoneClientExit(void)
{
	ZCRoomExit();
}



extern "C" TCHAR* ZoneClientName(void)
{
#ifdef ZONECLI_DLL
	GameGlobals pGameGlobals = (GameGlobals) ZGetGameGlobalPointer();
#endif

	return (gGameName);
}



extern "C" TCHAR* ZoneClientInternalName(void)
{
#ifdef ZONECLI_DLL
	GameGlobals	pGameGlobals = (GameGlobals) ZGetGameGlobalPointer();
#endif

	return (gGameDir);
}



extern "C" ZVersion ZoneClientVersion(void)
{
	return (zGameVersion);
}



extern "C" void ZoneClientMessageHandler(ZMessage* message)
{
}


// Instantiates a new game on the client side of the game at table and from the
// given seat. PlayerType indicates the type of player for the game: originator - one
// of the original players, joiner - one who joins an ongoing game, or kibitzer - one
// who is kibitzing the game. Also, the kibitzers parameters contains all the kibitzers
// at the given table and seat; it includes the given player also if kibitzing.
extern "C" IGameGame* ZoneClientGameNew( ZUserID userID, int16 tableID, int16 seat, int16 playerType, ZRoomKibitzers* kibitzers)
{
#ifdef ZONECLI_DLL
	GameGlobals			pGameGlobals	 = (GameGlobals)      ZGetGameGlobalPointer();
	ClientDllGlobals	pClientGlobals	 = (ClientDllGlobals) ZGetClientGlobalPointer();
#endif

	HRESULT hr;
//Game* pGame;

	gOCXHandle = pClientGlobals->m_OCXHandle;

    CComObject<CGame> *pIGG = NULL;
    hr = CComObject<CGame>::CreateInstance(&pIGG);

    if(FAILED(hr))
        return NULL;
	/*
	// Create game object
	pGame = new CGame( ghInstance );
	if ( !pGame )
		return NULL;
	*/
	// Initialize game object
	hr = pIGG->Init( ghInstance, userID, tableID, seat, playerType, kibitzers );
	if ( FAILED(hr) )
	{
		pIGG->Release();
		/*		
		delete pGame;
		*/
		return NULL;
	}
	/*
    IGameGame *pIGG = CGameGameDefault::BearInstance(pGame);
    if(!pIGG)
    {
        delete pGame;
        return NULL;
    }
	*/
	return pIGG;
}



extern "C" void	ZoneClientGameDelete(ZCGame cgame)
{
	CGame* pGame = (CGame*) cgame;
	pGame->RoomShutdown();	
}



extern "C" void ZoneClientGameAddKibitzer(ZCGame game, int16 seat, ZUserID userID)
{
	CGame* pGame = (CGame*) game;

	if ( game )
		pGame->AddKibitzer( seat, userID, TRUE );
}



extern "C" void ZoneClientGameRemoveKibitzer(ZCGame game, int16 seat, ZUserID userID)
{
	CGame* pGame = (CGame*) game;

	if ( game )
		pGame->RemoveKibitzer( seat, userID );
}



extern "C" ZBool ZoneClientGameProcessMessage(ZCGame gameP, uint32 messageType, void* message, int32 messageLen)
{
	CGame* pGame = (CGame*) gameP;
	
	switch( messageType )
	{
	case zGameMsgCheckIn:
		pGame->HandleCheckIn( message, messageLen );
		break;
	case zBGMsgTalk:
		pGame->HandleTalk( message, messageLen );
		break;
	case zBGMsgDiceRoll:
		pGame->HandleDiceRoll(message,messageLen);
        break;
	default:
		pGame->QueueMessage( messageType, (BYTE*) message, messageLen );
		break;
	}
	return TRUE;
}



void LaunchHelp()
{
	ZLaunchHelp(zGameHelpID);
}



/*
#define REGISTRY_PATH	_T("SOFTWARE\\Microsoft\\Internet Gaming Zone")
BOOL ZoneGetRegistryDword( const TCHAR* szGame, const TCHAR* szTag, DWORD* pdwResult )
{
	HKEY hKey;
	DWORD bytes;
	long status;
	TCHAR buff[2048];

	// get key to registry
	wsprintf( buff, _T("%s\\%s"), REGISTRY_PATH, szGame );
	status = RegOpenKeyEx( HKEY_CURRENT_USER, buff, 0, KEY_READ, &hKey );
	if (status != ERROR_SUCCESS)
		return FALSE;
	bytes = sizeof(DWORD);
	status = RegQueryValueEx( hKey, szTag, 0, NULL, (BYTE*) pdwResult, &bytes );

	// close registry
	RegCloseKey( hKey );
	return (status != ERROR_SUCCESS) ? FALSE : TRUE;
}



BOOL ZoneSetRegistryDword( const TCHAR* szGame, const TCHAR* szTag, DWORD dwValue )
{
	HKEY hKey;
	DWORD bytes;
	long status;
	TCHAR buff[2048];

	// create top level application key
	wsprintf( buff, _T("%s\\%s"), REGISTRY_PATH, szGame );
	status = RegCreateKeyEx(
				HKEY_CURRENT_USER,
				buff,
				0,
				_T("User Settings"),
				REG_OPTION_NON_VOLATILE,
				KEY_ALL_ACCESS,
				NULL,
				&hKey,
				&bytes );
	if (status != ERROR_SUCCESS)
		return FALSE;

	// write value
	status = RegSetValueEx( hKey, szTag, 0, REG_DWORD, (BYTE*) &dwValue, sizeof(DWORD) );

	// close registry
	RegCloseKey( hKey );
	return (status != ERROR_SUCCESS) ? FALSE : TRUE;
}
*/