//////////////////////////////////////////////////////////////////////////////
//
// Asura_GameSpy_Peer.h
//
// Copyright (c) 2004 Rebellion. All rights reserved.
//
// Description:
//
//     Asura wrapper for the Peer2 SDK
//
//////////////////////////////////////////////////////////////////////////////

// B E G I N   F I L E   W R A P P E R ///////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef ___ASURA_GAMESPY_PEER_H___
#define ___ASURA_GAMESPY_PEER_H___ 1

#include "Core/Asura_PlatformBasics.h"
#include "network/Asura_LobbyChat.h"
#include "GameSpy/peer/peer.h"

// C O N S T A N T S /////////////////////////////////////////////////////////
static const u_int uASURA_GAMESPY_PEER_GROUPROOMNAME_MAXLEN = 32;//incl null
static const u_int uASURA_GAMESPY_PEER_SERVERNAME_MAXLEN = 32;//incl null
static const u_int uASURA_GAMESPY_PEER_NICKNAME_EXT_MAXLEN = 16;//incl null

// C L A S S E S /////////////////////////////////////////////////////////////
class Asura_GameSpy_Peer_GroupRoom
{
	friend class Asura_GameSpy_Peer;

private:
	
	int m_iGroupID;
	u_int m_uNumPlayersInRoom;			// number of players not in a game
	u_int m_uMaxPlayersInRoom;			// max number of players in group room (not in games)
	u_int m_uNumGamesInRoom;			// number of games currently in room
	u_int m_uNumPlayingInRoom;			// number of players in games in this room.
	u_int m_uFilterFlags;				// project-specific filters for group room (e.g. region, skill etc)
	SBServer m_pxServer;
	Asura_UnicodeChar m_awcRoomName[uASURA_GAMESPY_PEER_GROUPROOMNAME_MAXLEN];
};


class Asura_GameSpy_Peer
{

	public:

		enum ConnectionState
		{
			PCN_None,
			PCN_ConnectingToServer,
			PCN_ConnectedToServer,	// transient state
			PCN_GettingListOfGroupRooms,
			PCN_WaitingToJoinGroupRoom,
			PCN_JoiningGroupRoom,
			PCN_GettingGroupRoomUserList,
			PCN_InGroupRoom,
			PCN_CreatingStagingRoom,
			PCN_JoiningStagingRoom,
			PCN_GettingStagingRoomUserList,
			PCN_HostingStagingRoom,
			PCN_ClientInStagingRoom,
			PCN_HostingGameStarting,
			PCN_ClientGameStarting,
			PCN_ConnectionFailed,
			PCN_JoinGroupRoomFailed,
			PCN_CreateStagingRoomFailed,
			PCN_JoinStagingRoomFailed,
			PCN_ListPlayersFailed,
			PCN_StagingRoomHostQuit,
			NumPeerStates
		};

		//Initialise takes an optional callback function, which get's called each time a new user is added
		//it allows a project to override mute status, set user IDs, and block the user from being added.
		static bool Initialise( bool (*pfnAddUser)(const Asura_UnicodeChar*, bool*, int*) = 0 );
		static void Update( void );
		static void Shutdown( void );

		// check the status to display messages such as "Joining Group Room..."
		// "Failed to join Staging Room" etc.
		static ConnectionState GetConnectionState( void );
		
		static void ConnectToChatServer(const Asura_UnicodeChar* wszPlayerName);

		// CJM 13/07/06
		// This version connects to GS with a unique nickname and password. The GS docs indicate that this should only be used with a custom GS namespace
		//  as the unique nick can expire.
		static void ConnectWithGPLogin(const int iNameSpaceID, const char* szNickNameExtension,
										const Asura_UnicodeChar* wszUniqueNickName, 
										const Asura_UnicodeChar* wszPassword);
		// CJM 13/07/06
		// This version connects to GS with a nickname, email and password.
		static void ConnectWithGPLogin(const int iNameSpaceID, 
										const char* szNickNameExtension,
										const Asura_UnicodeChar* wszNickName, 
										const Asura_UnicodeChar* wszEmail, 
										const Asura_UnicodeChar* wszPassword);
		static void DisconnectFromChatServer( void );

