/* Emacs style mode select   -*- C++ -*- */
/*----------------------------------------------------------------------------- */
/* */
/* $Id:$ */
/* */
/* Copyright (C) 1993-1996 by 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. */
/* */
/* $Log:$ */
/* */
/* DESCRIPTION:  Heads-up displays */
/* */
/*----------------------------------------------------------------------------- */

static const char
        rcsid[] = "$Id: hu_stuff.c,v 1.4 1997/02/03 16:47:52 b1 Exp $";

#include <ctype.h>

#include "doomdef.h"

#include "z_zone.h"

#include "m_swap.h"

#include "hu_stuff.h"
#include "hu_lib.h"
#include "w_wad.h"

#include "s_sound.h"

#include "doomstat.h"

/* Data. */
#include "dstrings.h"
#include "sounds.h"

/* */
/* Locally used constants, shortcuts. */
/* */
#define HU_TITLE        (mapnames[(gameepisode-1)*9+gamemap-1])
#define HU_TITLE2       (mapnames2[gamemap-1])
#define HU_TITLEP       (mapnamesp[gamemap-1])
#define HU_TITLET       (mapnamest[gamemap-1])
#define HU_TITLEHEIGHT  1
#define HU_TITLEX       0
#define HU_TITLEY       (167 - SHORT(hu_font[0]->height))

#define HU_INPUTTOGGLE  't'
#define HU_INPUTX       HU_MSGX
#define HU_INPUTY       (HU_MSGY + HU_MSGHEIGHT*(SHORT(hu_font[0]->height) +1))
#define HU_INPUTWIDTH   64
#define HU_INPUTHEIGHT  1



char*   chat_macros[] =
{
	HUSTR_CHATMACRO0,
	HUSTR_CHATMACRO1,
	HUSTR_CHATMACRO2,
	HUSTR_CHATMACRO3,
	HUSTR_CHATMACRO4,
	HUSTR_CHATMACRO5,
	HUSTR_CHATMACRO6,
	HUSTR_CHATMACRO7,
	HUSTR_CHATMACRO8,
	HUSTR_CHATMACRO9
};

char*   player_names[] =
{
	HUSTR_PLRGREEN,
	HUSTR_PLRINDIGO,
	HUSTR_PLRBROWN,
	HUSTR_PLRRED
};


char chat_char;                    /* remove later. */
static player_t*        plr;
patch_t*                hu_font[HU_FONTSIZE];
static hu_textline_t w_title;
boolean chat_on;
static hu_itext_t w_chat;
static boolean always_off = false;
static char chat_dest[MAXPLAYERS];
static hu_itext_t w_inputbuffer[MAXPLAYERS];

static boolean message_on;
boolean message_dontfuckwithme;
static boolean message_nottobefuckedwith;

static hu_stext_t w_message;
static int message_counter;

extern int showMessages;
extern boolean automapactive;

static boolean headsupactive = false;

/* */
/* Builtin map names. */
/* The actual names can be found in DStrings.h. */
/* */

char*   mapnames[] =    /* DOOM shareware/registered/retail (Ultimate) names. */
{

	HUSTR_E1M1,
	HUSTR_E1M2,
	HUSTR_E1M3,
	HUSTR_E1M4,
	HUSTR_E1M5,
	HUSTR_E1M6,
	HUSTR_E1M7,
	HUSTR_E1M8,
	HUSTR_E1M9,

	HUSTR_E2M1,
	HUSTR_E2M2,
	HUSTR_E2M3,
	HUSTR_E2M4,
	HUSTR_E2M5,
	HUSTR_E2M6,
	HUSTR_E2M7,
	HUSTR_E2M8,
	HUSTR_E2M9,

	HUSTR_E3M1,
	HUSTR_E3M2,
	HUSTR_E3M3,
	HUSTR_E3M4,
	HUSTR_E3M5,
	HUSTR_E3M6,
	HUSTR_E3M7,
	HUSTR_E3M8,
	HUSTR_E3M9,

	HUSTR_E4M1,
	HUSTR_E4M2,
	HUSTR_E4M3,
	HUSTR_E4M4,
	HUSTR_E4M5,
	HUSTR_E4M6,
	HUSTR_E4M7,
	HUSTR_E4M8,
	HUSTR_E4M9,

	"NEWLEVEL",
	"NEWLEVEL",
	"NEWLEVEL",
	"NEWLEVEL",
	"NEWLEVEL",
	"NEWLEVEL",
	"NEWLEVEL",
	"NEWLEVEL",
	"NEWLEVEL"
};

