//***************************************************************************
//
//								ABLERR.CPP
//
//***************************************************************************

#include "MW4Headers.hpp" 

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>

#ifndef ABLGEN_H
	#include "ablgen.h"
#endif

#ifndef ABLERR_H
	#include "ablerr.h"
#endif

#ifndef ABL_H
	#include "abl.h"
#endif

#ifndef GAMEOS_HPP
	#include <gameos\gameos.hpp>
#endif

bool gShowScriptErrors;

//***************************************************************************
namespace ABL
{

//----------
// EXTERNALS
	extern char*    tokenp;
	extern long     execLineNumber;
	extern long     lineNumber;
	extern long     FileNumber;
	extern char     SourceFiles[MAX_SOURCE_FILES][MAXLEN_FILENAME];
	extern ABLModulePtr CurModule;

	char ABLError::m_DetailErrorString[ABL_DETAIL_ERROR_STRING_SIZE];

//extern BOOL		debuggerCommandFlag;

//---------------------------------------------------------------------------

//----------------------
// SYNTAX ERROR messages

	char* syntaxErrorMessages[] = {
		"No syntax error",										// 0
		"Syntax error",
		"Too many errors",
		"Cannot open source file",
		"Unexpected end-of-file",
		"Invalid number",
		"Invalid fraction",
		"Invalid exponent",
		"Too many digits",
		"Real out of range",
		"Integer out of range",									// 10
		"MIssing right parenthesis",
		"Invalid expression",
		"Undefined identifier",
		"Redefined identifier",
		"Unexpected token",
		"Incompatible types",
		"Nesting too deep",
		"Code segment overflow",
		"Missing equal",
		"Missing semi-colon",									// 20
		"Invalid constant",
		"Not a constant identifier",
		"No record types",
		"Missing colon (ouch)",
		"Not a type identifier",
		"Invalid type",
		"Missing end",
		"Invalid identifier usage",
		"Too many subscripts",
		"Missing right bracket",								// 30
		"Incompatible assignment",
		"Missing until",
		"Missing then",
		"Invalid for control",
		"Missing identifier",
		"Missing to",
		"Missing period",
		"Missing module or fsm",
		"Missing library",
		"Already forwarded",									// 40
		"Invalid reference parameter",
		"Wrong number of parameters",
		"Missing begin",
		"Missing endvar",
		"No function nesting",
		"Missing code",
		"Missing endif",
		"Missing endwhile",
		"Missing endfor",
		"Missing endfunction",									// 50
		"Missing endmodule",
		"Missing endlibrary",
		"Missing do",
		"Invalid index type",
		"Missing comma",
		"Too many static variables",
		"Missing endcase",
		"Missing endswitch",
		"Missing constant",
		"Bad language directive parameter",						// 60
		"Unknown language directive",
		"Too Many Formal Parameters",
		"Too Many Local Variables",
		"Code was found outside of a state block in an fsm",
		"Cannot nest states within functions or other states",
		"Cannot forward declare states",
		"Missing endstate",
		"Cannot trans to a non state",
		"Cannot us the trans keyword in a non fsm",
		"A state was forwarded but not actually instantiated"
	};

//---------------------------------------------------------------------------

//-----------------------
// RUNTIME ERROR messages

	char* runtimeErrorMessages[] = {
		"Runtime stack overflow",
		"Infinite Loop",
		"Nested function call",
		"Unimplemented feature",
		"Value out of range",
		"Division by zero",
		"Invalid function argument",
		"Invalid case value",
		"Abort"
	};

//---------------------------------------------------------------------------

//--------
// GLOBALS

	long  errorCount = 0;
	ABLError *ablError;
  jmp_buf abl_jmp_buf;

	extern DebuggerPtr debugger;

//***************************************************************************

	void ABL_Fatal (long errCode, char* s)
	{

		STOP((s));
	}

//---------------------------------------------------------------------------

	void ABL_Assert (bool test, long errCode, char* s)
	{

#ifdef _DEBUG
		if (!test)
			STOP((s));
#endif
	}

//***************************************************************************

	void syntaxError (long errCode)
	{

		char errMessage[MAXLEN_ERROR_MESSAGE];
		sprintf(errMessage, "SYNTAX ERROR %s [line %d] - (type %d) %s\n", SourceFiles[FileNumber], lineNumber, errCode, syntaxErrorMessages[errCode]);
		if (ablError)
		{
			ablError->String (syntaxErrorMessages[errCode]);
			ablError->File (SourceFiles[FileNumber]);
			ablError->Line (lineNumber);
			ablError->Code (errCode);
			longjmp (abl_jmp_buf,1);
		}
		else
			ABL_Fatal(0, errMessage);

		*tokenp = NULL;
		errorCount++;

		if (errorCount > MAX_SYNTAX_ERRORS)
		{
			sprintf(errMessage, "Way too many syntax errors. ABL aborted.\n");
			ABL_Fatal(0, errMessage);
		}
	}

//---------------------------------------------------------------------------

	void runtimeError (long errCode)
	{

		char message[512];

		if (debugger)
		{
			sprintf(message, "RUNTIME ERROR:  [%d] %s", errCode, runtimeErrorMessages[errCode]);
			debugger->print(message);
			sprintf(message, "MODULE %s", CurModule->getName());
			debugger->print(message);
			if (FileNumber > -1)
				sprintf(message, "FILE %s", CurModule->getSourceFile(FileNumber));
			else
				sprintf(message, "FILE %s: unavailable");
			debugger->print(message);
			sprintf(message, "LINE %d", execLineNumber);
			debugger->print(message);
			debugger->debugMode();
		}

		sprintf(message, "ABL RUNTIME ERROR %s [line %d] - (type %d) %s\n", (FileNumber > -1) ? CurModule->getSourceFile(FileNumber) : "unavailable", execLineNumber, errCode, runtimeErrorMessages[errCode]);
		ABL_Fatal(-ABL_ERR_RUNTIME_ABORT, message);
	}

//***************************************************************************


	char *ABL_runtimeErrorString (char *str,int stringlen)
	{
		char line[25];
	
		*str = 0;
		if (ABL::FileNumber > -1)
		{
//			Str_Cat (str,"  FILE: ",stringlen);
			Str_Cat (str,CurModule->getSourceFile(FileNumber),stringlen);
		}
//		Str_Cat (str,"   LINE: ",stringlen);
	
		Str_Cat (str,"(",stringlen);
		itoa (execLineNumber,line,10);
		Str_Cat (str,line,stringlen);
		Str_Cat (str,")",stringlen);

		Str_Cat (str,"  MODULE: ",stringlen);
		Str_Cat (str,CurModule->getName (),stringlen);
		
		return str;
	}
	
}