		static void SetQuietMode(bool bQuietMode);
		static bool IsConnected();

		static bool SendMessage(const Asura_UnicodeChar* wszMessage);
		
		// interface for listing group rooms
		static u_int GetNumGroupRooms( void ) { return s_uNumGroupRooms; }
		static u_int GetNumPlayersInGroupRoom( u_int uGroupRoomIndex );
		static u_int GetMaxPlayersInGroupRoom( u_int uGroupRoomIndex );
		static u_int GetNumGamesInGroupRoom( u_int uGroupRoomIndex );
		static u_int GetNumPlayingInGroupRoom( u_int uGroupRoomIndex );
		static u_int GetFilterFlags( u_int uGroupRoomIndex );
		static Asura_UnicodeChar* GetGroupRoomName( u_int uGroupRoomIndex );
		static void JoinGroupRoom( u_int uGroupRoomIndex );
		static const char* GetGroupRoomCustomParam( u_int uGroupRoomIndex, const char* szParam);

		// when in a group room, options should include 'create game', 'join game' 
		// to join one of the listed servers, and 'refresh list'.
		// If a listed game is not in staging, then the client should load straight
		// into the game (if supporting late-entry).
		
		// when creating a game, if the game fails to get listed by gamespy
		// a callback will eventually be called which sets a flag. Check this 
		// flag and report the error to the user using GetErrorAddingServer().
		// Call StartGame to get all the clients' start game callbacks called.
		// Should probably carry on updating peer for a few seconds to make sure
		// the message got through, this will need testing.
		// SNH - 16/02/2004 14:47:51 - since Sniper uses QR2 while in-game, best not to 
		//		call StartGame until the network is initialised.
		// SNH - 14/10/2004 17:16:33 - Now Rogue is using peer in-game as well, so added
		//		a parameter to StartGame to optionally keep it reporting. Defaults to No - the previous behaviour.

		// Call StopGame to update the player's state with peer. Should be called when exiting the 
		// game on client and server.
		static void CreateGame( const Asura_UnicodeChar* wszRoomName, 
								int iMaxPlayers,
								const Asura_UnicodeChar* szPassword = NULL );
		static bool GetErrorAddingServer( void ) { return s_bErrorAddingServer; }
		static bool StartGame( bool bKeepReporting = false);
		static bool StopGame();
		
		// SNH: added this for joining in-game servers - lets peer know we're no longer in the group room
		static void Client_StartPlaying();

		// when joining a game (server in-game) call StopListingServers to let GameSpy
		//	know not to bother calling the ListingGamesCallback anymore. Only necessary
		//	if continuing to update Peer while ingame.
		static bool StopListingServers( void );

		// JoinStagingRoom returns false if couldn't join, in which case the 
		// user remains in the group room and the server browsing will remain 
		// initialized. Otherwise the group room will be left and server browsing
		// will be shutdown so if this returned true but you haven't successfully 
		// joined after a timeout you should call RejoinGroupRoom()
		static bool IsInStaging( u_int uServerIndex );
		static bool JoinStagingRoom( u_int uServerIndex, const Asura_UnicodeChar* szPassword = NULL );
		
		// call these to leave group rooms and staging rooms. Used for 'back' items.
		static bool LeaveGroupRoom( void );
		static bool LeaveStagingRoom( void );

		// staging room is implicitly left when creating or joining a staging
		// room, so call RejoinGroupRoom() if returning to that screen
		static void RejoinGroupRoom();

		// server listing interface - copied from Asura_GameSpy_ServerBrowsing
		// possibly this class could just call through
//		static u_int GetNumServers( void ) { return s_uNumServers; }
//		static const char* GetServerName( u_int uServerIndex );
//		static const char* GetGameType( u_int uServerIndex );
//		static int GetGameTypeID( u_int uServerIndex );
//		static const char* GetMapName( u_int uServerIndex );
//		static int GetMapID( u_int uServerIndex );
//		static int GetNumPlayers( u_int uServerIndex );
//		static int GetMaxPlayers( u_int uServerIndex );
//		static int GetPing( u_int uServerIndex );
//		static const char* GetServerIPAddress( u_int uServerIndex );
//		static u_short GetServerHostPort( u_int uServerIndex );
//		static int GetGameTimeLimit( u_int uServerIndex );
//		static int GetElapsedGameTime( u_int uServerIndex );
//		static int GetGameScoreLimit( u_int uServerIndex );
//		static int GetGameTeams( u_int uServerIndex );
//		static bool GetGameHasPassword( u_int uServerIndex );
//		static bool IsBehindSameNat( u_int uServerIndex );
//		static bool NeedToUseNatNeg( u_int uServerIndex );
//		static void SendNatNegCookie( u_int uServerIndex, int iCookie );

