#include "doomdef.h"
#include "p_local.h"
#include "b_bot.h"
#include "g_game.h"
#include "m_random.h"
#include "z_zone.h"
#include "r_things.h"
#include "doomstat.h"
#include "cmdlib.h"
#include "sc_man.h"
#include "stats.h"
#include "dstrings.h"
#include "c_dispatch.h"
#include "d_main.h"
#include "hu_stuff.h"
#include "v_video.h"
#include "sv_main.h"

cycle_t BotThinkCycles, BotSupportCycles;

void G_DoReborn (int playernum);

void B_Main (skullb_t *bot)
{
	BotThinkCycles = 0;

	if (consoleplayer != Net_Arbitrator || demoplayback)
		return;

	if (gamestate != GS_LEVEL)
		return;

	clock (BotThinkCycles);
	if (!freeze)
		B_Think (bot);
	unclock (BotThinkCycles);
}

bool B_Spawn (char *name, char *team)
{
	int i;

	if (netstate == NS_SERVER)
	{
		for (i=0; i<MAXPLAYERS; i++)
		{
			if (players[i].fragcount || playeringame[i])
				continue;

			break;
		}

		if (i == MAXPLAYERS)
		{
			for (i=0; i<MAXPLAYERS; i++)
			{
				if (!playeringame[i])
					break;
			}
		}
	}
	else
	{
		for (i=0; i<MAXPLAYERS; i++)
		{
			if (!playeringame[i] && (i != consoleplayer))
				break;
		}
	}

	if (i == MAXPLAYERS)
	{
		Printf (PRINT_HIGH, "The maximum of %d players/bots has been reached\n", MAXPLAYERS);
		return false;
	}

	if (name)
	{
		for (int j=0; j<MAXPLAYERS; j++)
		{
			if (playeringame[j] && players[j].skullb)
			{
				if (!stricmp(players[j].userinfo.netname, name) && stricmp(players[j].userinfo.netname, "quotebot"))
				{
					Printf (PRINT_HIGH, "%s is already in the game.\n", name);
					return false;
				}
			}
		}
	}

	// Add this back in when it's working right
/*	
	Net_WriteByte (DEM_ADDBOT);
	Net_WriteByte (j);
	Net_WriteString (name);
	Net_Command (DEM_ADDBOT, j, name, consoleplayer);
*/
	B_AddBot (i, name, team);

	return true;
}

void B_AddBot (int bnum, char *info, char *team)
{
	if (!B_CheckName (info))
	{
		Printf (PRINT_HIGH, "Could not find bot '%s'.\n", info);
		return;
	}
	skullb_s *bot = new skullb_s (info);
	bot->LinkToPlayer (bnum);
	if (playeringame[bnum]) // Bot successfully spawned
	{
		if (netstate == NS_SINGLEPLAYER)
			netstate = NS_FAKEMULTI; // Fake netgame mode
		players[bnum].playerstate = PST_ENTER;
		if (team)
		{
			if (teamgame.value)
			{
				// Pick a team for our bot
				if (!stricmp (team, teams[TM_BLUE].name))
					bot->player->team = TM_BLUE;
				else
					bot->player->team = TM_RED;
			}
			// Must be in teamplay mode, so just set the teamname
			else
				sprintf (bot->player->userinfo.team, "%s", team);
		}

		G_DoReborn (bnum);

		if (netstate != NS_SERVER)
			Printf (PRINT_HIGH, "%s joined the game\n", players[bnum].userinfo.netname);
		else
		{
			SV_BroadcastPrintf (PRINT_HIGH, "%s joined the game\n", players[bnum].userinfo.netname);

			// send to other players
			for (int i=0; i<MAXPLAYERS; i++)
			{
				client_t *cl = &clients[i];

				if (cl->cls < cs_spawned)
					continue;

				SV_SendUserInfo(bnum, &clients[i]);
			}
		}

		int x = P_Random (pr_botchat)%100;
	
		if (x < bot->info.chatty || bot->bottype == (bottype_t)BOT_ULTIMUS)
		{
			x = P_Random (pr_botchat)%5;
			bot->chatline = &chatinfo[bot->info.chatinfo].intro[x];
			bot->t_chat = bot->info.chattime;
		}

	}
}

