/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2006 Pat Raynor <raynorpat@sbcglobal.net>

This file is part of the Fortress Evolution source code.

Fortress Evolution 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.

The Fortress Evolution source code 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 Fortress Evolution; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/

// cg_consolecmds.c - text commands typed in at the local console, or executed by a key binding
#include "cg_local.h"
#include "../ui/ui_shared.h"
extern menuDef_t *menuScoreboard;

void CG_TargetCommand_f(void)
{
	int             targetNum;
	char            test[4];

	targetNum = CG_CrosshairPlayer();
	if(!targetNum)
	{
		return;
	}

	trap_Argv(1, test, 4);
	trap_SendConsoleCommand(va("gc %i %i", targetNum, atoi(test)));
}

/*
=================
CG_SizeUp_f

Keybinding command
=================
*/
static void CG_SizeUp_f(void)
{
	trap_Cvar_Set("cg_viewsize", va("%i", (int)(cg_viewsize.integer + 10)));
}


/*
=================
CG_SizeDown_f

Keybinding command
=================
*/
static void CG_SizeDown_f(void)
{
	trap_Cvar_Set("cg_viewsize", va("%i", (int)(cg_viewsize.integer - 10)));
}

/*
=============
CG_Viewpos_f

Debugging command to print the current position
=============
*/
static void CG_Viewpos_f(void)
{
	CG_Printf("(%i %i %i) : %i\n", (int)cg.refdef.vieworg[0], (int)cg.refdef.vieworg[1], (int)cg.refdef.vieworg[2], (int)cg.refdefViewAngles[YAW]);
}

static void CG_ScoresDown_f(void)
{
	CG_BuildSpectatorString();

	if(cg.scoresRequestTime + 2000 < cg.time)
	{
		// the scores are more than two seconds out of data, so request new ones
		cg.scoresRequestTime = cg.time;
		trap_SendClientCommand("score");

		// leave the current scores up if they were already
		// displayed, but if this is the first hit, clear them out
		if(!cg.showScores)
		{
			cg.showScores = qtrue;
			cg.numScores = 0;
		}
	}
	else
	{
		// show the cached contents even if they just pressed it within two seconds
		cg.showScores = qtrue;
	}
}

static void CG_ScoresUp_f(void)
{
	if(cg.showScores)
	{
		cg.showScores = qfalse;
		cg.scoreFadeTime = cg.time;
	}
}

extern menuDef_t *menuScoreboard;
void Menu_Reset();	// FIXME: add to right include file

static void CG_LoadHud_f(void)
{
	char            buff[1024];
	const char     *hudSet;

	memset(buff, 0, sizeof(buff));

	String_Init();
	Menu_Reset();

	trap_Cvar_VariableStringBuffer("cg_hudFiles", buff, sizeof(buff));
	hudSet = buff;
	if(hudSet[0] == '\0')
	{
		hudSet = "ui/hud.txt";
	}

	CG_LoadMenus(hudSet);
	menuScoreboard = NULL;
}


static void CG_scrollScoresDown_f(void)
{
	if(menuScoreboard && cg.scoreBoardShowing)
	{
		Menu_ScrollFeeder(menuScoreboard, FEEDER_SCOREBOARD, qtrue);
		Menu_ScrollFeeder(menuScoreboard, FEEDER_REDTEAM_LIST, qtrue);
		Menu_ScrollFeeder(menuScoreboard, FEEDER_BLUETEAM_LIST, qtrue);
	}
}


static void CG_scrollScoresUp_f(void)
{
	if(menuScoreboard && cg.scoreBoardShowing)
	{
		Menu_ScrollFeeder(menuScoreboard, FEEDER_SCOREBOARD, qfalse);
		Menu_ScrollFeeder(menuScoreboard, FEEDER_REDTEAM_LIST, qfalse);
		Menu_ScrollFeeder(menuScoreboard, FEEDER_BLUETEAM_LIST, qfalse);
	}
}