		static u_int GetMyPublicIPAddress( void );
		static bool SendNatNegotiateCookie( u_int uIP, u_short usPort, int iCookie );

		// force a peer update (use when hosting key values have changed - eg on returning from
		//		options submenus.
		static void ReportKeyValues();

		// send an Under the Table Message (UTM) to clients before game starts, with final map / gametype to use.
		static void SendRoomUTM(const char* szCommand, const char* szParameters);

		static bool IsInitialised( void );
		static void ParsePeerQuery( u_int uIP, u_short usPort, char* pcQueryData, u_int uDataLength );

		// use these to set player's Ready state. Allows clients to inform the host they are ready to play.
		//	Host can either wait until all clients are ready, or continue into game regardless.
		static void SetReadyState(bool bReady);
		static bool GetReadyState(const Asura_UnicodeChar* wszPlayerName);
		
		static bool GetNick(Asura_UnicodeChar* wszNameBuffer, u_int uBufferSize);

		static PEERJoinResult GetLastRoomJoinResult();

	private:

		// internal usage functions
		static void BeginListingServers( void );
		static void Refresh( void );
		static void RefreshServerList( void );

		// project-supplied functions
		static const char* Project_GetGroupRoomFieldsString();	// name(s) of group room field(s) to fetch. Should include filters field (see below)
																// if more than one, seperate with blackslashes
		static const char* Project_GetGroupRoomFilterString();	// name of group room field specifying region and other filters
		static u_int Project_GetGroupRoomFilterMask();			// specify bits to AND for allowed group rooms.
		static const Asura_UnicodeChar* Project_GetMapName( void );
		static const Asura_UnicodeChar* Project_GetGameTypeString( void );
		static const Asura_UnicodeChar* Project_GetGameModeString( void );
		static int Project_GetMapID( void );
		static int Project_GetGameTypeID( void );

		// handle a UTM 
		static void Project_InterpretUTM(const char* pcCommand, const char* pcParameters);

		// Huge list of callbacks

		/////////////////////////////////////////////////////////
		// callbacks for connecting to chat server
		/////////////////////////////////////////////////////////

		// This gets called when the connection attempt finishes.
		/////////////////////////////////////////////////////////
		static void ConnectCallback
		(
			PEER pxPeer,  // The peer object.
			PEERBool eSuccess,  // PEERTrue if success, PEERFalse if failure.
			int iFailureReason,  // If failure, the reason for it (PEER_DISCONNECTED, etc.)
			void* pParam  // User-data.
		);

		// This gets called if there is an error with
		//   the nickname while connecting.
		// Call peerRetryWithNick() to try another nick.  If it
		//   is called with a NULL nick, then the connect will be
		//   stopped, and peerConnectCallback will be called with
		//   failure.
		// The suggested nicks are only provided if type
		//   is PEER_INVALID_UNIQUENICK.
		/////////////////////////////////////////////////////////
		static void NickErrorCallback
		(
			PEER pxPeer,  // The peer object.
			int iType,  // The type of nick error (PEER_IN_USE, PEER_INVALID, etc.)
			const gsi_char* szNick,  // The bad nick.
			int iNumSuggestedNicks,  // The number of suggested nicks.
			const gsi_char** aszSuggestedNicks,  // The array of nicks.
			void* pParam  // User-data.
		);

		/////////////////////////////////////////////////////////
		// callbacks for listing group rooms
		/////////////////////////////////////////////////////////

