/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 *
 */

#include "glk/agt/agility.h"
#include "glk/agt/interp.h"

namespace Glk {
namespace AGT {

/* This module contains a miscellany of things that are somewhat */
/* system dependent but not enough so to justify being put in */
/* OS_<whatever>.c */
/* --writestr() and writeln().*/
/* --Hooks for sound, pictures, and fonts.  */
/* --yesno() and wait_return() */
/* --Some lower level file stuff */
/* --main() and command line parseing stuff */

#ifndef REPLACE_BNW

/* #define DEBUG_BELLS_AND_WHISTLES */

/* Warning for fontcmd, pictcmd, musiccmd:
  These all extract filenames from fontlist, pictlist, pixlist, songlist.
 Any of these are allowed to be NULL and this should be checked
 before accessing them.  */

#ifdef DEBUG_BELLS_AND_WHISTLES
void bnw_report(char *cmdstr, filename *list, int index) {
	writeln("");
	writestr(">** ");
	writestr(cmdstr);
	writestr(" ");
	if (list != NULL) {
		writestr(list[index]);
		writestr(" ");
	}
	writeln("**<");
}
#endif /* DEBUG_BELLS_AND_WHISTLES */

void fontcmd(int cmd, int font)
/* 0=Load font, name is fontlist[font]
   1=Restore original (pre-startup) font
   2=Set startup font. (<gamename>.FNT)
*/
{
#ifdef DEBUG_BELLS_AND_WHISTLES
	if (cmd == 0) bnw_report("Loading Font", fontlist, font);
	else if (cmd == 1) bnw_report("Restoring original font", NULL, 0);
#endif
	return;
}

void pictcmd(int cmd, int pict)
/* 1=show global picture, name is pictlist[pict]
   2=show room picture, name is pixlist[pict]
   3=show startup picture <gamename>.P..
  */
{
#ifdef DEBUG_BELLS_AND_WHISTLES
	if (cmd == 1) bnw_report("Showing picture", pictlist, pict);
	else if (cmd == 2) bnw_report("Showing pix", pixlist, pict);
	agt_waitkey();
#endif
	return;
}



int musiccmd(int cmd, int song)
/* For cmd=1 or 2, the name of the song is songlist[song]
  The other commands don't take an additional argument.
   1=play song
   2=repeat song
   3=end repeat
   4=end song
   5=suspend song
   6=resume song
   7=clean-up
   8=turn sound on
   9=turn sound off
   -1=Is a song playing? (0=false, -1=true)
   -2=Is the sound on?  (0=false, -1=true)
*/
{
	if (cmd == 8) sound_on = 1;
	else if (cmd == 9) sound_on = 0;
#ifdef DEBUG_BELLS_AND_WHISTLES
	switch (cmd) {
	case 1:
		bnw_report("Play song", songlist, song);
		break;
	case 2:
		bnw_report("Repeat song", songlist, song);
		break;
	case 3:
		bnw_report("End repeat", NULL, 0);
		break;
	case 4:
		bnw_report("End song", NULL, 0);
		break;
	case 5:
		bnw_report("Suspend song", NULL, 0);
		break;
	case 6:
		bnw_report("Resume song", NULL, 0);
		break;
	case 7:
		bnw_report("Clean up", NULL, 0);
		break;
	case 8:
		bnw_report("Sound On", NULL, 0);
		break;
	case 9:
		bnw_report("Sound Off", NULL, 0);
		break;
	case -1:
		return yesno("Is song playing?");
	case -2:
		return 1;
	}
#endif
	return 0;
}

#endif /* REPLACE_BNW */

static char linebuff[100];
static int lp;  /* Line pointer */
static rbool savenl = 0;
static rbool needfill; /* Used for paragraph filling */
static rbool quotemode = 0;

void debugout(const char *s) {
	int i;

	if (DEBUG_OUT) {
		debugfile->write(s, strlen(s));
	} else {
		lp = 0;
		for (; *s != 0; s++) {
			if (curr_x + lp >= screen_width || lp > 80) {
				if (lp + curr_x >= screen_width)
					lp = screen_width - curr_x - 1;
				linebuff[lp] = 0;
				agt_puts(linebuff);
				agt_newline();
				lp = 0;
			}
			if (*s == '\n') {
				linebuff[lp] = 0;
				agt_puts(linebuff);
				agt_newline();
				lp = 0;
			} else if (*s == '\t') {
				for (i = 0; i < 3; i++) linebuff[lp++] = ' ';
			} else if (*s >= 0 && *s <= 9) linebuff[lp++] = ' ';
			else linebuff[lp++] = *s;
		}
		linebuff[lp] = 0;
		agt_puts(linebuff);
	}
}


int close_pfile(genfile f, int ft)
/* ft=0 for script, 4 for log_in, 5 for log_out */
{
	delete f;
	return 0;
}



static char *get_log(void)
/* Read string from logfile_in */
{
	char *s;
	static int dead_log;

	if (!filevalid(log_in, fLOG)) { /* We are finishing up */
		if (++dead_log > 100) fatal("Internal error: LOG.");
		assert(BATCH_MODE);
		s = (char *)rmalloc(2);
		s[0] = ' ';
		s[1] = 0;
		return s;
	}

	s = (char *)rmalloc(1000);
	s[0] = ' ';
	s[1] = 0;
	(void)textgets(log_in, s, 1000);
	if (texteof(log_in)) {  /* Reached end of logfile */
		close_pfile(log_in, 1);
		log_in = BAD_TEXTFILE;
		if (BATCH_MODE) {
			writeln("");
			writeln("ERROR: Unexpected end of log file.");
			agt_quit(); /* This doesn't actually quit; it just sets things
			 up so we *will* quit. */
			dead_log = 0;
		} else {
			logflag &= ~2;
			fast_replay = 0;
		}
	} else { /* Need to delay or wait for keypress */
		if (logdelay == -1) agt_waitkey();
		else agt_delay(logdelay);
		if (s[0] != 0) writeln(s);
	}
	return s;
}


static void put_log(const char *s)
/* Write s to logfile_out */
{
	textputs(log_out, s);
	if (s[strlen(s) - 1] != '\n')
		textputs(log_out, "\n");
}


char *agt_readline(int in_type) {
	char *s;

	if (PURE_INPUT) agt_textcolor(-1);
	if (logflag & 2)
		s = get_log();
	else
		s = agt_input(in_type);

	if (g_vm->shouldQuit())
		return nullptr;

	if (PURE_INPUT)
		agt_textcolor(-2);

	if (logflag & 1)
		put_log(s);

	return s;
}

char agt_getchar(void) {
	char c, *s, buff[2];

	if (PURE_INPUT) agt_textcolor(-1);
	if (logflag & 2) {
		s = get_log();
		c = s[0];
		rfree(s);
	} else
		c = agt_getkey(1);
	if (PURE_INPUT) agt_textcolor(-2);
	if (logflag & 1) {
		buff[0] = c;
		buff[1] = 0;
		put_log(buff);
	}
	return c;
}

void agt_center(rbool b)
/* 1=turn on text centering, 0=turn off */
/* At the moment, this is only used for game end messages */
/* When it is on, text output with writeln() should be 'centered'; */
/* it is up to the interface to decide what that means. */
/* writestr() should not be called while centering is on. */
{
	center_on = b;
}

void agt_par(rbool b)
/* This has been added for the sake of anyone trying to get this to */
/*  work on less-than-80 column screens. My personal opinion is that this */
/* is probably hopeless; many AGT games assume 80-column format for   */
/* creating tables and ascii graphics. Nevertheless... */
/*  Text between an agt_par(1) and an agt_par(0) is logically connected */
/* (all part of one description) and so it *might* be possible to reformat */
/* it, treating multiple lines as being one paragraph. */
/*    At the very least, you should look for blank lines and indentation */
/* since a single section of text could contain multiple paragraphs. */
/* Sections of text _not_ between an agt_par(1) and an agt_par(0) should */
/* be treated as though each line were a new paragraph */
{
	par_fill_on = b;
	if (b == 0 && savenl) agt_newline();
	savenl = 0;
	needfill = 0;
}

/* This handles the various format code. They all show up after
   '\r'; unrecogonized codes are just ignored */
static uchar xlat_format_code(uchar c) {
	if (c == 0xFF) {
		if (fix_ascii) return trans_ibm[0xFF - 0x80];
		else return 0xFF;
	}
	return 0;
}

#define FMT_CODE_CNT 15

static void run_format_code(uchar c) {
	if (c < FMT_CODE_CNT)
		agt_textcolor(c - 3);
}

#define format_code(c) ((c>0 && c<=LAST_TEXTCODE)||((uchar)c==FORMAT_CODE))

void writestr(const char *s) {
	int i, j;
	char c;
	int endmark, old_x;

	if (savenl) {
		assert(par_fill_on);
		if (!isalnum(s[0])) agt_newline();
		else agt_puts(" ");
		/* If combining two lines, insert a space between them. */
	}
	savenl = 0;
	i = 0;
	lp = 0;

	while (s[i] != 0) {
		for (; s[i] != 0 && lp < 90 && curr_x + lp < screen_width; i++)
			if (s[i] == '\t')
				for (j = 0; j < TAB_SIZE && curr_x + lp < screen_width; j++) linebuff[lp++] = ' ';
			else if (format_code(s[i])) {
				linebuff[lp++] = ' ';    /* Color code */
				break;
			} else if (s[i] == '\r') { /* New format code */
				if (s[i + 1] == 0) continue; /* Bogus format code */
				if (((uchar)s[i + 1]) < FMT_CODE_CNT) break;
				c = (char)xlat_format_code((uchar)s[++i]);
				if (c != 0) linebuff[lp++] = c;
			} else if (s[i] == '\n') {
				break;
			} else linebuff[lp++] = s[i];

		linebuff[lp] = 0;

		/* Backtrack to last space; in case of formatting codes, we should
		 already have one */
		endmark = lp;

		if (!isspace(s[i]) && !format_code(s[i]) && s[i] != 0) {
			/* If we aren't conveniently at a break...*/
			do {    /* Find last space */
				endmark--;
			} while (endmark > 0 && !isspace(linebuff[endmark]));
		}

		if (endmark == 0 && !isspace(linebuff[endmark])) { /* Can't find a break */
			if (curr_x + lp < screen_width) /* Not a line break */
				endmark = lp; /* Break at end; it doesn't matter that much */
			else  /* We _need_ a line break but are having trouble finding one */
				if (curr_x > 0) /* already stuff on this line printed previously */
					endmark = 0; /* i.e. print out nothing; move it to next line */
				else   /* We have a single word that is longer than our line */
					endmark = screen_width; /* Give up */
		}

		c = linebuff[endmark];
		linebuff[endmark] = 0;
		old_x = curr_x;

		agt_puts(linebuff);

		linebuff[endmark] = c;

		if (old_x + lp >= screen_width)
			/* Need to insert line break and skip any spaces */
		{
			if (!quotemode) agt_newline();
			else return; /* In quote mode, just truncate */

			/* Now set up beginning of next line: skip over whitespace */
			while (endmark < lp && isspace(linebuff[endmark]))
				endmark++;  /* Eliminate EOL whitespace */
			if (endmark == lp) {
				/* Nothing left; eliminate whitespace at beginning
				            of next line */
				while (isspace(s[i]) && s[i] != '\r') i++;
				lp = endmark = 0;
			}
			needfill = 1;
			if (endmark == lp && s[i] == 0) {
				needfill = 2;
				return; /* If only spaces left, don't print them */
			}
		}

		/* Now copy remaining text */
		for (j = 0; endmark < lp; j++, endmark++) linebuff[j] = linebuff[endmark];
		lp = j;

		/* Now to deal with format codes */
		if ((unsigned char)s[i] == FORMAT_CODE) {
			i++;
			if (bold_mode) { /* Translate as BOLD toggle */
				if (textbold)
					agt_textcolor(-2);  /* Turn bold off */
				else agt_textcolor(-1); /* Turn bold on */
				textbold = !textbold;
			} else /* translate as BLACK */
				agt_textcolor(0);
		} else if (s[i] > 0 && s[i] <= LAST_TEXTCODE)
			agt_textcolor(s[i++]);
		else if (s[i] == '\r') {
			run_format_code((uchar)s[i + 1]);
			i += 2;
		} else if (s[i] == '\n') {
			i += 1;
			agt_newline();
		}
	}
}



void writeln(const char *s) {
	int i, pad;
	char *padstr;

	if (center_on && (int)strlen(s) + curr_x < screen_width) {
		pad = (screen_width - strlen(s)) / 2;
		padstr = (char *)rmalloc((pad + 1) * sizeof(char));
		for (i = 0; i < pad; i++) padstr[i] = ' ';
		padstr[i] = 0;
		agt_puts(padstr);
		rfree(padstr);
	}
	writestr(s);
	/* needfill=2 if writestr ended with a line that wrapped only
	   because of excess spaces (which have been discarded); needfill==1
	   if writestr wrapped a line for any reason */
	/* If needfill==2, we've already issued a new-line, so don't issue a
	   second one. */
	/* If needfill==1, set savenl rather than wrapping (writestr will
	   then decide to wrap or not depending on whether the next line starts
	   with text or nontext), *unless* we are version magx, in which case
	   the game author presumably knew what they were doing, so honor their
	   wishes. */
	if (par_fill_on && needfill == 1)
		if (aver >= AGX00) agt_newline();
		else savenl = 1;
	else if (needfill != 2)
		agt_newline();
	needfill = 0;
}


static char fixstatchar(uchar c)
/* Eliminate formating characters in the status line */
{
	if (c == '\t' || c <= LAST_TEXTCODE ||
	        (c == FORMAT_CODE) || c == '\r' || c == '\n')
		return ' ';
	return c;
}

void print_statline(void)
/* Use strings in l_stat and r_stat */
{
	int i, j;
	char *s, *t;
	static rbool lastline = 0; /* Was a non-empty status line printed  last time? */

	s = (char *)rmalloc((status_width + 1) * sizeof(char));

	/* If both strings empty, don't print the status line */
	if (l_stat[0] == 0 && r_stat[0] == 0 && !lastline) return;
	lastline = (l_stat[0] || r_stat[0]);

	i = status_width - strlen(l_stat) - strlen(r_stat);

	j = 0;
	if (r_stat[0] == 0) { /* Center the status line */
		while (j < i / 2) s[j++] = ' ';
		i -= j;
	} else if (i > 6) {
		s[j++] = ' ';
		i -= 2;
	}  /* If statline is wide enough, put a
					   space on each side */

	if ((int)strlen(l_stat) < status_width)  /* Copy left side of status line into s*/
		for (t = l_stat; *t != 0; t++) s[j++] = fixstatchar(*t);

	for (; i > 0; i--) s[j++] = ' '; /* Insert space between left and right sides */

	if (j + (int)strlen(r_stat) <= status_width) /*Copy right side into s */
		for (t = r_stat; *t != 0; t++) s[j++] = fixstatchar(*t);

	while (j < status_width) s[j++] = ' '; /* Pad any extra width with spaces */
	s[j] = 0; /* Put end of string marker */
	agt_statline(s); /* Output it */
	rfree(s);
}


void padout(int padleng) {
	int i;
	char *pstr;

	if (padleng <= 0) return;
	pstr = (char *)rmalloc(padleng + 1);
	for (i = 0; i < padleng; i++) pstr[i] = ' ';
	pstr[padleng] = 0;
	writestr(pstr);
	free(pstr);
}

static int textwidth(char *s) {
	int n;

	n = 0;
	for (; *s != 0; s++) n += (*s == '\t') ? TAB_SIZE : 1;
	return n;
}

void textbox(char *(txt[]), int len, unsigned long flags)
/* TB_TTL, TB_BOLD, TB_BORDER, TB_CENTER */
{
	int i, width, padwidth;
	int *linewidth;

	agt_textcolor(7);
	if (flags & TB_BOLD) agt_textcolor(-1);
	else agt_textcolor(-2);

	linewidth = (int *)rmalloc(len * sizeof(int));

	width = 0; /* This contains the maximum width of any line */
	for (i = 0; i < len; i++) {
		linewidth[i] = textwidth(txt[i]);
		if (linewidth[i] > width) width = linewidth[i];
	}

	agt_makebox(width, len, flags & ~(TB_BOLD | TB_CENTER));
	quotemode = 1;  /* So newlines will cause truncation rather than a
		   real newline */
	for (i = 0; i < len; i++) {
		padwidth = width - linewidth[i]; /* Amount of padding we need */
		if (flags & TB_CENTER) {
			padout(padwidth / 2);
			padwidth -= padwidth / 2;
		}
		writestr(txt[i]);
		padout(padwidth);
		if (i != len - 1) agt_qnewline();
	}
	agt_endbox();
	quotemode = 0; /* Back to normal */

	agt_textcolor(7);
	textbold = 0;
}


#ifndef REPLACE_MENU

int agt_menu(const char *header, int size, int width, menuentry *menu)
/* This is _very_ minimal as it stands */
{
	int i, j;
	char sbuff[10];
	int numcol, colheight;

	if (size == 0) return 0;

	width = width + 5;
	numcol = screen_width / width;
	colheight = size / numcol;
	if (size % numcol != 0) colheight++;

	writeln(header);
	for (i = 0; i < colheight; i++) {
		for (j = 0; j < numcol; j++) {
			if (j * colheight + i >= size) break;
			sprintf(sbuff, "%2d.", j * colheight + i + 1);
			writestr(sbuff);
			writestr(menu[j * colheight + i]);
			if (j < numcol - 1) padout(width - 3 - strlen(menu[j * colheight + i]));
		}
		writeln("");
	}
	do {
		writestr("Choice:");
		i = read_number() - 1;
		if (i < 0 || i >= size)
			writeln("Please choose an option from the menu.");
	} while (i < 0 || i >= size);
	return i;
}

#endif /* REPLACE_MENU */



void prompt_out(int n)
/* n=1 standard prompt
   n=2 question prompt */
{
	agt_textcolor(7);
	if (PURE_INPUT && n == 1) agt_textcolor(-1);
	if (n == 1) {
		agt_newline();
		gen_sysmsg(1, ">", MSG_MAIN, nullptr);
	}
	if (n == 2) agt_puts("? ");
	agt_textcolor(7);
}

void agt_waitkey(void) {
	if (BATCH_MODE || fast_replay)
		return;
	agt_getkey(0);
}


void wait_return(void) {
	writeln("          --- HIT ANY KEY ---");
	agt_waitkey();
}


rbool yesno(const char *s)
/* True for yes, false for no. */
{
	char c;

	writestr(s);
	writestr(" ");
	c = 'y';
	do {
		if (c != 'y')
			writestr("Please answer <y>es or <n>o. ");
		c = tolower(agt_getchar());
	} while (c != 'y' && c != 'n' && !quitflag);
	return (c == 'y');
}


void set_test_mode(fc_type fc) {
	const char *errstr;

	log_in = readopen(fc, fLOG, &errstr);

	if (make_test) {
		if (errstr == nullptr)
			fatal("Log file already exists.");
		log_out = writeopen(fc, fLOG, nullptr, &errstr);
		if (errstr != nullptr)
			fatal("Couldn't create log file.");
		logflag = 1;
		return;
	}

	logdelay = 0;
	if (errstr != nullptr)
		fatal("Couldn't open log file.");
	logflag = 2;

	script_on = 1;
	scriptfile = writeopen(fc, fSCR, nullptr, &errstr);
	if (errstr != nullptr)
		fatal("Couldn't open script file.");
}


#ifndef REPLACE_GETFILE

/* This opens the file refered to by fname and returns it */
static genfile uf_open(fc_type fc, filetype ext, rbool rw) {
	char *errstr;
	genfile f;

	if (rw) { /* Check to see if we are overwriting... */
		if (fileexist(fc, ext) && ext != fSCR) {
			if (!yesno("This file already exists; overwrite?"))
				/* That is, DON'T overwrite */
				return badfile(ext);
		}
		f = writeopen(fc, ext, NULL, &errstr);
	} else
		f = readopen(fc, ext, &errstr);
	if (errstr != NULL) writeln(errstr);
	return f;
}

static fc_type last_save = NULL;
static fc_type last_log = NULL;
static fc_type last_script = NULL;


genfile get_user_file(int ft)
/* ft= 0:script, 1:save 2:restore, 3:log(read) 4:log(write)  */
/* Should return file in open state, ready to be read or written to,
   as the case may be */
{
	/* int extlen;*/
	rbool rw;  /* True if writing, false if reading */
	filetype ext;
	genfile fd;
	fc_type def_fc, fc;
	char *fname;
	char *ftype;
	char *p, *q;

	switch (ft) {
	case 0:
		ftype = "script ";
		def_fc = last_script;
		rw = 1;
		ext = fSCR;
		break;
	case 1:
		ftype = "save ";
		def_fc = last_save;
		rw = 1;
		ext = fSAV;
		break;
	case 2:
		ftype = "restore ";
		def_fc = last_save;
		rw = 0;
		ext = fSAV;
		break;
	case 3:
		ftype = "log ";
		def_fc = last_log;
		rw = 0;
		ext = fLOG;
		break;
	case 4:
		ftype = "log ";
		def_fc = last_log;
		rw = 1;
		ext = fLOG;
		break;
	default:
		writeln("<INTERNAL ERROR: invalid file type>");
		return badfile(fSAV);
	}

	writestr(" ");
	writestr("Enter ");
	if (ftype != NULL) writestr(ftype);
	writestr("file name");
	if (def_fc != NULL) {
		char *s;
		s = formal_name(def_fc, ext);
		writestr(" (");
		writestr(s);
		writestr(")");
		rfree(s);
	}
	writestr(": ");

	if (PURE_INPUT) agt_textcolor(-1);
	fname = agt_input(4);
	if (PURE_INPUT) agt_textcolor(-2);

	/* Delete whitespace before and after the file name. */
	for (p = fname; isspace(*p); p++);
	if (*p == 0) { /* Line is all whitespace; use default if there is one */
		if (def_fc == NULL) {
			writeln("Never mind.");
			rfree(fname);
			return badfile(ext);
		} else {
			rfree(fname);
			fc = def_fc;
		}
	} else {   /* Line is _not_ all whitespace: we have a file name */
		for (q = fname; *p != 0; p++, q++)
			*q = *p;
		q--;
		while (isspace(*q)) q--;
		q++;
		*q = 0;
		fc = init_file_context(fname, ext);
	}

	fd = uf_open(fc, ext, rw);

	if (!filevalid(fd, ext)) {
		if (fc != def_fc) release_file_context(&fc);
		return fd;
	}

	switch (ft) {
	case 0:
		last_script = fc;
		break;
	case 1:
		last_save = fc;
		break;
	case 2:
		last_save = fc;
		break;
	case 3:
		last_log = fc;
		break;
	case 4:
		last_log = fc;
		break;
	}
	if (fc != def_fc) release_file_context(&def_fc);
	return fd;
}


void set_default_filenames(fc_type fc) {
	last_save = convert_file_context(fc, fSAV, NULL);
	last_log = convert_file_context(fc, fLOG, NULL);
	last_script = convert_file_context(fc, fSCR, NULL);
}



#endif  /* REPLACE_GETFILE */




void script(uchar onp) {
	if (onp == script_on)
		if (onp == 0) writeln("Scripting wasn't on.");
		else writeln("Scripting is already on.");
	else if (onp == 1) {
		scriptfile = get_user_file(0);
		if (filevalid(scriptfile, fSCR)) script_on = 1;
	} else if (filevalid(scriptfile, fSCR)) {
		close_pfile(scriptfile, 0);
		scriptfile = BAD_TEXTFILE;
		script_on = 0;
	}
}


void logon(void) {
	if (logflag & 1) {
		writeln("Already logging");
		return;
	}
	log_out = get_user_file(4);
	if (filevalid(log_out, fLOG))
		logflag |= 1;
}

void replay(int delay) {
	if (logflag & 2) return; /* Nested replays are meaningless */
	log_in = get_user_file(3);
	if (filevalid(log_in, fLOG)) {
		logflag |= 2;
		logdelay = delay;
	}
}


/* These two are intended to be called by the platform-dependent
   interface (e.g. if the user had chosen these from some general purpose
   menu) */
/* They're never called from the rest of the code */

void agt_save(void) {
	g_vm->saveGame();
}

void agt_restore(void) {
	doing_restore = 1;
}

void agt_restart(void) {
	doing_restore = 2;
}

void agt_quit(void) {
	doing_restore = 4;
}


/* This should be rmalloc'd */
static fc_type newgame_fc;

fc_type new_game(void) {
	return newgame_fc;
}

void agt_newgame(fc_type fc) {
	newgame_fc = fc;
	doing_restore = 3;
}

#if 0
static rbool end_cmd_options;
#endif

void set_default_options(void) {
	init_flags();
	flag = (rbool *)rmalloc(sizeof(rbool));
	debug_parse = 0;
	DEBUG_AGT_CMD = 0;
	DEBUG_EXEC_VERB = 0;
	DEBUG_DISAMBIG = 0;
	DEBUG_SMSG = 0;
}

void helpmsg(void) {
	/*
	  printf(" -i Try to use IBM character set.\n");
	  printf(" -1 IRUN Mode: Print messages in first person\n");
	  printf(" -h Print out this message\n");
	  printf(" -d Debug metacommand execution\n");
	  printf(" -t Test mode; see accompanying documentation. Implies -r.\n");
	  printf(" -c Create test file.\n");
	  printf(" -m Force descriptions to be loaded from disk.\n");
	#ifdef OPEN_AS_TEXT
	  printf(" -b Open data files as binary files.\n");
	#endif
	  printf("\nTechnical options (intended for debugging AGiliTy itself).\n");
	  printf(" -p Debug parser\n");
	  printf(" -x Debug verb execution loop\n");
	  printf(" -a Debug disambiguation system\n");
	  printf(" -s Debug STANDARD message handler\n");
	*/
}

#if 0
static rbool setarg(char **optptr) {
	if ((*optptr)[1] == '+') {
		(*optptr)++;
		return 1;
	}
	if ((*optptr)[1] == '-') {
		(*optptr)++;
		return 0;
	}
	return 1;
}
#endif

#define fixcase(c) tolower(c)

#if 0
void parse_options(char *opt, char *next) {
	/*
	if (opt[0]=='-' && opt[1]==0)
	{end_cmd_options=1;return;}
	for(;*opt!=0;opt++)
	switch(fixcase(*opt))
	  {
	  case 'p': debug_parse=setarg(&opt);break;
	  case 'a': DEBUG_DISAMBIG=setarg(&opt);break;
	  case 'd': DEBUG_AGT_CMD=setarg(&opt);break;
	  case 'x':DEBUG_EXEC_VERB=setarg(&opt);break;
	  case 's':DEBUG_SMSG=setarg(&opt);break;
	#ifdef MEM_INFO
	  case 'M': DEBUG_MEM=setarg(&opt);break;
	#endif
	  case 'm': descr_maxmem=0; break;
	  case 'i': fix_ascii_flag=!setarg(&opt);break;
	  case 't': BATCH_MODE=setarg(&opt); break;
	  case 'c': make_test=setarg(&opt); break;
	  case '1': irun_mode=setarg(&opt);break;
	#ifdef OPEN_FILE_AS_TEXT
	  case 'b': open_as_binary=setarg(&opt);break;
	#endif
	  default:printf("Do not recognize option %c\n",*opt);
	helpmsg();
	exit(EXIT_FAILURE);
	  }
	*/
}
#endif

#ifndef REPLACE_MAIN

int main(int argc, char *argv[]) {
	int i;
	char *gamefile;

	set_default_options();
	end_cmd_options = 0;
	gamefile = NULL;
	for (i = 1; i < argc; i++)
		if (argv[i][0] == '-' && !end_cmd_options)
			parse_options(argv[i] + 1, argv[i + 1]);
		else if (gamefile == NULL)
			gamefile = argv[i];
		else fatal("Please specify only one game\n");
	if (gamefile == NULL)  {
		helpmsg();
		exit(EXIT_FAILURE);
	}

	init_interface(argc, argv);
	/* From this point on, MUST use writestr/writeln or may
	   cause problems w/ the interfaces on some platforms
	   that have to keep track of cursor position */

	run_game(init_file_context(gamefile, fDA1));
	return EXIT_SUCCESS;
}

#endif /* REPLACE_MAIN */

} // End of namespace AGT
} // End of namespace Glk