static void CG_TellTarget_f(void)
{
	int             clientNum;
	char            command[128];
	char            message[128];

	clientNum = CG_CrosshairPlayer();
	if(clientNum == -1)
	{
		return;
	}

	trap_Args(message, 128);
	Com_sprintf(command, 128, "tell %i %s", clientNum, message);
	trap_SendClientCommand(command);
}

static void CG_TellAttacker_f(void)
{
	int             clientNum;
	char            command[128];
	char            message[128];

	clientNum = CG_LastAttacker();
	if(clientNum == -1)
	{
		return;
	}

	trap_Args(message, 128);
	Com_sprintf(command, 128, "tell %i %s", clientNum, message);
	trap_SendClientCommand(command);
}

static void CG_VoiceTellTarget_f(void)
{
	int             clientNum;
	char            command[128];
	char            message[128];

	clientNum = CG_CrosshairPlayer();
	if(clientNum == -1)
	{
		return;
	}

	trap_Args(message, 128);
	Com_sprintf(command, 128, "vtell %i %s", clientNum, message);
	trap_SendClientCommand(command);
}

static void CG_VoiceTellAttacker_f(void)
{
	int             clientNum;
	char            command[128];
	char            message[128];

	clientNum = CG_LastAttacker();
	if(clientNum == -1)
	{
		return;
	}

	trap_Args(message, 128);
	Com_sprintf(command, 128, "vtell %i %s", clientNum, message);
	trap_SendClientCommand(command);
}

static void CG_NextTeamMember_f(void)
{
	CG_SelectNextPlayer();
}

static void CG_PrevTeamMember_f(void)
{
	CG_SelectPrevPlayer();
}

// ASS U ME's enumeration order as far as task specific orders, OFFENSE is zero, CAMP is last
static void CG_NextOrder_f(void)
{
	clientInfo_t   *ci = cgs.clientinfo + cg.snap->ps.clientNum;

	if(ci)
	{
		if(!ci->teamLeader && sortedTeamPlayers[cg_currentSelectedPlayer.integer] != cg.snap->ps.clientNum)
		{
			return;
		}
	}
	if(cgs.currentOrder < TEAMTASK_CAMP)
	{
		cgs.currentOrder++;

		if(cgs.currentOrder == TEAMTASK_RETRIEVE)
		{
			if(!CG_OtherTeamHasFlag())
			{
				cgs.currentOrder++;
			}
		}

		if(cgs.currentOrder == TEAMTASK_ESCORT)
		{
			if(!CG_YourTeamHasFlag())
			{
				cgs.currentOrder++;
			}
		}

	}
	else
	{
		cgs.currentOrder = TEAMTASK_OFFENSE;
	}
	cgs.orderPending = qtrue;
	cgs.orderTime = cg.time + 3000;
}


static void CG_ConfirmOrder_f(void)
{
	trap_SendConsoleCommand(va("cmd vtell %d %s\n", cgs.acceptLeader, VOICECHAT_YES));
	trap_SendConsoleCommand("+button5; wait; -button5");
	if(cg.time < cgs.acceptOrderTime)
	{
		trap_SendClientCommand(va("teamtask %d\n", cgs.acceptTask));
		cgs.acceptOrderTime = 0;
	}
}

static void CG_DenyOrder_f(void)
{
	trap_SendConsoleCommand(va("cmd vtell %d %s\n", cgs.acceptLeader, VOICECHAT_NO));
	trap_SendConsoleCommand("+button6; wait; -button6");
	if(cg.time < cgs.acceptOrderTime)
	{
		cgs.acceptOrderTime = 0;
	}
}

static void CG_TaskOffense_f(void)
{
	if(cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF)
	{
		trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONGETFLAG));
	}
	else
	{
		trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONOFFENSE));
	}
	trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_OFFENSE));
}

static void CG_TaskDefense_f(void)
{
	trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONDEFENSE));
	trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_DEFENSE));
}

static void CG_TaskPatrol_f(void)
{
	trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONPATROL));
	trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_PATROL));
}

static void CG_TaskCamp_f(void)
{
	trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONCAMPING));
	trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_CAMP));
}

static void CG_TaskFollow_f(void)
{
	trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONFOLLOW));
	trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_FOLLOW));
}

