/*
 * curses_con.c - curses based implementation of the Quake 3 console
 *
 * Copyright (C) 2005  Ed Schouten <ed@fxq.nl>
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <curses.h>
#include <string.h>
#include <stdarg.h>

/*
 * We can't include "../game/q_shared.h" with the color definitions;
 * This will conflict with <curses.h>.
 */

static void Sys_ConsoleInputReset ();
static WINDOW *win_log, *win_cmd;

#define CMDBUF_LEN	256
static char cmdbuf[CMDBUF_LEN];
static int cmdbuf_pos = 0;

#define ERRBUF_LEN	256

#define COLOR_MAX	7
#define COLOR_DEFAULT	7

/* Specified in unix/unix_main.c */
void Sys_Exit (int ex);

/*
 * Sys_ConsoleInputInit: Initialise the console
 */
void Sys_ConsoleInputInit ()
{
	initscr ();

#ifdef CURSES_COLOR
	/* Add colors */
	start_color ();
	
	/* Initialise our palette */
	use_default_colors ();
	init_pair (1, COLOR_RED, -1);
	init_pair (2, COLOR_GREEN, -1);
	init_pair (3, COLOR_YELLOW, -1);
	init_pair (4, COLOR_BLUE, -1);
	init_pair (5, COLOR_CYAN, -1);
	init_pair (6, COLOR_MAGENTA, -1);
	init_pair (7, -1, -1);
#endif /* CURSES_COLOR */

	/* Add the log window */
	win_log = newwin (LINES - 1, 0, 0, 0);
	scrollok (win_log, TRUE);

	/* Add the command prompt */
	win_cmd = newwin (1, 0, LINES - 1, 0);
	nodelay (win_cmd, TRUE);
	noecho ();
	keypad (win_cmd, TRUE);
	Sys_ConsoleInputReset ();
}

/*
 * Sys_ConsoleInputShutdown: Shutdown the console
 */
void Sys_ConsoleInputShutdown ()
{
	delwin (win_log);
	delwin (win_cmd);
	endwin ();
}

/*
 * Sys_ConsoleInputReset: reset the input field
 */
static void Sys_ConsoleInputReset ()
{
	werase (win_cmd);
	wmove (win_cmd, 0, 0);
	waddch (win_cmd, ']');

	wrefresh (win_cmd);
}

/*
 * Sys_ConsoleRefresh: refresh the console (after window resizement)
 */
static void Sys_ConsoleRefresh ()
{
	wrefresh (win_log);
	wrefresh (win_cmd);
}

/*
 * Sys_ConsoleInput: check for console input and return a command when
 *                   a newline is detected
 */
char *Sys_ConsoleInput ()
{
	int key = wgetch (win_cmd);
	
	/* No input */
	if (key == ERR) return NULL;

	/* Basic character input */
	if ((key >= ' ') && (key <= '~') &&
		(cmdbuf_pos < CMDBUF_LEN - 1))
	{
		cmdbuf[cmdbuf_pos++] = key;
		waddch (win_cmd, key);
		return NULL;
	}

	switch (key)
	{
		/* Return - flush command buffer */
		case '\n':
			/* Mark the end of our input */
			cmdbuf[cmdbuf_pos] = '\0';

			/* Reset our prompt */
			Sys_ConsoleInputReset ();

			/* Flush the command */
			cmdbuf_pos = 0;
			return cmdbuf;

#if 0	/* XXX: Broken */
		/* Page Down and Page Up - scrolling */
		case KEY_NPAGE:
			wscrl (win_log, 10);
			Sys_ConsoleRefresh ();
			break;
		case KEY_PPAGE:
			wscrl (win_log, -10);
			Sys_ConsoleRefresh ();
			break;
#endif
		
		/* Backspace - remove character */
		case '\b':
		case KEY_BACKSPACE:
			if (cmdbuf_pos)
			{
				cmdbuf_pos--;
				waddstr (win_cmd, "\b \b");
			}
			break;
	}

	/* Return nothing by default */
	return NULL;
}

/*
 * Sys_Print: Print a message to the console
 */
void Sys_Print (const char *msg)
{
	int i;
#ifdef CURSES_COLOR
	char col;

	/* Set the default color at the beginning of the line */
	wattron (win_log, COLOR_PAIR (COLOR_DEFAULT));
#endif /* CURSES_COLOR */

	for (i = 0; i < strlen (msg); i++)
	{
		if (msg[i] == '^')
		{
#ifdef CURSES_COLOR
			/* A color modifier */
			col = (msg[i+1] - '0') % COLOR_MAX;

			/* Wrap 0 (black) to the default color */
			col = col ? col : COLOR_DEFAULT;

			wattron (win_log, COLOR_PAIR (col));
#endif /* CURSES_COLOR */

			/* Takes one character extra */
			i++;
		}
		else
			/* A regular character */
			waddch (win_log, msg[i]);
	}

	Sys_ConsoleRefresh ();
}

/*
 * Sys_Error: Print an error message and shutdown the game afterwards
 */
void Sys_Error (const char *err, ...)
{
	va_list args;
	char msg[ERRBUF_LEN];

	Sys_ConsoleInputShutdown ();

	fprintf (stderr, "Sys_Error: ");

	va_start (args, err);
	vfprintf (stderr, err, args);
	va_end (args);

	/* Errors don't have a trailing newline */
	fprintf (stderr, "\n");

	Sys_Exit (1);
}
