#include "quakedef.h"

#ifdef WEBSERVER

#include "iweb.h"

#ifdef CLIENTONLY
IWEBFILE *IWebGenerateFile(char *name)
{
	return NULL;
}
#else

char lastrecordedmvd[MAX_QPATH];

IWeb_FileGen_t *IWeb_GenerationBuffer;
int IWeb_GenerationBufferTotal;

void IWeb_MoreGeneratedResize(int newsize)
{
	IWeb_FileGen_t *ob;

	if (IWeb_GenerationBuffer && IWeb_GenerationBufferTotal >= newsize)
		return;	//already big enough

	ob = IWeb_GenerationBuffer;
	IWeb_GenerationBuffer = BZ_Malloc(sizeof(IWeb_GenerationBuffer) + newsize);
	
	IWeb_GenerationBuffer->data = (char *)(IWeb_GenerationBuffer+1);
	if (ob)
	{
		memcpy(IWeb_GenerationBuffer->data, ob->data, ob->len);
		BZ_Free(ob);
	}

	IWeb_GenerationBufferTotal = newsize;
}
void IWeb_Generate(const char *buf)
{
	long count = strlen(buf);
	if (!IWeb_GenerationBuffer || IWeb_GenerationBuffer->len + count >= IWeb_GenerationBufferTotal)
		IWeb_MoreGeneratedResize(IWeb_GenerationBufferTotal + count+(16*1024));

	memcpy(&IWeb_GenerationBuffer->data[IWeb_GenerationBuffer->len], buf, count);
	IWeb_GenerationBuffer->len+=count;
}

int Rank_Enumerate (unsigned int first, unsigned int last, void (*callback) (const rankinfo_t *ri));	//leader first.

void IWeb_ParseForm(char *info, int infolen, char *text)
{
	char *eq, *and;
	char *token, *out;
	*info = '\0';
	if (!text)
		return;
	while(*text)
	{
		eq = strchr(text, '=');
		if (!eq)
			break;
		*eq = '\0';
		and = strchr(eq+1, '&');
		if (and)
			*and = '\0';

		for (out = token = eq+1; *token;)
		{
			if (*token == '+')
			{
				*out++ = ' ';
				token++;
			}
			else if (*token == '%' && token[1] && token[2])
			{
				int c = 0;

				if (token[1] >= '0' && token[1] <= '9')
				{
					c += token[1] - '0';
				}
				else if (token[1] >= 'a' && token[1] <= 'f')
				{
					c += token[1] - 'a'+10;
				}
				else if (token[1] >= 'A' && token[1] <= 'F')
				{
					c += token[1] - 'A'+10;
				}
				c*=16;
				if (token[2] >= '0' && token[2] <= '9')
				{
					c += token[2] - '0';
				}
				else if (token[2] >= 'a' && token[2] <= 'f')
				{
					c += token[2] - 'a'+10;
				}
				else if (token[2] >= 'A' && token[2] <= 'F')
				{
					c += token[2] - 'A'+10;
				}

				*out++ = c;
				token+=3;
			}
			else
				*out++ = *token++;
		}
		*out = '\0';

		Info_SetValueForKey(info, text, eq+1, infolen);
		if (!and)
			return;
		text = and+1;
	}
}

void IWeb_GenerateAdminFile(char *parms, char *content, int contentlength)
{
	extern char	outputbuf[];	//redirected buffer - always null termed.
	char info[16384];
	char *pwd;
	char *cmd;
	char *mark, *start;

	extern cvar_t	rcon_password;
	IWeb_Generate("<HTML><HEAD><TITLE>FTEQWSV - admin</TITLE></HEAD><BODY>");
	if (*rcon_password.string)
	{
		IWeb_ParseForm(info, sizeof(info), content);
		pwd = Info_ValueForKey(info, "pwd");
		cmd = Info_ValueForKey(info, "cmd");

		IWeb_Generate("<FORM action=\"admin.html\" method=\"post\">");
		IWeb_Generate("<CENTER>");
		IWeb_Generate("<input name=pwd value=\"");
		if (!strcmp(rcon_password.string, pwd))
			IWeb_Generate(rcon_password.string);
		IWeb_Generate("\">");
		IWeb_Generate("<BR>");
		IWeb_Generate("<input name=cmd maxsize=255 size=40 value=\"\">");
		IWeb_Generate("<BR>");
		IWeb_Generate("<input type=submit value=\"Submit\" name=btn>");
		IWeb_Generate("</CENTER>");
		IWeb_Generate("</FORM>");

		if (!strcmp(rcon_password.string, pwd))
		{
			Con_Printf("Web based rcon: %s\n", cmd);
			SV_BeginRedirect(RD_OBLIVION, host_client->language);
			Cmd_ExecuteString(cmd, RESTRICT_RCON);
			for (mark = start = outputbuf; *mark; mark++)
			{
				if (*mark == '\n')
				{
					*mark = '\0';
					IWeb_Generate(start);
					IWeb_Generate("<br>");
					start = mark+1;
				}

			}
			IWeb_Generate(start);
			SV_EndRedirect();
		}
		else if (*pwd)
			IWeb_Generate("Password is incorrect.");
	}
	else
		IWeb_Generate("<H1>Remote administration is not enabled.<H2>");
	IWeb_Generate("</BODY></HTML>");
}


