/**
*
* \file Asura_GameSpy_GP.h
*
* Created by Richard May - 19/01/2004 10:30:54
*
* Copyright (C) 2002 Rebellion, All Rights Reserved.
*
* \brief
*
**/


#ifdef ASURA_USE_PRAGMA_ONCE
	#pragma once
#endif

#ifndef __ASURA_GAMESPY_GP_H__
#define __ASURA_GAMESPY_GP_H__

#ifdef ASURA_SUPPORT_GAMESPY

/************/
/* Includes.*/
/************/

#include "Network/GameSpy/Asura_GameSpy_Defines.h"


/***********************/
/* Supported features. */
/***********************/

#ifndef ASURA_GAMESPY_GP_ALLOW_NONUNIQUENICKS
#define ASURA_GAMESPY_GP_ALLOW_NONUNIQUENICKS 0
#endif
#ifndef ASURA_GAMESPY_GP_SUPPORT_BUDDIES 
#define ASURA_GAMESPY_GP_SUPPORT_BUDDIES 0
#endif

/************/
/* Typedefs */
/************/
typedef GPGetInfoResponseArg Asura_GSGP_ProfileInfo;
typedef GPProfile Asura_GSGP_ProfileID;

/************************/
/* Forward Declarations */
/************************/
class Asura_GameSpy_GP_Buddy;
class Asura_GameSpy_GP_BuddyRequest;
class Asura_GameSpy_GP_BuddyMessage;

/************/
/* Classes. */
/************/

/*************************************************************
 *
 * Class Name    : Asura_GameSpy_GP
 *
 * Author        : Richard May
 *
 * Description   : Wrapper for GameSpy's Presence and Messaging SDK
 *
 *************************************************************/
class Asura_GameSpy_GP
{
	friend class Asura_GSGP_Internal;

public:
	/* Public interface functions. */
	static void Initialise(void);
	static void Shutdown(void);
	static bool IsInitialised(void) { return s_bIsInitialised; }

	static void Update(void);
		
	static ASURA_GSGP_RESULT ConnectProfile( const Asura_UnicodeChar* wszNickname, const Asura_UnicodeChar* wszEmail, const Asura_UnicodeChar* wszPassword );
	static ASURA_GSGP_RESULT CreateProfile( const Asura_UnicodeChar* wszNickname, const Asura_UnicodeChar* wszEmail, const Asura_UnicodeChar* wszPassword, bool bAutoConnect=true );
	static bool DisconnectProfile();

	static bool WasCreateSuccessful(void)  { return s_bCreateSuccess; }
	static bool WasConnectSuccessful(void) { return s_bConnectSuccess; }

	static ASURA_GSGP_RESULT RequestProfileInfo( Asura_GSGP_ProfileID iProfileID );
	static const Asura_GSGP_ProfileInfo* GetRequestedProfileInfo(void);
	static ASURA_GSGP_RESULT RequestProfileInfoCustom( Asura_GSGP_ProfileID iProfileID, GPCallback pfCallBack, void* pData );

	//SetProfileSearchCallBack must be called before ProfileSearch.
	//the callback function passed in will be called when a search result from ProfileSearch is received
	//parameters passed back are:
	//void* user data passed in to ProfileSearch
	//int number of matches
	//int* array of ints storing the profile IDs of each match
	//char** array of char*s pointing to the nick of each match
	//char** " unique nicks
	//char** " firstnames
	//char** " lastnames
	//char** " email addresses
	static void SetProfileSearchCallBack(void (*pfnProfileSearch)(void*, int, int*,
		char**, char**, char**, char**, char**));
	static ASURA_GSGP_RESULT ProfileSearch(const char* szNick,
		const char* szUniqueNick, const char* szEmail,
		const char* szFirstName, const char* szLastName, void* pParam);

	static Asura_GSGP_ProfileID   GetCurrentProfileID(void) { return s_iCurrentProfile; }
	static const char* GetCurrentProfileUniqueNick(void) { return s_acCurrentNick; }
	static const char* GetCurrentProfilePassword(void) { return s_acCurrentPassword; }

#ifdef ASURA_USE_GUI_MENU_SYSTEM
	static const Asura_UnicodeChar* GetMenuNick() { return s_pwcMenuNick; }
	static const Asura_UnicodeChar* GetMenuEmail() { return s_pwcMenuEmail; }
	static const Asura_UnicodeChar* GetMenuPass() { return s_pwcMenuPass; }
	static void InitMenuLoginDetails( const Asura_UnicodeChar* wszNick, const Asura_UnicodeChar* wszEmail, const Asura_UnicodeChar* wszPass );
#endif

