#include "AdeptHeaders.hpp"
#include "GameOS\Network.hpp"
#include "GameOS\GunGameList.h"
#include "GameSpy.h"
#include <dplay.h>
#include <dplobby.h>

#ifdef NEW_GAMESPY
#define NEW_GAMESPY_HOST
#define NEW_GAMESPY_CLIENT
#endif



#ifndef RELEASE_PTR
#define RELEASE_PTR(p) if (p) { (p)->Release(); (p)=NULL; }
#endif

#ifndef NEW_GAMESPY
static char szGameSpyAddress[256];
char * GameSpyOld::szGameSpyAddress = szGameSpyAddress;
int GameSpyOld::status;
#endif

//========================================================================
//========================================================================
int __stdcall GameSpy::GetStatus( void )
{
    return 0;
}

//========================================================================
//========================================================================
int __stdcall GameSpy::GetNetStatus( void )
{
    return 0;
}

//========================================================================
//========================================================================
int __stdcall GameSpy::GetLastError( void )
{
    gosASSERT(0);
    return -1;
}


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


//========================================================================
//========================================================================
const char GAMESPY_KEY_PRODUCT_NAME[]		= "prodname";
const char GAMESPY_KEY_GAME_TYPE[]			= "gametype";
const char GAMESPY_KEY_NUM_PLAYERS[]		= "numplayers";
const char GAMESPY_KEY_MAX_PLAYERS[]		= "maxplayers";
const char GAMESPY_KEY_MAP_TYPE[]			= "mapname";
const char GAMESPY_KEY_GAME_NAME[]			= "gamename";
const char GAMESPY_KEY_PRODUCT_VERSION[]	= "gamever";
const char GAMESPY_KEY_INSTANCE[]			= "guid";
const char GAMESPY_PLAYER_KEY_PLAYER[]		= "player";
const char GAMESPY_PLAYER_KEY_CLAN[]		= "team";
const char GAMESPY_KEY_LOCATION[]			= "location";
const char GAMESPY_KEY_HOSTNAME[]			= "hostname";
const char GAMESPY_KEY_HOSTPORT[]			= "hostport";
const char GAMESPY_KEY_GAMEMODE[]			= "gamemode";
const char GAMESPY_KEY_TIMELIMIT[]			= "timelimit";
const char GAMESPY_KEY_FRAGLIMIT[]			= "fraglimit";
const char GAMESPY_KEY_TEAMPLAY[]			= "teamplay";
const char GAMESPY_KEY_RANKEDSERVER[]		= "rankedserver";
const char GAMESPY_KEY_FLAGS[]				= "flags";
const char GAMESPY_KEY_PASSWORD_PROTECTED[]	= "passworded";

//========================================================================
//========================================================================
class GameSpyServerBrowser : public ServerBrowser
{
	friend bool __stdcall InitGameSpyServerBrowser(char *szMasterAddress);

private:
	// general use
	virtual	bool __stdcall Initialize(void);
	virtual	bool __stdcall Disconnect(void);
	virtual int __stdcall GetStatus(void);
	virtual bool __stdcall Synchronize(void);
	virtual const char *__stdcall GetDescription(void);
	virtual bool __stdcall Release(void);

	// for browsers
    virtual bool __stdcall PrepareJoinGame(const char * szGameName, void **ppDPlay);

	// other
	virtual bool __stdcall PrepareRefresh(void);
	virtual bool __stdcall Refresh(char *gameID);
	virtual bool __stdcall RefreshServerInfo(char *gameID);
	virtual bool __stdcall StartUpdate(void);
	virtual bool __stdcall CancelActivity(void);
	virtual bool __stdcall GetNetStatus(void);

	static int __stdcall EnumSessionsCallback( LPCDPSESSIONDESC2 lpSessionDesc, LPDWORD lpdwTimeOut, DWORD dwFlags, void* lpContext );

	bool m_bDownLoadingGames;

#ifdef NEW_GAMESPY_CLIENT
	GameSpyClient *	m_pClient;
#endif

};

