//-----------------------------------------------------------------------------
//
//  $Logfile:: /Source/sv_gamespy.c                                           $
// $Revision:: 2                                                              $
//   $Author:: Burgermac                                                      $
//     $Date:: 12/27/00 7:17 PM                                               $
//
// Copyright (C) 2000 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
// DESCRIPTION:
// Gamespy server code

#include "server.h"
#include "sv_gqueryreporting.h"
#include "gutil.h"

static cvar_t *sv_location;

extern cvar_t *hostname;

static char   gamemode[128];

/*
==================
SV_NumClients
==================
*/
int SV_NumClients( void )
{
	int i, count = 0;

	for ( i = 0; i < maxclients->value; i++ )
	{
		if ( svs.clients )
		{
			if ( svs.clients[i].state >= cs_connected )
			{
				count++;
			}
		}
	}

   return count;
}


/*
================================
basic_callback
sends a (sample) response to the basic query 
includes the following keys:
  \gamename\
  \gamever\
  \location\
================================
*/
static void basic_callback(char *outbuf, int maxlen, void *userdata)
{
	Info_SetValueForKey( outbuf, "gamename",  GAME_NAME );
	Info_SetValueForKey( outbuf, "gamever",   va( "%4.2f", VERSION ) );
	Info_SetValueForKey( outbuf, "location",  va( "%i", (int)sv_location->value ) );

	Com_DPrintf(DEVELOPER_MSG_GAMESPY, "Basic callback, sent: %s\n\n", outbuf);
}


/*
================================
info_callback
Sends a (sample) response to the info query 
including the following keys:
  \hostname\
  \hostport\
  \mapname\
  \gametype\
  \numplayers\
  \maxplayers\
  \gamemode\
================================
*/
static void info_callback(char *outbuf, int maxlen, void *userdata)
{
	char infostring[1024];

	infostring[0] = 0;

	Info_SetValueForKey( infostring, "hostname",    hostname->string );
	Info_SetValueForKey( infostring, "hostport",    Cvar_VariableString( "port" ) );
	Info_SetValueForKey( infostring, "mapname",     sv.name );
	Info_SetValueForKey( infostring, "gametype",    Cvar_VariableString( "deathmatch" ) );
	Info_SetValueForKey( infostring, "numplayers",  va( "%i", SV_NumClients() ) );
	Info_SetValueForKey( infostring, "maxplayers",  maxclients->string );
	Info_SetValueForKey( infostring, "gamemode",    gamemode );

	assert( strlen( infostring ) < maxlen );

	if ( strlen( infostring ) < maxlen )
	{
		strcpy( outbuf, infostring );
	}
      
	Com_DPrintf(DEVELOPER_MSG_GAMESPY, "Info callback, sent: %s\n\n", outbuf);
}

/*
================================
rules_callback
Sends a response to the rules query. You may
need to add custom fields for your game in here. Some are provided
as an example 
The following rules are included:
  \timelimit\
  \fraglimit\
  \rankedserver\
================================
*/
static void rules_callback(char *outbuf, int maxlen, void *userdata)
{
	char infostring[1024];

	infostring[0] = 0;

	Info_SetValueForKey( infostring, "timelimit",       Cvar_VariableString( "timelimit" ) );
	Info_SetValueForKey( infostring, "fraglimit",       Cvar_VariableString( "fraglimit" ) );
	Info_SetValueForKey( infostring, "rankedserver",    Cvar_VariableString( "g_rankedserver" ) );

	assert( strlen( infostring ) < maxlen );

	if ( strlen( infostring ) < maxlen )
	{
		strcpy( outbuf, infostring );
	}
      
	Com_DPrintf(DEVELOPER_MSG_GAMESPY, "Rules callback, sent: %s\n\n", outbuf);
}

/*
================================
players_callback
sends the players and their information. 
Note that \ characters are not stripped out of player names. If
your game allows players or team names with the \ character, you will need
to strip or change it here. 
The following keys are included for each player:
  \player_N\
  \frags_N\
  \deaths_N\
  \ping_N\
================================
*/
static void players_callback(char *outbuf, int maxlen, void *userdata)
{
	int i;
	char infostring[128];
	player_state_t *ps;
	int currlen=0;


	for ( i = 0; i < maxclients->value; i++ )
	{
		if ( svs.clients )
		{
			if ( svs.clients[i].state >= cs_connected )
			{
				ps = &svs.clients[i].edict->client->ps;

				Com_sprintf( infostring, sizeof(infostring), "\\player_%d\\%s\\frags_%d\\%d\\ping_%d\\%d", i, svs.clients[i].name, i, ps->stats[STAT_FRAGS], i, svs.clients[i].ping);

				if ( strlen( infostring ) + currlen < maxlen )
				{
					strcat( outbuf, infostring );
					currlen += (int)strlen( infostring );
				}
			}
		}
	}
}

/*
================================
SV_GamespyHeartbeat
================================
*/
void SV_GamespyHeartbeat(void)
{
	qr_send_statechanged( NULL );
}

/*
================================
SV_ProcessGamespyQueries
================================
*/
void SV_ProcessGamespyQueries(void)
{
	qr_process_queries( NULL );
}

/*
================================
SV_ShutdownGamespy
================================
*/
void SV_ShutdownGamespy(void)
{
	// set gamemode to exiting
	strcpy( gamemode, "exiting" );

	// do a state change 
	qr_send_statechanged(NULL);

	// shutdown gs stuff
	qr_shutdown(NULL);
}

/*
================================
SV_InitGamespy
================================
*/
qboolean SV_InitGamespy(void)
{
	cvar_t *port;
	char secret_key[9];
	int ret;

	// Initialize the gamespy subsystem and cvars
	sv_location       = Cvar_Get( "sv_location",       "1",      CVAR_ARCHIVE );
	port = Cvar_Get ("port", va("%d", PORT_SERVER), CVAR_NOSET);

	// set gamemode to openplaying
	strcpy( gamemode, "openplaying" );
   
	//set the secret key, in a semi-obfuscated manner
	secret_key[0] = 'I';
	secret_key[1] = 'j';
	secret_key[2] = '1';
	secret_key[3] = 'u';
	secret_key[4] = 'A';
	secret_key[5] = 'B';
	secret_key[6] = '\0';
	

	//call qr_init with the query port number and gamename, default IP address, and no user data
	ret = qr_init( NULL, NULL, port->intValue-1, GAME_NAME, secret_key, basic_callback, info_callback, rules_callback, players_callback, NULL);

	if ( ret != 0)
	{
		Com_DPrintf(DEVELOPER_MSG_GAMESPY, "Error starting query sockets in SV_GamespyInit\n");
		return false;
	}

	return true;
}