	static ASURA_GSGP_ERRORCODE   GetErrorCode(void);	
	static ASURA_GSGP_RESULT RegisterUniqueNickname( const Asura_UnicodeChar* wszNickname );

	static Asura_UnicodeChar* const* GetSuggestedNicknames( int* piSuggestions );
	static ASURA_GSGP_RESULT RequestSuggestNickname( const Asura_UnicodeChar* wszNickname );
	
	static int GetStatus(void) { return s_iCurrentStatus; }
	static bool IsUniqueNickValid(void) { return s_bUniqueNickValid; }
	static bool IsLoggedIn(void) { return (s_iCurrentProfile != -1); }
	static bool HasEverLoggedIn(void) { return s_bHasEverLoggedIn; }

	// in-game status - szStatusText is a text version of the enum value. e.g. "online".
	// If we're in a game also pass the servers address as a string in the form address:port.
	static void SetActiveStatus( ASURA_GSGP_ACTIVESTATUS eStatus, const char* szStatusText, const char* szAddress );
	
#if ASURA_GAMESPY_GP_SUPPORT_BUDDIES
	// Basic buddy listing functionality. 
	static u_int GetNumBuddies( void );
	static const Asura_UnicodeChar* GetBuddyName( u_int uBuddyIndex );
	static const int GetBuddyProfileID( u_int uBuddyIndex );
	static ASURA_GSGP_ACTIVESTATUS GetBuddyStatus( u_int uBuddyIndex, u_int* puIP = 0, u_short* pusPort = 0 );
	// note that after calling DeleteBuddy buddy indexes may change.
	static void DeleteBuddy( u_int uBuddyIndex );
	static u_int GetBuddyIndexFromProfileID( int iProfileID );// returns uASURA_GAMESPY_MAX_BUDDIES if not found.

	// to add a buddy you call SendBuddyRequest() with the profile ID got from a player list.
	// This sends the request off. When/if the reply (accept/deny) comes in, GetNumPendingBuddyRequests
	// will return non-zero. Calling Accept/Refuse removes the request from the list.
	static void SendBuddyRequest( int iBuddyProfileID );
	static u_int GetNumPendingBuddyRequests( void ) { return s_uNumPendingBuddyRequests; }
	static const Asura_UnicodeChar* GetBuddyRequestSender( u_int uIndex );
	static const int GetBuddyRequestSenderID( u_int uIndex );
	static void AcceptBuddyRequest( u_int uIndex );
	static void RefuseBuddyRequest( u_int uIndex );

	// Buddy messaging - message can be up to uASURA_GAMESPY_MAX_BUDDY_MESSAGE_LENGTH (1024)
	// in order to save memory I've left conversion to Unicode up to calling functions.
	static void SendBuddyMessage( u_int uBuddyIndex, const char* szMessage );
	static u_int GetNumBuddyMessages( void ) { return s_uNumBuddyMessages; }
	static const Asura_UnicodeChar* GetBuddyMessageSender( u_int uIndex );
	static const int GetBuddyMessageSenderID( u_int uIndex );
	static const char* GetBuddyMessage( u_int uIndex );
	static u_int GetBuddyMessageTimeSent( u_int uIndex );
	// similar interface for archived messages
	static u_int GetNumArchivedBuddyMessages( void );
	static const Asura_UnicodeChar* GetArchivedBuddyMessageSender( u_int uArchiveIndex );
	static const int GetArchivedBuddyMessageSenderID( u_int uIndex );
	static const char* GetArchivedBuddyMessage( u_int uIndex );
	static u_int GetArchivedBuddyMessageTimeSent( u_int uIndex );

	// for finding profiles that I've allowed to put me on their buddy list
	static bool SearchForReverseBuddies();	// returns false if failed (e.g. a search already in progress)
	static bool IsSearchingForReverseBuddies();	// returns true if search is in progress
	static bool WasReverseBuddiesSuccessful(); // returns false if the last search failed.
	static u_int GetNumReverseBuddies();
	static int GetReverseBuddyProfileID(u_int uReverseBuddyIndex);
	static const Asura_UnicodeChar* GetReverseBuddyName(u_int uReverseBuddyIndex);
	static bool RevokeBuddy(u_int uReverseBuddyIndex);

