//file for builtin implementations relevent to only clientside VMs (menu+csqc).
#include "quakedef.h"

#include "pr_common.h"
#include "shader.h"

#if defined(CSQC_DAT) || defined(MENU_DAT)



int MP_TranslateFTEtoDPCodes(int code)
{
	switch(code)
	{
	case K_TAB:				return 9;
	case K_ENTER:			return 13;
	case K_ESCAPE:			return 27;
	case K_SPACE:			return 32;
	case K_BACKSPACE:		return 127;
	case K_UPARROW:			return 128;
	case K_DOWNARROW:		return 129;
	case K_LEFTARROW:		return 130;
	case K_RIGHTARROW:		return 131;
	case K_ALT:				return 132;
	case K_CTRL:			return 133;
	case K_SHIFT:			return 134;
	case K_F1:				return 135;
	case K_F2:				return 136;
	case K_F3:				return 137;
	case K_F4:				return 138;
	case K_F5:				return 139;
	case K_F6:				return 140;
	case K_F7:				return 141;
	case K_F8:				return 142;
	case K_F9:				return 143;
	case K_F10:				return 144;
	case K_F11:				return 145;
	case K_F12:				return 146;
	case K_INS:				return 147;
	case K_DEL:				return 148;
	case K_PGDN:			return 149;
	case K_PGUP:			return 150;
	case K_HOME:			return 151;
	case K_END:				return 152;
	case K_KP_HOME:			return 160;
	case K_KP_UPARROW:		return 161;
	case K_KP_PGUP:			return 162;
	case K_KP_LEFTARROW:	return 163;
	case K_KP_5:			return 164;
	case K_KP_RIGHTARROW:	return 165;
	case K_KP_END:			return 166;
	case K_KP_DOWNARROW:	return 167;
	case K_KP_PGDN:			return 168;
	case K_KP_ENTER:		return 169;
	case K_KP_INS:			return 170;
	case K_KP_DEL:			return 171;
	case K_KP_SLASH:		return 172;
	case K_KP_MINUS:		return 173;
	case K_KP_PLUS:			return 174;
	case K_PAUSE:			return 255;
	case K_JOY1:			return 768;
	case K_JOY2:			return 769;
	case K_JOY3:			return 770;
	case K_JOY4:			return 771;
	case K_AUX1:			return 772;
	case K_AUX2:			return 773;
	case K_AUX3:			return 774;
	case K_AUX4:			return 775;
	case K_AUX5:			return 776;
	case K_AUX6:			return 777;
	case K_AUX7:			return 778;
	case K_AUX8:			return 779;
	case K_AUX9:			return 780;
	case K_AUX10:			return 781;
	case K_AUX11:			return 782;
	case K_AUX12:			return 783;
	case K_AUX13:			return 784;
	case K_AUX14:			return 785;
	case K_AUX15:			return 786;
	case K_AUX16:			return 787;
	case K_AUX17:			return 788;
	case K_AUX18:			return 789;
	case K_AUX19:			return 790;
	case K_AUX20:			return 791;
	case K_AUX21:			return 792;
	case K_AUX22:			return 793;
	case K_AUX23:			return 794;
	case K_AUX24:			return 795;
	case K_AUX25:			return 796;
	case K_AUX26:			return 797;
	case K_AUX27:			return 798;
	case K_AUX28:			return 799;
	case K_AUX29:			return 800;
	case K_AUX30:			return 801;
	case K_AUX31:			return 802;
	case K_AUX32:			return 803;
	case K_MOUSE1:			return 512;
	case K_MOUSE2:			return 513;
	case K_MOUSE3:			return 514;
	case K_MOUSE4:			return 517;
	case K_MOUSE5:			return 518;
	case K_MOUSE6:			return 519;
	case K_MOUSE7:			return 520;
	case K_MOUSE8:			return 521;
	case K_MOUSE9:			return 522;
	case K_MOUSE10:			return 523;
	case K_MWHEELDOWN:		return 515;//K_MOUSE4;
	case K_MWHEELUP:		return 516;//K_MOUSE5;
	default:				return code;
	}
}

