//////////////////////////////////////////////////////////////////////////////
//
// Asura_GameSpy_ServerBrowsing.h
//
// Copyright (c) 2003 Rebellion. All rights reserved.
//
// Description:
//
//     project-independent code to deal with getting server info from GameSpy
//	   There are 2 classes:-
//		Asura_GameSpy_ServerBrowsing deals with filters and all the data for 
//		maintaining server lists.
//		Asura_GameSpy_ServerBrowsingSDK does the SDK calls for actually 
//		getting the data from the master server.
//	   The Asura Peer SDK interface uses Asura_GameSpy_ServerBrowsing.
//     You don't need to Initialise/Shutdown Asura_GameSpy_ServerBrowsing as
//		that is done by the SDK wrappers.
//
//////////////////////////////////////////////////////////////////////////////

// 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_SERVERBROWSING_H___
#define ___ASURA_GAMESPY_SERVERBROWSING_H___ 1

#ifdef ASURA_SUPPORT_GAMESPY

// asura
#include "Core/Asura_PlatformBasics.h"

// middleware
#include "GameSpy/serverbrowsing/sb_serverbrowsing.h"

class Asura_GameSpy_ServerBrowsing
{
	public:
		
		enum KeyType
		{
			KeyType_GameVersion,
			KeyType_ServerNameString,
			KeyType_GameTypeString,
			KeyType_MapNameString,
			KeyType_GameTypeID,
			KeyType_MapID,
			KeyType_NumPlayers,
			KeyType_MaxPlayers,
			KeyType_Ping,		// ping is only valid for sorting - not for filtering
			KeyType_Password,
			NumKeyTypes
		};

		enum StringFilterOperator
		{
			StringOperator_Equals,
			StringOperator_Contains,
		};

		enum NumericalFilterOperator
		{
			BinaryOperator_Equals,
			BinaryOperator_NotEqual,
			BinaryOperator_LessThan,
			BinaryOperator_LessThanOrEquals,
			BinaryOperator_GreaterThan,
			BinaryOperator_GreaterThanOrEquals,
			NumNumericalOperators
		};

	public:

		static void Initialise( u_int uMaxServers, bool bUsePeerSDK );
		static void Reset( void );
		static void Shutdown( void );

		static bool IsInitialised(void) { return s_bInitialised; }

		static void AddServer( SBServer pxServer );
		static void RemoveServer( SBServer pxServer );
		static SBServer GetServer( u_int uServerIndex );
		
		static u_int GetNumServers( void ) { return s_uNumServers; }
		static u_int GetMaxServers( void ) { return s_uMaxServers; }

		// SNH - 01/07/2004 10:28:55 - char* version of GetServerName returns exactly what the server reports.
		//		Unicode version converts the string using UTF8ToUSC2String, so needs a buffer to work in.
		static const char* GetServerName( u_int uServerIndex );
		static void GetServerName( u_int uServerIndex, Asura_UnicodeChar* wszNameBuffer, u_int uBufferLength);
		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 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 ServerHasBasicKeys(u_int uServerIndex);
		static bool ServerHasFullKeys(u_int uServerIndex);
		//allow projects to fetch values for their own custom keys
		static const char* GetCustomKey( u_int uServerIndex, char* szKeyName);
		static int GetCustomKeyAsInt( u_int uServerIndex, char* szKeyName);
		static bool GetCustomKeyAsBool( u_int uServerIndex, char* szKeyName);

		// game mode includes "openplaying" when in game, "openstaging" when in staging room, etc.
		static const char* GetGameMode( u_int uServerIndex );
		
		// servers are added to the s_apxServerList as 'unrequested'. When you call the
		//	functions above (eg to add servers to a list on a menu page), set each as
		//	requested. This allows you to search the server list for new servers and
		//	add them to your menu as they arrive.
		static u_int GetNumberOfUnrequestedServers(void) { return s_uNumUnrequestedServers; }
		static void SetServerRequested(u_int uServerIndex, bool bListed);
		static bool HasServerBeenRequested(u_int uServerIndex);
		
		// player details
		static const char* GetPlayerName( u_int uServerIndex, u_int uPlayerIndex );
		static int GetPlayerTeam( u_int uServerIndex, u_int uPlayerIndex );
		static int GetPlayerScore( u_int uServerIndex, u_int uPlayerIndex );
		static int GetPlayerDeaths( u_int uServerIndex, u_int uPlayerIndex );
		static int GetPlayerPing( u_int uServerIndex, u_int uPlayerIndex );