//========================================================================
//========================================================================
bool __stdcall InitGameSpyServerBrowser(char *szMasterAddress)
{
#ifndef NEW_GAMESPY
	GameSpyOld::status = GS_INIT_BROWSER;
#endif

	GameSpyServerBrowser *pGS = new GameSpyServerBrowser();

	if (pGS == NULL)
		return NULL;

#ifdef NEW_GAMESPY_CLIENT
	pGS->m_pClient = GameSpyClient::Create(szMasterAddress);
#endif

	pGS->Register();
	return true;
}

//========================================================================
//========================================================================
bool __stdcall GameSpyServerBrowser::Release(void)
{
	Disconnect();
	Unregister();
#ifdef NEW_GAMESPY_CLIENT
	if (m_pClient)
	{
		m_pClient->Release();
		m_pClient=NULL;
	}
#endif


	delete this;

	return true;
}


//========================================================================
//========================================================================
bool __stdcall GameSpyServerBrowser::Initialize(void)
{
	m_bDownLoadingGames = true;
#ifdef NEW_GAMESPY_CLIENT
	if (m_pClient)
	{
		if (!m_pClient->BeginQuerying())
			m_bDelete = true;
	}
#else
	if (GameSpyOld::BeginQueryingGameSpy())
		GameSpyOld::status = GS_CONNECTED;
#endif
	return true;
}

//========================================================================
//========================================================================
bool __stdcall GameSpyServerBrowser::Disconnect(void)
{
#ifdef NEW_GAMESPY_CLIENT
	if (m_pClient)
	{
		m_pClient->EndQuerying();
	}
#else
	GameSpyOld::EndQueryingGameSpy();
	GameSpyOld::status = GS_DISCONNECTED;
#endif

	return true;
}

//========================================================================
//========================================================================
const char *__stdcall GameSpyServerBrowser::GetDescription(void)
{
	return "GameSpy";
}

//========================================================================
//========================================================================
int __stdcall GameSpyServerBrowser::GetStatus(void)
{
	return true;
}