		// Gets called once for each group room when listing group rooms.
		// After this has been called for each group room, it will be
		// called one more time with groupID==0 and name==NULL.
		/////////////////////////////////////////////////////////////////
		static void ListGroupRoomsCallback
		(
			PEER pxPeer,  // The peer object.
			PEERBool eSuccess,  // PEERTrue if success, PEERFalse if failure.
			int iGroupID,  // A unique ID for this group.
			SBServer pxServerBrowser,  // The server object for this group room.
			const gsi_char* szName,  // The group room's name.
			int iNumWaiting,  // The number of players in the room.
			int iMaxWaiting,  // The maximum number of players allowed in the room.
			int iNumGames,  // The number of games either staging or running in the group.
			int iNumPlaying,  // The total number of players in games in the group.
			void* pParam  // User-data.
		);

		/////////////////////////////////////////////////////////
		// callbacks for joining room
		/////////////////////////////////////////////////////////
		
		// This gets called when an attempt to join or create a room has finished.
		//////////////////////////////////////////////////////////////////////////
		static void JoinRoomCallback
		(
			PEER pxPeer,  // The peer object.
			PEERBool eSuccess,  // PEERTrue if success, PEERFalse if failure.
			PEERJoinResult eResult,  // The result of the attempt.
			RoomType eRoomType,  // The type of room joined/created.
			void* pParam  // User-data.
		);

		/////////////////////////////////////////////////////////
		// callbacks for listing players in a room
		/////////////////////////////////////////////////////////
		
		// Called for each player in a room being enumerated, and once
		//   when finished, with index==-1 and nick==NULL.
		//////////////////////////////////////////////////////////////
		static void EnumPlayersCallback
		(
			PEER pxPeer,  // The peer object.
			PEERBool eSuccess,  // PEERTrue if success, PEERFalse if failure.
			RoomType eRoomType,  // The room whose players are being enumerated.
			int iIndex,  // The index of the player (0 to (N - 1)).  -1 when finished.
			const gsi_char* szNick,  // The nick of the player.
			int iFlags,  // This player's flags (see #define's above).  PANTS|03.12.01
			void* pParam  // User-data.
		);

		//////////////////////////////////////////////////////////////////////////
		// callbacks needed for listing of games
		//////////////////////////////////////////////////////////////////////////

		// Called with info on games being listed.
		// Used to maintain a list of running games and staging rooms.
		// The server object is a unique way of identifying each game.
		// It can also be used with the calls in the "SBServer Object Functions" section
		//   of sb_serverbrowsing.h to find out more info about the server.
		// If staging==PEERTrue, the game hasn't started yet, it's still in the staging room
		//   use peerJoinStagingRoom() to join the staging room, or if staging==peerfalse
		//   use the server object to get the game's IP and port to join with.
		// During the _intial_ listing of games, progress is the percentage (0-100) of the
		//   games that have been added.  Once the initial listing is completed,
		//   progress will always be 100.
		// PANTS|09.11.00 - The "password" key will be set to 1 for games that are
		// passworded.  This can be checked with ServerGetIntValue(server, "password", 0).
		/////////////////////////////////////////////////////////////////////////////////////
		static void ListingGamesCallback
		(
			PEER pxPeer,  // The peer object.
			PEERBool eSuccess,  // PEERTrue if success, PEERFalse if failure.
			const gsi_char* szName,  // The name of the game being listed.
			SBServer pxServer,  // The server object for this game.
			PEERBool eStaging,  // If PEERTrue, this is a staging room and not a running game.
			int iMsg,  // The type of message this is.
				// PEER_CLEAR:
				//   Clear the list.  This has the same effect as if this was called
				//   with PEER_REMOVE for every server listed.
				// PEER_ADD:
				//   This is a new server. Add it to the list.
				// PEER_UPDATE:
				//   This server is already on the list, and its been updated.
				// PEER_REMOVE:
				//   Remove this server from the list.  The server object for this server
				//   should not be used again after this callback returns.
			int iProgress,  // The percent of servers that have been added.
			void* pParam  // User-data.
		);

		/////////////////////////////////////////////////////////
		// callbacks needed to create PEER object
		/////////////////////////////////////////////////////////