int MP_TranslateDPtoFTECodes(int code)
{
	switch(code)
	{
	case 9:			return K_TAB;
	case 13:		return K_ENTER;
	case 27:		return K_ESCAPE;
	case 32:		return K_SPACE;
	case 127:		return K_BACKSPACE;
	case 128:		return K_UPARROW;
	case 129:		return K_DOWNARROW;
	case 130:		return K_LEFTARROW;
	case 131:		return K_RIGHTARROW;
	case 132:		return K_ALT;
	case 133:		return K_CTRL;
	case 134:		return K_SHIFT;
	case 135:		return K_F1;
	case 136:		return K_F2;
	case 137:		return K_F3;
	case 138:		return K_F4;
	case 139:		return K_F5;
	case 140:		return K_F6;
	case 141:		return K_F7;
	case 142:		return K_F8;
	case 143:		return K_F9;
	case 144:		return K_F10;
	case 145:		return K_F11;
	case 146:		return K_F12;
	case 147:		return K_INS;
	case 148:		return K_DEL;
	case 149:		return K_PGDN;
	case 150:		return K_PGUP;
	case 151:		return K_HOME;
	case 152:		return K_END;
	case 160:		return K_KP_HOME;
	case 161:		return K_KP_UPARROW;
	case 162:		return K_KP_PGUP;
	case 163:		return K_KP_LEFTARROW;
	case 164:		return K_KP_5;
	case 165:		return K_KP_RIGHTARROW;
	case 166:		return K_KP_END;
	case 167:		return K_KP_DOWNARROW;
	case 168:		return K_KP_PGDN;
	case 169:		return K_KP_ENTER;
	case 170:		return K_KP_INS;
	case 171:		return K_KP_DEL;
	case 172:		return K_KP_SLASH;
	case 173:		return K_KP_MINUS;
	case 174:		return K_KP_PLUS;
	case 255:		return K_PAUSE;

	case 768:		return K_JOY1;
	case 769:		return K_JOY2;
	case 770:		return K_JOY3;
	case 771:		return K_JOY4;
	case 772:		return K_AUX1;
	case 773:		return K_AUX2;
	case 774:		return K_AUX3;
	case 775:		return K_AUX4;
	case 776:		return K_AUX5;
	case 777:		return K_AUX6;
	case 778:		return K_AUX7;
	case 779:		return K_AUX8;
	case 780:		return K_AUX9;
	case 781:		return K_AUX10;
	case 782:		return K_AUX11;
	case 783:		return K_AUX12;
	case 784:		return K_AUX13;
	case 785:		return K_AUX14;
	case 786:		return K_AUX15;
	case 787:		return K_AUX16;
	case 788:		return K_AUX17;
	case 789:		return K_AUX18;
	case 790:		return K_AUX19;
	case 791:		return K_AUX20;
	case 792:		return K_AUX21;
	case 793:		return K_AUX22;
	case 794:		return K_AUX23;
	case 795:		return K_AUX24;
	case 796:		return K_AUX25;
	case 797:		return K_AUX26;
	case 798:		return K_AUX27;
	case 799:		return K_AUX28;
	case 800:		return K_AUX29;
	case 801:		return K_AUX30;
	case 802:		return K_AUX31;
	case 803:		return K_AUX32;
	case 512:		return K_MOUSE1;
	case 513:		return K_MOUSE2;
	case 514:		return K_MOUSE3;
	case 517:		return K_MOUSE4;
	case 518:		return K_MOUSE5;
	case 519:		return K_MOUSE6;
	case 520:		return K_MOUSE7;
	case 521:		return K_MOUSE8;
	case 522:		return K_MOUSE9;
	case 523:		return K_MOUSE10;
	case 515:		return K_MWHEELDOWN;//K_MOUSE4;
	case 516:		return K_MWHEELUP;//K_MOUSE5;
	default:		return code;
	}
}

//string	findkeysforcommand(string command) = #610;
void QCBUILTIN PF_cl_findkeysforcommand (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char *cmdname = PR_GetStringOfs(prinst, OFS_PARM0);
	int keynums[2];
	char keyname[512];

	M_FindKeysForCommand(0, cmdname, keynums);

	keyname[0] = '\0';

	Q_strncatz (keyname, va(" \'%i\'", MP_TranslateFTEtoDPCodes(keynums[0])), sizeof(keyname));
	Q_strncatz (keyname, va(" \'%i\'", MP_TranslateFTEtoDPCodes(keynums[1])), sizeof(keyname));

	RETURN_TSTRING(keyname);
}