char*   mapnames2[] =   /* DOOM 2 map names. */
{
	HUSTR_1,
	HUSTR_2,
	HUSTR_3,
	HUSTR_4,
	HUSTR_5,
	HUSTR_6,
	HUSTR_7,
	HUSTR_8,
	HUSTR_9,
	HUSTR_10,
	HUSTR_11,

	HUSTR_12,
	HUSTR_13,
	HUSTR_14,
	HUSTR_15,
	HUSTR_16,
	HUSTR_17,
	HUSTR_18,
	HUSTR_19,
	HUSTR_20,

	HUSTR_21,
	HUSTR_22,
	HUSTR_23,
	HUSTR_24,
	HUSTR_25,
	HUSTR_26,
	HUSTR_27,
	HUSTR_28,
	HUSTR_29,
	HUSTR_30,
	HUSTR_31,
	HUSTR_32
};


char*   mapnamesp[] =   /* Plutonia WAD map names. */
{
	PHUSTR_1,
	PHUSTR_2,
	PHUSTR_3,
	PHUSTR_4,
	PHUSTR_5,
	PHUSTR_6,
	PHUSTR_7,
	PHUSTR_8,
	PHUSTR_9,
	PHUSTR_10,
	PHUSTR_11,

	PHUSTR_12,
	PHUSTR_13,
	PHUSTR_14,
	PHUSTR_15,
	PHUSTR_16,
	PHUSTR_17,
	PHUSTR_18,
	PHUSTR_19,
	PHUSTR_20,

	PHUSTR_21,
	PHUSTR_22,
	PHUSTR_23,
	PHUSTR_24,
	PHUSTR_25,
	PHUSTR_26,
	PHUSTR_27,
	PHUSTR_28,
	PHUSTR_29,
	PHUSTR_30,
	PHUSTR_31,
	PHUSTR_32
};


char *mapnamest[] =     /* TNT WAD map names. */
{
	THUSTR_1,
	THUSTR_2,
	THUSTR_3,
	THUSTR_4,
	THUSTR_5,
	THUSTR_6,
	THUSTR_7,
	THUSTR_8,
	THUSTR_9,
	THUSTR_10,
	THUSTR_11,

	THUSTR_12,
	THUSTR_13,
	THUSTR_14,
	THUSTR_15,
	THUSTR_16,
	THUSTR_17,
	THUSTR_18,
	THUSTR_19,
	THUSTR_20,

	THUSTR_21,
	THUSTR_22,
	THUSTR_23,
	THUSTR_24,
	THUSTR_25,
	THUSTR_26,
	THUSTR_27,
	THUSTR_28,
	THUSTR_29,
	THUSTR_30,
	THUSTR_31,
	THUSTR_32
};


const char*     shiftxform;

const char french_shiftxform[] =
{
	0,
	1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
	11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
	21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
	31,
	' ', '!', '"', '#', '$', '%', '&',
	'"', /* shift-' */
	'(', ')', '*', '+',
	'?', /* shift-, */
	'_', /* shift-- */
	'>', /* shift-. */
	'?', /* shift-/ */
	'0', /* shift-0 */
	'1', /* shift-1 */
	'2', /* shift-2 */
	'3', /* shift-3 */
	'4', /* shift-4 */
	'5', /* shift-5 */
	'6', /* shift-6 */
	'7', /* shift-7 */
	'8', /* shift-8 */
	'9', /* shift-9 */
	'/',
	'.', /* shift-; */
	'<',
	'+', /* shift-= */
	'>', '?', '@',
	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
	'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
	'[', /* shift-[ */
	'!', /* shift-backslash - OH MY GOD DOES WATCOM SUCK */
	']', /* shift-] */
	'"', '_',
	'\'', /* shift-` */
	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
	'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
	'{', '|', '}', '~', 127

};

const char english_shiftxform[] =
{

	0,
	1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
	11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
	21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
	31,
	' ', '!', '"', '#', '$', '%', '&',
	'"', /* shift-' */
	'(', ')', '*', '+',
	'<', /* shift-, */
	'_', /* shift-- */
	'>', /* shift-. */
	'?', /* shift-/ */
	')', /* shift-0 */
	'!', /* shift-1 */
	'@', /* shift-2 */
	'#', /* shift-3 */
	'$', /* shift-4 */
	'%', /* shift-5 */
	'^', /* shift-6 */
	'&', /* shift-7 */
	'*', /* shift-8 */
	'(', /* shift-9 */
	':',
	':', /* shift-; */
	'<',
	'+', /* shift-= */
	'>', '?', '@',
	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
	'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
	'[', /* shift-[ */
	'!', /* shift-backslash - OH MY GOD DOES WATCOM SUCK */
	']', /* shift-] */
	'"', '_',
	'\'', /* shift-` */
	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
	'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
	'{', '|', '}', '~', 127
};