		// Called when the connection to the server gets disconnected.
		//////////////////////////////////////////////////////////////
		static void DisconnectedCallback
		(
			PEER pxPeer,  // The peer object.
			const gsi_char* szReason,  // The reason for the disconnection.
			void* pParam  // User-data.
		);

		// Called when a message is sent to a room the local player is in.
		//////////////////////////////////////////////////////////////////
		static void RoomMessageCallback
		(
			PEER pxPeer,  // The peer object.
			RoomType eRoomType,  // The type of room that the message was in.
			const gsi_char* szNick,  // The nick of the player who sent the message.
			const gsi_char* szMessage,  // The text of the message.
			MessageType eMessageType,  // The type of message.
			void* pParam  // User-data.
		);

		// Called when a UTM is sent to a room the local player is in.
		//////////////////////////////////////////////////////////////
		static void RoomUTMCallback
		(
			PEER pxPeer,  // The peer object.
			RoomType eRoomType,  // The type of room that the UTM was in.
			const gsi_char* szNick,  // The nick of the player who sent the UTM.
			const gsi_char* szCommand, // The UTM command for this message.
			const gsi_char* szParameters,  // Any parameters for this UTM.
			PEERBool eAuthenticated,  // True if this has been authenticated by the server.
			void* pParam  // User-data.
		);

		// Called when the name of a room the player is in changes.
		// The new name can be checked with peerGetRoomName.
		///////////////////////////////////////////////////////////
		static void RoomNameChangedCallback
		(
			PEER pxPeer,  // The peer object.
			RoomType eRoomType,  // The type of room that the name changed in.
			void* pParam  // User-data
		);

		// Called when a room's mode changes.
		///////////////////////////////////////////////////////////
		static void RoomModeChangedCallback
		(
			PEER pxPeer,  // The peer object.
			RoomType eRoomType,  // The type of room that the name changed in.
			CHATChannelMode * mode,  // The current mode for this room.
			void* pParam  // User-data
		);

		// Called when a private message is received from another player.
		/////////////////////////////////////////////////////////////////
		static void PlayerMessageCallback
		(
			PEER pxPeer,  // The peer object.
			const gsi_char* szNick,  // The nick of the player who sent the message.
			const gsi_char* szMessage,  // The text of the message.
			MessageType eMessageType,  // The type of message.
			void* pParam  // User-data
		);

		// Called when a private UTM is received from another player.
		/////////////////////////////////////////////////////////////
		static void PlayerUTMCallback
		(
			PEER pxPeer,  // The peer object.
			const gsi_char* szNick,  // The nick of the player who sent the UTM.
			const gsi_char* szCommand, // The UTM command for this message.
			const gsi_char* szParameters,  // Any parameters for this UTM.
			PEERBool eAuthenticated,  // True if this has been authenticated by the server.
			void* pParam  // User-data
		);

		// Called when a player's ready state changes,
		// from a call to peerSetReady().
		//////////////////////////////////////////////
		static void ReadyChangedCallback
		(
			PEER pxPeer,  // The peer object.
			const gsi_char* szNick,  // The nick of the player who's ready state changed.
			PEERBool eReady,  // The player's new ready state.
			void* pParam  // User-data.
		);

		// Called when the host of a staging room launches the game,
		// with a call to peerStartGame().
		// The public and private IPs and ports of the server can
		// be obtained from the server object.
		////////////////////////////////////////////////////////////
		static void GameStartedCallback
		(
			PEER pxPeer,  // The peer object.
			SBServer xServer,  // A server object representing this host.
			const gsi_char* szMessage,  // A message that was passed into peerStartGame().
			void* pParam  // User-data.
		);

		// A player joined a room.
		//////////////////////////
		static void PlayerJoinedCallback
		(
			PEER pxPeer,  // The peer object.
			RoomType eRoomType,  // The type of room that the player joined.
			const gsi_char* szNick,  // The nick of the player that joined.
			void* pParam  // User-data.
		);

		// A player left a room.
		////////////////////////
		static void PlayerLeftCallback
		(
			PEER pxPeer,  // The peer object.
			RoomType eRoomType,  // The type of room that the player left.
			const gsi_char* szNick,  // The nick of the player that left.
			const gsi_char* szReason,  // The reason the player left.
			void* pParam  // User-data.
		);