//========================================================================
//========================================================================
bool __stdcall GameSpyServerBrowser::Synchronize(void)
{
//#ifndef NEW_GAMESPY_HOST
//	GameSpy::ProcessGameSpy();
//#endif

#ifdef NEW_GAMESPY_CLIENT
	if (m_pClient)
	{
		if (m_bDownLoadingGames && !m_pClient->Synchronize())
		{
			// we're done downloading the server list
			m_bDownLoadingGames = false;
		}
		Browse::GameList * pGameList = GetGameList();

		for(int c=0 ; c<m_pClient->GetNumberOfGames() ; c++ )
		{
			char szGameIdentifier[256];
			//char szGUID[50];

			strncpy( szGameIdentifier, "GS: ", sizeof(szGameIdentifier));
			strncat( szGameIdentifier, m_pClient->GetServerString(c, GAMESPY_KEY_HOSTNAME), sizeof(szGameIdentifier));
			strncat( szGameIdentifier, m_pClient->GetServerAddress(c), sizeof(szGameIdentifier));

			const char * const pszGameName = m_pClient->GetServerString(c, GAMESPY_KEY_HOSTNAME);
			if ((pszGameName==NULL) || (pszGameName[0]==0))
				continue;

#ifdef PREPEND_PREFIX_TO_GAME_NAMES
			char szGameName[256];
			strncpy( szGameName, "GS: ", sizeof(szGameName));
			strncat( szGameName, pszGameName, sizeof(szGameName));
			pszGameName = szGameName;
#endif

			if (pGameList->CreateEntry(szGameIdentifier))
			{
				//
				// get the index of the game type
				//
				int iGameType = -1;
				char szGameType[256];
				if (m_pClient->GetServerString(c, GAMESPY_KEY_GAME_TYPE))
					iGameType = atoi(m_pClient->GetServerString(c, GAMESPY_KEY_GAME_TYPE));
				else
				{
					// go through until we get a NULL, then subtract one to get the last one
					for (iGameType=0 ; Environment.GetSpecialGameData(0, iGameType, 0, NULL) != NULL ; iGameType++);
					iGameType--;
				}
				Environment.GetSpecialGameData(0, iGameType, sizeof(szGameType), szGameType);

				//
				// the game didn't exist yet, so make it now
				//
				pGameList->SetField(szGameIdentifier, GAMELIST_KEY_MOD_NAME,			"Standard");
				pGameList->SetField(szGameIdentifier, GAMELIST_KEY_PRODUCT_NAME,		m_pClient->GetServerString(c, GAMESPY_KEY_PRODUCT_NAME));
				pGameList->SetField(szGameIdentifier, GAMELIST_KEY_PRODUCT_VERSION,		m_pClient->GetServerString(c, GAMESPY_KEY_PRODUCT_VERSION));
				pGameList->SetField(szGameIdentifier, GAMELIST_KEY_SERVER_ADDRESS,		m_pClient->GetServerAddress(c));
				pGameList->SetField(szGameIdentifier, GAMELIST_KEY_SERVER_PORT,			m_pClient->GetServerString(c, GAMESPY_KEY_HOSTPORT));
				pGameList->SetField(szGameIdentifier, GAMELIST_KEY_SERVER_NAME,			pszGameName);
				pGameList->SetField(szGameIdentifier, GAMELIST_KEY_NUM_PLAYERS,			m_pClient->GetServerString(c, GAMESPY_KEY_NUM_PLAYERS));
				pGameList->SetField(szGameIdentifier, GAMELIST_KEY_MAX_PLAYERS,			m_pClient->GetServerString(c, GAMESPY_KEY_MAX_PLAYERS));
				pGameList->SetField(szGameIdentifier, GAMELIST_KEY_MAP_TYPE,			m_pClient->GetServerString(c, GAMESPY_KEY_MAP_TYPE));
				pGameList->SetField(szGameIdentifier, GAMELIST_KEY_GAME_TYPE,			szGameType);
				pGameList->SetField(szGameIdentifier, GAMELIST_KEY_PASSWORD_PROTECTED,	m_pClient->GetServerString(c, GAMESPY_KEY_PASSWORD_PROTECTED));
				pGameList->SetField(szGameIdentifier, GAMELIST_KEY_INSTANCE,			m_pClient->GetServerString(c, GAMESPY_KEY_INSTANCE));
				pGameList->SetField(szGameIdentifier, GAMELIST_KEY_BROWSER_HANDLE,		GetBrowserHandle());
				pGameList->SetField(szGameIdentifier, GAMELIST_KEY_FLAGS,				m_pClient->GetServerString(c, GAMESPY_KEY_FLAGS));
				pGameList->SetField(szGameIdentifier, GAMELIST_KEY_PROTOCOL,			GAMELIST_VALUE_PROTOCOL_GAMESPY);


 				Browse::PlayerList * pList = 0;
				pList = pGameList->GetPlayerList( szGameIdentifier );

				if (pList)
				{
					pList->RemoveAll();
					int num = atoi(m_pClient->GetServerString(c, GAMESPY_KEY_NUM_PLAYERS));
					for (int i = 0; i < num ; i++)
					{
						pList->CreateEntry(m_pClient->GetPlayerString(c, i, GAMESPY_PLAYER_KEY_PLAYER));
						pList->SetField(m_pClient->GetPlayerString(c, i, GAMESPY_PLAYER_KEY_PLAYER), PLAYERLIST_KEY_PLAYER_NAME, m_pClient->GetPlayerString(c, i, GAMESPY_PLAYER_KEY_PLAYER));
						pList->SetField(m_pClient->GetPlayerString(c, i, GAMESPY_PLAYER_KEY_PLAYER), PLAYERLIST_KEY_CLAN_NAME, m_pClient->GetPlayerString(c, i, GAMESPY_PLAYER_KEY_CLAN));
					}
				}

			}
		}


	}
#else
	if (m_bDownLoadingGames && !GameSpyOld::SynchronizeServerList())
	{
		// we're done downloading the server list
		m_bDownLoadingGames = false;
	}

	Browse::GameList * pGameList = GetGameList();

	for(int c=0 ; c<GameSpyOld::GetNumberOfGames() ; c++ )
	{
		char szGameIdentifier[256];
		//char szGUID[50];

		strncpy( szGameIdentifier, "GS: ", sizeof(szGameIdentifier));
		strncat( szGameIdentifier, GameSpyOld::GetServerString(c, GAMESPY_KEY_GAME_NAME), sizeof(szGameIdentifier));
		strncat( szGameIdentifier, GameSpyOld::GetServerAddress(c), sizeof(szGameIdentifier));

		char *pszGameName = GameSpyOld::GetServerString(c, GAMESPY_KEY_GAME_NAME);
		if ((pszGameName==NULL) || (pszGameName[0]==0))
			continue;

#ifdef PREPEND_PREFIX_TO_GAME_NAMES
		char szGameName[256];
		strncpy( szGameName, "GS: ", sizeof(szGameName));
		strncat( szGameName, pszGameName, sizeof(szGameName));
		pszGameName = szGameName;
#endif

		if (pGameList->CreateEntry(szGameIdentifier))
		{
			//
			// the game didn't exist yet, so make it now
			//
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_MOD_NAME,			"Standard");
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_PRODUCT_NAME,		GameSpyOld::GetServerString(c, GAMESPY_KEY_PRODUCT_NAME));
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_PRODUCT_VERSION,		GameSpyOld::GetServerString(c, GAMESPY_KEY_PRODUCT_VERSION));
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_SERVER_ADDRESS,		GameSpyOld::GetServerAddress(c));
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_SERVER_PORT,			"15");
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_SERVER_NAME,			pszGameName);
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_NUM_PLAYERS,			GameSpyOld::GetServerString(c, GAMESPY_KEY_NUM_PLAYERS));
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_MAX_PLAYERS,			GameSpyOld::GetServerString(c, GAMESPY_KEY_MAX_PLAYERS));
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_MAP_TYPE,			GameSpyOld::GetServerString(c, GAMESPY_KEY_MAP_TYPE));
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_GAME_TYPE,			GameSpyOld::GetServerString(c, GAMESPY_KEY_GAME_TYPE));
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_PASSWORD_PROTECTED,	"No");
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_INSTANCE,			GameSpyOld::GetServerString(c, GAMESPY_KEY_INSTANCE));
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_BROWSER_HANDLE,		GetBrowserHandle());
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_FLAGS,				GameSpyOld::GetServerString(c, GAMESPY_KEY_FLAGS));
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_PROTOCOL,			GAMELIST_VALUE_PROTOCOL_GAMESPY);


 			Browse::PlayerList * pList = 0;
			pList = pGameList->GetPlayerList( szGameIdentifier );

			if (pList)
			{
				pList->RemoveAll();
				int num = atoi(GameSpyOld::GetServerString(c, GAMESPY_KEY_NUM_PLAYERS));
				for (int i = 0; i < num ; i++)
				{
					pList->CreateEntry(GameSpyOld::GetPlayerString(c, i, GAMESPY_PLAYER_KEY_PLAYER));
					pList->SetField(GameSpyOld::GetPlayerString(c, i, GAMESPY_PLAYER_KEY_PLAYER), PLAYERLIST_KEY_PLAYER_NAME, GameSpyOld::GetPlayerString(c, i, GAMESPY_PLAYER_KEY_PLAYER));
				}
			}

		}
		else
		{
			//
			// just update what may have changed
			//
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_PRODUCT_NAME,		GameSpyOld::GetServerString(c, GAMESPY_KEY_PRODUCT_NAME));
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_GAME_TYPE,			GameSpyOld::GetServerString(c, GAMESPY_KEY_GAME_TYPE));
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_NUM_PLAYERS,			GameSpyOld::GetServerString(c, GAMESPY_KEY_NUM_PLAYERS));
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_MAX_PLAYERS,			GameSpyOld::GetServerString(c, GAMESPY_KEY_MAX_PLAYERS));
			pGameList->SetField(szGameIdentifier, GAMELIST_KEY_MAP_TYPE,			GameSpyOld::GetServerString(c, GAMESPY_KEY_MAP_TYPE));

 			Browse::PlayerList * pList = 0;
			pList = pGameList->GetPlayerList( szGameIdentifier );

			if (pList)
			{
				pList->RemoveAll();
				int num = atoi(GameSpyOld::GetServerString(c, GAMESPY_KEY_NUM_PLAYERS));
				for (int i = 0; i < num ; i++)
				{
					pList->CreateEntry(GameSpyOld::GetPlayerString(c, i, GAMESPY_PLAYER_KEY_PLAYER));
					pList->SetField(GameSpyOld::GetPlayerString(c, i, GAMESPY_PLAYER_KEY_PLAYER), PLAYERLIST_KEY_PLAYER_NAME, GameSpyOld::GetPlayerString(c, i, GAMESPY_PLAYER_KEY_PLAYER));
				}
			}

		}
	}



