/* Standard TOS funktionen bekannt machen: 			*/

#include <tos.h>
#include <vdi.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ext.h>
#include <screen.h>

#include "gfx.h"
#include "gui.h"
#include "editor.h"
#include "script.h"
#include "keys.h"
#include "sets.h"
#include "ezxml/ezxml.h"
#include "main.h"


#ifdef __AHCC__
	void    vq_chcell( int handle, int *rows, int *columns );
	#define vq_chcells vq_chcell
#endif

#define DEC_VERSION 	0.3
#define INFO 		"HELP=HELP, RETURN=TOGGLE, Q=QUIT, Fx=SELECT SET, SHIFT+Fx=SAVE SET"
char * filtermask[] = {"*.PR*", "*.AC*", "*.CP*"};

#define PRG_FILTER	0
#define ACC_FILTER	1
#define CPX_FILTER	2

 /*#define DEBUG 1 */
 
#define COL_LEN 14


#ifndef WITHOUT_GFX	/*	Grahical boot manager? */
#define LIST_START 4
#else
#define LIST_START 2
#endif



/* quit variable, program exits				*/
/* when quit == 1							*/
short quit;

/* Current filter for directory listing 	*/
char filter = PRG_FILTER;

/* list of files for each filter: */
#define FLIST_MAX 127
char filelist[3][FLIST_MAX+1][14];

short cursor = -1;
short numfiles[3] = {0,0,0};

long timeout = 3;
char * basepath[3] = {"C:\\AUTO", "C:", "C:"};
char resort[3];

/* id, name and handle of current loaded set: */
short currentset = -1;
char currentscript[SCRIPT_MAX_LEN+1];
const char * setname = NULL;
ezxml_t set=NULL;
ezxml_t cfgitem;
ezxml_t ezxmlh;
char * default_config_str = ""
	"<config>"
		"<prgpath>C:\\AUTO</prgpath>"
		"<cpxpath>C:</cpxpath>"
		"<accpath>C:</accpath>"
		"<timeout>3</timeout>"
		"<lastscript></lastscript>"
	"</config>";
char * examplescript = ""
	" #initial script for set: %s\n"
	" #supported commands:\n"
	" #parameters marked with * are optional\n"
	" #pause *message   -  waits for any keypress\n"
	" #echo *message    -  prints message to screen or just newline\n"
	" #set echo off     -  turn on/off verbose command output\n"
	" #copy src dst     -  copy file from source to destination\n"
	" #rewrite file match replace 	- replace all matching strings in file\n"
	"";
char * cfg_titles[] = {"AUTO Path", "ACC Path", "CPX Path", "Boot Timeout"};
char * cfg_items[] = {"prgpath", "accpath", "cpxpath", "timeout"};

void dbg(char * str)
{
	Cconws( str );
	Cconws( "\r\n" );
	getch();
}

void die( char * str ) 
{
	Cconws( str );
	Cconws("\n");
	Cconws("Press any key...\n");
	getch();
	exit( 1 );
}


void draw_list_header( void )
{
#ifdef WITHOUT_GFX
	fillspace(0, 1, c_cols, 0);
#endif
	textxy( 2,           LIST_START, (filter==PRG_FILTER) ? 1 : 0, "PRG:" );
	textxy( 2+COL_LEN, 	LIST_START, (filter==ACC_FILTER) ? 1 : 0, "ACC:" );
	textxy( 2+COL_LEN*2, LIST_START, (filter==CPX_FILTER) ? 1 : 0, "CPX:" );	
}

void draw_list_item( int _filter, int idx )
{ 
	short inv = ( _filter == filter && idx == cursor ) ? 1 : 0;
	int y = idx + LIST_START + 1;
	if( (idx >= numfiles[_filter]) || (idx < 0) ){
		return; 
	}
	if( y >= c_rows-3 )
		y=c_rows-3;
	textxy( 2+(_filter*COL_LEN), y, inv, "            ");
	textxy( 2+(_filter*COL_LEN), y, inv, filelist[_filter][idx] );
}

void draw_list( short _filter )
{
	short i;
	for( i=0; i<numfiles[_filter]; i++ ){
		draw_list_item( _filter, i );
	}
}