		// server filtering - you can create your own filter strings using SQL
		// syntax, and then call SetFilter(), or you can use the provided functions 
		// for some common filters. Use operator enums above to construct filters
		// based on logical operations for anything not provided if you want to 
		// avoid getting into the SQL stuff.
		static void ResetFilter( void );
		static bool AddStringFilter( KeyType eKeyType, StringFilterOperator eOperator, const char* szValue );
		static bool AddIntFilter( KeyType eKeyType, NumericalFilterOperator eOperator, int iValue );
		static bool AddFloatFilter( KeyType eKeyType, NumericalFilterOperator eOperator, float fValue );
		static bool AddComparisonFilter( KeyType eKeyTypeLHS, NumericalFilterOperator eOperator, KeyType eKeyTypeRHS);

		static bool AddFilter( const char* szFilter );
		static bool IsStringFilter( KeyType eKeyType );
		static bool IsIntFilter( KeyType eKeyType );
		static bool IsFloatFilter( KeyType eKeyType );


		static bool AddMinPlayersFilter( u_int uMinPlayers );
		static bool AddNotFullFilter( void );
		static void SetMaxPing( u_int uMaxPing )
		{
			// can't filter on ping, but this will stop servers showing up if they have too high a ping.
			// cleared by ResetFilter;
			s_uMaxPing = uMaxPing;
		}

		static void SetFilter( const char* szFilter ) { s_szFilter = szFilter; }
		static const char* GetFilter( void ) { return s_szFilter; }

		static bool IsBehindSameNat( SBServer pxServer );
		static bool NeedToUseNatNeg( u_int uServerIndex );
		static void SendNatNegCookie( u_int uServerIndex, int iCookie );
		static const char* GetServerIPAddress( u_int uServerIndex );	// returns dotted ip
		static u_int GetServerInetAddress( u_int uServerIndex );		// return IP as u_int
		static u_short GetServerHostPort( u_int uServerIndex );
		//as above but always return public versions. used for reporting to gamespy
		static u_int GetServerPublicInetAddress( u_int uServerIndex );		// return IP as u_int
		static u_short GetServerPublicHostPort( u_int uServerIndex );

	private:
		
		static u_int GetMyPublicIPAddress( void );
		
		// these Project_GetXXX functions are deprecated
		static const char* Project_GetGameName( void );
		static const char* Project_GetGameKey( void );
		static int Project_GetMinVersion( void );
		static int Project_GetCurrentVersion( void );

		// data
		static bool s_bInitialised;
		static const char* s_szFilter;
		static char s_acFilterBuffer[MAX_FILTER_LEN];

		static SBServer* s_apxServerList;	// array of SBServer objects, created when Initialise is called.
		static u_int s_uMaxServers;
		static u_int s_uNumServers;

		static u_int s_uNumUnrequestedServers;	// number of servers in the s_apxServerList which haven't been requested yet by project code.
		static bool* s_pbServersRequested;	// which server's details have been requested by eg the server list menu page.

		static u_int s_uMaxPing;
		static bool s_bUsePeerSDK;
};


class Asura_GameSpy_ServerBrowsingSDK
{

	public:

#ifdef ASURA_USE_GUI_MENU_SYSTEM
		static void AddConsoleCmdsAndVars();
#endif

		static void Initialise( bool bLan, u_int uMaxConcurrentUpdates = 10, u_int uMaxServers = 256);
		static void Shutdown( void );
		static void Update( void );
		static void Refresh( void );

		static bool IsInitialised( void ) { return s_bInitialised; }

		//override basic fields to project specific set
		static void SetBasicFields(unsigned char* aucBasicFields, u_int uNumBasicFields);

		static void SortList(Asura_GameSpy_ServerBrowsing::KeyType eKeyType, bool bAscending);
		static bool IsUpdating( void ) { return s_bIsUpdating; }
		// server details
		static bool GetFullServerDetails( u_int uServerIndex );

		static u_int GetMyPublicIPAddress( void );
		static bool SendNatNegotiateCookie( const char* szIP, u_short usPort, int iCookie );

	private:
		static void PopulateBasicFields( void );

		static void SBCallback(ServerBrowser pxServerBrowser, SBCallbackReason eReason, SBServer pxServer, void* pUserData);

		// data
		static bool s_bInitialised;
		static ServerBrowser s_pxServerBrowser;
		static bool s_bLan;
		static bool s_bIsUpdating;
		static Asura_GameSpy_ServerBrowsing::KeyType s_eSortKey;	// if not NumKeyTypes, automatically sort list when it's complete
		static bool s_bSortAscending;								// for when sorting automatically

		static unsigned char* s_aucBasicFields;
		static u_int s_uNumBasicFields;
		static bool s_bAssignedBasicFields;
};

#endif //#ifdef ASURA_SUPPORT_GAMESPY
// E N D   F I L E   W R A P P E R ///////////////////////////////////////////

#endif // #ifndef ___ASURA_GAMESPY_SERVERBROWSING_H___
