/**************************************************************
*		Popup error reporting package (sayerr.c)                *
***************************************************************/
#include <stdio.h>
#include <stdarg.h>
#include <conio.h>
#include <bios.h>
#include <string.h>
#include <dos.h>
#include <process.h>
#include <errno.h>
#include "popup.h"
#include "\tc\myincs\mouse.h"
static char *level_msg[] = {"WARNING","ERROR"};
static char *pmsg = "Press <Enter> or <ESC> ...";

/*	The way the error/trace windows work:  If errw/msgw is NULL, then
	an error/trace message is popped up at errx/msgx, erry/msgy.
	Else, the window errw/msgw (which should have been already
	popped up) will be used.  If errw/msgw is already defined, then
	the errx/msgx and erry/msgy coordinates are ignored. */

int errx = CTRWIN;			/* default to center of the screen */
int erry = CTRWIN;
windesc *errw = NULL;		/* default to popup window */
int msgx = CTRWIN;			/* same for messages */
int msgy = CTRWIN;
windesc *msgw = NULL;

void numnewlines(char *s, int *n, int *w)
/*	Count number of newlines in the string s, also, return
	maximum width of the lines of the message */
{
	int j,k;
	for (*n=0,j=0,*w=0,k=0; (s[j] != 0); j++,k++) {
		if (s[j] == '\n') {
			(*n)++;
			if (k > *w) *w = k; k = 0;
		}
		if (k > *w) *w = k;
	}
}

void popmsg(int x,int y,char *msg,char *title,char soundout,wincolors *wc)
/*	Pops up the message msg at (x,y) - (absolute coordinates),
	with title as the window header.  If soundout != 0, then the
	alarm will sound.  It will then wait for a key press before
	unpopping the window.
	The message can contain newlines, which are accounted for in
	the size of the window.  Note: it SHOULD usually contain a new
	line at the end, or your message might scroll off the screen.
	The (x,y) cursor positions use the same codes as for popup windows. */
{
	int wd, ht, c, k;
	windesc *w;
	/* Compute height and width of iwndow */
	numnewlines(msg,&ht,&wd);
	/* add in forder, and prompt message to size computations */
	ht += 3;
	if (wd < (strlen(pmsg)+1)) wd = strlen(pmsg)+3; else wd += 3;
	w = draw_win(x, y, wd, ht, title, popup, wc);
	mouse_off(1);
	cprintf(msg);
	cprintf(pmsg);
	mouse_on(1);
	if (soundout) beep();
	do {
		while(!(k = mouse_trigger(0)));
		if (k == CTRLC) exit(0);					/* control c aborts */
		if (k != CRKEY && k != ESCKEY) beep();	/* only cr or esc allowed */
	} while (k != CRKEY && k != ESCKEY);
	rmv_win(w);
}

void reperr(int level, char *msg)
/* Reports the error in the error window.
	Level = 0 means warning, level = 1 means error. */
{
	windesc *wsave;
	if (errw == NULL) {	/*popup error window */
		popmsg(errx, erry, msg, level_msg[level], 1, &errcolors);
	}
	else {	/* else route to existing error window */
		wsave = curr_win;
		slct_win(errw);
		mprintf("%s: %s", level_msg[level], msg);
		slct_win(wsave);
	}
}

void repmsg(char *msg)
/*	Reports the message in the message window. */
{
	windesc *wsave;
	if (msgw == NULL) {	/* popup message window */
		popmsg(msgx, msgy, msg," Msg ", 0, &msgcolors);
	}
	else {	/* else route to existing message window */
		wsave = curr_win;
		slct_win(msgw);
		mprintf("Msg: &s", msg);
		slct_win(wsave);
	}
}

void sayerr(int ferr, int errflag, int lno, char *pname, char *fmt,...)
/*	The parameters work as follows:
	ferr			if 1, then the last DOS error message is printed
	errflag		if 1, treat as warning, 2 treat as error, else
					just treat as a message
	lno,pname	if pname = "", they're ignored, else they're treated
					as a line number and source file name.
	fmt,...		a format string followed by optional arguments
					NOTE: formatting should not exceed 255 characters */
{
	va_list arg_ptr;
	char t[255];
	int j;
	if (*pname) {
		j = sprintf(t, "On line %d in pgm %s\r\n", lno, pname);
	}
	else j = 0;
	if (ferr == 1) {
		j += sprintf(t+j, "%s\r", strerror(errno));	/* add last DOS error */
	}
	va_start(arg_ptr,fmt);			/* point to optional arguments */
	vsprintf(t+j, fmt, arg_ptr);	/* add rest of formatted string */
	va_end(arg_ptr);
	switch(errflag) {
		case 1:
			reperr(0,t);		/* just a warning */
			break;
		case 2:
			reperr(1,t);		/* an error */
			break;
		default:
			repmsg(t);			/* or a plain old message */
	}
}

unsigned int getkey(void)
/*	Waits for and returns the scan-ascii code of the next key available.
	Does not echo.  Pops up an abort window on ctrl-c. */
{
	windesc *w;
	int k;
	while(1) {	/* loop until non-ctrl-c key, or abort */
		k = bioskey(0);
		if (k == CTRLC) {
			w = draw_win(CTRWIN, CTRWIN, 25, 3, "", popup, &errcolors);
			k = bioskey(0);
			rmv_win(w);
			if ((k == 0x1559) || (k == 0x1579)) {	/* "Y" or "y" */
				mouse_reset();	/* don't forget to reset the mouse */
				exit(1);
			}
		} else break;
	}
	return k;
}

void beep(void)
/* sounds the bell */
{
	sound(50);
	delay(25);
	nosound();
}