void QCBUILTIN PF_cl_getkeybind (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char *binding = Key_GetBinding(MP_TranslateDPtoFTECodes(G_FLOAT(OFS_PARM0)));
	RETURN_TSTRING(binding);
}

void QCBUILTIN PF_cl_stringtokeynum(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	int i;
	int modifier;
	char *s;

	s = PR_GetStringOfs(prinst, OFS_PARM0);
	i = Key_StringToKeynum(s, &modifier);
	if (i < 0 || modifier != ~0)
	{
		G_FLOAT(OFS_RETURN) = -1;
		return;
	}
	i = MP_TranslateFTEtoDPCodes(i);
	G_FLOAT(OFS_RETURN) = i;
}

//string	keynumtostring(float keynum) = #609;
void QCBUILTIN PF_cl_keynumtostring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	int code = G_FLOAT(OFS_PARM0);

	code = MP_TranslateDPtoFTECodes (code);

	RETURN_TSTRING(Key_KeynumToString(code));
}


void QCBUILTIN PF_cl_playingdemo (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	G_FLOAT(OFS_RETURN) = !!cls.demoplayback;
}

void QCBUILTIN PF_cl_runningserver (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
#ifdef CLIENTONLY
	G_FLOAT(OFS_RETURN) = false;
#else
	G_FLOAT(OFS_RETURN) = sv.state != ss_dead;
#endif
}



#ifndef NOMEDIA

// #487 float(string name) gecko_create( string name )
void QCBUILTIN PF_cs_gecko_create (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char *shadername = PR_GetStringOfs(prinst, OFS_PARM0);
	cin_t *cin;
	cin = R_ShaderGetCinematic(R_RegisterShader(shadername, 
				"{\n"
					"{\n"
						"videomap http:\n"
					"}\n"
				"}\n"
			));

	if (!cin)
		G_FLOAT(OFS_RETURN) = 0;
	else
		G_FLOAT(OFS_RETURN) = 1;
}
// #488 void(string name) gecko_destroy( string name )
void QCBUILTIN PF_cs_gecko_destroy (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
}
// #489 void(string name) gecko_navigate( string name, string URI )
void QCBUILTIN PF_cs_gecko_navigate (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char *shader = PR_GetStringOfs(prinst, OFS_PARM0);
	char *command = PR_GetStringOfs(prinst, OFS_PARM1);
	cin_t *cin;
	cin = R_ShaderFindCinematic(shader);

	if (!cin)
		return;

	Media_Send_Command(cin, command);
}
// #490 float(string name) gecko_keyevent( string name, float key, float eventtype )
void QCBUILTIN PF_cs_gecko_keyevent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char *shader = PR_GetStringOfs(prinst, OFS_PARM0);
	int key = G_FLOAT(OFS_PARM1);
	int eventtype = G_FLOAT(OFS_PARM2);
	cin_t *cin;
	cin = R_ShaderFindCinematic(shader);

	if (!cin)
		return;
	Media_Send_KeyEvent(cin, MP_TranslateDPtoFTECodes(key), (key>127)?0:key, eventtype);
}
// #491 void gecko_mousemove( string name, float x, float y )
void QCBUILTIN PF_cs_gecko_mousemove (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char *shader = PR_GetStringOfs(prinst, OFS_PARM0);
	float posx = G_FLOAT(OFS_PARM1);
	float posy = G_FLOAT(OFS_PARM2);
	cin_t *cin;
	cin = R_ShaderFindCinematic(shader);

	if (!cin)
		return;
	Media_Send_MouseMove(cin, posx, posy);
}
// #492 void gecko_resize( string name, float w, float h )
void QCBUILTIN PF_cs_gecko_resize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char *shader = PR_GetStringOfs(prinst, OFS_PARM0);
	float sizex = G_FLOAT(OFS_PARM1);
	float sizey = G_FLOAT(OFS_PARM2);
	cin_t *cin;
	cin = R_ShaderFindCinematic(shader);
	if (!cin)
		return;
	Media_Send_Resize(cin, sizex, sizey);
}
// #493 vector gecko_get_texture_extent( string name )
void QCBUILTIN PF_cs_gecko_get_texture_extent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char *shader = PR_GetStringOfs(prinst, OFS_PARM0);
	float *ret = G_VECTOR(OFS_RETURN);
	int sx, sy;
	cin_t *cin;
	cin = R_ShaderFindCinematic(shader);
	if (cin)
	{
		Media_Send_GetSize(cin, &sx, &sy);
	}
	else
	{
		sx = 0;
		sy = 0;
	}
	ret[0] = sx;
	ret[1] = sy;
	ret[2] = 0;
}
#endif