void draw_main( void ){
	short i,x;
	for( i=LIST_START; i<c_rows-1; i++ ){
		fillspace(0, i, c_cols, 0);
	}
	draw_list_header();
	for( x=0; x<3; x++) {
		draw_list( x );
	}
}

void draw_list_sets( char active )
{
	short i, inv;
	short maxidx;
	ezxml_t lset;
	const char * name;
	char spare[255];

	maxidx = 9;
		
	for( i=0; i <= maxidx; i++){
		name = " (empty) ";
		lset = get_set_by_pos( i ) ;
		if( lset != NULL ){
			name = ezxml_attr( lset, "name");
		}
		sprintf(spare, "F%02d %s", i, name );
		inv = ( i==(short)active ) ? 1 : 0;
		textxy( 2, i+LIST_START+2, inv, spare );
	}

}

void list_sets(void){

	char sh, ascii;
	short i;
	short code, loaded = 0;

	for( i=LIST_START; i<c_rows-1; i++ ){
		fillspace(0, i, c_cols, 0);
	}

	textxy( 2, LIST_START,   1, "Boot sets:");
	textxy( 2, LIST_START+1, 0, "----------");
	draw_list_sets( -1 );

	getkey(&sh, &code, &ascii);
	switch( code ) {
	
		case F1_BASE:
		case F1_BASE+1*0x100:
		case F1_BASE+2*0x100:
		case F1_BASE+3*0x100:
		case F1_BASE+4*0x100:
		case F1_BASE+5*0x100:
		case F1_BASE+6*0x100:
		case F1_BASE+7*0x100:
		case F1_BASE+8*0x100:
		case F1_BASE+9*0x100:
			load_set( (short)(code - F1_BASE)/0x100 );
			loaded = 1;
		break;
		
		default: 
			
		break;
	}
	draw_main();
	if( set == NULL || loaded == 0){
		draw_info( INFO );
	}
}

void help( void ) 
{
	short line=LIST_START;
	int i,n=0;
	for( i=0; i<3; i++){
		if(numfiles[i] > n)
			n = numfiles[i];
	}
	for( i=LIST_START; i<=n+2; i++ ){
		fillspace(0, i, c_cols, 0);
	}
	textxy( 1, line++, 1, "Mainscreen Keys: ");
	textxy( 1, line++, 0, " ");
	textxy( 1, line++, 0, "Help:           Show this screen.");
	textxy( 1, line++, 0, "Enter:          Toogle active/inactive");
	textxy( 1, line++, 0, "ESC/Q/q:        Continue boot / save changes.");
	textxy( 1, line++, 0, "Shift+A:        Move file up.");
	textxy( 1, line++, 0, "Shift+Y:        Move file down.");
	textxy( 1, line++, 0, "Shift+F1-F10:   Save Set 1-10.");
	textxy( 1, line++, 0, "F1-F10:         Load Set 1-10.");
	textxy( 1, line++, 0, "C:              Configuration.");
	textxy( 1, line++, 0, "D:              Delete current set.");
	textxy( 1, line++, 0, "E:              Edit Script for current set.");
	textxy( 1, line++, 0, "L:              List available sets.");
	textxy( 1, line++, 0, "S:              Save without exit.");
	Cconin();
	draw_main();
}


char * cfg_str( const char * name, char * def)
{
	char * ret = def;
	ezxml_t item;
	if( ezxmlh == NULL || name == NULL )
		return("");
	item = ezxml_child(ezxmlh, name);
	if( item != NULL ){
		ret = item->txt;
	}
	if( ret == NULL )
		ret = def;
	return( ret );
}

void init_config_vars( void )
{
	FILE * fp;
	char drive;
	static char def_prg[128];
	static char def_misc[128];
	
	if( ezxmlh == NULL ) {
		ezxmlh = ezxml_parse_file("SBOOT.XML");
	}
	if( ezxmlh == NULL ){
		fp = fopen("SBOOT.XML", "w");
		if( fp ){
			fwrite( default_config_str, strlen(default_config_str), 1, fp );
			fclose( fp );
			ezxmlh = ezxml_parse_file( "SBOOT.XML" );
		}
	}
	if( ezxmlh != NULL ) {
		drive = 'A'+Dgetdrv();
		sprintf( def_prg, "%c:\\AUTO", drive );
		basepath[0] = cfg_str( "prgpath", def_prg );
		
		sprintf( def_misc, "%c:", drive );
		basepath[1] = cfg_str( "accpath", def_misc );
		basepath[2] = cfg_str( "cpxpath", def_misc );
		timeout = atoi( cfg_str("timeout", "3") );
		strncpy( currentscript, cfg_str("lastscript", ""), SCRIPT_MAX_LEN );
	}
}