void IWeb_GenerateRankingsFileCallback(const rankinfo_t *ri)
{
	IWeb_Generate("<TR><TD ALIGN = \"center\">");
	IWeb_Generate(ri->h.name);
	IWeb_Generate("</TD><TD ALIGN = \"center\">");
	IWeb_Generate(va("%i", ri->s.kills));
	IWeb_Generate("</TD><TD ALIGN = \"center\">");
	IWeb_Generate(va("%i", ri->s.deaths));
	IWeb_Generate("</TD>");
	IWeb_Generate("</TR>");
}

void IWeb_GenerateRankingsFile (char *parms, char *content, int contentlength)
{
	IWeb_Generate("<HTML><HEAD></HEAD><BODY>");

	if (Rank_OpenRankings())
	{
		IWeb_Generate("<TABLE CELLSPACING=\"1\" CELLPADDING=\"1\">");
		IWeb_Generate("<CAPTION>Players</CAPTION>");
		if (Rank_Enumerate(atoi(parms), atoi(parms)+20, IWeb_GenerateRankingsFileCallback) == 20)
		{
			IWeb_Generate("</TABLE>");
			if (atoi(parms) >= 20)
				IWeb_Generate(va("<A HREF=allplayers.html?%i>Less</A>", atoi(parms)-20));
			else if (atoi(parms) > 0)
				IWeb_Generate(va("<A HREF=allplayers.html?%i>Less</A>", 0));
			IWeb_Generate(va("<A HREF=allplayers.html?%i>More</A>", atoi(parms)+20));
		}
		else
		{
			IWeb_Generate("</TABLE>");
			if (atoi(parms) >= 20)
				IWeb_Generate(va("<A HREF=allplayers.html?%i>Less</A>", atoi(parms)-20));
			else if (atoi(parms) > 0)
				IWeb_Generate(va("<A HREF=allplayers.html?%i>Less</A>", 0));
		}
	}
	else
		IWeb_Generate("<H1>Rankings are disabled. Sorry.<H2>");
	IWeb_Generate("</BODY></HTML>");
}

void IWeb_GenerateIndexFile (char *parms, char *content, int contentlength)
{
	extern cvar_t	rcon_password;
	char *s, *o;
	char key[128], value[128];
	int l;
	qboolean added;
	client_t *cl;
	IWeb_Generate("<HTML><HEAD><TITLE>FTEQWSV</TITLE></HEAD><BODY>");
	IWeb_Generate("<H1>");
	IWeb_Generate(hostname.string);
	IWeb_Generate("</H1>");

	IWeb_Generate("<A HREF=\"http://fte.quakesrc.org\">Server website</A><P>");

	if (Rank_OpenRankings())
		IWeb_Generate("<A HREF=\"allplayers.html\">Click here to see ranked players.</A><P>");
	if (*rcon_password.string)
		IWeb_Generate("<A HREF=\"admin.html\">Admin.</A><P>");

	s = svs.info;

	IWeb_Generate("<TABLE CELLSPACING=\"1\" CELLPADDING=\"1\">");
	IWeb_Generate("<CAPTION>Server Info</CAPTION>");
	if (*s == '\\')
		s++;
	while (*s)
	{
		o = key;
		while (*s && *s != '\\')
			*o++ = *s++;

		l = o - key;
//		if (l < 20)
//		{
//			memset (o, ' ', 20-l);
//			key[20] = 0;
//		}
//		else
			*o = 0;
		
		IWeb_Generate("<TR><TD ALIGN = \"center\">");
		IWeb_Generate(key);

		if (!*s)
		{
			IWeb_Generate("MISSING VALUE\n");
			return;
		}

		o = value;
		s++;
		while (*s && *s != '\\')
			*o++ = *s++;
		*o = 0;

		if (*s)
			s++;
		
		IWeb_Generate("</TD><TD ALIGN = \"center\">");
		IWeb_Generate(value);
		IWeb_Generate("</TD></TR>");
	}

	IWeb_Generate("</TABLE>");

	IWeb_Generate("<P><TABLE CELLSPACING=\"1\" CELLPADDING=\"1\">");
	IWeb_Generate("<CAPTION>Players</CAPTION>");
	added = false;
	for (l = 0, cl = svs.clients; l < sv.allocated_client_slots; l++, cl++)
	{
		if (cl->state <= cs_zombie)
			continue;

		IWeb_Generate("<TR><TD ALIGN = \"center\">");
		IWeb_Generate(cl->name);
		IWeb_Generate("</TD><TD ALIGN = \"center\">");
		IWeb_Generate(va("%i", cl->old_frags));
		IWeb_Generate("</TD></TR>");
		added = true;
	}
	if (!added)
	{
		IWeb_Generate("<TR><TD ALIGN = \"center\">");
		IWeb_Generate("No players on server");
		IWeb_Generate("</TD><TD ALIGN = \"center\">");
	}

	IWeb_Generate("</TABLE>");

	IWeb_Generate("</BODY></HTML>");
}