	static bool RevokeBuddyByProfileID(int iBuddyProfileID);
#endif

private:
	/* Helper functions. */
	static void CreateCallback ( GPConnection* pxConnection, void* pArg, void* pParam );
	static void ConnectCallback( GPConnection* pxConnection, void* pArg, void* pParam );	
	static void RequestInfoCallback1( GPConnection* pxConnection, void* pArg, void* pParam );
	static void ProfileSearchCallback( GPConnection* pxConnection, void* pArg, void* pParam );
	static void RequestBuddyInfoCallback( GPConnection* pxConnection, void* pArg, void* pParam );
	static void RequestMessageSenderInfoCallback( GPConnection* pxConnection, void* pArg, void* pParam );
	static void ReverseBuddyCallback( GPConnection* pxConnection, void* pArg, void* pParam );
	static void SuggestNickCallback( GPConnection* pxConnection, void* pArg, void* pParam );
	static void RegisterNickCallback( GPConnection* pxConnection, void* pArg, void* pParam );
	static void ErrorCallback( GPConnection* pxConnection, void* pArg, void* pParam );

	static void GameTransferCallback( GPConnection* pxConnection, void* pArg, void* pParam );
	static void GameRecvBuddyAuthCallback( GPConnection* pxConnection, void* pArg, void* pParam );
	static void GameRecvBuddyRevokeCallback( GPConnection* pxConnection, void* pArg, void* pParam );
	
	// buddy functions
	static void BuddyRequestCallback( GPConnection* pxConnection, void* pArg, void* pParam );	
	static void BuddyStatusCallback( GPConnection* pxConnection, void* pArg, void* pParam );
	static void BuddyMessageCallback( GPConnection* pxConnection, void* pArg, void* pParam );
	static void GameInviteCallback( GPConnection* pxConnection, void* pArg, void* pParam );

#ifdef ASURA_USE_GUI_MENU_SYSTEM
	static bool ConnectProfileFromMenus(bool bHelp);
	static bool CreateProfileFromMenus(bool bHelp);
	static bool RequestNickSuggestionsFromMenus(bool bHelp);
	static bool GetNickSuggestionFromMenus(u_int uIndex, bool bHelp, bool bInterrogate);
	static bool UseNickSuggestionFromMenus(u_int uIndex, bool bHelp, bool bInterrogate);
#endif

private:
	/* Data. */
	static GPConnection s_xConnection; // connection to presence & messaging server	
	static Asura_GSGP_ProfileID   s_iCurrentProfile; // currently logged in profile. -1 if not logged in		
	static Asura_GSGP_ProfileInfo s_xCurrentProfileInfo; // last retrieved profile info
	static Asura_UnicodeChar*     s_awszSuggestedNicknames[uASURA_GAMESPY_MAX_NICKNAME_SUGGESTIONS];
	static int					  s_iNumSuggestions;

	static int  s_iCurrentStatus;
	static bool s_bConnectSuccess;
	static bool s_bCreateSuccess;
	static bool s_bUniqueNickValid;
	static bool s_bIsInitialised;
	static bool s_bHasEverLoggedIn;
	static char s_acCurrentNick[uASURA_GAMESPY_NICKNAME_MAX_LENGTH];
	static char s_acCurrentPassword[uASURA_GAMESPY_PASSWORD_MAX_LENGTH];

#ifdef ASURA_USE_GUI_MENU_SYSTEM
	// storage for vars setup in menus
	static Asura_UnicodeChar* s_pwcMenuNick;
	static Asura_UnicodeChar* s_pwcMenuEmail;
	static Asura_UnicodeChar* s_pwcMenuPass;
	static GPErrorCode s_eErrorCode;
#endif

#if ASURA_GAMESPY_GP_SUPPORT_BUDDIES
	// buddy data
	static u_int s_uNumBuddies;
	static Asura_GameSpy_GP_Buddy* s_axBuddyList;
	static bool s_bIsReverseBuddiesResultOK;
	static u_int s_uNumReverseBuddies;
	static Asura_GameSpy_GP_Buddy* s_axReverseBuddyList;

	static u_int s_uNumPendingBuddyRequests;
	static Asura_GameSpy_GP_BuddyRequest* s_axBuddyRequests;

	static u_int s_uNumBuddyMessages;
	static Asura_GameSpy_GP_BuddyMessage* s_axBuddyMessages;
#endif

	static void (*s_pfnProfileSearch)(void*, int, int*,
		char**, char**, char**, char**, char**);
};
/* end of class Asura_GameSpy_GP */

#endif //#ifdef ASURA_SUPPORT_GAMESPY
/****************/
/* End of file. */
/****************/
#endif//__ASURA_GAMESPY_GP_H__
