#include <stdio.h>

#include "adltypes.h"
#include "adlprog.h"
#include "adlrun.h"
#include "adldef.h"
#include "virtmem.h"
#include "vstring.h"

struct	pagetab
    codetab;
struct	actrec
    actlist[ NUMACT ];
address
    ip;
int16
    stack[ STACKSIZE ],
    sp,
    bp,
    numact,
    curract,
    Verb,
    Prep,
    Iobj,
    Inoun,
    Imod,
    NumDobj,
    Conj[ NUMDO ],
    Dnoun[ NUMDO ],
    Dobj[ NUMDO ],
    Dmod[ NUMDO ],
    *vecverb,
    vecsize = NUMVEC,
    demons[ NUMDEM],
    fuses[ NUMFUS ],
    ftimes[ NUMFUS ],
    f_actors[ NUMFUS ],
    numd,
    numf,
    currturn,
    prompter,
    wordwrite,
    numsave,
    restarted,
    debug,
    header,
#if AMIGA
    scrwidth = 70,
#else
    scrwidth = 79,
#endif
    numcol,
    Phase,
    /* The following 6 vars are not actually used in adlrun,
       but we need to define them for the loader. */
    NUM_VARS,
    NUM_ROUTS,
    NUM_OBJS,
    NUM_VERBS,
    NUM_PREP;
char
    *inname = "adlcomp.out",
    *r_name = "\0",
    *USAGE = "Usage: adlrun [filename] [-d] [-h] [-r savefile]\n",
    *H_STR = "%-48sScore: %-4d  Moves: %-4d\n",
    tempc[ NUMTEMP ],		/* Temporary strings */
    savec[ NUMSAVE ];		/* "Permanent" strings */
FILE
    *infile = NULL;
FILE
    *wordfile = (FILE *)0,
    *scriptfile = (FILE *)0;

struct exit_place
    exits[ 5 ];

#if 0 && MSDOS
	extern char
	    *getml();
#	define calloc( size, num )	getml( (long)(size * num) )
#endif

#define	islegal(c)	(c&&(c!=' ')&&(c!='\t')&&(c!='\n')&&(c!='-'))


int adlmain( int argc, char **argv )
{
    getadlargs( argc, argv );
    while( 1 ) {
	if( SET_EXIT( 4 ) == 0 ) {
	    break;
	}
    }
    if( restarted ) {
	init( 0 );
    }
    else {
	init( 1 );
    }
    driver();
    return 0;
}


void getadlargs( int argc, char **argv )
{  
    int
	i;
    char
	*getnext();

    for( i = 1; i < argc; i++ ) {
	if( *argv[ i ] == '-' ) {
	    switch( *++argv[ i ] ) {
	    case 'd' :
		debug = 1;
		break;
	    case 'h' :
		header = 1;
		break;
	    case 'r' :
		r_name = getnext( &i, argv );
		break;
	    default  :
		fputs( USAGE, stderr );
		exit( -1 );
	    }
	}
	else if( !strcmp( inname, "adlcomp.out" ) ) {
	    inname = argv[ i ];
	}
	else {
	    fputs( USAGE, stderr );
	    exit( -1 );
	}
    }
}


void init( int16 first )
{
    int16
	me,
	*temp;

    if( first ) {
	vecverb = (int16 *)calloc( vecsize, sizeof( int16 ) );
	if( vecverb == (int16 *)0 ) {
	    error( ADLERR_MEMORY );
	}
	insertkey( ",",		COMMA,	0, 0 );
	insertkey( "and",	CONJ,	0, 0 );
	insertkey( "but",	CONJ,	1, 0 );
	insertkey( ".",		SEP,	0, 0 );
	insertkey( "!",		SEP,	0, 0 );
	insertkey( "?",		SEP,	0, 0 );
	insertkey( "then",	SEP,	0, 0 );

	rand_seed();
        infile = fopen( inname, "rb+" );
	if( !infile ) {
	    fprintf( stderr, "Error opening file %s\n", inname );
	    exit( -1 );
	}

	head_setup();
	sayer( "ADL interpreter - Version 4.0 - December 7, 1994\n" );
	sayer( "Copyright 1985-1994 by Ross Cunniff\n" );
	sayer( "All rights reserved.\n" );

	/* Read in the input file */
	fseek( infile, 0L, 0 );
	fread( &hdr, sizeof( struct header ), 1, infile );
	if( hdr.magic != M_ADL ) {
	    fprintf( stderr, "%s: Not an ADL datafile.\n", inname );
	    head_term();
	    exit( -1 );
	}

	/* Read the arrays */

	read_symtab( infile, &hdr.symindex );
	loadarray( (char **)&routspace,	&hdr.routindex, 1 );
	loadarray( (char **)&str_tab,	&hdr.strtabindex, 1 );
	loadarray( (char **)&prepspace,	&hdr.prepindex, 1 );
	loadarray( (char **)&verbsyn,	&hdr.vsindex, 1 );
	loadarray( (char **)&nounspace,	&hdr.nounindex, 1 );

	/* Initialize virtual code and string stuff */
	vsinit( infile, hdr.strindex.ptr, 1, tempc, savec, &numsave, str_tab );
	vm_init( infile, hdr.codeindex.ptr, &codetab, 0 );

    }	/* if( first ) */

    temp = stack;
    loadarray( (char **)&temp,		&hdr.varindex, 0 );
    loadarray( (char **)&verbspace,	&hdr.verbindex, first );
    loadarray( (char **)&objspace,	&hdr.objindex, first );

    if( scriptfile != (FILE *)0 ) {
	fclose( scriptfile );
	scriptfile = (FILE *)0;
    }

    if( wordwrite ) {
	fclose( wordfile );
    }

    /* Initialize some variables (This is for ($spec 2) -> restart) */
    sp = bp = NUMVAR;
    ip = curract = numd = numf = 0;
    wordwrite = numsave = prompter = currturn = 0;

    actlist[ 0 ].linebuf = actlist[ 0 ].savebuf;
    *actlist[ 0 ].linebuf = '\0';
    actlist[ 0 ].interact = 1;
    numact = 0;

    clearmacro();

    if( *r_name ) {
	restoregame( r_name );
	r_name = "\0";
    }
    else {
	callone( _START );
    }

    restarted = 0;
}


