#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "struct.h"

/*
 *	Executive.c:	Version 1.10
 *	Author:		Alan Cox
 *	Last Changed:	14/12/90
 *
 *	Purpose:
 *		Provides a re-entrant executive for interpreting the system
 *	tables, and executing actions. Provides error reporting for the
 *	failure situations also.
 *
 *	Bugs & Limits
 *
 *	Functions Provided:
 *		ReportError,GoSplat,ExecTable,ExecLine,NextLineMove,GetCLine,
 *	SetCLine,Arg,TQuery,TQuery2,NQuery,NQuery2,DoConsult.
 *
 *	Functions Used:
 *		panic,DoRedraw,Exec_Cmd.
 *
 */

static LINE *nln;
extern TABLE *Table;
extern char **Messages;

tag SysFlags[256];
int CurTable= -1;
int CurLine=  -1;
int CurStat= -1;

void ReportError(file,line,m)
char *file;
int line;
int m;
{
	log_error("Error: File %s Line %d, Invalid item reference of %d.\n",file,line,m);
	log_error("Table %d Line %d   (MAXITEM=%d).\n",CurTable,CurLine,NObs());	
	panic();
}

void ReportLines()
{
	fprintf(stderr,"Table %d Line %d Stat %d  (MAXITEM=%d).\n",CurTable,CurLine,CurStat,NObs());
	fflush(stderr);
}

void MsgError(file,line,m)
char *file;
int line;
char *m;
{
	log_error("Error: File %s Line %d, %s.\n",file,line,m);
	log_error("Table %d Line %d   (MAXITEM=%d).\n",CurTable,CurLine,NObs());	
	panic();
}

void GoSplat()
{
	FILE *f=fopen("fail_report","a");
	fprintf(f,"Caught signal: Table %d Line %d Stat %d.\n",CurTable,CurLine,CurStat);
	fprintf(f,"Abandoning all hope!\n");
	fclose(f);
	panic();
}

/*
 *	Run a table - REENTRANT
 */

struct StackFrame *StackContext()
{
	struct StackFrame *Frame=(struct StackFrame *)malloc(
				sizeof(struct StackFrame));
	if(Frame==NULL)
	{
		log_error("Out of memory.\n");
		panic();
	}
	bzero((char *)Frame,sizeof(*Frame));
	Frame->Previous=SysStack;
	SysStack=Frame;
	return(Frame);
}

void RestoreContext()
{
	struct StackFrame *t=SysStack;
	SysStack=t->Previous;
	free((char *)t);
}
 
void ExecTable(n)
int n;
{
	DoExecTable(Table[n],n);
}

int DoExecTable(n,nm)
TABLE n;
int nm;
{
	static int Recurse=0;
	LINE *ol=nln;
	int ot=CurTable;
	int pl=CurLine;
	int os=CurStat;
	if(Booted==0)
		return(0);	/* Dont run tables till boot complete */
				/* ie - tables from queries! */
	if(n==NULL)
		return(0);	/* Nothing to run */
	CurStat=0;
	if(Recurse>MAXRECURSE)
	{
		log_error("[EXECUTIVE]: Recursive Trap\n");
		return(-1);
	}
	StackContext();
	SeekFor=0;
/*	printf("EXECT-OK\n");*/
	Recurse++;
	CurLine=0;
	CurTable=nm;
	nln=n;
	while(1)/*nln[0][0]!=-1)*/
	{
		if(ExecLine(*nln)==5)	/* DONE */
			break;
		nln++;
		CurLine++;
	}
	nln=ol;
	CurTable=ot;
	CurLine=pl;
	CurStat=os;
	if(CurTable==-1)
		DoRedraw();	/* Redraw of screen status */
	Recurse--;
	RestoreContext();
	return(0);
}

static LINE tl;

/*
 *	Run a line REENTRANT
 */

ExecLine(n)
LINE n;
{
	extern int SeekFor;
	LINE otl=tl;
	tl=n;
/*	printf("[%d,%d,%d]\n",tl[0],tl[1],tl[2]);*/
	if(tl[0]!=-1&&tl[0]!=NUM(SysFlags[3]))	/* Verb ? */
	{
		tl=otl;
		return(1);
	}
	if(tl[1]!=-1&&tl[1]!=NUM(SysFlags[1]))	/* Noun1 */
	{
		tl=otl;
		return(1);
	}
	if(tl[2]!=-1&&tl[2]!=NUM(SysFlags[2]))	/* Noun2 */
	{
		tl=otl;
		return(1);
	}
/*	printf(".(%d,%d,%d)\n",NUM(SysFlags[3]),NUM(SysFlags[1]),NUM(SysFlags[2]));*/
	CurStat=0;
	tl+=3;	/* Point at data */
	while(*tl!=-1)
	{
		int nf,v;
		nf=0;
/*		printf("{%d}",*tl);*/
		if(*tl==255)	/* NOT /'-' marker*/
		{
			nf=1;
			tl++;
/*			printf("{%d}",*tl);			*/
		}
		if(*tl==0&&SeekFor==0)	/* DONE */
		{
			tl=otl;
			return(5);
		}
		v=ExecCmd(*tl);	/* Do function */
		CurStat++;
		if((v&&nf)||((!v)&&(!nf)))
		{
			tl=otl;
			return(0);	/* Condition failed */
		}
		tl++;
	}
	tl=otl;
	return(0);
}

void NextLineMove(v)	/* Shift line */
int v;
{
	nln+=v;
	CurLine+=v;
}

GetCLine()
{
	return(CurLine);
}