		// The local player was kicked from a room.
		///////////////////////////////////////////
		static void KickedCallback
		(
			PEER pxPeer,  // The peer object.
			RoomType eRoomType,  // The type of room that the player was kicked from.
			const gsi_char* szNick,  // The nick of the player that did the kicking.
			const gsi_char* szReason,  // An optional reason for the kick.
			void* pParam  // User-data.
		);

		// The entire player list for this room has been updated.
		/////////////////////////////////////////////////////////
		static void NewPlayerListCallback
		(
			PEER pxPeer,  // The peer object.
			RoomType eRoomType,  // The type of room.
			void* pParam  // User-data
		);

		// A player in one of the rooms changed his nick.
		/////////////////////////////////////////////////
		static void PlayerChangedNickCallback
		(
			PEER pxPeer,  // The peer object.
			RoomType eRoomType,  // The type of the room the nick changed was in.
			const gsi_char* szOldNick,  // The player's old nick.
			const gsi_char* szNewNick,  // The player's new nick.
			void* pParam  // User-data.
		);

		// The IP and ProfileID for this player has just been received.
		// PANTS|01.08.01
		// This gets called for all players (who are using peer) in a room
		// shortly after joining.  It will be called with nick==NULL after
		// getting info for all the players.
		//////////////////////////////////////////////////////////////////
		static void PlayerInfoCallback
		(
			PEER pxPeer,  // The peer object.
			RoomType eRoomType,  // The room the info was gotten in.
			const gsi_char* szNick,  // The nick of the player the info is for.
			u_int uIP,  // The player's IP.
			int iProfileID,  // The player's profile ID.
			void* pParam  // User-data.
		);

		// This gets called when a player's flags have changed.
		///////////////////////////////////////////////////////
		static void PlayerFlagsChangedCallback
		(
			PEER pxPeer,  // The peer object.
			RoomType eRoomType,  // The room the flags were changed in.
			const gsi_char* szNick,  // The player whose flags have changed.
			int iOldFlags,  // The player's old flags.
			int iNewFlags,  // The player's new flags.
			void* pParam  // User-data
		);

		// An updated ping for a player, who may be in any room(s).
		///////////////////////////////////////////////////////////
		static void PingCallback
		(
			PEER pxPeer,  // The peer object.
			const gsi_char* szNick,  // The other player's nick.
			int iPing,  // The ping.
			void* pParam  // User-data.
		);

		// An updated cross-ping between two players in the staging room.
		/////////////////////////////////////////////////////////////////
		static void CrossPingCallback
		(
			PEER pxPeer,  // The peer object.
			const gsi_char* szNick1,  // The first player's nick.
			const gsi_char* szNick2,  // The second player's nick.
			int iCrossPing,  // The cross-ping.
			void* pParam  // User-data.
		);

		// This is called for watch keys when a room is joined, for
		// watch keys when another player joins, and for any newly 
		// set watch keys.
		///////////////////////////////////////////////////////////
		static void GlobalKeyChangedCallback
		(
			PEER pxPeer,  // The peer object.
			const gsi_char* szNick,  // The player whose key changed.
			const gsi_char* szKey,  // The key.
			const gsi_char* szValue,  // The value.
			void* pParam  // User-data.
		);

		// This is called for watch keys when a room is joined, for
		// watch keys when another player joins, for any newly 
		// set watch keys, and when a broadcast key is changed.
		///////////////////////////////////////////////////////////
		static void RoomKeyChangedCallback
		(
			PEER pxPeer,  // The peer object.
			RoomType eRoomType,  // The room the player is in.
			const gsi_char* szNick,  // The player whose key changed.
			const gsi_char* szKey,  // The key.
			const gsi_char* szValue,  // The value.
			void* pParam  // User-data.
		);

		// Called to report QR server keys.
		// Use qr2_buffer_add or qr2_buffer_add_int to
		// add this key's information to the buffer.
		//////////////////////////////////////////////
		static void QRServerKeyCallback
		(
			PEER pxPeer,  // The peer object.
			int iKey,  // The key for which to report information.
			qr2_buffer_t pxBuffer,  // Fill in the information using this buffer.
			void* pParam  // User-data.
		);