void B_Remove (char *name)
{
	for (int i=0; i<MAXPLAYERS; i++)
	{
		if (playeringame[i] && players[i].skullb && !(stricmp (players[i].userinfo.netname, name)))
		{
			playeringame[i] = false;
			players[i].isbot = false;
			delete players[i].skullb;
			if (netstate == NS_SERVER)
				SV_BroadcastPrintf (PRINT_HIGH, "%s left the game\n", players[i].userinfo.netname);
			else
				Printf (PRINT_HIGH, "%s left the game\n", players[i].userinfo.netname);

			if (netstate == NS_SERVER)
			{
				// tell others clients about it		
				for (int j=0; j<MAXPLAYERS; j++)
				{
					client_t *cl = &clients[j];
	
					if (cl->cls < cs_spawned)
						continue;

					MSG_WriteByte(&cl->reliablebuf, svc_disconnectclient);
					MSG_WriteByte(&cl->reliablebuf, i);
				}
			}

			// [BC] Don't take flags with
			if (teamgame.value && players[i].team != TM_NONE)
			{
				AActor *mo;
				player_s *player = &players[i];
				teaminfo_s *other;

				if (player->team == TM_BLUE)
					other = &teams[TM_RED];
				else
					other = &teams[TM_BLUE];

				if (player->cards[other->ourkey])
				{
					player->cards[other->ourkey] = false;
					mo = new AActor (player->mo->x, player->mo->y, ONFLOORZ, other->ours);
					mo->flags |= MF_DROPPED;
					if (other->ourkey == it_blueskull)
						mo->tid = 666;
					else
						mo->tid = 667;
					mo->AddToHash ();
					if (dmflags2 & DF2_YES_IRETURN)
						other->returnroutine;
					else if (!(dmflags2 & DF2_YES_RETURN))
						other->returnTics = SKULLTICS;
				}
			}

			if (players[i].mo)
			{
				players[i].mo->Destroy ();
				players[i].mo = NULL;
			}
			return;
		}
	}

	Printf (PRINT_HIGH, "Could not find bot %s\n", name);
}

void B_RemoveBots (void)
{
	for (int i=0; i<MAXPLAYERS; i++)
	{
		if (playeringame[i] && players[i].skullb)
		{
			playeringame[i] = false;
			players[i].isbot = false;
			delete players[i].skullb;

			if (netstate == NS_SERVER)
			{
				SV_BroadcastPrintf (PRINT_HIGH, "%s left the game\n", players[i].userinfo.netname);

				// tell others clients about it		
				for (int j=0; j<MAXPLAYERS; j++)
				{
					client_t *cl = &clients[j];
	
					if (cl->cls < cs_spawned)
						continue;

					MSG_WriteByte(&cl->reliablebuf, svc_disconnectclient);
					MSG_WriteByte(&cl->reliablebuf, i);
				}
			}

			// [BC] Don't take flags with
			if (teamgame.value && players[i].team != TM_NONE)
			{
				AActor *mo;
				player_s *player = &players[i];
				teaminfo_s *other;

				if (player->team == TM_BLUE)
					other = &teams[TM_RED];
				else
					other = &teams[TM_BLUE];

				if (player->cards[other->ourkey])
				{
					player->cards[other->ourkey] = false;
					mo = new AActor (player->mo->x, player->mo->y, ONFLOORZ, other->ours);
					mo->flags |= MF_DROPPED;
					if (other->ourkey == it_blueskull)
						mo->tid = 666;
					else
						mo->tid = 667;
					mo->AddToHash ();
					if (dmflags2 & DF2_YES_IRETURN)
						other->returnroutine;
					else if (!(dmflags2 & DF2_YES_RETURN))
						other->returnTics = SKULLTICS;
				}
			}

			if (players[i].mo)
			{
				players[i].mo->Destroy ();
				players[i].mo = NULL;
			}
		}
	}

	if (netstate == NS_FAKEMULTI)
		netstate = NS_SINGLEPLAYER;
}

BEGIN_STAT (bots)
{
	sprintf (out, "think = %04.1f ms  support = %04.1f ms",
		(double)BotThinkCycles * 1000 * SecondsPerCycle,
		(double)BotSupportCycles * 1000 * SecondsPerCycle);
}
END_STAT (bots)