static void CG_TaskRetrieve_f(void)
{
	trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONRETURNFLAG));
	trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_RETRIEVE));
}

static void CG_TaskEscort_f(void)
{
	trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONFOLLOWCARRIER));
	trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_ESCORT));
}

static void CG_TaskOwnFlag_f(void)
{
	trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_IHAVEFLAG));
}

static void CG_TauntKillInsult_f(void)
{
	trap_SendConsoleCommand("cmd vsay kill_insult\n");
}

static void CG_TauntPraise_f(void)
{
	trap_SendConsoleCommand("cmd vsay praise\n");
}

static void CG_TauntTaunt_f(void)
{
	trap_SendConsoleCommand("cmd vtaunt\n");
}

static void CG_TauntDeathInsult_f(void)
{
	trap_SendConsoleCommand("cmd vsay death_insult\n");
}

static void CG_TauntGauntlet_f(void)
{
	trap_SendConsoleCommand("cmd vsay kill_guantlet\n");
}

static void CG_TaskSuicide_f(void)
{
	int             clientNum;
	char            command[128];

	clientNum = CG_CrosshairPlayer();
	if(clientNum == -1)
		return;

	Com_sprintf(command, 128, "tell %i suicide", clientNum);
	trap_SendClientCommand(command);
}

/*
==================
CG_StartOrbit_f
==================
*/
static void CG_StartOrbit_f(void)
{
	char            var[MAX_TOKEN_CHARS];

	trap_Cvar_VariableStringBuffer("developer", var, sizeof(var));
	if(!atoi(var))
	{
		return;
	}
	if(cg_cameraOrbit.value != 0)
	{
		trap_Cvar_Set("cg_cameraOrbit", "0");
		trap_Cvar_Set("cg_thirdPerson", "0");
	}
	else
	{
		trap_Cvar_Set("cg_cameraOrbit", "5");
		trap_Cvar_Set("cg_thirdPerson", "1");
		trap_Cvar_Set("cg_thirdPersonAngle", "0");
		trap_Cvar_Set("cg_thirdPersonRange", "100");
	}
}

/*
==============
CG_StartCamera
==============
*/
void CG_StartCamera(const char *name, qboolean startBlack)
{
	char lname[MAX_QPATH];

	Com_StripExtension(name, lname, sizeof(lname));
	Q_strcat(lname, sizeof(lname), ".camera");

	if(trap_loadCamera(va("cameras/%s", lname)))
	{
		cg.cameraMode = qtrue;

		if(startBlack)
		{
			CG_Fade(255, 0, 0);	// go black
			CG_Fade(0, cg.time, 1500);
		}
		trap_startCamera(cg.time);	// camera on in client
	}
	else
	{
		CG_Printf("Unable to load camera %s\n",name);
	}
}

/*
==================
CG_Camera_f
==================
*/
static void CG_Camera_f(void)
{
	char name[MAX_QPATH];

	trap_Argv(1, name, sizeof(name));
	CG_StartCamera(name, qfalse);
}

typedef struct
{
	char           *cmd;
	void            (*function) (void);
} consoleCommand_t;