char frenchKeyMap[128]=
{
	0,
	1,2,3,4,5,6,7,8,9,10,
	11,12,13,14,15,16,17,18,19,20,
	21,22,23,24,25,26,27,28,29,30,
	31,
	' ','!','"','#','$','%','&','%','(',')','*','+',';','-',':','!',
	'0','1','2','3','4','5','6','7','8','9',':','M','<','=','>','?',
	'@','Q','B','C','D','E','F','G','H','I','J','K','L',',','N','O',
	'P','A','R','S','T','U','V','Z','X','Y','W','^','\\','$','^','_',
	'@','Q','B','C','D','E','F','G','H','I','J','K','L',',','N','O',
	'P','A','R','S','T','U','V','Z','X','Y','W','^','\\','$','^',127
};

char ForeignTranslation(unsigned char ch)
{
	return ch < 128 ? frenchKeyMap[ch] : ch;
}

void HU_Init(void)
{

	int i;
	int j;
	char buffer[9];

	if (french)
		shiftxform = french_shiftxform;
	else
		shiftxform = english_shiftxform;

	/* load the heads-up font */
	j = HU_FONTSTART;
	for (i=0; i<HU_FONTSIZE; i++)
	{
		sprintf(buffer, "STCFN%.3d", j++);
		hu_font[i] = (patch_t *) W_CacheLumpName(buffer, PU_STATIC);
	}

}

void HU_Stop(void)
{
	headsupactive = false;
}

void HU_Start(void)
{

	int i;
	char*       s;

	if (headsupactive)
		HU_Stop();

	plr = &players[consoleplayer];
	message_on = false;
	message_dontfuckwithme = false;
	message_nottobefuckedwith = false;
	chat_on = false;

	/* create the message widget */
	HUlib_initSText(&w_message,
	                HU_MSGX, HU_MSGY, HU_MSGHEIGHT,
	                hu_font,
	                HU_FONTSTART, &message_on);

	/* create the map title widget */
	HUlib_initTextLine(&w_title,
	                   HU_TITLEX, HU_TITLEY,
	                   hu_font,
	                   HU_FONTSTART);

	switch ( gamemode )
	{
	case shareware:
	case registered:
	case retail:
		s = HU_TITLE;
		break;

/* FIXME
      case pack_plut:
        s = HU_TITLEP;
        break;
      case pack_tnt:
        s = HU_TITLET;
        break;
 */

	case commercial:
	default:
		s = HU_TITLE2;
		break;
	}

	while (*s)
		HUlib_addCharToTextLine(&w_title, *(s++));

	/* create the chat widget */
	HUlib_initIText(&w_chat,
	                HU_INPUTX, HU_INPUTY,
	                hu_font,
	                HU_FONTSTART, &chat_on);

	/* create the inputbuffer widgets */
	for (i=0; i<MAXPLAYERS; i++)
		HUlib_initIText(&w_inputbuffer[i], 0, 0, 0, 0, &always_off);

	headsupactive = true;

}

void HU_Drawer(void)
{

	HUlib_drawSText(&w_message);
	HUlib_drawIText(&w_chat);
	if (automapactive)
		HUlib_drawTextLine(&w_title, false);

}

void HU_Erase(void)
{

	HUlib_eraseSText(&w_message);
	HUlib_eraseIText(&w_chat);
	HUlib_eraseTextLine(&w_title);

}

void HU_Ticker(void)
{

	int i, rc;
	char c;

	/* tick down message counter if message is up */
	if (message_counter && !--message_counter)
	{
		message_on = false;
		message_nottobefuckedwith = false;
	}

	if (showMessages || message_dontfuckwithme)
	{

		/* display message if necessary */
		if ((plr->message && !message_nottobefuckedwith)
		    || (plr->message && message_dontfuckwithme))
		{
			HUlib_addMessageToSText(&w_message, 0, plr->message);
			plr->message = 0;
			message_on = true;
			message_counter = HU_MSGTIMEOUT;
			message_nottobefuckedwith = message_dontfuckwithme;
			message_dontfuckwithme = 0;
		}

	} /* else message_on = false; */

	/* check for incoming chat characters */
	if (netgame)
	{
		for (i=0; i<MAXPLAYERS; i++)
		{
			if (!playeringame[i])
				continue;
			if (i != consoleplayer
			    && (c = players[i].cmd.chatchar))
			{
				if (c <= HU_BROADCAST)
					chat_dest[i] = c;
				else
				{
					if (c >= 'a' && c <= 'z')
						c = (char) shiftxform[(unsigned char) c];
					rc = HUlib_keyInIText(&w_inputbuffer[i], c);
					if (rc && c == KEY_ENTER)
					{
						if (w_inputbuffer[i].l.len
						    && (chat_dest[i] == consoleplayer+1
						        || chat_dest[i] == HU_BROADCAST))
						{
							HUlib_addMessageToSText(&w_message,
							                        player_names[i],
							                        w_inputbuffer[i].l.l);

							message_nottobefuckedwith = true;
							message_on = true;
							message_counter = HU_MSGTIMEOUT;
							if ( gamemode == commercial )
								S_StartSound(0, sfx_radio);
							else
								S_StartSound(0, sfx_tink);
						}
						HUlib_resetIText(&w_inputbuffer[i]);
					}
				}
				players[i].cmd.chatchar = 0;
			}
		}
	}

}

