/*
 * 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.
 *
 * =======================================================================
 *
 * The CTF ingame menu.
 *
 * =======================================================================
 */

#include "../header/local.h"

/* Note that the pmenu entries are duplicated 
   this is so that a static set of pmenu entries can be used 
   for multiple clients and changed without interference 
   note that arg will be freed when the menu is closed, it
    must be allocated memory */
pmenuhnd_t *
PMenu_Open(edict_t *ent, pmenu_t *entries, int cur, int num, void *arg)
{
	pmenuhnd_t *hnd;
	pmenu_t *p;
	int i;

	if (!ent->client)
	{
		return NULL;
	}

	if (ent->client->menu)
	{
		gi.dprintf("warning, ent already has a menu\n");
		PMenu_Close(ent);
	}

	hnd = malloc(sizeof(*hnd));

	hnd->arg = arg;
	hnd->entries = malloc(sizeof(pmenu_t) * num);
	memcpy(hnd->entries, entries, sizeof(pmenu_t) * num);

	/* duplicate the strings since they may be from static memory */
	for (i = 0; i < num; i++)
	{
		if (entries[i].text)
		{
			hnd->entries[i].text = strdup(entries[i].text);
		}
	}

	hnd->num = num;

	if ((cur < 0) || !entries[cur].SelectFunc)
	{
		for (i = 0, p = entries; i < num; i++, p++)
		{
			if (p->SelectFunc)
			{
				break;
			}
		}
	}
	else
	{
		i = cur;
	}

	if (i >= num)
	{
		hnd->cur = -1;
	}
	else
	{
		hnd->cur = i;
	}

	ent->client->showscores = true;
	ent->client->inmenu = true;
	ent->client->menu = hnd;

	PMenu_Do_Update(ent);
	gi.unicast(ent, true);

	return hnd;
}

void
PMenu_Close(edict_t *ent)
{
	int i;
	pmenuhnd_t *hnd;

	if (!ent->client->menu)
	{
		return;
	}

	hnd = ent->client->menu;

	for (i = 0; i < hnd->num; i++)
	{
		if (hnd->entries[i].text)
		{
			free(hnd->entries[i].text);
		}
	}

	free(hnd->entries);

	if (hnd->arg)
	{
		free(hnd->arg);
	}

	free(hnd);
	ent->client->menu = NULL;
	ent->client->showscores = false;
}

/* 
 * Only use on pmenu's that have been called with PMenu_Open 
 */
void
PMenu_UpdateEntry(pmenu_t *entry, const char *text, int align,
		SelectFunc_t SelectFunc)
{
	if (entry->text)
	{
		free(entry->text);
	}

	entry->text = strdup(text);
	entry->align = align;
	entry->SelectFunc = SelectFunc;
}

void
PMenu_Do_Update(edict_t *ent)
{
	char string[1400];
	int i;
	pmenu_t *p;
	int x;
	pmenuhnd_t *hnd;
	char *t;
	qboolean alt = false;

	if (!ent->client->menu)
	{
		gi.dprintf("warning:  ent has no menu\n");
		return;
	}

	hnd = ent->client->menu;

	strcpy(string, "xv 32 yv 8 picn inventory ");

	for (i = 0, p = hnd->entries; i < hnd->num; i++, p++)
	{
		if (!p->text || !*(p->text))
		{
			continue; /* blank line */
		}

		t = p->text;

		if (*t == '*')
		{
			alt = true;
			t++;
		}

		sprintf(string + strlen(string), "yv %d ", 32 + i * 8);

		if (p->align == PMENU_ALIGN_CENTER)
		{
			x = 196 / 2 - strlen(t) * 4 + 64;
		}
		else if (p->align == PMENU_ALIGN_RIGHT)
		{
			x = 64 + (196 - strlen(t) * 8);
		}
		else
		{
			x = 64;
		}

		sprintf(string + strlen(string), "xv %d ", x - ((hnd->cur == i) ? 8 : 0));

		if (hnd->cur == i)
		{
			sprintf(string + strlen(string), "string2 \"\x0d%s\" ", t);
		}
		else if (alt)
		{
			sprintf(string + strlen(string), "string2 \"%s\" ", t);
		}
		else
		{
			sprintf(string + strlen(string), "string \"%s\" ", t);
		}

		alt = false;
	}

	gi.WriteByte(svc_layout);
	gi.WriteString(string);
}

void
PMenu_Update(edict_t *ent)
{
	if (!ent->client->menu)
	{
		gi.dprintf("warning:  ent has no menu\n");
		return;
	}

	if (level.time - ent->client->menutime >= 1.0)
	{
		/* been a second or more since last update, update now */
		PMenu_Do_Update(ent);
		gi.unicast(ent, true);
		ent->client->menutime = level.time;
		ent->client->menudirty = false;
	}

	ent->client->menutime = level.time + 0.2;
	ent->client->menudirty = true;
}

void
PMenu_Next(edict_t *ent)
{
	pmenuhnd_t *hnd;
	int i;
	pmenu_t *p;

	if (!ent->client->menu)
	{
		gi.dprintf("warning:  ent has no menu\n");
		return;
	}

	hnd = ent->client->menu;

	if (hnd->cur < 0)
	{
		return; /* no selectable entries */
	}

	i = hnd->cur;
	p = hnd->entries + hnd->cur;

	do
	{
		i++, p++;

		if (i == hnd->num)
		{
			i = 0, p = hnd->entries;
		}

		if (p->SelectFunc)
		{
			break;
		}
	}
	while (i != hnd->cur);

	hnd->cur = i;

	PMenu_Update(ent);
}

void
PMenu_Prev(edict_t *ent)
{
	pmenuhnd_t *hnd;
	int i;
	pmenu_t *p;

	if (!ent->client->menu)
	{
		gi.dprintf("warning:  ent has no menu\n");
		return;
	}

	hnd = ent->client->menu;

	if (hnd->cur < 0)
	{
		return; /* no selectable entries */
	}

	i = hnd->cur;
	p = hnd->entries + hnd->cur;

	do
	{
		if (i == 0)
		{
			i = hnd->num - 1;
			p = hnd->entries + i;
		}
		else
		{
			i--, p--;
		}

		if (p->SelectFunc)
		{
			break;
		}
	}
	while (i != hnd->cur);

	hnd->cur = i;

	PMenu_Update(ent);
}

void
PMenu_Select(edict_t *ent)
{
	pmenuhnd_t *hnd;
	pmenu_t *p;

	if (!ent->client->menu)
	{
		gi.dprintf("warning:  ent has no menu\n");
		return;
	}

	hnd = ent->client->menu;

	if (hnd->cur < 0)
	{
		return; /* no selectable entries */
	}

	p = hnd->entries + hnd->cur;

	if (p->SelectFunc)
	{
		p->SelectFunc(ent, hnd);
	}
}