#endif

	return true;
}

//========================================================================
//========================================================================
BOOL PASCAL GameSpyServerBrowser::EnumSessionsCallback( LPCDPSESSIONDESC2 lpSessionDesc, LPDWORD lpdwTimeOut, DWORD dwFlags, void* lpContext )
{
	return FALSE;
}

//========================================================================
// PrepareJoinGame
//
// This is called just before open is called on a game. In here, we must
// set the DirectPlay object to be the correct protocol and to correctly
// enumerate the game on the LAN
//
//========================================================================
bool __stdcall GameSpyServerBrowser::PrepareJoinGame(const char * szGameName, void **ppDPlay)
{
	IDirectPlay4A *				lpDP = NULL;
	IDirectPlayLobby3 *			lpDPL = NULL;
	HRESULT						hr;

	//
	// get the IP address of the game in question
	//
	const char *szIPAddress;
	const char *szGameIdentifier;
    szGameIdentifier = GetGameList()->GetIDFromField( GAMELIST_KEY_SERVER_NAME, szGameName );
	szIPAddress = GetGameList()->GetDataField(szGameIdentifier, GAMELIST_KEY_SERVER_ADDRESS);
	const char *szPort = GetGameList()->GetDataField(szGameIdentifier, GAMELIST_KEY_SERVER_PORT);
	int port;
	if (szPort)
		port = atoi(szPort);
	else
		port = 0;


	//
	// create the DirectPlay object
	//
	if (FAILED(hr = CoCreateInstance( CLSID_DirectPlay, NULL, CLSCTX_ALL, IID_IDirectPlay4A, (VOID**)&lpDP)))
		goto fail;

	//
	// release the original GameOS DirectPlay object
	//
	if (*(IDirectPlay4A **)ppDPlay)
	{
		(*(IDirectPlay4A **)ppDPlay)->Release();
		*(IDirectPlay4A **)ppDPlay = NULL;
	}
	
	//
	// copy the DirectPlay object back to the GameOS DirectPlay object
	//
	*(IDirectPlay4A **)ppDPlay = lpDP;

	//
	// create a lobby object
	//

	//
	// create a DirectPlayLobby object for creation of an address
	//
	if (FAILED(hr = CoCreateInstance( CLSID_DirectPlayLobby, NULL, CLSCTX_ALL, IID_IDirectPlayLobby3, (VOID**)&lpDPL)))
		goto fail;

	//
	// create the address needed
	//
	DPCOMPOUNDADDRESSELEMENT comAdd[3];
	DWORD Size;
	void* p_address;

	comAdd[0].guidDataType	= DPAID_ServiceProvider;
	comAdd[0].dwDataSize	= sizeof(GUID);
	comAdd[0].lpData		= (void*)&DPSPGUID_TCPIP;
	comAdd[1].guidDataType	= DPAID_INet;								// Create a compund address
	comAdd[1].dwDataSize	= strlen(szIPAddress) + 1;
	comAdd[1].lpData		= (void *)szIPAddress;
	comAdd[2].guidDataType	= DPAID_INetPort;
	comAdd[2].dwDataSize	= sizeof(port);
	comAdd[2].lpData		= (void *)&port;

	int num_elements;
	if (port)
		num_elements = 3;
	else
		num_elements = 2;

	//
	// create the address
	//
	lpDPL->CreateCompoundAddress(comAdd, num_elements, NULL, &Size );
	p_address = (void*)gos_Malloc(Size);
	if (FAILED(hr = lpDPL->CreateCompoundAddress(comAdd, num_elements, p_address, &Size )))
		goto fail;

	//
	// initialize the connection
	//
	if (FAILED(hr = lpDP->InitializeConnection(p_address, 0)))
		goto fail;

	//
	// enumerate
	//
	if (true)
	{
		DPSESSIONDESC2	dpsd;
		memset( &dpsd, 0, sizeof(dpsd) );

		dpsd.dwSize		= sizeof(dpsd);
		memcpy( &dpsd.guidApplication, &Environment.NetworkGUID, sizeof(GUID) );
		DWORD dwFlags = DPENUMSESSIONS_RETURNSTATUS | DPENUMSESSIONS_ALL | DPENUMSESSIONS_PASSWORDREQUIRED;

		if (FAILED(hr = lpDP->EnumSessions(&dpsd, 0, EnumSessionsCallback, 0, dwFlags )))
			goto fail;
	}

	return true;

fail:
	RELEASE_PTR(lpDPL);
	return false;
}