/* draw the global configuration */
void draw_config(void){

	short line=LIST_START, inv;
	int i,n=0;
	char spare[200];
	char * cfgstr = NULL;

	for( i=0; i<3; i++){
		if(numfiles[i] > n)
			n = numfiles[i];
	}
	for( i=LIST_START; i<=n+2; i++ ){
		fillspace(0, i, c_cols, 0);
	}
	textxy( 1, line++, 1, "Configuration: ");
	textxy( 1, line++, 0, " ");
	for( i=0; i<sizeof(cfg_items)/4; i++ ){
		cfgstr = cfg_str( cfg_items[i], "" );
		inv = (cursor == i) ? 1 : 0;  
		sprintf((char*)&spare, "%12s: %s", cfg_titles[i], cfgstr );
		textxy( 1, line++, inv, (char*)&spare );	
	}
}

void draw_config_item( short n ){
	
	char * cfgstr;
	char spare[200];
	short inv;
	
	if( n<0 || n>(sizeof(cfg_items)/4)-1 )
		return;
	
	cfgstr = cfg_str( cfg_items[n], "");
	inv = (cursor == n) ? 1 : 0;
	sprintf( (char*)&spare, "%12s: %s", cfg_titles[n], cfgstr );
	textxy( 1, LIST_START+2+n, inv, (char*)&spare );
}


const char * ask_for_string( char * query, const char * current, short max )
{
	static char buf[200];
	int i;
	if( max > 199 ) 
		max = 199;
	if( current == NULL ){
		sprintf( (char*)&buf, "%s:", query );
		textxy( 0, c_rows-2, 1, buf );
	}
	else {
		sprintf( (char*)&buf, "%s (%s):", query, current );
		textxy( 0, c_rows-2, 1, buf );
	}
	Rev_on();
	scanf("%s", &buf);
	buf[max]=0;
	i = 0;
	while( buf[i] != 0){
		if( buf[i] == 10 || buf[i] == 13 ){
			buf[i] = 0;
			break;
		}
		i++;
	}
	Rev_off();
	fillspace( 0, c_rows-2, c_cols, 0);
	if( strlen((char*)&buf) < 1 )
		return( current );
	return( (char*)&buf );
}


/* move file from / to - this is not an simple rename */
long move_file( char * src, char * dst)
{
	long err, count;
	short srcf, dstf;
	static buf[8192];
	
	srcf = Fopen( src, 0 );
	dstf = Fcreate( dst, 0 );
	
	if( srcf < 0 || dstf < 0 ){
		printf("Error open file\r\n");
		if( srcf > 0)
			Fclose( srcf );
		if( dstf > 0 )
			Fclose( srcf );
		return( -2 );
	}
	
	count = Fread( srcf, 8192, &buf );
	if( count > 0 ){
		do{
			Fwrite(dstf, count, &buf );
			count = Fread( srcf, 8192, &buf);
		}while( count > 0 );
	}
	
	Fclose(dstf);
	Fclose(srcf);	
	
	err = Fdelete( src );
	if( err != 0 ) 
		return( err );
		
	return( 0 );
}