		// Called to report QR player keys.
		// Use qr2_buffer_add or qr2_buffer_add_int to
		// add this key's information to the buffer.
		//////////////////////////////////////////////
		static void QRPlayerKeyCallback
		(
			PEER pxPeer,  // The peer object.
			int iKey,  // The key for which to report information.
			int iIndex,  // The index of the player for which to report info.
			qr2_buffer_t pxBuffer,  // Fill in the information using this buffer.
			void* pParam  // User-data.
		);

		// Called to report QR team keys.
		// Use qr2_buffer_add or qr2_buffer_add_int to
		// add this key's information to the buffer.
		//////////////////////////////////////////////
		static void QRTeamKeyCallback
		(
			PEER pxPeer,  // The peer object.
			int iKey,  // The key for which to report information.
			int iIndex,  // The index of the team for which to report info.
			qr2_buffer_t pxBuffer,  // Fill in the information using this buffer.
			void* pParam  // User-data.
		);

		// Called to get a list of keys to be reported.
		// Use qr2_keybuffer_add() to add keys.
		// The following keys do not need to be added, as peer already adds them:
		// GAMENAME_KEY, HOSTNAME_KEY, NUMPLAYERS_KEY, MAXPLAYERS_KEY,
		// GAMEMODE_KEY, PASSWORD_KEY, GROUPID_KEY, PLAYER__KEY, PING__KEY.
		/////////////////////////////////////////////////////////////////////////
		static void QRKeyListCallback
		(
			PEER pxPeer,  // The peer object.
			qr2_key_type eType,  // The type of keys being asked for (key_server, key_player, or key_team).
			qr2_keybuffer_t pxKeyBuffer,  // Fill in the keys using this buffer.
			void* pParam  // User-data.
		);

		// Called to get a count of the number of players or teams.
		///////////////////////////////////////////////////////////
		static int QRCountCallback
		(
			PEER pxPeer,  // The peer object.
			qr2_key_type eType,  // The type of count to return (key_player or key_team).
			void* pParam  // User-data.
		);

		// Called when there is an error reporting the server.
		//////////////////////////////////////////////////////
		static void QRAddErrorCallback
		(
			PEER pxPeer,  // The peer object.
			qr2_error_t eError,  // The type of error.
			gsi_char* szErrorString,  // A text string containing the error.
			void* pParam  // User-data.
		);

		// Called when hosting a server and a nat-negotiate cookie is received.
		///////////////////////////////////////////////////////////////////////
		static void QRNatNegotiateCallback
		(
			PEER pxPeer,  // The peer object.
			int iCookie,  // A cookie sent from a potential client.
			void* pParam  // User-data.
		);

		// Called when hosting a server with the server's public reporting address.
		///////////////////////////////////////////////////////////////////////////
		static void QRPublicAddressCallback
		(
			PEER pxPeer,  // The peer object.
			u_int uIP,  // The public reporting IP
			u_short usPort,  // The public reporting port
			void* pParam  // User-data.
		);


		// internal data
		static PEER s_pxPeer;
		static ConnectionState s_eConnectionState;
		static u_int s_uNicknameModifier;	// number added to make nickname unique.
		static char s_acNickNameExtension[uASURA_GAMESPY_PEER_NICKNAME_EXT_MAXLEN];
		static RoomType s_eRoomType;
		static Asura_GameSpy_Peer_GroupRoom* s_pxGroupsRoomArray;
		static u_int s_uNumGroupRooms;
		static u_int s_uGroupRoomIndex;	// remember which group room we're in for rejoin.
		static SBServer s_pxStagingServer;
		static bool s_bErrorAddingServer;

		// SNH: added this so we can tell when the password is bad.
		static PEERJoinResult s_eLastRoomJoinResult;
		
		// and this to avoid nicks of the form [2][1]NickName
		static char s_szAttemptedNick[uASURA_CHAT_MAX_USERNAME_LEN];
};

// E N D   F I L E   W R A P P E R ///////////////////////////////////////////

#endif // #ifndef ___ASURA_GAMESPY_PEER_H___