//========================================================================
//========================================================================
bool __stdcall GameSpyServerBrowser::PrepareRefresh(void)
{
	return true;
}

//========================================================================
//========================================================================
bool __stdcall GameSpyServerBrowser::Refresh(char *gameID)
{
    return true;
}

//========================================================================
//========================================================================
bool __stdcall GameSpyServerBrowser::RefreshServerInfo(char *gameID)
{
    Browse::GameList * gameList = ServerBrowser::GetGameList();

    if ( gameList == NULL )
    {
        return false;
    }

    // find out the protocol type for the game
    const char * pProtocol = gameList->GetDataField( gameID, GAMELIST_KEY_PROTOCOL );

    if ( pProtocol == NULL )
    {
        // no such game or no protocol identified for it.
        return false;
    }

    // see if the protocl matches our type
    if ( strcmp( pProtocol, GAMELIST_VALUE_PROTOCOL_GAMESPY ) )
    {
        // this isn't us
        return false;
    }

    // mdm - change this if we want to spawn a player query for the specific server.
    //       right now all player data is downloaded with an update so we don't have any
    //       work to do.
    // assume we already have the player data, so set success right away.
    gameList->SetField( gameID, GAMELIST_KEY_SERVER_INFO_STATUS, "1" );
    return true;

}