/* sort files matching _filter mask on disk */
void sort_files(char _filter)
{
	short i;
	char * anim[] = {"|", "/", "-", "\\"};  
	long err;
	char buf[256];
	char buf2[256];
	
	sprintf(buf, "%s\\SBOOTTMP", basepath[_filter] );
	if( Dcreate(buf) < 0 ){
		draw_info("Error creating temp. Dir!");
		sleep(1);
	}
	
	for( i=0; i<numfiles[_filter]-1; i++){
		sprintf(buf, "%s Processing: %s", anim[i%4], filelist[_filter][i]);
		draw_info(buf);
		sprintf(buf2, "%s\\SBOOTTMP\\%s", basepath[_filter], (char*)&filelist[_filter][i]);
		sprintf(buf, "%s\\%s", basepath[_filter], filelist[_filter][i]);
		err =  move_file( buf, buf2 );
		if(err != 0 ){
			sprintf(buf, "Error sorting files. Restore files from %s.", (char*)&buf2 );
			draw_info(buf);
			sleep(1);
			return;
		}
	}

	for( i=0; i<numfiles[_filter]-1; i++) {
		sprintf(buf, "%s Processing: %s", anim[i%4], &filelist[_filter][i]);
		draw_info(buf);
		sprintf(buf, "%s\\%s", basepath[_filter], &filelist[_filter][i]);
		sprintf(buf2, "%s\\SBOOTTMP\\%s", basepath[_filter], &filelist[_filter][i]);
		if( move_file( buf2, buf ) != 0 ){
			sprintf( buf, "Error sorting files. Restore files from %s.", &buf2 );
			draw_info(buf);
			sleep(1);
			return;
		}
	}
	
	sprintf(buf, "%s\\SBOOTTMP", basepath[_filter] );
	if( Ddelete(buf) < 0 ) {
		draw_info("Error deleting temp. directory!");
		sleep(1);
	}
	return;
}

void save_settings( void )
{
	FILE * fp;
	char * cfg;
	int i=0;
	
	for( i=0; i<3; i++) {
		if( resort[i] == 1  ){
			sort_files( i );
			resort[0] = 0;
		}
	}
	fp = fopen("SBOOT.XML", "w");
	if( fp ){
		cfg = ezxml_toxml(ezxmlh);
		fwrite( cfg, strlen(cfg), 1, fp );
		fclose( fp );
		free( cfg );
	}
	draw_info("Settings saved.");
}


/* init variables and envioronement */
void init( void )
{
	
	init_config_vars();
	init_gui();
}

void set_active( short index , short oldfilter )
{
	short y, old=cursor;

	if( numfiles[filter] == 0 ){
		/* verstecken ? */
		return;
	} 
	
	/* wenn max. index erreicht wurde, 					*/
	/* cursor wieder auf 0 setzen...					*/
	if( index >= numfiles[filter] ) {
		index = 0;
	}

	/* bzw. wenn erster ueberschritten, dann auf letzten*/
	if( index < 0 ) {
		index = numfiles[filter] - 1;
	} 

	/* wenn der cursor schonmal gezeichnet wurde, 		*/
	/* dann alte ausgabe mit leerzeichen ueberschreiben:*/
	cursor = index;
	if( old >= 0 ) {
		/*textxy( 0+(filter*COL_LEN), cursor + LIST_START, 0, " ");	*/
		draw_list_item( oldfilter, old );
	}
	
	
	/* index neu setzen und bildschirmpos. berechnen */
	y = cursor + LIST_START+1;

	/* markierung ausgeben: */
	/*textxy( 0+(filter*COL_LEN), y, 0, ">");*/
	draw_list_item( filter, cursor );

	/* und den alpha cursor um eins nach links 			*/
	/* da sonst der buchstabe des aktuellen eintrags 	*/
	/* vom cursor ueberdeckt ist: 						*/
	Goto_pos( y, 0+(filter*COL_LEN) );
}


void fill_list( char * path) 
{
	int err;
	struct ffblk blk;

	numfiles[filter] = 0;
	err = findfirst( path, &blk, 0xff);
	while( err == 0 && numfiles[filter] <=FLIST_MAX ){
		strncpy( filelist[filter][numfiles[filter]], blk.ff_name, 14 );
		numfiles[filter]++;
		err = findnext( &blk );
	}
}

void set_filter( char _filter )
{
	char * base = basepath[_filter];
	
	char path[255];
	memset( &path, 0, 255 );
	filter = _filter;
	sprintf(path, "%s\\%s", base, filtermask[filter] );
	fill_list( path );
}

void move_cur( signed char direction )
{
	char prevfile[14];
	short bak; 
		
	if( cursor+direction < 0 )
		return;
	if( cursor+direction >= numfiles[filter] )
		return;
	
	bak = cursor;
	set_active( cursor+direction, filter );
	cursor = bak;
	strcpy(prevfile, filelist[filter][cursor+direction]);
	strcpy(filelist[filter][cursor+direction], filelist[filter][cursor]);
	strcpy(filelist[filter][cursor], prevfile);
	cursor += direction;
	draw_list_item( filter, bak );
	draw_list_item( filter, cursor );
	resort[filter] = 1;
}

