/*	$NetBSD: io.c,v 1.14 2009/08/31 08:27:16 dholland Exp $	*/

/*
 * io.c - input/output routines for Phantasia
 */

#include <sys/cdefs.h>

#include <ctype.h>
#include <math.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "macros.h"
#include "phantdefs.h"
#include "phantstruct.h"
#include "phantglobs.h"
//#include "pathnames.h"

#undef bool
#include <curses.h>

static void catchalarm(int) __dead;

void
getstring(char *cp, int mx)
{
	char   *inptr;		/* pointer into string for next string */
	int     x, y;		/* original x, y coordinates on screen */
	int     ch;		/* input */

	getyx(stdscr, y, x);	/* get coordinates on screen */
	inptr = cp;
	*inptr = '\0';		/* clear string to start */
	--mx;			/* reserve room in string for nul terminator */

	do
		/* get characters and process */
	{
		if (Echo)
			mvaddstr(y, x, cp);	/* print string on screen */
		clrtoeol();	/* clear any data after string */
		refresh();	/* update screen */

		ch = getchar();	/* get character */

		switch (ch) {
		case CH_ERASE:	/* back up one character */
			if (inptr > cp)
				--inptr;
			break;

		case CH_KILL:	/* back up to original location */
			inptr = cp;
			break;

		case CH_NEWLINE:	/* terminate string */
			break;

		case CH_REDRAW:/* redraw screen */
			clearok(stdscr, TRUE);
			continue;

		default:	/* put data in string */
			if (ch >= ' ' || Wizard)
				/* printing char; put in string */
				*inptr++ = ch;
		}

		*inptr = '\0';	/* terminate string */
	}
	while (ch != CH_NEWLINE && inptr < cp + mx);
}

void
more(int where)
{
	mvaddstr(where, 0, "-- more --");
	getanswer(" ", FALSE);
}

double
infloat(void)
{
	double  result;		/* return value */

	getstring(Databuf, SZ_DATABUF);
	if (sscanf(Databuf, "%lf", &result) < 1)
		/* no valid number entered */
		result = 0.0;

	return (result);
}

int
inputoption(void)
{
	++Player.p_age;		/* increase age */

	if (Player.p_ring.ring_type != R_SPOILED)
		/* ring ok */
		return (getanswer("T ", TRUE));
	else
		/* bad ring */
	{
		getanswer(" ", TRUE);
		return ((int) ROLL(0.0, 5.0) + '0');
	}
}

void
interrupt(void)
{
	char    line[81];	/* a place to store data already on screen */
	int     loop;		/* counter */
	int     x, y;		/* coordinates on screen */
	int     ch;		/* input */
	unsigned savealarm;	/* to save alarm value */

#ifdef SYS3
	signal(SIGINT, SIG_IGN);
#endif
#ifdef SYS5
	signal(SIGINT, SIG_IGN);
#endif

	savealarm = alarm(0);	/* turn off any alarms */

	getyx(stdscr, y, x);	/* save cursor location */

	for (loop = 0; loop < 80; ++loop) {	/* save line on screen */
		move(4, loop);
		line[loop] = inch();
	}
	line[80] = '\0';	/* nul terminate */

	if (Player.p_status == S_INBATTLE || Player.p_status == S_MONSTER)
		/* in midst of fighting */
	{
		mvaddstr(4, 0, "Quitting now will automatically kill your character.  Still want to ? ");
		ch = getanswer("NY", FALSE);
		if (ch == 'Y')
			death("Bailing out");
		/* NOTREACHED */
	} else {
		mvaddstr(4, 0, "Do you really want to quit ? ");
		ch = getanswer("NY", FALSE);
		if (ch == 'Y')
			leavegame();
		/* NOTREACHED */
	}

	mvaddstr(4, 0, line);	/* restore data on screen */
	move(y, x);		/* restore cursor */
	refresh();

#ifdef SYS3
	signal(SIGINT, interrupt);
#endif
#ifdef SYS5
	signal(SIGINT, interrupt);
#endif

	alarm(savealarm);	/* restore alarm */
}

int
getanswer(const char *choices, phbool def)
{
	int     ch;		/* input */
	volatile int	loop;	/* counter */
	volatile int	oldx, oldy;	/* original coordinates on screen */

	getyx(stdscr, oldy, oldx);
	alarm(0);		/* make sure alarm is off */

	for (loop = 3; loop; --loop)
		/* try for 3 times */
	{
		if (setjmp(Timeoenv) != 0)
			/* timed out waiting for response */
		{
			if (def || loop <= 1)
				/* return default answer */
				break;
			else
				/* prompt, and try again */
				goto YELL;
		} else
			/* wait for response */
		{
			clrtoeol();
			refresh();
#ifdef BSD41
			sigset(SIGALRM, catchalarm);
#else
			signal(SIGALRM, catchalarm);
#endif
			/* set timeout */
			if (Timeout)
				alarm(7);	/* short */
			else
				alarm(600);	/* long */

			ch = getchar();

			alarm(0);	/* turn off timeout */

			if (ch < 0)
				/* caught some signal */
			{
				++loop;
				continue;
			} else
				if (ch == CH_REDRAW)
					/* redraw screen */
				{
					clearok(stdscr, TRUE);	/* force clear screen */
					++loop;	/* don't count this input */
					continue;
				} else
					if (Echo) {
						addch(ch);	/* echo character */
						refresh();
					}
			if (islower(ch))
				/* convert to upper case */
				ch = toupper(ch);

			if (def || strchr(choices, ch) != NULL)
				/* valid choice */
				return (ch);
			else
				if (!def && loop > 1)
					/* bad choice; prompt, and try again */
				{
			YELL:		mvprintw(oldy + 1, 0, "Please choose one of : [%s]\n", choices);
					move(oldy, oldx);
					clrtoeol();
					continue;
				} else
					/* return default answer */
					break;
		}
	}

	return (*choices);
}

static void
catchalarm(int dummy __unused)
{
	longjmp(Timeoenv, 1);
}