//========================================================================
//========================================================================
bool __stdcall GameSpyServerBrowser::StartUpdate(void)
{
	m_bDownLoadingGames = true;
#ifdef NEW_GAMESPY_CLIENT
	if (m_pClient)
		m_pClient->BeginQuerying();
#else
	GameSpyOld::BeginQueryingGameSpy();
#endif
	return true;
}

//========================================================================
//========================================================================
bool __stdcall GameSpyServerBrowser::CancelActivity(void)
{
	m_bDownLoadingGames = false;
#ifdef NEW_GAMESPY_CLIENT
	if (m_pClient)
		m_pClient->EndQuerying();
#else
	GameSpyOld::EndQueryingGameSpy();
#endif
	return true;
}

//========================================================================
//========================================================================
bool __stdcall GameSpyServerBrowser::GetNetStatus(void)
{
	return m_bDownLoadingGames;
}






















//========================================================================
//========================================================================
class GameSpyServerAdvertiser : public ServerAdvertiser
{
	friend bool __stdcall InitGameSpyServerAdvertiser(char *szMasterAddress);

private:
	// general use
	virtual	bool __stdcall Initialize(void);
	virtual	bool __stdcall Disconnect(void);
	virtual bool __stdcall Synchronize(void);
	virtual bool __stdcall Release(void);
	virtual const char * __stdcall GetDescription(void);