void QCBUILTIN PF_soundlength (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char *sample = PR_GetStringOfs(prinst, OFS_PARM0);

	sfx_t *sfx = S_PrecacheSound(sample);
	if (!sfx || sfx->failedload)
		G_FLOAT(OFS_RETURN) = 0;
	else
	{
		sfxcache_t cachebuf, *cache;
		if (sfx->decoder.decodedata)
			cache = sfx->decoder.decodedata(sfx, &cachebuf, 0x7ffffffe, 0);
		else
			cache = sfx->decoder.buf;
		G_FLOAT(OFS_RETURN) = (cache->soundoffset+cache->length) / (float)snd_speed;
	}
}

#ifdef CL_MASTER
#include "cl_master.h"

void QCBUILTIN PF_cl_gethostcachevalue (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	hostcacheglobal_t hcg = G_FLOAT(OFS_PARM0);
	G_FLOAT(OFS_RETURN) = 0;
	switch(hcg)
	{
	case SLIST_HOSTCACHEVIEWCOUNT:
		CL_QueryServers();
		Master_CheckPollSockets();
		G_FLOAT(OFS_RETURN) = Master_NumSorted();
		return;
	case SLIST_HOSTCACHETOTALCOUNT:
		CL_QueryServers();
		Master_CheckPollSockets();
		G_FLOAT(OFS_RETURN) = Master_TotalCount();
		return;

	case SLIST_MASTERQUERYCOUNT:
	case SLIST_MASTERREPLYCOUNT:
	case SLIST_SERVERQUERYCOUNT:
	case SLIST_SERVERREPLYCOUNT:
		G_FLOAT(OFS_RETURN) = 0;
		return;

	case SLIST_SORTFIELD:
		G_FLOAT(OFS_RETURN) = Master_GetSortField();
		return;
	case SLIST_SORTDESCENDING:
		G_FLOAT(OFS_RETURN) = Master_GetSortDescending();
		return;
	default:
		return;
	}
}

//void 	resethostcachemasks(void) = #615;
void QCBUILTIN PF_cl_resethostcachemasks(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	Master_ClearMasks();
}
//void 	sethostcachemaskstring(float mask, float fld, string str, float op) = #616;
void QCBUILTIN PF_cl_sethostcachemaskstring(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	int mask = G_FLOAT(OFS_PARM0);
	int field = G_FLOAT(OFS_PARM1);
	char *str = PR_GetStringOfs(prinst, OFS_PARM2);
	int op = G_FLOAT(OFS_PARM3);

	Master_SetMaskString(mask, field, str, op);
}
//void	sethostcachemasknumber(float mask, float fld, float num, float op) = #617;
void QCBUILTIN PF_cl_sethostcachemasknumber(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	int mask = G_FLOAT(OFS_PARM0);
	int field = G_FLOAT(OFS_PARM1);
	int str = G_FLOAT(OFS_PARM2);
	int op = G_FLOAT(OFS_PARM3);

	Master_SetMaskInteger(mask, field, str, op);
}
//void 	resorthostcache(void) = #618;
void QCBUILTIN PF_cl_resorthostcache(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	Master_SortServers();
}
//void	sethostcachesort(float fld, float descending) = #619;
void QCBUILTIN PF_cl_sethostcachesort(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	Master_SetSortField(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
}
//void	refreshhostcache(void) = #620;
void QCBUILTIN PF_cl_refreshhostcache(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	MasterInfo_Refresh();
}
//float	gethostcachenumber(float fld, float hostnr) = #621;
void QCBUILTIN PF_cl_gethostcachenumber(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	float ret = 0;
	int keynum = G_FLOAT(OFS_PARM0);
	int svnum = G_FLOAT(OFS_PARM1);
	serverinfo_t *sv;
	sv = Master_SortedServer(svnum);

	ret = Master_ReadKeyFloat(sv, keynum);

	G_FLOAT(OFS_RETURN) = ret;
}
void QCBUILTIN PF_cl_gethostcachestring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char *ret;
	int keynum = G_FLOAT(OFS_PARM0);
	int svnum = G_FLOAT(OFS_PARM1);
	serverinfo_t *sv;

	sv = Master_SortedServer(svnum);
	ret = Master_ReadKeyString(sv, keynum);

	RETURN_TSTRING(ret);
}