void toggle_cur( void )
{
	long n;
	char fullpath[255];
	char newpath[255];
	char * base = basepath[ filter ];
	char * curfile = filelist[filter][cursor];
	char end = 'G';
	char oldend = ' ';

	if( numfiles[filter] <= 0 ) {
		return;
	}

	if( (strlen(curfile) + strlen(base) + 2) < 255 ) {
		sprintf( fullpath, "%s\\%s", base, curfile );
		n = strlen(curfile);
		oldend = curfile[n-1];
		/* Programm auf inaktiv geschaltet? */
		if( (curfile[n-1] == 'X' &&  filter != CPX_FILTER ) 
			|| (curfile[n-1] == 'Z' && filter == CPX_FILTER ) ){
			if( filter == ACC_FILTER )
				end = 'C';
			if( filter == CPX_FILTER )
				end = 'X';
			curfile[n-1] = end;
		} else {

			/* Programm deaktivieren */
			if( filter == CPX_FILTER ){
				curfile[n-1] = 'Z';
			} else {
				curfile[n-1] = 'X';
			}
		}
		sprintf( newpath, "%s\\%s", base, curfile );
		if( Frename( 0, (const char*)&fullpath, (char*)&newpath ) != 0 ) {
			/* Datei konnte nicht umbennant werden, */
			/* liste wiederherstellen */
			curfile[n-1] = oldend;
		} else {
			draw_list_item( filter, cursor );
		}
	} 
}

void delete_set( short index ) 
{
	const char * attr;
	const char * yesno;
	char query[255];
	ezxml_t lset = NULL;
	for( lset = ezxml_child(ezxmlh, "set"); lset; lset = lset->next){
		attr = ezxml_attr(lset, "pos" );
		if( attr != NULL ){
			if( atoi(attr) == index  ){
				sprintf(query, "Delete Set %s? (yes/no)", ezxml_attr(lset, "name") );
				yesno = ask_for_string(
						query,
						NULL,
						3
					);
				if(strncmp("yes", yesno, 3) == 0 ){
					ezxml_remove( lset );
				}
			}	
		}
	}
	draw_title( NULL );
	draw_info( INFO );

	/* set default filter and draw list: */
	set_filter( CPX_FILTER );
	set_filter( ACC_FILTER );
	set_filter( PRG_FILTER );	
	draw_main();
}

void write_set( short index, short create ) 
{
	int i,x;
	size_t l;
	const char * attr;
	ezxml_t lset = NULL, item = NULL;
	static char spare[255];
	char * settag[4] = {"prg", "acc", "cpx", "custom"};
	char * query = "Enter new Set name";
	char removed = 0;
	char * script=NULL;

	item = NULL;
	if( create != 0 ) {
		setname = NULL;
	}
	for( lset = ezxml_child(ezxmlh, "set"); lset; lset = lset->next){
		attr = ezxml_attr(lset, "pos" );
		if( attr != NULL ){
			if( atoi(attr) == index  ){
				if( removed == 0 && create != 0 ) {
					setname = ask_for_string(
						query,
						ezxml_attr(lset, "name"),
						12 
					);
				}
				ezxml_remove( lset );
				removed++;
			}	
		}
	}
	
	if( setname == NULL ) {

		if( create == 0 ) 
			return;
			
		setname = ask_for_string(
			query,
			NULL,
			12
		);
		if( setname == NULL ){
			setname = spare;
			sprintf((char*)setname, "SET%d", index );
		}
	}
	
	set = ezxml_add_child(ezxmlh, "set", 0);
	currentset = index;
	
	sprintf( spare, "%d", index);
	ezxml_set_attr_d(set, "pos", spare );
	ezxml_set_attr_d(set, "name", setname );
	item = ezxml_add_child(set, "script", 0);
	printf("removed: %ld\n");
	if( removed > 0  ){
		ezxml_set_txt_d(item, currentscript );
	}
	else{
		ezxml_set_txt_d(item, "" );
	}
	for( i=0; i<4; i++ ){
		if( i <= CPX_FILTER ){
			for( x=0; x<numfiles[i]; x++){
				l = strlen( filelist[i][x] );
				if( i == CPX_FILTER && filelist[i][x][l-1] == 'Z' 
					|| i < CPX_FILTER && filelist[i][x][l-1] == 'X'
				)
					continue;
				item = ezxml_add_child(set, settag[i], 0);
				ezxml_set_txt_d(item, (char*)&filelist[i][x]);
			}
		}
	}
	sprintf((char*)&spare, "Added set %s for F%d.", setname, index+1 );
	draw_title( NULL );
	draw_main();
	draw_info((char*)spare);
}