	// for servers
	virtual bool __stdcall CreateGame(const char *szGameName, const char *szPlayerName, int MaxPlayers, const char *szPassword, const GUID &guidInstance, DWORD dwFlags);
	virtual bool __stdcall CreatePlayer(DWORD dwItemID, const char *szPlayerName, bool bBot);
	virtual bool __stdcall RemovePlayer(DWORD dwItemID, const char *szPlayerName, bool bBot);
	virtual bool __stdcall SetItemValue(DWORD dwPlayer, const char * szName , const char * szValue);
	virtual bool __stdcall SetFlags(DWORD dwFlags);

	static int __stdcall EnumSessionsCallback( LPCDPSESSIONDESC2 lpSessionDesc, LPDWORD lpdwTimeOut, DWORD dwFlags, void* lpContext );

	GameSpyHost *m_pHost;
};



//========================================================================
//========================================================================
bool __stdcall InitGameSpyServerAdvertiser(char *szMasterAddress)
{
	GameSpyServerAdvertiser *pGS = new GameSpyServerAdvertiser();

	if (pGS == NULL)
		return NULL;

#ifdef NEW_GAMESPY_HOST
	pGS->m_pHost = GameSpyHost::Create(szMasterAddress);
#endif
	pGS->Register();

	return true;
}

//========================================================================
//========================================================================
bool __stdcall GameSpyServerAdvertiser::Release(void)
{
#ifdef NEW_GAMESPY_HOST
	m_pHost->Release();
#endif
	Disconnect();
	Unregister();
	delete this;

	return true;
}


//========================================================================
//========================================================================
bool __stdcall GameSpyServerAdvertiser::Initialize(void)
{
	return true;
}

//========================================================================
//========================================================================
bool __stdcall GameSpyServerAdvertiser::Disconnect(void)
{
	return true;
}

//========================================================================
//========================================================================
const char *__stdcall GameSpyServerAdvertiser::GetDescription(void)
{
	return "GameSpy";
}

//========================================================================
//========================================================================
bool __stdcall GameSpyServerAdvertiser::Synchronize(void)
{
#ifdef NEW_GAMESPY_HOST
	m_pHost->Synchronize();
#else
	GameSpyOld::ProcessGameSpy();
#endif
	return true;
}

//========================================================================
//========================================================================
bool __stdcall GameSpyServerAdvertiser::CreateGame(const char *szGameName, const char *szPlayerName, int MaxPlayers, const char *szPassword, const GUID &guidInstance, DWORD dwFlags)
{
#ifdef NEW_GAMESPY_HOST
	if (m_pHost->BeginAdvertising(szGameName, MaxPlayers, szPassword, guidInstance, dwFlags))
	{
		if ((dwFlags & NETFLAGS_DEDICATED_FLAG)==0)
			m_pHost->AddPlayer((int) gos_NetInformation( gos_MyID, 0, NULL ), szPlayerName, NULL, 0);

		m_pHost->SetKey(GAMELIST_KEY_SERVER_PORT, (char *)GetDirectPlayPort());

		return true;
	}
	else
		m_bDelete=true;

	return false;
#else
	return GameSpyOld::BeginAdvertisingOnGameSpy(szGameName, szPlayerName, MaxPlayers, szPassword, guidInstance, false, dwFlags);
#endif
}

//========================================================================
//========================================================================
bool __stdcall GameSpyServerAdvertiser::CreatePlayer(DWORD dwItemID, const char *szPlayerName, bool bBot)
{
#ifdef NEW_GAMESPY_HOST
	m_pHost->AddPlayer(dwItemID, szPlayerName, NULL, 0);
#else
	GameSpyOld::AddPlayer(dwItemID, szPlayerName, NULL, 0);
#endif
	return true;
}

//========================================================================
//========================================================================
bool __stdcall GameSpyServerAdvertiser::RemovePlayer(DWORD dwItemID, const char *szPlayerName, bool bBot)
{
#ifdef NEW_GAMESPY_HOST
	m_pHost->RemovePlayer(dwItemID, szPlayerName, NULL, 0);
#else
	GameSpyOld::RemovePlayer(dwItemID, szPlayerName, NULL, 0);
#endif
	return true;
}