//float	gethostcacheindexforkey(string key) = #622;
void QCBUILTIN PF_cl_gethostcacheindexforkey(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char *keyname = PR_GetStringOfs(prinst, OFS_PARM0);

	G_FLOAT(OFS_RETURN) = Master_KeyForName(keyname);
}
//void	addwantedhostcachekey(string key) = #623;
void QCBUILTIN PF_cl_addwantedhostcachekey(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	PF_cl_gethostcacheindexforkey(prinst, pr_globals);
}

void QCBUILTIN PF_cl_getextresponse(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	//this does something weird
	G_INT(OFS_RETURN) = 0;
}
#else
void PF_cl_gethostcachevalue (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals){G_FLOAT(OFS_RETURN) = 0;}
void PF_cl_gethostcachestring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) {G_INT(OFS_RETURN) = 0;}
//void 	resethostcachemasks(void) = #615;
void PF_cl_resethostcachemasks(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals){}
//void 	sethostcachemaskstring(float mask, float fld, string str, float op) = #616;
void PF_cl_sethostcachemaskstring(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals){}
//void	sethostcachemasknumber(float mask, float fld, float num, float op) = #617;
void PF_cl_sethostcachemasknumber(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals){}
//void 	resorthostcache(void) = #618;
void PF_cl_resorthostcache(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals){}
//void	sethostcachesort(float fld, float descending) = #619;
void PF_cl_sethostcachesort(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals){}
//void	refreshhostcache(void) = #620;
void PF_cl_refreshhostcache(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) {}
//float	gethostcachenumber(float fld, float hostnr) = #621;
void PF_cl_gethostcachenumber(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals){G_FLOAT(OFS_RETURN) = 0;}
//float	gethostcacheindexforkey(string key) = #622;
void PF_cl_gethostcacheindexforkey(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals){G_FLOAT(OFS_RETURN) = 0;}
//void	addwantedhostcachekey(string key) = #623;
void PF_cl_addwantedhostcachekey(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals){}
#endif




void QCBUILTIN PF_shaderforname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char *str = PR_GetStringOfs(prinst, OFS_PARM0);
	char *defaultbody = PF_VarString(prinst, 1, pr_globals);

	shader_t *shad;

	if (*defaultbody)
		shad = R_RegisterShader(str, defaultbody);
	else
		shad = R_RegisterSkin(str, NULL);
	if (shad)
		G_FLOAT(OFS_RETURN) = shad-r_shaders + 1;
	else
		G_FLOAT(OFS_RETURN) = 0;
}


void QCBUILTIN PF_cl_GetBindMap (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	G_VECTOR(OFS_RETURN)[0] = 1;
	G_VECTOR(OFS_RETURN)[1] = 0;
	G_VECTOR(OFS_RETURN)[2] = 0;
}
void QCBUILTIN PF_cl_SetBindMap (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	int primary = G_FLOAT(OFS_PARM0+0);
	int secondary = G_FLOAT(OFS_PARM0+1);
//	if (IN_SetBindMap(primary, secondary))
//		G_FLOAT(OFS_RETURN) = 1;
	G_FLOAT(OFS_RETURN) = 0;
}

#endif