ezxml_t load_set( short index )
{
	struct ffblk blk;
	long err;
	short i,l;
	const char * attr;
	char found;
	ezxml_t item = NULL, item2 = NULL;
	char cpath1[255];
	char cpath2[255];
	char cpath3[255];
	char * path1 = cpath1;
	char * path2 = cpath2;
	char * path3 = cpath3;
	char * settag[4] = {"prg", "acc", "cpx"};
	char * enabled;
	
	const char * attrs[] = {"pos", "name"};
	char disabled[14];
	
	setname = NULL;
	set = NULL;
	currentset = -1;
	
	for( set = ezxml_child(ezxmlh, "set"); set; set = set->next){
		attr = ezxml_attr( set, "pos" );
		if( attr != NULL ){
			if( atoi(attr) == index ){
				setname = ezxml_attr( set, "name" );
				currentset = index;
				item = ezxml_child( set, "script" );
				strncpy(currentscript, ezxml_txt( item ), SCRIPT_MAX_LEN );
				currentscript[SCRIPT_MAX_LEN]=0;
				break;
			}
		}
	}
	
	if( set == NULL ){
		draw_info("Set not found!");
		currentset = -1;
		setname = NULL;
		return ( set ); 
	} 

	/* 
		set lastscript, so that no load of set is required when booting
	*/
	if( strlen(currentscript) > 0 ) {
		item = ezxml_child(ezxmlh, "lastscript");
		if( item == NULL ) {
			item = ezxml_add_child(ezxmlh, "lastscript", 0);
		}
		ezxml_set_txt_d(item, currentscript );
	}
	
	for( i=0; i<=CPX_FILTER; i++ ){
		sprintf( path1, "%s\\%s", basepath[i], filtermask[i]);
		err = findfirst( path1, &blk, 0xff);
		while( err == 0 ){
			found = 0;
			for( item = ezxml_child(set, settag[i]); item; item=item->next){
				enabled = ezxml_txt( item );
				
				if( strcmp((char*)&blk.ff_name, (char*)enabled) == 0 ){
						/* found  file as enabled */
						found = 1;
						break;						
				}
				strcpy(disabled, enabled);
				l = strlen((char*)&disabled)-1;
				if( i == CPX_FILTER )
					disabled[l] = 'Z';
				else 
					disabled[l] = 'X';
				
				if( strcmp( (char*)&blk.ff_name, (char*)&disabled) == 0 ){
					/* found file as disabled */
					found = 1;
					sprintf(path3, "%s\\%s", basepath[i], enabled );
					sprintf(path2, "%s\\%s", basepath[i], &blk.ff_name );
					Frename( 0, path2, path3 );
				} 
			} 
			if( found == 0 ) {
				/* file not found in xml, so disable it... */
				
				strcpy( (char*)&disabled, (char*)&blk.ff_name );
				l = strlen((char*)&disabled)-1;
				if( i == CPX_FILTER )
					disabled[l] = 'Z';
				else 
					disabled[l] = 'X';
				if( strcmp((char*)&disabled, (char*)&blk.ff_name) != 0 ){
					sprintf( path2, "%s\\%s", basepath[i], (char*)&blk.ff_name );
					sprintf( path3, "%s\\%s", basepath[i], (char*)&disabled );
					Frename( 0, path2, path3 );
				}
			}
			err = findnext( &blk );
		}	
		
	}
	set_filter( CPX_FILTER );
	set_filter( ACC_FILTER );
	set_filter( PRG_FILTER );
	draw_main();
	if( setname == NULL )
		sprintf(path1, "Loaded set F%d.", index+1 );
	else 
		sprintf(path1, "Loaded set %s.", setname );
	draw_info(path1);
	return( set );
}