void driver( void )
{
    int
	i;

    /* Outermost adlrun loop (never exited except to quit adlrun) */
    while( 1 ) {

	vsflush();	/* Clear out the temporary strings */
	curract = 0;

	/* Daemon loop */
	for( curract = numact - 1; curract >= 0; curract-- ) {
	    Phase = 0;
	    if( SET_EXIT( 1 ) == 0 ) {
		if( SET_EXIT( 0 ) == 0 ) {
		    execdems();
		}
	    }
	}
	CLR_EXIT( 0 );

	/* Main actor loop */
	for( curract = numact - 1; curract >= 0; curract-- ) {
	    if( SET_EXIT( 1 ) != 0 ) {
		continue;
	    }

	    /* Delete actor if not interactive and line buffer is empty */
	    if( (*PSTRING == 0) && (INTERACT == 0) ) {
		delactor( CURRACT );
		continue;		/* with for loop */
	    }

	    /* Read and parse the user's input */
	    initvars();
	    while( 1 ) {
		if( SET_EXIT( 3 ) == 0 ) {
		    break;
		}
	    }
	    if( get_buffer() < 0 ) {
		continue;
	    }

	    /* Call the appropriate routines */
	    callrouts();

	    CLR_EXIT( 3 );
	}	/* for( curract ... ) */
    }		/* outer while( 1 ) */
}


char *getnext( int *which, char **argv )
{
    if( *++argv[ *which ] ) {
	return argv[ *which ];
    }
    else {
	return argv[ ++*which ];
    }
}


void rand_seed( void )
{
    long
	time( long * );

    SRAND( (int)time( (long *)0 ) );
}

/* VARARGS */
void loadarray( char **a, struct adldir *d, int16 first )
{
    if( first && (d->numobjs * d->objsize) ) {
	*a = calloc( d->numobjs, d->objsize );
	if( *a == (char *)0 )
	    error( ADLERR_MEMORY );
    }
    fseek( infile, d->ptr, 0 );
    fread( *a, d->numobjs, d->objsize, infile );
}


void getchunk( char **s, char *word )
{
    if( !**s ) {
	*word = '\0';
	return;
    }
    if( islegal( **s ) ) {
	while( islegal( **s ) ) {
	    *word++ = *((*s)++);
	}
    }
    else if( **s == '\t' ) {			/* Expand the tab */
	strcpy( word, "        " );
	word[ 8 - (numcol % 8) ] = '\0';
	(*s)++;
	return;
    }
    else {
	*word++ = *((*s)++);
    }
    *word = '\0';
}


int get_buffer( void )
{
    /* Loop for user input */
    while( 1 ) {
	/* Get a non-empty line */
	if( !*PSTRING ) {
	    PSTRING = &SAVEBUF[ 0 ];
	    u_prompt();
	    getstring( PSTRING );
	}

	/* Parse the string */
	if( !parse() ) {
	    *PSTRING = '\0';
	    initvars();		/* Failed parse; init the variables	*/
	    if( INTERACT ) {
		continue;	/* with While (interactive actor, try again) */
	    }
	    else {
		delactor( CURRACT );
	    	return -1;	/* from While (the actor needs to die) */
	    }
	}
	else {
	    break;		/* The parse was successful */
	}
    }
    return 0;
}


int16 noun_exists( int16 adj, int16 noun )
{
    int16
	t;

    for( t = nounspace[ noun ]; t != 0; t = objspace[ t ].others ) {
	if( objspace[ t ].adj == adj ) {
	    return t;
	}
    }
    return -1;
}

/*** EOF adlrun.c ***/
