/*
   Copyright (C) 1997-2001 Id Software, Inc.

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

   See the GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

 */

#include "server.h"
#include "../qcommon/webdownload.h"
#include "../matchmaker/mm_common.h"

#define GETCMD_URL "http://www.warsow.net/servercmd.php?key="
#define GETCMD_FILE "servercmd.txt"

// unused atm
#define LOCK_TIMEOUT 20000 // 20 seconds

static qboolean mm_initialized = qfalse;
mempool_t *svmm_mempool;
cvar_t *sv_mmserver;

//================
// SV_MM_SendMsgToServer
// Sends a msg to mm and adds it to the packet list
//================
static void SV_MM_SendMsgToServer( const char *format, ... )
{
	va_list argptr;
	char msg[1024];

#ifndef ENABLE_MATCHMAKER
	return;
#endif

	va_start( argptr, format );
	Q_vsnprintfz( msg, sizeof( msg ), format, argptr );
	va_end( argptr );

	if( !*msg )
		return;

	MM_SendMsgToServer( &svs.socket_udp, msg );
}

//================
// SV_MM_CanHostMM
// returns whether server is capable of hosting a match
//================
qboolean SV_MM_CanHostMM( void )
{
	int i, playercount = 0, tvclients = 0;

	if( !sv_allowmm->integer )
		return qfalse;

	// count tv clients
	for( i = 0 ; i < sv_maxclients->integer ; i++ )
	{
		if( svs.clients[i].tvclient )
			tvclients++;
	}

	// server must be able to handle at least 8 players plus any tv clients it has connected
	if( sv_maxclients->integer < 8 + tvclients )
		return qfalse;

	for( i = 0 ; i < sv_maxclients->integer ; i++ )
	{
		if( svs.clients[i].edict->r.svflags & SVF_FAKECLIENT || svs.clients[i].tvclient )
			continue;

		if( svs.clients[i].state >= CS_CONNECTING )
			playercount++;
	}

	return !( qboolean )playercount;
}

//================
// SV_MM_Init
// Initialize matchmaking components
//================
void SV_MM_Init( void )
{
#ifndef ENABLE_MATCHMAKER
	return;
#endif

	if( !sv_allowmm->integer )
		return;

	if( mm_initialized )
		return;

	mm_mempool = Mem_AllocPool( NULL, "Matchmaker" );

	sv_mmserver = Cvar_Get( MM_SERVER_VAR, MM_SERVER_IP, CVAR_ARCHIVE );

	mm_initialized = qtrue;
}

//================
// SV_MM_Shutdown
// Shutdown matchmaking stuff
//================
void SV_MM_Shutdown( void )
{
#ifndef ENABLE_MATCHMAKER
	return;
#endif

	if( !sv_allowmm->integer )
		return;

	if( !mm_initialized )
		return;

	Mem_FreePool( &mm_mempool );

	mm_initialized = qfalse;
}

//================
// SV_MMC_Cmd
// Received a cmd message from MM, retrieve the command and execute it
//================
void SV_MMC_Cmd( const socket_t *socket, const netadr_t *address )
{
	char line[MAX_MM_CMD_LEN], *cmd;
#ifdef LOCAL_TEST
	int filenum;
#else
	int len;
	char *url;
	qboolean success;
	FILE *f;
#endif

#ifndef ENABLE_MATCHMAKER
	return;
#endif

	// this server doesn't allow matchmaking
	if( !sv_allowmm->integer )
	{
		SV_MM_SendMsgToServer( "reply nomm" );
		return;
	}

	// not from mm
	if( strcmp( NET_AddressToString( address ), sv_mmserver->string ) )
		return;

	// two arguments, cmd and <key>
	if( Cmd_Argc() != 2 )
		return;

	// if its not 32 characters long, its not a valid key
	if( strlen( Cmd_Argv( 1 ) ) != 32 )
		return;

	// get the command the matchmaking server wants us to execute
#ifdef LOCAL_TEST
	FS_FOpenFile( "mmcmd.txt", &filenum, FS_READ );
	FS_Read( line, sizeof( line ), filenum );
#else
	len = strlen( GETCMD_URL ) + 32 + 1;
	url = Mem_TempMalloc( len );
	Q_snprintfz( url, len, GETCMD_URL "%s", Cmd_Argv( 1 ) );

	success = Web_Get( url, NULL, GETCMD_FILE, qfalse, 2, 2, NULL );
	if( !success )
		return;

	f = fopen( GETCMD_FILE, "r" );
	if( !f )
		return;

	memset( line, 0, sizeof( line ) );
	fgets( line, sizeof( line ), f );
	// cleanup
	fclose( f );
	remove( GETCMD_FILE );
#endif

	// send matchmaker a nocmd reply, we didnt get anything
	if( !*line )
	{
		SV_MM_SendMsgToServer( "reply nocmd" );
		return;
	}

	Cmd_TokenizeString( line );
	cmd = Cmd_Argv( 0 );

#ifdef OLD_GAMESERVER_CHECKING
	// lock the server ready for a possible match
	// we will automatically release the lock
	// after a certain amount of time, or mm
	// will tell us to
	if( !Q_stricmp( cmd, "lock" ) )
	{
		if( !SV_MM_CanHostMM() )
		{
			SV_MM_SendMsgToServer( "reply failed" );
			return;
		}

		sv.mm.locked = svs.realtime;
		SV_MM_SendMsgToServer( "reply success" );
		return;
	}

	// unlock the server
	// always reply with success
	if( !Q_stricmp( cmd, "unlock" ) )
	{
		sv.mm.locked = 0;
		SV_MM_SendMsgToServer( "reply success" );
		return;
	}
#endif

	// set the password on the server
	if( !Q_stricmp( cmd, "setpass" ) )
	{
		char *pass = Cmd_Argv( 1 );

		if ( !SV_MM_CanHostMM() || !pass || !*pass )
		{
			SV_MM_SendMsgToServer( "reply failed" );
			return;
		}

		Cvar_ForceSet( "password", pass );
		SV_MM_SendMsgToServer( "reply success" );
		return;
	}

	// setup the server ready for a match
	if( !Q_stricmp( cmd, "setup" ) )
	{
		int gametype, maxclients, scorelimit;
		float timelimit;
		char *password;
		qboolean falldamage;

		password = Cmd_Argv( 1 );
		if( !password || !*password )
		{
			SV_MM_SendMsgToServer( "reply failed" );
			return;
		}

		gametype = atoi( Cmd_Argv( 2 ) );
		if( !MM_GetGameTypeNameByTag( gametype ) )
		{
			SV_MM_SendMsgToServer( "reply failed" );
			return;
		}

		MM_GetGameTypeInfo( gametype, &maxclients, &scorelimit, &timelimit, &falldamage );

		ge->SetupMM( maxclients, gametype, password, scorelimit, timelimit, falldamage );

		SV_MM_SendMsgToServer( "reply success" );
	}
}