void config( void )
{
	short prevcursor;
	char ascii,sh;
	short code, key;
	char ig=0;
	short exit = 0;
	const char * input;
	char changed = 0;
	ezxml_t item;

	cursor = 0;		
	draw_config();
	draw_info("ESC/Q=Leave, ENTER=Edit item.");

	do{
		ig = 0;
		key = getkey(&sh, &code, &ascii);
		switch( code  ){
	
			case CURS_DOWN:
				prevcursor = cursor; 
				cursor = ((cursor + 1) % (sizeof(cfg_items)/4));  
				draw_config_item( prevcursor );
				draw_config_item( cursor );
				ig=1;
			break;

			case CURS_UP:
				prevcursor = cursor;
				cursor = ((cursor - 1) % (sizeof(cfg_items)/4));
				if( cursor < 0 ){
					cursor = (sizeof(cfg_items)/4)-1;
				}
				draw_config_item( prevcursor );
				draw_config_item( cursor );
				ig = 1;
			break;
			
			case ESC:
				exit = 1;
			break;
			
			default: 
				/* printf("Code: 0x%x, key: 0x%x, ascii: 0x%x\n",code, key, ascii ); */ 
			break;
		}
		
		if( ig != 1 && exit != 1){
			switch( key ){
				case 'Q':
				case 'q':
					exit = 1;
				break;
				
				case 10:
				case 13:
				input = cfg_str( cfg_items[cursor], "NULL" );
				input = ask_for_string( "New Value",  input, 12);
				if( (input != NULL) && (strlen(input) > 0) && (ezxmlh != NULL) ) {
					item = ezxml_child(ezxmlh, cfg_items[cursor]);
					if( item ){  
						ezxml_set_txt_d( item, input );
						init_config_vars();
						fillspace(0, cursor, c_cols, 0);
						draw_config();
						changed = 1;
					}
				}
				break;
				
				default: break;
			}
		}
	} while ( exit != 1 );
	if( changed == 1 ) {
		set_filter( CPX_FILTER );
		set_filter( ACC_FILTER );
		set_filter( PRG_FILTER );	
	}
	cursor = prevcursor;
	draw_info( INFO );
	draw_main();
}


void input( void )