typedef struct {
	char *name;
	void (*GenerationFunction) (char *parms, char *content, int contentlength);
	float lastgenerationtime;
	float oldbysecs;
	IWeb_FileGen_t *buffer;
	int genid;
} IWebFile_t;

IWebFile_t IWebFiles[] = {
	{"allplayers.html", IWeb_GenerateRankingsFile},
	{"index.html", IWeb_GenerateIndexFile},
	{"admin.html", IWeb_GenerateAdminFile}
};

IWEBFILE *IWebGenerateFile(char *name, char *content, int contentlength)
{
	int fnum;
	char *parms;
	int len;

	if (!sv.state)
		return NULL;

	if (*lastrecordedmvd && !strcmp(name, "lastdemo.mvd"))
		if (strcmp(name, "lastdemo.mvd"))	//no infinate loops please...
			return IWebFOpenRead(lastrecordedmvd);

	parms = strchr(name, '?');
	if (!parms)
		parms = name + strlen(name);
	len = parms-name;
	if (*parms)
		parms++;

	if (!*name)
		return NULL;


	for (fnum = 0; fnum < sizeof(IWebFiles) / sizeof(IWebFile_t); fnum++)
	{
		if (!Q_strncasecmp(name, IWebFiles[fnum].name, len+1))
		{
			IWEBFILE *ret;
			if (IWebFiles[fnum].buffer)
			{
				if (IWebFiles[fnum].lastgenerationtime+10 < Sys_DoubleTime() || contentlength||*parms)	//10 sec lifetime
				{
					IWebFiles[fnum].buffer->references--;		//remove our reference and check free
					if (IWebFiles[fnum].buffer->references<=0)
					{
						BZ_Free(IWebFiles[fnum].buffer);
						IWebFiles[fnum].buffer = NULL;
					}
				}
			}
			if (!IWebFiles[fnum].buffer)
			{
				if (IWeb_GenerationBuffer!=NULL)
					Sys_Error("Recursive file generation\n");
				IWebFiles[fnum].GenerationFunction(parms, content, contentlength);
				IWebFiles[fnum].buffer = IWeb_GenerationBuffer;

				if (!contentlength)
				{
					IWeb_GenerationBuffer->references++;	//so it can't be sent once and freed instantly.
					IWebFiles[fnum].lastgenerationtime = Sys_DoubleTime();
				}
				else
					IWebFiles[fnum].lastgenerationtime = -10;
			}			

			ret = IWebMalloc(sizeof(IWEBFILE));
			if (!ret)
			{
				BZ_Free(IWeb_GenerationBuffer);
				return NULL;
			}
			ret->f = NULL;
			ret->bufferdata = IWebFiles[fnum].buffer;
			ret->length = ret->bufferdata->len;
			ret->bufferdata->references++;
			ret->pos = 0;
			ret->start = 0;
			ret->end = ret->start+ret->length;

			IWeb_GenerationBuffer = NULL;

			return ret;
		}
	}
	return NULL;
}

#endif
#endif