//========================================================================
//========================================================================
bool __stdcall GameSpyServerAdvertiser::SetItemValue(DWORD dwPlayer, const char * szName , const char * szValue)
{
#ifdef NEW_GAMESPY_HOST
	m_pHost->SetKey(szName, szValue, dwPlayer);
#else
	GameSpyOld::SetKey(szName, szValue);
#endif
	return true;
}


//========================================================================
//========================================================================
bool __stdcall GameSpyServerAdvertiser::SetFlags(DWORD dwFlags)
{
#ifdef NEW_GAMESPY_HOST
	m_pHost->SetFlags(dwFlags);
#else
	char szValue[256];
	sprintf(szValue, "%u", dwFlags);
	GameSpyOld::SetKey(GAMESPY_KEY_FLAGS, szValue);
#endif
	return true;
}
























































#ifndef NEW_GAMESPY

//========================================================================
//========================================================================
void GameSpyOld::GetGameSpyAddress(char *szGameSpyAddress, int size)
{
	int s=size;
	gos_LoadDataFromRegistry(GAMESPY_MASTER_SERVER_KEY, szGameSpyAddress, (DWORD *)&size);
	if (size == 0)
	{
		gos_SaveStringToRegistry(GAMESPY_MASTER_SERVER_KEY, GAMESPY_MASTER_ADDR, sizeof(GAMESPY_MASTER_ADDR));
		strncpy(szGameSpyAddress, GAMESPY_MASTER_ADDR, s);
	}
}

//========================================================================
//========================================================================
int GameSpyOld::GetHeartbeatPort(void)
{
	int port;
	int size = sizeof(port);

	gos_LoadDataFromRegistry(GAMESPY_MASTER_HEARTBEAT_PORT_KEY, &port, (DWORD *)&size);
	if (size == 0)
	{
		port = GAMESPY_MASTER_HEARTBEAT_PORT;
		gos_SaveDataToRegistry(GAMESPY_MASTER_HEARTBEAT_PORT_KEY, &port, sizeof(port));
	}

	return port;
}

//========================================================================
//========================================================================
int GameSpyOld::GetQueryPort(void)
{
	int port;
	int size = sizeof(port);

	gos_LoadDataFromRegistry(GAMESPY_MASTER_QUERY_PORT_KEY, &port, (DWORD *)&size);
	if (size == 0)
	{
		port = GAMESPY_MASTER_QUERY_PORT;
		gos_SaveDataToRegistry(GAMESPY_MASTER_QUERY_PORT_KEY, &port, sizeof(port));
	}

	return port;
}

//========================================================================
//========================================================================
int GameSpyOld::GetServerListPort(void)
{
	int port;
	int size = sizeof(port);

	gos_LoadDataFromRegistry(GAMESPY_MASTER_SERVERLIST_PORT_KEY, &port, (DWORD *)&size);
	if (size == 0)
	{
		port = GAMESPY_MASTER_SERVERLIST_PORT;
		gos_SaveDataToRegistry(GAMESPY_MASTER_SERVERLIST_PORT_KEY, &port, sizeof(port));
	}

	return port;
}
#endif





//========================================================================
//========================================================================
HWND CreateOffScreenNotificationWindow(void)
{
	static const char s_szNotificationWindowClass[] = "NotificationClass";

	WNDCLASSEX wcex;

	wcex.cbSize			= sizeof(wcex);
	wcex.style			= 0;
	wcex.lpfnWndProc	= 0;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 4;	// 4 extra bytes indicating...
	wcex.hInstance		= 0;
	wcex.hIcon			= 0;
	wcex.hCursor		= 0;
	wcex.hbrBackground	= 0;
	wcex.lpszMenuName	= 0;
	wcex.lpszClassName	= 0;
	wcex.hIconSm		= 0;


	//ATOM ThisClass = RegisterClassEx(&wcex);

	return NULL;
}