{
	char ascii,sh;
	short code, key, old;
	char spare[255];
	char ig=0;	
	char * tmp;
	key = getkey(&sh, &code, &ascii);
	/*
	sprintf(&spare, "cook: %04x, sh: %02x, code: %04x, ascii: %0x2",
		key, sh, code, ascii
	);
	textxy(1, 1, 0, &spare );
	*/
	switch( code  ){
	
		case CURS_DOWN: 
			set_active( cursor + 1, filter );
			ig=1;
		break;

		case CURS_UP:
			set_active( cursor - 1, filter );
			ig = 1;
		break;
		
		case HELP:
			help();
			draw_main();
			ig = 1;
		break;
		
		case F11_BASE:
		case F11_BASE+1*0x100:
		case F11_BASE+2*0x100:
		case F11_BASE+3*0x100:
		case F11_BASE+4*0x100:
		case F11_BASE+5*0x100:
		case F11_BASE+6*0x100:
		case F11_BASE+7*0x100:
		case F11_BASE+8*0x100:
		case F11_BASE+9*0x100:
			write_set( (short)(code - F11_BASE)/0x100, 1 );
			ig = 1;
		break;
		
		case F1_BASE:
		case F1_BASE+1*0x100:
		case F1_BASE+2*0x100:
		case F1_BASE+3*0x100:
		case F1_BASE+4*0x100:
		case F1_BASE+5*0x100:
		case F1_BASE+6*0x100:
		case F1_BASE+7*0x100:
		case F1_BASE+8*0x100:
		case F1_BASE+9*0x100:
			load_set( (short)(code - F1_BASE)/0x100 );
			ig = 1;
		break;
		
		case CURS_LEFT:
			if( filter > 0 ){
				old = filter;
				set_filter( (filter-1) % 3 );
				draw_list_item( old, cursor );
				cursor = (cursor <= (numfiles[filter]-1)) ? cursor : (numfiles[filter]-1);  
				draw_list_header();
				set_active( cursor, old );
			}
			ig = 1;
		break;
		
		case CURS_RIGHT:
			old = filter;
			set_filter( (filter+1) % 3 );
			draw_list_item( old, cursor );
			cursor = (cursor <= (numfiles[filter]-1)) ? cursor : 0 ;  
			draw_list_header();
			set_active( cursor, old );
			ig = 1;
		break;
		
		case ESC: 
			ig = 1;
			quit = 1;
		break;
		
		case CTRL_S:
			if( ascii == 19 ){ 
				save_settings(); 
				ig = 1;
			}
		break;
	}
	
	if( ig == 1 )
		return;
	
	switch( key ) 
	{
		case 'q': 
		case 'Q':
			quit = 1;
		break;

		case '\n':
		case '\r':
		case ' ':
			toggle_cur();
		break;
	
		case 'A':
			move_cur( -1 );
		break;
		
		case 'Y':
			move_cur( 1 );
		break;
		
		case 'C':
		case 'c':
			config();
		break;
		
		case 'l':
		case 'L':
			list_sets();
		break;

		case 'S':
			save_settings();
		break;
		
		case 'D':
			if( set != NULL ) 
				delete_set(currentset);
		break;
		
		case 'E':
		case 'e':
			if( set != NULL ) {
				if( ezxml_attr(set, "script") != NULL ){
					sprintf(currentscript, "%s", ezxml_attr(set, "script") );
				}
				if( strlen(currentscript) < 1 ){
					sprintf(currentscript, examplescript, setname );
				}

				sprintf( spare, "Edit script for Set: %s", setname);
				tmp = edit_text(spare , currentscript );
				if ( tmp ) {
					strncpy( currentscript, tmp, SCRIPT_MAX_LEN );
					currentscript[SCRIPT_MAX_LEN] = 0;
					write_set(currentset, 0);
				} else {
					if( ezxml_attr(set, "script") != NULL ){
						sprintf(currentscript, "%s", ezxml_attr(set, "script") );
					}
				}
				end_edit_text();
				clear_workarea();
				draw_title( NULL );
				draw_info( INFO );

				/* set default filter and draw list: */
				set_filter( CPX_FILTER );
				set_filter( ACC_FILTER );
				set_filter( PRG_FILTER );	
				draw_main();
			} else {
				draw_info("You must load a set before editing it's script!");
			}
		break;

		default: break;
	}
}


int main(void)
{
	long avail = 0;
	long prev=0, cur;
	char spare[255];

	init();
	draw_title( NULL );
	draw_info( INFO );

	/* set default filter and draw list: */
	set_filter( CPX_FILTER );
	set_filter( ACC_FILTER );
	set_filter( PRG_FILTER );	
	draw_main();
	sprintf((char*)&spare, "%d", (short)timeout);
	textxy( c_cols-1,  c_rows-1, 0,  spare);
	/* wait for character, or timeout */
	prev = cur = clock()/CLK_TCK;
	while( timeout >= 0 ) {
		avail = Cconis();
		if( avail != 0 )
			break;
		cur = (long)(clock()/CLK_TCK);
		if( cur > prev ){
			prev = (long)cur;
			timeout--;
			if( timeout >= 0 ){
				sprintf(spare, "%d", (short)timeout);
				textxy( c_cols-1, c_rows-1, 0,  (char*)&spare);
			}
		}
	}
	
	if( avail == 0 ) {
		goto end;
	}
	/* clear the last time output: */
	textxy( c_cols-1, c_rows-1, 1,  " ");
	
	/*
	screen = Physbase();
	*(long*)(screen) = 0xFF0000;
	*/
	
	/* handle user input: */
	while ( quit != 1 ) {
		input();
	}
	
	save_settings();

end: 
	
	Clear_home();
	
	if( strlen( currentscript ) > 1 ){
		execute_script( currentscript );
	}
	
	if( vdivh != 0 )
		v_clsvwk( vdivh );
	if( vdiph != 0 )
		v_clswk( vdiph );
	if( ezxmlh ) 
		ezxml_free( ezxmlh );
	return( 0 );
}