#define QUEUESIZE               128

static char chatchars[QUEUESIZE];
static int head = 0;
static int tail = 0;


void HU_queueChatChar(char c)
{
	if (((head + 1) & (QUEUESIZE-1)) == tail)
	{
		plr->message = HUSTR_MSGU;
	}
	else
	{
		chatchars[head] = c;
		head = (head + 1) & (QUEUESIZE-1);
	}
}

char HU_dequeueChatChar(void)
{
	char c;

	if (head != tail)
	{
		c = chatchars[tail];
		tail = (tail + 1) & (QUEUESIZE-1);
	}
	else
	{
		c = 0;
	}

	return c;
}

boolean HU_Responder(event_t *ev)
{

	static char lastmessage[HU_MAXLINELENGTH+1];
	char*               macromessage;
	boolean eatkey = false;
	static boolean shiftdown = false;
	static boolean altdown = false;
	unsigned char c;
	int i;
	int numplayers;

	static char destination_keys[MAXPLAYERS] =
	{
		HUSTR_KEYGREEN,
		HUSTR_KEYINDIGO,
		HUSTR_KEYBROWN,
		HUSTR_KEYRED
	};

	static int num_nobrainers = 0;

	numplayers = 0;
	for (i=0; i<MAXPLAYERS; i++)
		numplayers += playeringame[i];

	if (ev->data1 == KEY_RSHIFT)
	{
		shiftdown = ev->type == ev_keydown;
		return false;
	}
	else if (ev->data1 == KEY_RALT || ev->data1 == KEY_LALT)
	{
		altdown = ev->type == ev_keydown;
		return false;
	}

	if (ev->type != ev_keydown)
		return false;

	if (!chat_on)
	{
		if (ev->data1 == HU_MSGREFRESH)
		{
			message_on = true;
			message_counter = HU_MSGTIMEOUT;
			eatkey = true;
		}
		else if (netgame && ev->data1 == HU_INPUTTOGGLE)
		{
			eatkey = chat_on = true;
			HUlib_resetIText(&w_chat);
			HU_queueChatChar(HU_BROADCAST);
		}
		else if (netgame && numplayers > 2)
		{
			for (i=0; i<MAXPLAYERS; i++)
			{
				if (ev->data1 == destination_keys[i])
				{
					if (playeringame[i] && i!=consoleplayer)
					{
						eatkey = chat_on = true;
						HUlib_resetIText(&w_chat);
						HU_queueChatChar(i+1);
						break;
					}
					else if (i == consoleplayer)
					{
						num_nobrainers++;
						if (num_nobrainers < 3)
							plr->message = HUSTR_TALKTOSELF1;
						else if (num_nobrainers < 6)
							plr->message = HUSTR_TALKTOSELF2;
						else if (num_nobrainers < 9)
							plr->message = HUSTR_TALKTOSELF3;
						else if (num_nobrainers < 32)
							plr->message = HUSTR_TALKTOSELF4;
						else
							plr->message = HUSTR_TALKTOSELF5;
					}
				}
			}
		}
	}
	else
	{
		c = ev->data1;
		/* send a macro */
		if (altdown)
		{
			c = c - '0';
			if (c > 9)
				return false;
			/* fprintf(stderr, "got here\n"); */
			macromessage = chat_macros[c];

			/* kill last message with a '\n' */
			HU_queueChatChar(KEY_ENTER); /* DEBUG!!! */

			/* send the macro message */
			while (*macromessage)
				HU_queueChatChar(*macromessage++);
			HU_queueChatChar(KEY_ENTER);

			/* leave chat mode and notify that it was sent */
			chat_on = false;
			strcpy(lastmessage, chat_macros[c]);
			plr->message = lastmessage;
			eatkey = true;
		}
		else
		{
			if (french)
				c = ForeignTranslation(c);
			if (shiftdown || (c >= 'a' && c <= 'z'))
				c = shiftxform[c];
			eatkey = HUlib_keyInIText(&w_chat, c);
			if (eatkey)
			{
				/* static unsigned char buf[20]; // DEBUG */
				HU_queueChatChar(c);

				/* sprintf(buf, "KEY: %d => %d", ev->data1, c); */
				/*      plr->message = buf; */
			}
			if (c == KEY_ENTER)
			{
				chat_on = false;
				if (w_chat.l.len)
				{
					strcpy(lastmessage, w_chat.l.l);
					plr->message = lastmessage;
				}
			}
			else if (c == KEY_ESCAPE)
				chat_on = false;
		}
	}

	return eatkey;

}
