// Copyright 1994 Brad Pitzel
//
// Feel free to use/distribute/modify as long as credit/copyrights for myself 
// are included.

// a layer on top of the svgalib library.
// Routines to setup the initialize the screen/svgalib/etc, restore back
// to text when all done, throw up a few messages/prompts, get simple
// string input from the user, etc..

#include "Ui.h"

GraphicsContext Ui::backscreen;
GraphicsContext Ui::physicalscreen;


int Ui::vgaMode;
int Ui::virtualScn=0;

int Ui::fontHt;
int Ui::fontW;

struct termios Ui::old;

// set drawing to virtualScn screen
void Ui::drawToVirtual() 
	{
	if (!virtualScn) {
		// Create virtual screen.
		gl_setcontextvgavirtual(vgaMode);
		gl_setclippingwindow(0,0,WIDTH-1,HEIGHT-1);
		gl_getcontext(&backscreen);
		virtualScn=1;
		}
	gl_setcontext(&backscreen); 
	}


void Ui::init()
	{
	
	vga_init();

	// graphics mode to use
	vgaMode = G320x200x256;

	if (!vga_hasmode(vgaMode)) {
		printf("Mode not available.\n");
		exit(-1);
	}

	// trap signals to restore text mode, etc
	signal(SIGHUP, die);
	signal(SIGINT, die);
	signal(SIGQUIT, die);
	signal(SIGILL, die);
	signal(SIGTRAP, die);
	signal(SIGABRT, die);
	signal(SIGFPE, die);
	signal(SIGKILL, die);
	signal(SIGSEGV, die);
	signal(SIGTERM, die);
	signal(SIGSTOP, die);
	signal(SIGTSTP, die);
	signal(SIGTTIN, die);
	signal(SIGTTOU, die);

		
	vga_setmode(vgaMode);
	gl_setcontextvga(vgaMode);	// Physical screen context.
	gl_setclippingwindow(0,0,WIDTH-1,HEIGHT-1);
	gl_getcontext(&physicalscreen);
	gl_setrgbpalette();
	
	initFont();


	int tmp;
	struct termios current;
	
	tmp = tcgetattr(fileno(stdin), &Ui::old);
	if (tmp)
		printf("tcgetattr = %d\n", tmp);

	tmp = tcgetattr(fileno(stdin), &current);
	if (tmp)
		printf("tcgetattr = %d\n", tmp);

	current.c_lflag = current.c_lflag & ~ (ICANON | ECHO ); 
	current.c_cc[VMIN] = 1;
	current.c_cc[VTIME] = 1;	/* 0.1 sec intercharacter timeout */

	tmp = tcsetattr(fileno(stdin), TCSAFLUSH, &current);
	if (tmp)
		printf("tcsetattr = %d\n", tmp);



}

void Ui::die(int x)
{
	Ui::restore();

	//system("textmode");

	cerr << "Ui::Received signal " << x << endl;

	exit(-1);
}


void Ui::restore()
{

// restore tty
int tmp;
tmp = tcsetattr(fileno(stdin), 0, &Ui::old);
if (tmp)
	printf("tcsetattr = %d\n", tmp);


// svgalib
if (virtualScn)
	gl_freecontext(&backscreen);

vga_setmode(TEXT);

}


void Ui::initFont()
{
void *font;

fontHt = 8;
fontW = 8;

font = malloc(256*fontW*fontHt*BYTESPERPIXEL);
gl_expandfont( fontW, fontHt, 255, gl_font8x8, font );
gl_setfont( fontW, fontHt, font );
}



void Ui::message( int y, const char *msg )
{
int x1, y1, x2, y2;
int mx, my, len;

len = strlen(msg);

mx = (WIDTH - len*fontW) >> 1;
x1 = mx - 1;
x2 = mx + len*fontW;

my = y;
y1 = my - 1;
y2 = my + fontHt;

// put box around text
gl_line(x1,y1,x2,y1,255);
gl_line(x1,y2,x2,y2,255);
gl_line(x1,y1,x1,y2,255);
gl_line(x2,y1,x2,y2,255);

gl_write( mx, my, (char *)msg );
}


// prompt user, return 1=yes, 0=no
char Ui::yesNo( const char *msg )
{
	char result=-1;
	GraphicsContext GCold;
	
	gl_getcontext(&GCold);

	drawToPhysical();
	
	String s = msg;
	s += " (y/n) ?";

	Ui::message( (const char *)s );

	while (result<0)
		switch (getchar())
			{
			case 'y':
			case 'Y':
				result = 1;
				break;
			
			case 'n':
			case 'N':
				result = 0;
				break;
			}
	
	//gl_clearscreen(0);
	gl_setcontext(&GCold);
	return result;
}


// get text input from user
// len must be 1 less than msg buffer to allow for 0 at end
int Ui::input( int x, int y, char *msg, int len )
{
int pos=0;
int xp=x;
int done=0;
int key=0;
char buf[1];

//make sure input buf is null terminated
*(msg+len)=0;

gl_write( x, y, msg );

while(!done)
	{
	drawCursor(xp,y);
	key = getchar();
	hideCursor(xp,y);
	
	switch (key) {

		case 10:
			done   = 1;
			break;

		case 127:	// backspace
			if (pos>0)
				{
				pos--;
				xp -= fontW;
				gl_writen(xp,y,1," ");
				*(msg+pos)=' ';
				}
	
		default: //regular characters, i.e a-z,0-9,etc..
			if ( (pos<len) && (key >= ' ') && (key<127) )
				{
				buf[0] = (char)key;
				*(msg+pos) = buf[0];
				gl_writen(xp,y,1,buf);
				pos++;
				xp += fontW;
				}
		}
	
	}

// NULL terminate string
*(msg+pos)=0;

return key;
}


inline void Ui::drawCursor(int x, int y)
	{
	gl_line(x, y+fontHt, x+fontW-1, y+fontHt, 255);
	}

inline void Ui::hideCursor(int x, int y)
	{
	gl_line(x, y+fontHt, x+fontW-1, y+fontHt, 0);
	}