static consoleCommand_t commands[] = {
	{"testModel", CG_TestModel_f},
	{"testGun", CG_TestGun_f},
	{"testAnimation", CG_TestAnimation_f},
	{"testAnimation2", CG_TestAnimation2_f},
	{"testOmniLight", CG_TestOmniLight_f},
	{"testProjLight", CG_TestProjLight_f},
	{"testFlashLight", CG_TestFlashLight_f},
	{"nextframe", CG_TestModelNextFrame_f},
	{"prevframe", CG_TestModelPrevFrame_f},
	{"nextskin", CG_TestModelNextSkin_f},
	{"prevskin", CG_TestModelPrevSkin_f},
	{"viewpos", CG_Viewpos_f},
	{"+scores", CG_ScoresDown_f},
	{"-scores", CG_ScoresUp_f},
	{"+zoom", CG_ZoomDown_f},
	{"-zoom", CG_ZoomUp_f},
	{"sizeup", CG_SizeUp_f},
	{"sizedown", CG_SizeDown_f},
	{"weapnext", CG_NextWeapon_f},
	{"weapprev", CG_PrevWeapon_f},
	{"weapon", CG_Weapon_f},
	{"tcmd", CG_TargetCommand_f},
	{"loadhud", CG_LoadHud_f},
	{"tell_target", CG_TellTarget_f},
	{"tell_attacker", CG_TellAttacker_f},
	{"vtell_target", CG_VoiceTellTarget_f},
	{"vtell_attacker", CG_VoiceTellAttacker_f},
	{"nextOrder", CG_NextOrder_f},
	{"confirmOrder", CG_ConfirmOrder_f},
	{"denyOrder", CG_DenyOrder_f},
	{"taskOffense", CG_TaskOffense_f},
	{"taskDefense", CG_TaskDefense_f},
	{"taskPatrol", CG_TaskPatrol_f},
	{"taskCamp", CG_TaskCamp_f},
	{"taskFollow", CG_TaskFollow_f},
	{"taskRetrieve", CG_TaskRetrieve_f},
	{"taskEscort", CG_TaskEscort_f},
	{"taskSuicide", CG_TaskSuicide_f},
	{"taskOwnFlag", CG_TaskOwnFlag_f},
	{"tauntKillInsult", CG_TauntKillInsult_f},
	{"tauntPraise", CG_TauntPraise_f},
	{"tauntTaunt", CG_TauntTaunt_f},
	{"tauntDeathInsult", CG_TauntDeathInsult_f},
	{"tauntGauntlet", CG_TauntGauntlet_f},
	{"scoresDown", CG_scrollScoresDown_f},
	{"scoresUp", CG_scrollScoresUp_f},
	{"startOrbit", CG_StartOrbit_f},
	{"camera", CG_Camera_f},
	{"loaddeferred", CG_LoadDeferredPlayers}
};

/*
=================
CG_ConsoleCommand

The string has been tokenized and can be retrieved with
Cmd_Argc() / Cmd_Argv()
=================
*/
qboolean CG_ConsoleCommand(void)
{
	const char     *cmd;
	int             i;

	// don't allow console commands until a snapshot is present
	if(!cg.snap)
		return qfalse;

	cmd = CG_Argv(0);

	for(i = 0; i < sizeof(commands) / sizeof(commands[0]); i++)
	{
		if(!Q_stricmp(cmd, commands[i].cmd))
		{
			commands[i].function();
			return qtrue;
		}
	}

	return qfalse;
}


/*
=================
CG_InitConsoleCommands

Let the client system know about all of our commands
so it can perform tab completion
=================
*/
void CG_InitConsoleCommands(void)
{
	int             i;

	for(i = 0; i < sizeof(commands) / sizeof(commands[0]); i++)
	{
		trap_AddCommand(commands[i].cmd);
	}

	//
	// the game server will interpret these commands, which will be automatically
	// forwarded to the server after they are not recognized locally
	//
	trap_AddCommand("kill");
	trap_AddCommand("say");
	trap_AddCommand("say_team");
	trap_AddCommand("tell");
	trap_AddCommand("vsay");
	trap_AddCommand("vsay_team");
	trap_AddCommand("vtell");
	trap_AddCommand("vtaunt");
	trap_AddCommand("vosay");
	trap_AddCommand("vosay_team");
	trap_AddCommand("votell");
	trap_AddCommand("give");
	trap_AddCommand("god");
	trap_AddCommand("notarget");
	trap_AddCommand("noclip");
	trap_AddCommand("team");
	trap_AddCommand("follow");
	trap_AddCommand("levelshot");
	trap_AddCommand("addbot");
	trap_AddCommand("setviewpos");
	trap_AddCommand("callvote");
	trap_AddCommand("vote");
	trap_AddCommand("callteamvote");
	trap_AddCommand("teamvote");
	trap_AddCommand("stats");
	trap_AddCommand("teamtask");
	trap_AddCommand("loaddefered");	// FIXME: spelled wrong, but not changing for demo
}