void SetCLine(v)
int v;
{
	NextLineMove(v-GetCLine()-1);
}

/*
 *	Obtain an argument
 */

tag Arg()
{
	tag v;
	v= *++tl;
	if(IFOBJ(v)&&VAL(v)>30999)	/* ?x */
	{
		return(LOC(ISOBJ(VAL(v)-31000)));
	}
	if(IFNUM(v)&&VAL(v)>29999)	/* !x */
	{
		return(SysFlags[VAL(v)-30000]);
	}
	return(v);
}

char *TQuery(i,def,c)
tag i;
char *def;
int c;
{
	tag sa_flags[19];
	if(OBJECT(i)->ob_Table==NULL)
		return(def);
	memcpy((char *)sa_flags,(char *)SysFlags,19*sizeof(tag));
       /*	OBJ(i);	/* check is an object */
	SysFlags[8]=SysFlags[0];
	SysFlags[0]=i;
	SysFlags[1]= ISNUM(-1);
	SysFlags[2]= ISNUM(-1);
	SysFlags[3]= ISNUM(c);
	SysFlags[17]= ISNUM(-1);
	if(DoExecTable(OBJECT(i)->ob_Table,-i)==-1)
	{
		log_error("Reference was: %s [query code %d] default=%s\n",
			OBJECT(i)->ob_Name,c,def);
	}
	c=SysFlags[17];
	memcpy((char *)SysFlags,(char *)sa_flags,19*sizeof(tag));
	if(VAL(c)==-1)
		return(def);
	else
		return(Messages[MSG(c)]);
}

char *TQuery2(i,def,c,d)
tag i;
char *def;
int c,d;
{
	tag sa_flags[19];
	if(OBJECT(i)->ob_Table==NULL)
		return(def);
	memcpy((char *)sa_flags,(char *)SysFlags,19*sizeof(tag));
	/*OBJ(i);*/
	SysFlags[8]=SysFlags[0];
	SysFlags[0]=i;
	SysFlags[1]= ISNUM(-1);
	SysFlags[2]= ISNUM(-1);
	SysFlags[3]= ISNUM(c);
	SysFlags[17]= ISNUM(-1);
	SysFlags[18]= ISNUM(d);
	if(DoExecTable(OBJECT(i)->ob_Table,-i)==-1)
	{
		log_error("Reference was: %s [query code %d] default=%s\n",
			OBJECT(i)->ob_Name,c,def);
	}
	c=SysFlags[17];
	memcpy((char *)SysFlags,(char *)sa_flags,19*sizeof(tag));
	if(VAL(c)==-1)
		return(def);
	else
		return(Messages[MSG(c)]);
}

tag NQuery(i,def,c)
tag i;
int def;
int c;
{
	tag rv=def;
	tag sa_flags[19];
	if(OBJECT(i)->ob_Table==NULL)
		return(def);
	memcpy((char *)sa_flags,(char *)SysFlags,19*sizeof(tag));
	/*OBJ(i);*/
	SysFlags[8]=SysFlags[0];
	SysFlags[0]=i;
	SysFlags[1]= ISNUM(-1);
	SysFlags[2]= ISNUM(-1);
	SysFlags[3]= ISNUM(c);
	SysFlags[17]= ISNUM(def);
	SysFlags[18]= ISNUM(-1);
	if(DoExecTable(OBJECT(i)->ob_Table,-i)==-1)
	{
		log_error("Reference was: %s [query code %d] default=%s\n",
			OBJECT(i)->ob_Name,c,def);
	}
	if(VAL(SysFlags[18])!= -1)
		rv=VAL(SysFlags[18]);
	memcpy((char *)SysFlags,(char *)sa_flags,19*sizeof(tag));
	/*NUM(rv);*/
	return(rv);
}

tag NQuery2(i,def,c,d)
tag i;
int def;
int c,d;
{
	tag rv;
	tag sa_flags[19];
	if(OBJECT(i)->ob_Table==NULL)
		return(def);
	memcpy((char *)sa_flags,(char *)SysFlags,19*sizeof(tag));
	SysFlags[8]=SysFlags[0];
	SysFlags[0]=i;
	SysFlags[1]=ISNUM(-1);
	SysFlags[2]=ISNUM(-1);
	SysFlags[3]= ISNUM(c);
	SysFlags[17]= ISNUM(def);
	SysFlags[18]=ISNUM(d);
	if(DoExecTable(OBJECT(i)->ob_Table,-i)==-1)
	{
		log_error("Reference was: %s [query code %d] default=%s\n",
			OBJECT(i)->ob_Name,c,def);
	}
	rv=SysFlags[17];
	if(VAL(SysFlags[18])==-1)
		rv=def;
	memcpy((char *)SysFlags,(char *)sa_flags,19*sizeof(tag));
	return(rv);
}

void DoConsult(i,v,n,n2)
tag i;
int v,n,n2;
{
	tag sa_flags[19];
	if(OBJECT(i)->ob_Table==NULL)
		return;
	memcpy((char *)sa_flags,(char *)SysFlags,19*sizeof(tag));
	SysFlags[8]=SysFlags[0];
	SysFlags[0]=i;
	SysFlags[1]=ISNUM(n);
	SysFlags[2]=ISNUM(n2);
	SysFlags[3]=ISNUM(v);
	if(DoExecTable(OBJECT(i)->ob_Table,-i)==-1)
	{
		log_error("Reference was: %s [consult code %d]\n",
			OBJECT(i)->ob_Name,v);
	}
	memcpy((char *)SysFlags,(char *)sa_flags,19*sizeof(tag));
	return;
}