/*
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 "../g_local.h"
#include "ai_local.h"
#include "g_fakeclient.h"



//===============================================================
//
//				FAKECLIENTS
//
//===============================================================


//==========================================
//  G_FindFakeClientbyState
// 
//==========================================
fakeclient_t *G_FindFakeClientbyState (int state)
{
	int i;
	fakeclient_t *fakeclient;
	
	for (i = 0; i < MAX_BOTS; i++)
	{
		fakeclient = fakeClients + i + 1;
		if (fakeclient->state == state)	//found
			return fakeclient;
	}
	return NULL;
}


//==========================================
// G_FindFakeClientbyEdict
// Only tracks fakeClients in use!
//==========================================
fakeclient_t *G_FindFakeClientbyEdict (edict_t *ent)
{
	int i;
	fakeclient_t *fakeclient;

	if (!(ent->r.svflags & SVF_FAKECLIENT))
		return NULL;

	for (i = 0; i < MAX_BOTS; i++)
	{
		fakeclient = fakeClients + i + 1;
		if (ent == fakeclient->ent && fakeclient->state == FAKECLIENT_STATE_INUSE )
			return fakeclient;
	}
	return NULL;
}


//==========================================
// G_FakeClientEmptyTrash
// Make sure the fakeClients list is sane
//==========================================
void G_FakeClientEmptyTrash( void )
{
	fakeclient_t *fakeclient;
	int i;

	for (i = 0; i < MAX_BOTS; i++)
	{
		fakeclient = fakeClients + i + 1;
		if (fakeclient->state < FAKECLIENT_STATE_INUSE )
		{
			if (fakeclient->state == FAKECLIENT_STATE_CONNECTED && fakeclient->ent)
			{
				trap_DropClient(fakeclient->ent, DROP_TYPE_GENERAL, "G_FakeClientEmptyTrash");
			}

			fakeclient->state = FAKECLIENT_STATE_FREE;
			fakeclient->ent = NULL;
			fakeclient->respawn = NULL;
		}
	}
}

//==========================================
// G_FakeClientDisconnect
// called from ClientDisconnect
//==========================================
void G_FakeClientDisconnect (edict_t *ent)
{
	fakeclient_t *fakeclient;

	if ( !(ent->r.svflags & SVF_FAKECLIENT) )
		return;

	fakeclient = G_FindFakeClientbyEdict (ent);
	if (!fakeclient){
		G_Printf ( "G_FakeClientDisconnect: Couldn't find the fakeclient" );
		return;
	}

	if ( fakeclient->state == FAKECLIENT_STATE_INUSE )
	{
		fakeclient->state = FAKECLIENT_STATE_FREE;
		fakeclient->ent->r.svflags &= ~SVF_FAKECLIENT;
		fakeclient->ent = NULL;
		fakeclient->respawn = NULL;
		return;
	}

	//something was wrong
	if (developer->integer)
		G_Printf ("G_FakeClientDisconnect: Couldn't find the fakeclient\n");
}


//==========================================
// G_FakeClientBeginConnection
// called from ClientConnect
//==========================================
qboolean G_FakeClientBeginConnection (edict_t *ent)
{
	fakeclient_t *fakeclient;

	fakeclient = G_FindFakeClientbyState(FAKECLIENT_STATE_FREE);
	if (!fakeclient)
	{
		if (developer->integer)
			G_Printf ("G_FakeClientBeginConnection: failed to find a free fakeclient\n");
		return qfalse;
	}

	//init
	fakeclient->ent = ent;
	fakeclient->respawn = NULL;
	fakeclient->state = FAKECLIENT_STATE_CONNECTING;
	return qtrue;
}


//==========================================
// G_SpawnFakeClient
// returns the fakeclient connected as spectator
//==========================================
fakeclient_t *G_SpawnFakeClient ( char *fakeUserinfo, char *fakeIP )
{
	edict_t		*ent;
	fakeclient_t	*fakeClient;
	int			count=0;
	int			i;

	G_FakeClientEmptyTrash();

	//count spawned fakeClients
	for (i = 0; i < game.maxclients; i++)
	{
		ent = game.edicts + i + 1;
		if (ent->r.svflags & SVF_FAKECLIENT)
			count++;
	}
	ent = NULL;

	//always keep a free server slot for a player
	if (count+2 > game.maxclients)//|| count+1>sv_maxbots->integer)
	{
		G_Printf ("SpawnFakeClient: Max slots reached.\n");
		return NULL;
	}

	trap_FakeClientConnect (fakeUserinfo, fakeIP);

	//find our client
	fakeClient = G_FindFakeClientbyState(FAKECLIENT_STATE_CONNECTING);
	if (!fakeClient) {
		G_Printf("ERROR: Couldn't find the connecting FakeClient.\n");
		G_FakeClientEmptyTrash();
		return NULL;
	}

	fakeClient->state = FAKECLIENT_STATE_CONNECTED;
	return fakeClient;
}

//==========================================
// G_FakeClientStartAsSpectator
// Only makes effect when connecting
//==========================================
qboolean G_FakeClientStartAsSpectator (edict_t *ent)
{
	fakeclient_t	*fakeClient;
	
	if ( !(ent->r.svflags & SVF_FAKECLIENT) )
		return qfalse;
	
	//put as spectator only when it's connecting
	fakeClient = G_FindFakeClientbyState (FAKECLIENT_STATE_CONNECTING);
	if (!fakeClient || fakeClient->ent != ent)
		return qfalse;
	
	// start as 'observer'
	ent->movetype = MOVETYPE_NOCLIP;
	ent->r.solid = SOLID_NOT;
	ent->r.svflags |= SVF_NOCLIENT;
	ent->r.client->ps.POVnum = ENTNUM(ent);
	trap_LinkEntity(ent);
	
	return qtrue;
}

//==========================================
// G_FakeClientRespawn
// called at finishing standard respawn
//==========================================
void G_FakeClientRespawn (edict_t *ent)
{
	fakeclient_t	*fakeclient;

	if ( !(ent->r.svflags & SVF_FAKECLIENT) )
		return;

	fakeclient = G_FindFakeClientbyEdict (ent);

	if (fakeclient && fakeclient->respawn)
		fakeclient->respawn(ent);
}

