#include "munga.h"
#pragma hdrstop

#include "gaugrend.h"
#include "lamp.h"
#include "mover.h"
#include "terrain.h"
#include "app.h"

// #define LOCAL_TEST

#if defined(LOCAL_TEST)
#	define Test_Tell(n) DEBUG_STREAM << n
#else
#	define Test_Tell(n)
#endif

 #define PROFILE_GAUGES

#if defined(TRACE_GAUGE_RENDERER)
	BitTrace Gauge_Renderer("Gauge Renderer");
#endif

//#######################################################################
// Miscellaneous utilities
//#######################################################################
int
	LookupTable::Search(const char *string)
{
	Check_Pointer(this);
	Verify(string != NULL);

	LookupTable
		*table = this;

	for(; table->typeString!=NULL; ++table)
	{
		if (stricmp(string, table->typeString) == 0)
		{
			break;
		}
	}
	Check_Fpu();
	return table->value;
}


//#######################################################################
// GaugeSymbol
//#######################################################################

GaugeSymbol::GaugeSymbol(
	GaugeSymbol **head_pointer,
	const char *new_label,
	GaugeInterpreterOffset new_offset,
	Logical new_resolved
)
{
	Check(this);
	Check_Pointer(head_pointer);
	Check_Pointer(new_label);
	Test_Tell(
		"GaugeSymbol::GaugeSymbol(" << head_pointer <<
		"," << new_label <<
		"," << new_offset <<
		"," << new_resolved <<
		")\n"
	);

	nextSymbol = *head_pointer;
	*head_pointer = this;

	Str_Copy(label, new_label, sizeof(label));
	offset = new_offset;
	resolved = new_resolved;
	Check_Fpu();
}

GaugeSymbol::~GaugeSymbol()
{
	Check(this);
	Check_Fpu();
}

Logical
	GaugeSymbol::TestInstance() const
{
	return True;
}

//#######################################################################
// GaugeSymbolTable
//#######################################################################
GaugeSymbolTable::GaugeSymbolTable(char *table_pointer)
{
	Test_Tell(
		"GaugeSymbolTable::GaugeSymbolTable(" << ((void *) table_pointer) <<
		")\n"
	);
	Check_Pointer(this);

	head = NULL;
	tablePointer = table_pointer;
	Check_Fpu();
}

GaugeSymbolTable::~GaugeSymbolTable()
{
	Test_Tell(
		"GaugeSymbolTable::~GaugeSymbolTable()\n"
	);
	Check(this);

	GaugeSymbol
		*symbol,
		*next_symbol;

	for(symbol=head; symbol!=NULL; symbol=next_symbol)
	{
		Check(symbol);

		next_symbol = symbol->nextSymbol;
		Unregister_Object(symbol);
		delete symbol;
	}
	head = NULL;
	Check_Fpu();
}

Logical
	GaugeSymbolTable::TestInstance() const
{
	return True;
}

void
	GaugeSymbolTable::Add(const char *label, GaugeInterpreterOffset new_offset)
{
	Check(this);
	Check_Pointer(label);

	Test_Tell(
		"GaugeSymbolTable::Add(" << label <<
		"," << new_offset <<
		")\n"
	);

	GaugeSymbol
		*symbol;

	//-------------------------------------------------
	// Check to see if this label already exists
	//-------------------------------------------------
	for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol)
	{
		Check(symbol);

		if (stricmp(label, symbol->label) == 0)
		{
			Test_Tell("Exists.\n");
			//-------------------------------------------------
			// It DOES exist. Has it already been resolved?
			//-------------------------------------------------
			if (!symbol->resolved)
			{
				Test_Tell("Unresolved.\n");
				//-------------------------------------------------
				// No, resolve all forward references to it
				//-------------------------------------------------
				// Forward references (references to undefined
				// labels) are saved as a singly-linked list
				// of offsets within the table itself: each
				// reference to the label contains an offset to
				// the previous reference.  The list is
				// terminated by an offset of -1.
				//-------------------------------------------------
				GaugeInterpreterOffset
					table_offset,
					next_offset,
					*offset_pointer;

				for (
						table_offset=symbol->offset;
						table_offset>=0;
						table_offset = next_offset)
				{
					Test_Tell("Resolving " << table_offset << "\n");

					offset_pointer =
						(GaugeInterpreterOffset *) &tablePointer[table_offset];

					next_offset = *offset_pointer;
					*offset_pointer = (GaugeInterpreterOffset) new_offset;  
				}
				symbol->offset = new_offset;
				symbol->resolved = True;
				Test_Tell("Done!\n");
				Check_Fpu();
				return;
			}
			else
			{
				Test_Tell("Resolved?!?!?.\n");
				//-------------------------------------------------
				// Yes, this is an error.  Throw a fit.
				//-------------------------------------------------
				DEBUG_STREAM << "label =" << label << "\n" << std::flush;
				Fail("Already resolved");
			}
		}
	}
	//-------------------------------------------------
	// This is a new, resolved definition: just add it
	//-------------------------------------------------
	Test_Tell("New.\n");
#	if DEBUG_LEVEL > 0
		symbol = new GaugeSymbol(&head, label, new_offset, True);
		Check(symbol);
		Register_Object(symbol);
#	else
		new GaugeSymbol(&head, label, new_offset, True);
#	endif
	Check_Fpu();
}

GaugeInterpreterOffset
	GaugeSymbolTable::Refer(
		const char *label,
		GaugeInterpreterOffset new_offset
	)
{
	Check(this);
	Check_Pointer(label);

	Test_Tell(
		"GaugeSymbolTable::Refer(" << label <<
		"," << new_offset <<
		")\n"
	);

	GaugeSymbol
		*symbol;

	//-------------------------------------------------
	// Check to see if this label already exists
	//-------------------------------------------------
	for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol)
	{
		Check(symbol);

		if (stricmp(label, symbol->label) == 0)
		{
			Test_Tell("Exists.\n");
			//-------------------------------------------------
			// It DOES exist.  Is it resolved?
			//-------------------------------------------------
			if (symbol->resolved)
			{
				Test_Tell("Resolved.\n");
				//-------------------------------------------------
				// Yes, return the value.
				//-------------------------------------------------
				Check_Fpu();
				return symbol->offset;
			}
			else
			{
				Test_Tell("Unresolved.\n");
				//-------------------------------------------------
				// No, add to the list of forward references.
				//-------------------------------------------------
				GaugeInterpreterOffset
					previous_offset = symbol->offset;

				Test_Tell("Returning previous " << previous_offset << ".\n");
				symbol->offset = new_offset;
				Check_Fpu();
				return previous_offset;
			}
		}
	}
	//-------------------------------------------------
	// This is a new forward reference.
	// A (-1) is returned to mark the end of
	// the reference chain.
	//
	// IT IS NOT AN ERROR!
	//-------------------------------------------------
	Test_Tell("New.\n");
#	if DEBUG_LEVEL > 0
		symbol = new GaugeSymbol(&head, label, new_offset, False);
		Check(symbol);
		Register_Object(symbol);
#	else
		new GaugeSymbol(&head, label, new_offset, False);
#	endif
	Check_Fpu();
	return -1;
}

GaugeInterpreterOffset
	GaugeSymbolTable::Get(const char *label)
{
	Test_Tell(
		"GaugeSymbolTable::Get(" << label <<
		")\n"
	);
	Check(this);
	Check_Pointer(label);

	GaugeSymbol
		*symbol;

	//-------------------------------------------------
	// Check to see if this label exists
	//-------------------------------------------------
	for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol)
	{
		Check(symbol);

		if (stricmp(label, symbol->label) == 0)
		{
			Test_Tell("Exists.\n");
			//-------------------------------------------------
			// It DOES exist.  Is it resolved?
			//-------------------------------------------------
			if (symbol->resolved)
			{
				Test_Tell("Resolved.\n");
				//-------------------------------------------------
				// Yes, return the value.
				//-------------------------------------------------
				Check_Fpu();
				return symbol->offset;
			}
			else
			{
				Test_Tell("Unresolved (error).\n");
				//-------------------------------------------------
				// Return error.
				//-------------------------------------------------
				Check_Fpu();
				return errUnresolvedForwardReference;
			}
		}
	}
	//-------------------------------------------------
	// Undefined, return error.
	//-------------------------------------------------
	Test_Tell("Undefined (error).\n");
	Check_Fpu();
	return errUndefinedSymbol;
}

const char *
	GaugeSymbolTable::LabelFromValue(GaugeInterpreterOffset value)
{
#	if defined SHOW_EVERYTHING
		Test_Tell(
			"GaugeSymbolTable::LabelFromValue(" << value <<
			")\n"
		);
#	endif
	Check(this);

	GaugeSymbol
		*symbol;

	//-------------------------------------------------
	// Check to see if this label exists
	//-------------------------------------------------
	for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol)
	{
		Check(symbol);

		if (symbol->offset == value)
		{
			//-------------------------------------------------
			// It DOES exist.  Is it resolved?
			//-------------------------------------------------
			if (symbol->resolved)
			{
				//-------------------------------------------------
				// Yes, return the value.
				//-------------------------------------------------
				Check_Fpu();
				return symbol->label;
			}
			else
			{
				//-------------------------------------------------
				// Return error.
				//-------------------------------------------------
				Check_Fpu();
				return NULL;
			}
		}
	}
	//-------------------------------------------------
	// Undefined, return error.
	//-------------------------------------------------
	Check_Fpu();
	return NULL;
}

Logical
	GaugeSymbolTable::UnresolvedForwardReferences()
{
	Test_Tell(
		"GaugeSymbolTable::UnresolvedForwardReferences()\n"
	);
	Check(this);

	GaugeSymbol
		*symbol;

	//-------------------------------------------------
	// Check for unrersolved symbols
	//-------------------------------------------------
	for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol)
	{
		Test_Tell("Symbol '" << symbol->label << "' at " << symbol << "\n");
		Check(symbol);

		if (!symbol->resolved)
		{
			Test_Tell("Unresolved!\n");
			Check_Fpu();
			return True;
		}
	}
	//-------------------------------------------------
	// Everything is resolved!
	//-------------------------------------------------
	Test_Tell("All is resolved.\n");
	Check_Fpu();
	return False;
}

//#######################################################################
// GaugeInterpreter
//#######################################################################
GaugeInterpreter::GaugeInterpreter()
{
	Test_Tell("GaugeInterpreter::GaugeInterpreter()\n");
	Check_Pointer(this);
	//-------------------------------------------------
	// Create interpreter table
	//-------------------------------------------------
	interpreterTable = new char[interpreterTableSize];
	Check_Pointer(interpreterTable);
	Register_Pointer(interpreterTable);
	//-------------------------------------------------
	// Clear attribute variable array
	//-------------------------------------------------
	for (int i=0; i<maxVariableNameArrayIndex; ++i)
	{
		attributeNameArray[i] = NULL;
	}
	//-------------------------------------------------
	// Create empty symbol table
	//-------------------------------------------------
	symbolTable = new GaugeSymbolTable(interpreterTable);
	Check(symbolTable);
	Register_Object(symbolTable);

	primitiveTable = NULL;
	primitiveCount = 0;

	currentOffset = 0;

	Check_Fpu();
}

GaugeInterpreter::~GaugeInterpreter()
{
	Test_Tell("GaugeInterpreter::~GaugeInterpreter()\n");
	Check(this);
	//-------------------------------------------------
	// Delete primitive table
	//-------------------------------------------------
	if (primitiveTable != NULL)
	{
		Check_Pointer(primitiveTable);
		Unregister_Pointer(primitiveTable);
		delete[] primitiveTable;
	}
	//-------------------------------------------------
	// Delete symbol table
	//-------------------------------------------------
	Check(symbolTable);
	Unregister_Object(symbolTable);
	delete symbolTable;
	//-------------------------------------------------
	// Delete interpreter table
	//-------------------------------------------------
	Check_Pointer(interpreterTable);
	Unregister_Pointer(interpreterTable);
	delete[] interpreterTable;

	Check_Fpu();
}

Logical
	GaugeInterpreter::TestInstance() const
{
	return True;
}

const char *
	GaugeInterpreter::GetToken()
{
#	if defined(SHOW_EVERYTHING)
		Test_Tell("GetToken()\n");
#	endif
	Check(this);

	if (tokenNotTaken)
	{
#		if defined(SHOW_EVERYTHING)
			Test_Tell("Returning previously rejected token\n");
#		endif
		tokenNotTaken = False;
		return currentToken;
	}

	char
		*char_pointer = currentToken;
	int
		running,
		c;
	enum ParsingState
	{
		parsingWhiteSpace,
		parsingToken,
		parsingComment,
		parsingString
	};
	ParsingState
		parsingState = parsingWhiteSpace;

	for(running=1; running; )
	{
		c = file.sgetc();		// check next character without pulling it

		if ((char_pointer - currentToken) >= sizeof(currentToken))
		{
				Fail("Token too large");
				return NULL;
		}

		if (c < 0)
		{
			if (char_pointer == currentToken)
			{
#				if defined(SHOW_EVERYTHING)
					Test_Tell("EOF, NULL\n");
#				endif
				return NULL;
			}
			else
			{
				*char_pointer = '\0';
#				if defined(SHOW_EVERYTHING)
					Test_Tell("EOF, token=<" << currentToken << ">\n");
#				endif
				return currentToken; 
			}
		}

		if (c == '\n')
		{
#			if defined(SHOW_EVERYTHING)
				Test_Tell("newline\n");
#			endif
			++lineNumber;
		}

		switch(parsingState)
		{
		case parsingWhiteSpace:
			switch(c)
			{
			case ' ':
			case '\t':
			case '\r':
			case '\n':
			case '\0':
				file.stossc();		// discard character
				break;

			case '#':
				file.stossc();		// discard character
#				if defined(SHOW_EVERYTHING)
					Test_Tell("start comment\n");
#				endif
				parsingState = parsingComment;
				break;
				
			default:
#				if defined(SHOW_EVERYTHING)
					Test_Tell("non-white\n");
#				endif
				parsingState = parsingToken;
				break;
			}
			break;
			
		case parsingToken:
			switch(c)
			{
			default:
				file.stossc();		// discard character
				*char_pointer++ = (char) c;
				break;

			case '"':
				file.stossc();		// discard character
				if (char_pointer == currentToken)
				{
#					if defined(SHOW_EVERYTHING)
						Test_Tell("start string\n");
#					endif
					parsingState = parsingString;
				}
				else
				{
					*char_pointer = '\0';
#					if defined(SHOW_EVERYTHING)
						Test_Tell("start string, token=<" << currentToken << ">\n");
#					endif
					return currentToken;
				}
				break;

			case '{':
			case '}':
			case '(':
			case ')':
			case ',':
			case '=':
			case ';':
				if (char_pointer == currentToken)
				{
					file.stossc();		// discard character
					*char_pointer++ = (char) c;
				}
				*char_pointer = '\0';
#				if defined(SHOW_EVERYTHING)
					Test_Tell("punctuation, token=<" << currentToken << ">\n");
#				endif
				return currentToken;

			case '#':
				file.stossc();		// discard character
#				if defined(SHOW_EVERYTHING)
					Test_Tell("start comment\n");
#				endif
				parsingState = parsingComment;
				break;
				
			case ' ':
			case '\t':
			case '\r':
			case '\n':
			case '\0':
				file.stossc();		// discard character
				*char_pointer = '\0';
#				if defined(SHOW_EVERYTHING)
					Test_Tell("trailing white, token=<" << currentToken << ">\n");
#				endif
				return currentToken;
			}
			break;

		case parsingComment:
			file.stossc();		// discard character
			switch(c)
			{
			case '\n':
			case '\r':
				if (char_pointer == currentToken)
				{
#					if defined(SHOW_EVERYTHING)
						Test_Tell("end of comment\n");
#					endif
					parsingState = parsingWhiteSpace;
				}
				else
				{
					*char_pointer = '\0';
#					if defined(SHOW_EVERYTHING)
						Test_Tell("end of comment, token=<" <<currentToken<< ">\n");
#					endif
					return currentToken;
				}
				break;
			}
			break;

		case parsingString:
			file.stossc();		// discard character
			if (c == '"')
			{
				*char_pointer = '\0';
#				if defined(SHOW_EVERYTHING)
					Test_Tell("end of string, token=<" << currentToken << ">\n");
#				endif
				return currentToken;
			}
			else
			{
				*char_pointer++ = (char) c;
			}
			break;
		}
	}
	Fail("Unintended exit");
	Check_Fpu();
	return NULL;
}

void
	GaugeInterpreter::UngetPreviousToken()
{
	Check(this);
	tokenNotTaken = True;
	Check_Fpu();
}

Logical
	GaugeInterpreter::GetInteger(int *int_pointer)
{
	Test_Tell(
		"GaugeInterpreter::GetInteger(" << ((void *) int_pointer) <<
		")..."
	);
	Check(this);
	Check_Pointer(int_pointer);

	const char
		*token = GetToken();
	Check_Pointer(token);
	Test_Tell("token=" << token << "...");

	int
		c,
		value = 0;
	Logical
		result,
		is_negative = False;

	if (*token == '-')
	{
		is_negative = True;
		++token;
	}

	if (*token == '0')
	{
		++token;
		if (*token == '\0')
		{
			Test_Tell("found zero value\n");
			*int_pointer = 0;
			return True;
		}
	}

	if (*token == 'x' || *token == 'X')
	{
		for(++token; *token != '\0'; ++token)
		{
			c = toupper(*token);

			if (!isxdigit(c))
			{
				 return False;
			}

			if (c > '9')
			{
				c -= ('A'-':');
			}
			value = (value << 4) + (c - '0');
		}
		result = True;
	}
	else
	{
		for( ; *token != '\0'; ++token)
		{
			c = *token;
			if (!isdigit(c))
			{
				 return False;
			}
			value = (value*10) + (c - '0');
		}
		result = True;
	}

	if (result == True)
	{
		if (is_negative)
		{
			value = - value;
		}
		Test_Tell("found value " << value << "\n");
		*int_pointer = value;
	}
#	if defined(LOCAL_TEST)
	else
	{
		Test_Tell("FAILED\n");
	}
#	endif
	Check_Fpu();
	return result;
}

Logical
	GaugeInterpreter::GetScalar(Scalar *scalar_pointer)
{
	Test_Tell(
		"GaugeInterpreter::GetScalar(" << ((void *) scalar_pointer) <<
		")..."
	);
	Check(this);
	Check_Pointer(scalar_pointer);

	const char
		*token = GetToken();
	Check_Pointer(token);
	Test_Tell("token=" << token << "\n");

	float				// HACK - I don't know how to avoid an explicit 'float'...
		value;
	Logical
		is_negative = False;

	if (*token == '-')
	{
		is_negative = True;
		++token;
	}

	if (sscanf(token, "%f", &value) > 0)
	{
		Test_Tell("found " << value << "\n");

		if (is_negative)
		{
			value = - value;
		}
		*scalar_pointer = (Scalar) value;
		return True;
	}
	ReportParsingError("Token not a scalar value");
	Check_Fpu();
	return False;
}

Logical
	GaugeInterpreter::GetVector(Vector2DOf<int> *vector)
{
	Test_Tell("GaugeInterpreter::GetVector(" << ((void *) vector) << ")...");
	Check(this);
	Check_Pointer(vector);

	Vector2DOf<int>
		local_vector;

	if (strcmp(GetToken(), "(") != 0)
	{
		ReportParsingError("Missing leading '(' for 2D vector");
		return False;
	}
	if (!GetInteger(&local_vector.x))
	{
		return False;
	}
	if (strcmp(GetToken(), ",") != 0)
	{
		ReportParsingError("Missing ',' for 2D vector");
		return False;
	}
	if (!GetInteger(&local_vector.y))
	{
		return False;
	}
	if (strcmp(GetToken(), ")") != 0)
	{
		ReportParsingError("Missing trailing ')' for 2D vector");
		return False;
	}

	*vector = local_vector;
	Check_Fpu();
	return True;
}

Logical
	GaugeInterpreter::GetRate(GaugeRate *rate)
{
	Test_Tell("GaugeInterpreter::GetRate(" << ((void *) rate) << ")...");
	Check(this);
	const char
		*text = GetToken();
	Test_Tell("token='" << text << "'\n");
	Check_Pointer(text);
	Check_Pointer(rate);

	int
		c;
	//-----------------------------------------------
	// Get rate (A..P)
	//-----------------------------------------------
	c = *text;
	if (!isalpha(c))
	{
		ReportParsingError("Token is not a valid rate");
	}
	else
	{
		c = toupper(c);
		if ((c >= 'A') && (c <= 'Z'))
		{
			*rate = Gauge::ConvertIndexToRate(c -'A');
			Check_Fpu();
			return True;
		}
		else
		{
			ReportParsingError("Token is not a valid rate");
		}
	}
	Check_Fpu();
	return False;
}

Logical
	GaugeInterpreter::GetModeMask(ModeMask *mask_pointer)
{
	Test_Tell(
		"GaugeInterpreter::GetLong(" << ((void *) mask_pointer) <<
		")..."
	);
	Check(this);
	Check_Pointer(mask_pointer);

	const char
		*token = GetToken();
	Check_Pointer(token);
	Test_Tell("token=" << token << "...");

	int
		c;
	ModeMask
		value = (ModeMask) 0;
	Logical
		result = False,
		is_negative = False;

	//------------------------------------------------------
	// Deal with negative sign here
	//------------------------------------------------------
	if (*token == '-')
	{
		is_negative = True;
		++token;
	}

	if (isalpha(*token))
	{
		//------------------------------------------------------
		// Check for a named constant
		//------------------------------------------------------
		Check(application);
		Check(application->GetModeManager());

		result = application->GetModeManager()->ModeStringLookup(token, &value);
	}
	else
	{
		//--------------------------------------------------------
		// Not a named constant. must be either number or an error
		//--------------------------------------------------------
		if (*token == '0')
		{
			++token;
			result = True;		// might be a single lonely zero (which is legit)
		}

		if (*token == 'x' || *token == 'X')
		{
			//--------------------------------------------------------
			// Process hex value
			//--------------------------------------------------------
			for(++token; *token != '\0'; ++token)
			{
				c = toupper(*token);

				if (!isxdigit(c))
				{
					 return False;
				}

				if (c > '9')
				{
					c -= ('A'-':');
				}
				value = (value << 4) + (ModeMask) (c - '0');
			}
			result = True;
		}
		else
		{
			//--------------------------------------------------------
			// Process decimal value
			//--------------------------------------------------------
			for( ; *token != '\0'; ++token)
			{
				c = *token;
				if (!isdigit(c))
				{
					Check_Fpu();
					return result;
				}
				value = (value*10) + (ModeMask) (c - '0');
			}
			result = True;
		}
	}

	if (result == True)
	{
		if (is_negative)
		{
			value = - value;
		}
		Test_Tell("found value " << value << "\n");
		*mask_pointer = value;
	}
#	if defined(LOCAL_TEST)
	else
	{
		Test_Tell("FAILED\n");
	}
#	endif
	Check_Fpu();
	return result;
}

void
	GaugeInterpreter::ReportParsingError(
	  const char *string
	)
{
	Check(this);
	Check_Pointer(string);

	DEBUG_STREAM <<
		"Interpreter parsing error:" << string <<
		" in line " << lineNumber <<
		"\n";
	Fail("Parsing error");
}

void
	GaugeInterpreter::Initialize(
		const char *file_name,
		MethodDescription **method_list,
		Warehouse *warehouse_pointer
	)
{
	Check(this);
	Check_Pointer(file_name);
	Check_Pointer(method_list);
	Check(warehouse_pointer);
	//------------------------------------------------------------------------
	// Determine the number of primitives
	//------------------------------------------------------------------------
	MethodDescription
		*method_entry,
		**list;

	primitiveCount = 0;
	list = method_list;
	while(list != NULL)
	{
		Check_Pointer(list);
		method_entry = *list++;
		Check_Pointer(method_entry);
		if (method_entry->name == NULL)
		{
			//-------------------------------------------------------------
			// Attempt to chain to next list: if NULL, we're done.
			//-------------------------------------------------------------
			list = method_entry->parameterList[0].data.nextMethodList;
		}
		else
		{
			//-------------------------------------------------------------
			// Increment the primitive count
			//-------------------------------------------------------------
			++primitiveCount;
		}
	}
	//------------------------------------------------------------------------
	// Allocate the primitive table
	//------------------------------------------------------------------------
	primitiveTable = new MethodDescription*[primitiveCount];
	Register_Pointer(primitiveTable);
	//------------------------------------------------------------------------
	// Fill in the primitiveTable
	//------------------------------------------------------------------------
	MethodDescription
		**method_pointer = primitiveTable;

	list = method_list;
	while(list != NULL)
	{
		Check_Pointer(list);
		method_entry = *list++;
		Check_Pointer(method_entry);
		if (method_entry->name == NULL)
		{
			//-------------------------------------------------------------
			// Attempt to chain to next list: if NULL, we're done.
			//-------------------------------------------------------------
			list = method_entry->parameterList[0].data.nextMethodList;
		}
		else
		{
			//-------------------------------------------------------------
			// Save a pointer to the method description
			//-------------------------------------------------------------
			Verify((method_pointer-primitiveTable) < primitiveCount);
			*(method_pointer++) = method_entry;			
		}
	}
	//------------------------------------------------------------------------
	// Parse the text file to build the interpreter table
	//------------------------------------------------------------------------
	//file.open(file_name, std::ios::in|std::ios::nocreate, std::filebuf::openprot);
	// alternate line added by RB 1/6/2007
	file.open(file_name, std::ios::in, std::ios::_Openprot);

	if (!file.is_open())
	{
		DEBUG_STREAM << "Cannot open interpreter file '" << file_name << "'\n" << std::flush;
	}
	else
	{
		lineNumber = 1;
		tokenNotTaken = False;

		const char
			*name;
		char
			local_name[32];
		//----------------------------------------------------
		// Parse the statement:
		//           <name> { <body> }
		//----------------------------------------------------
		//

		while((name = GetToken()) != NULL )
		{
			Str_Copy(local_name, name, sizeof(local_name));

			if (stricmp(GetToken(), "{") != 0)
			{
				ReportParsingError("Missing '{'");
			}
			symbolTable->Add(local_name, currentOffset);
			GetProcedureBody(method_list, warehouse_pointer);
		}
		if (symbolTable->UnresolvedForwardReferences())
		{
			ReportParsingError("Unresolved forward references");
		}
		file.close();

		{
			GaugeInterpreterCommand
				command = endMarker;
			Insert(&command, sizeof(GaugeInterpreterCommand));
#			if defined(LOCAL_TEST)
				DumpTable();
#			endif
		};
	}
	//------------------------------------------------------------------------
	// All done!
	//------------------------------------------------------------------------
	Check_Fpu();
}

void
	GaugeInterpreter::GetProcedureBody(
		MethodDescription **method_list,
		Warehouse *warehouse_pointer
	)
{
	Check(this);
	Check_Pointer(method_list);
	Check(warehouse_pointer);

	int
		running = 1;
	GaugeInterpreterCommand
		command;
	const char
		*name;
	char
		local_name[32];

	while (running)
	{
		name = GetToken();
		if (name == NULL)
		{
			ReportParsingError("Internal error (NULL token)");
		}

		Str_Copy(local_name, name, sizeof(local_name));

		if (stricmp(name, "}") == 0)
		{
			Test_Tell("End\n");
			command = returnCommand;
			Insert(&command, sizeof(GaugeInterpreterCommand));
			break;
		}
		else if (*name == '@')		// example: @1 = ppc/reloadtime;
		{
			if (strlen(name) != 2)
			{
				ReportParsingError("Ill-formed attribute variable index");
			}
			unsigned char
				index = (unsigned char) ((*(name+1)) - '0');

			if (index > maxVariableNameArrayIndex)
			{
				ReportParsingError("Illegal attribute variable index");
			}

			if (strcmp(GetToken(), "=") != 0)
			{
				ReportParsingError("Missing '='");
			}
			Test_Tell("Attribute variable\n");
			command = attributeVariableCommand;
			Insert(&command, sizeof(GaugeInterpreterCommand));
			Insert(&index, sizeof(unsigned char));
			InsertString(GetToken());
		}
		else if (stricmp(name, "enable") == 0)
		{
			if (strcmp(GetToken(), "=") != 0)
			{
				ReportParsingError("Missing '='");
			}

			ModeMask
				mode_mask;
			GetModeMask(&mode_mask);		// fails to debugger if bad input

			Test_Tell("Enable\n");
			command = enableCommand;
			Insert(&command, sizeof(GaugeInterpreterCommand));
			Insert(&mode_mask, sizeof(ModeMask));
		}
		else if (stricmp(name, "disable") == 0)
		{
			if (strcmp(GetToken(), "=") != 0)
			{
				ReportParsingError("Missing '='");
			}

			ModeMask
				mode_mask;
			GetModeMask(&mode_mask);		// fails to debugger if bad input

			Test_Tell("Disable\n");
			command = disableCommand;
			Insert(&command, sizeof(GaugeInterpreterCommand));
			Insert(&mode_mask, sizeof(ModeMask));
		}
		else if (stricmp(name, "offset") == 0)
		{
			if (strcmp(GetToken(), "=") != 0)
			{
				ReportParsingError("Missing '='");
			}

			Vector2DOf<int>
				offset;

			GetVector(&offset);	// fails to debugger if input bad

			Test_Tell("offset\n");
			command = addOffsetCommand;
			Insert(&command, sizeof(GaugeInterpreterCommand));
			Insert(&offset, sizeof(Vector2DOf<int>));
		}
		else if (stricmp(name, "port") == 0)
		{
			if (strcmp(GetToken(), "=") != 0)
			{
				ReportParsingError("Missing '='");
			}

			command = setPortIndexCommand;
			Insert(&command, sizeof(GaugeInterpreterCommand));
			InsertString(GetToken());
		}
		else	// must be either call or primitive
		{
			const char
				*token = GetToken();
			if (stricmp(token, "(") == 0)
			{
				if (
						ParsePrimitive(
							local_name,
							method_list,
							warehouse_pointer
						) == False
					)
				{
					//
					// BT DEV-GAUGES bring-up: the BT-specific gauge primitive
					// table (BTL4MethodDescription, btl4grnd.cpp) is still a stub
					// -- the BT gauge widget classes (PlayerStatus, ...) aren't
					// reconstructed yet, so they don't resolve here.  Rather than
					// Fail() -- which pops a modal assert dialog and FREEZES the
					// game mid-parse -- SKIP the unknown primitive's parameter
					// list so the parse can continue: it still registers every
					// label (e.g. Bhk1Init -> MechInit) and runs the base
					// "configure" primitives that build the gauge PORTS/surfaces
					// (the beachhead needs the 'sec'/radar surface, not the
					// widgets).  Gated on BT_DEV_GAUGES so the POD path keeps the
					// strict Fail (it needs a complete, real method table).
					//
					if (getenv("BT_DEV_GAUGES") != NULL)
					{
						const char
							*skip_token;
						int
							paren_depth = 1;	// the '(' already consumed above
						while (
								(paren_depth > 0) &&
								((skip_token = GetToken()) != NULL)
							)
						{
							if (stricmp(skip_token, "(") == 0)
								++paren_depth;
							else if (stricmp(skip_token, ")") == 0)
								--paren_depth;
						}
						UngetPreviousToken();	// leave ')' for the check below
					}
					else
					{
						ReportParsingError("Undefined primitive");
					}
				}
				if (stricmp(GetToken(), ")") != 0)
				{
					ReportParsingError("Missing ')'");
				}
			}
			else
			{
				UngetPreviousToken();

				Test_Tell("Call to '" << local_name << "'\n");

				command = callCommand;
				Insert(&command, sizeof(GaugeInterpreterCommand));

				Check(symbolTable);
				GaugeInterpreterOffset
					offset = symbolTable->Refer(local_name, currentOffset);
				Insert(&offset, sizeof(GaugeInterpreterOffset));
			}
		}

		if (stricmp(GetToken(), ";") != 0)
		{
			ReportParsingError("Missing ';'");
		}
	}
	Check_Fpu();
}

Logical
	GaugeInterpreter::ParsePrimitive(
		const char *name,
		MethodDescription **method_list,
		Warehouse *warehouse_pointer
	)
{
	Test_Tell(
		"GaugeInterpreter::ParsePrimitive(" << name <<
		", " << method_list <<
		", " << warehouse_pointer <<
		")\n"
	);
	Check(this);
	Check_Pointer(name);
	Check_Pointer(method_list);
	Check(warehouse_pointer);

	MethodDescription
		*method_entry,
		**list;
	GaugeInterpreterCommand
		command_number = nextAvailableCommand;
	int
		i;
	Logical
		first_parameter = True;

	list = method_list;
	while(list != NULL)
	{
		Check_Pointer(list);
		method_entry = *list++;
		Check_Pointer(method_entry);
		if (method_entry->name == NULL)
		{
			//-------------------------------------------------------------
			// Attempt to chain to next list: if NULL, we didn't match.
			//-------------------------------------------------------------
			list = method_entry->parameterList[0].data.nextMethodList;
		}
		else
		{
			//-------------------------------------------------------------
			// Attempt to match this entry
			//-------------------------------------------------------------
			Test_Tell("<" << method_entry->name << ">\n");
			if (stricmp(method_entry->name, name) != 0)
			{
				command_number = (GaugeInterpreterCommand) (command_number + 1);
			}
			else
			{
				//-------------------------------------------------------
				// Name found, attempt to procure parameters
				//-------------------------------------------------------
				Test_Tell("Found, attempt to match parameters\n");
				for (
						i=0;
						method_entry->parameterList[i].type !=
							ParameterDescription::typeEmpty;
						++i
					 )
				{
					//-------------------------------------------------------
					// Eat commas (after first parameter)
					//-------------------------------------------------------
					if (first_parameter)
					{
						first_parameter = False;
					}
					else
					{
						if (stricmp(GetToken(), ",") != 0)
						{
							ReportParsingError("Missing ','");
							return False;
						}
					}
					//-------------------------------------------------------
					// Read a parameter
					//-------------------------------------------------------
					if (method_entry->parameterList[i].
							Extract(this, warehouse_pointer) == False
						)
					{
						//----------------------------------------------
						// Not found, error
						//----------------------------------------------
						ReportParsingError("Wrong or missing parameter");
						return False;
					}
				}
				//-------------------------------------------------------
				// All parameters found, write to the interpreter table
				//-------------------------------------------------------
				Test_Tell("All parameters matched\n");

				Check_Pointer(method_entry->execute); // make sure it's executable
				Verify((command_number-nextAvailableCommand) >= 0);
				Verify((command_number-nextAvailableCommand) < primitiveCount);

				Insert(&command_number, sizeof(GaugeInterpreterCommand));

				for (
						i=0;
						method_entry->parameterList[i].type !=
							ParameterDescription::typeEmpty;
						++i
					 )
				{
					method_entry->parameterList[i].Save(this);
				}
				Test_Tell("All done\n");
				Check_Fpu();
				return True;
			}
		}
	}
	//-------------------------------------------------------------
	// Name not matched, return error
	//-------------------------------------------------------------
	Test_Tell("Not found!\n");
	Check_Fpu();
	return False;
}

void
	GaugeInterpreter::Insert(const void *value_pointer, int size_in_chars)
{
#	if defined(SHOW_EVERYTHING)
		Test_Tell(
			"GaugeInterpreter::Insert(" << ((void *) value_pointer) <<
			"," << size_in_chars <<
			")\n"
		);
#	endif
	Check(this);
	Check_Pointer(value_pointer);
	Verify(size_in_chars > 0);

	Verify((currentOffset+size_in_chars) < interpreterTableSize);

	char
		*source;

	for(
		source= (char *) value_pointer;
		size_in_chars!=0;
		++source, --size_in_chars
	)
	{
		interpreterTable[currentOffset++] = *source;
	}
	Check_Fpu();
}

void *
	GaugeInterpreter::Retrieve(int size_in_chars)
{
#	if defined(SHOW_EVERYTHING)
		Test_Tell(
			"GaugeInterpreter::Retrieve(" << size_in_chars << ")\n"
		);
#	endif
	Check(this);

	Verify(size_in_chars > 0);

	Verify(currentOffset >= 0);
	Verify(currentOffset < interpreterTableSize);

	void
		*here = &interpreterTable[currentOffset];

	currentOffset = (GaugeInterpreterOffset) (currentOffset + size_in_chars);
	Verify(currentOffset < interpreterTableSize);
	
	Check_Fpu();
	return here;
}

void
	GaugeInterpreter::InsertString(const char *string)
{
	Check(this);
	Check_Pointer(string);

	unsigned short
		length = (unsigned short) (strlen(string)+1);

	Test_Tell(
		"GaugeInterpreter::InsertString(" << string <<
		"), len=" << length << "\n"
	);

	Verify(length < ParameterDescription::maxStringLength);

	Insert(&length, sizeof(unsigned short));
	Insert(string, length);
	Check_Fpu();
}

const char *
	GaugeInterpreter::RetrieveString()
{
#	if defined(SHOW_EVERYTHING)
		Test_Tell(
			"GaugeInterpreter::RetrieveString()='"
		);
#	endif
	Check(this);

	const char
		*pointer;

	unsigned short
		length = *(unsigned short *) Retrieve(sizeof(unsigned short));

	Verify(length < ParameterDescription::maxStringLength);

	pointer = (const char *) &interpreterTable[currentOffset];
	Check_Pointer(pointer);

	currentOffset = (GaugeInterpreterOffset) (currentOffset + length);

#	if defined(SHOW_EVERYTHING)
		Test_Tell( pointer << "', len=" << length << "\n");
#	endif
	Check_Fpu();
	return pointer;
}


void
	GaugeInterpreter::Interpret(
		const char *label,
		GaugeRenderer *renderer,
		int display_port_index,
		Vector2DOf<int> position,
		Entity *entity
	)
{
	Test_Tell(
		"GaugeInterpreter::Interpret('" << label <<
		"'," << renderer <<
		"," << display_port_index <<
		"," << position <<
		"," << entity <<
		"\n"
	);
	Check(this);
	Check_Pointer(label);
	Check(renderer);
	// 'entity' is allowed to be NULL

	Check(symbolTable);
	Check_Pointer(interpreterTable);

	GaugeInterpreterOffset
		offset = symbolTable->Get(label);
	if (offset < 0)
	{
		DEBUG_STREAM << "GaugeInterpreter: undefined label '" << label << "'\n" << std::flush;
	}
	else
	{
		InterpretFromOffset(
			offset,
			renderer,
			display_port_index,
			position,
			entity
		);
	}
	Check_Fpu();
}

void
	GaugeInterpreter::InterpretFromOffset(
		GaugeInterpreterOffset offset,
		GaugeRenderer *renderer,
		int display_port_index,
		Vector2DOf<int> original_position,
		Entity *entity
	)
{
	Test_Tell(
		"GaugeInterpreter::InterpretFromOffset(" << offset <<
		"," << renderer <<
		"," << display_port_index <<
		"," << original_position <<
		"," << entity <<
		"\n"
	);
	Check(this);
	Check(renderer);
	Verify(offset >= 0);
	// 'entity' is allowed to be NULL
	Check_Pointer(interpreterTable);

	currentOffset = offset;

	GaugeInterpreterCommand
		command;

	int
		running = 1;
	Vector2DOf<int>
		position;

	position = original_position;

	while(running)
	{
		command = *(GaugeInterpreterCommand *)
			Retrieve(sizeof(GaugeInterpreterCommand));
		switch(command)
		{
		case endMarker:
		case returnCommand:
			Test_Tell("Return\n");
			running = 0;
			break;

		case setPortIndexCommand:
			{
				const char
					*port_name = RetrieveString();
				Test_Tell("Set port=" << port_name << "\n");
				//------------------------------------------
				// Replace variable if needed
				//------------------------------------------
				port_name = ReplaceVariable(port_name);

				int
					port = renderer->FindGraphicsPort(port_name);

				if (port >= 0)
				{
					display_port_index = port;
				}
				else
				{
					Tell(
						"GaugeInterpreter::InterpretFromOffset: port '"<<
						port_name << "' not found!\n"
					);
				}
			}       
			break;

		case addOffsetCommand:
			{
				Vector2DOf<int>
					temp;

				temp = *(Vector2DOf<int> *) Retrieve(sizeof(Vector2DOf<int>));
				Test_Tell("Add offset " << std::dec << temp);
				position.x = original_position.x + temp.x;
				position.y = original_position.y + temp.y;
				Test_Tell(" to " << position << "\n");
			}
			break;

		case attributeVariableCommand:
			{
				unsigned char
					index = *(unsigned char *)Retrieve(sizeof(unsigned char));
				const char
					*attribute_name = RetrieveString();
				Test_Tell(
					"attribute variable #" << index << "=" << attribute_name << "\n"
				);

				Verify(index < maxVariableNameArrayIndex);
				attributeNameArray[index] = attribute_name;
			}       
			break;
		case callCommand:
			{
				GaugeInterpreterOffset
					new_offset =
						*(GaugeInterpreterOffset *) 
							Retrieve(sizeof(GaugeInterpreterOffset));

				Test_Tell("Call " << std::hex << new_offset << std::dec << "\n");
				offset = currentOffset;			// save for call

				InterpretFromOffset(
					new_offset,
					renderer,
					display_port_index,
					position,
					entity
				);
				currentOffset = offset;			// restore offset
			}
			break;

		case enableCommand:
			Test_Tell("Enable\n");
			{
				Check(application);
				Check(application->GetModeManager());

				application->GetModeManager()->AddModeMask(
					*(ModeMask*)Retrieve(sizeof(ModeMask))
				);
			}
			break;

		case disableCommand:
			Test_Tell("Disable\n");
			{
				Check(application);
				Check(application->GetModeManager());

				application->GetModeManager()->RemoveModeMask(
					*(ModeMask*)Retrieve(sizeof(ModeMask))
				);
			}
			break;

		default:
			command = (GaugeInterpreterCommand) (command - nextAvailableCommand);
			Verify(command < primitiveCount);
			Check_Pointer(primitiveTable);

			Test_Tell("****" << primitiveTable[command]->name<< "\n");
			primitiveTable[command]->Execute(
				display_port_index,
				position,
				entity,
				renderer
			);
			break;
		}
	}
	Check_Fpu();
}

const char *
	GaugeInterpreter::ReplaceVariable(const char *string)
{
	Check(this);
	Verify(string != NULL);
	if (*string == '@')
	{
		unsigned char
			index = *(string+1);
		if ((index >= '0') && (index <= '9'))
		{
			string = attributeNameArray[index - '0'];
			Verify(string != NULL);
			Test_Tell(
				"Variable @" << index << " replaced with '" << string <<"'\n"
			);
		}
	}
	Check_Fpu();
	return string;
}

void
	GaugeInterpreter::DumpTable()
{
	Test_Tell("GaugeInterpreter::DumpTable\n");
	Check(this);

	GaugeInterpreterCommand
		command;

	const char
		*label;

	currentOffset = 0;
	do
	{
		label = symbolTable->LabelFromValue(currentOffset);
		if (label != NULL)
		{
			DEBUG_STREAM << label << ":\n" << std::flush;
		}

		DEBUG_STREAM << "   " << std::hex << currentOffset << ":" << std::flush;

		command = *(GaugeInterpreterCommand *)
			Retrieve(sizeof(GaugeInterpreterCommand));
		switch(command)
		{
		case endMarker:
			DEBUG_STREAM << "---------End of table---------\n" << std::flush;
			break;

		case returnCommand:
			DEBUG_STREAM <<"return\n" << std::flush;
			break;

		case setPortIndexCommand:
			{
				const char
					*port_name = RetrieveString();
				DEBUG_STREAM << "setport '" << port_name << "'\n" << std::flush;
			}       
			break;

		case addOffsetCommand:
			{
				Vector2DOf<int>
					offset =	*(Vector2DOf<int> *) Retrieve(sizeof(Vector2DOf<int>));

				DEBUG_STREAM << "offset " << std::dec << offset << "\n" << std::flush;
			}
			break;

		case callCommand:
			{
				GaugeInterpreterOffset
					new_offset =
						*(GaugeInterpreterOffset *) 
							Retrieve(sizeof(GaugeInterpreterOffset));

				DEBUG_STREAM << "call 0x" << new_offset << " (" << std::flush;

				const char
					*name = symbolTable->LabelFromValue(new_offset);

				if (name == NULL)
				{
					DEBUG_STREAM << "UNDEFINED!!!)\n" << std::flush;
				}
				else
				{
					DEBUG_STREAM << name << ")\n" << std::flush;
				}
			}
			break;

		case enableCommand:
			{
				ModeMask
					mask = *(ModeMask*)Retrieve(sizeof(ModeMask));
				DEBUG_STREAM << "enable 0x" << mask << "\n" << std::flush;
			}
			break;

		case disableCommand:
			{
				ModeMask
					mask = *(ModeMask*)Retrieve(sizeof(ModeMask));
				DEBUG_STREAM << "disable 0x" << mask << "\n" << std::flush;
			}
			break;

		default:
			{
				MethodDescription
					*method_entry = primitiveTable[command-nextAvailableCommand];
				DEBUG_STREAM << method_entry->name << ":\n" << std::flush;

				int
					i;
				for (
						i=0;
						method_entry->parameterList[i].type !=
							ParameterDescription::typeEmpty;
						++i
					 )
				{
					//-------------------------------------------------------
					// Show a parameter
					//-------------------------------------------------------
					method_entry->parameterList[i].DumpInterpreterEntry(
						this,
						"          "
					);
				}
			}
			break;
		}
	}
	while(command != endMarker);
	Check_Fpu();
}

//#############################################################################
// ParameterDescription
//#############################################################################
ParameterDescription::~ParameterDescription()
{
	Check_Fpu();
}

#if DEBUG_LEVEL <= 0
void
	ParameterDescription::CheckIt(int /*this_type*/)
{
}
#else
void
	ParameterDescription::CheckIt(int this_type)
{
	Check_Pointer(this);
	Verify(type == this_type);

	switch(type)
	{
	case typeEmpty:
	case typeRate:
	case typeModeMask:
	case typeInteger:
	case typeColor:
	case typeScalar:
	case typeVector:
	case typeRectangle:
		break;
		 
	case typeAttribute:
	case typeString:
		if (data.string != NULL)
		{
			Check_Pointer(data.string);
		}
		break;

	default:
		Fail("Illegal parameter type!");
	}
	Check_Fpu();
}
#endif

void
	ParameterDescription::ShowInstance(
		char *indent
	)
{
	Check_Pointer(this);
	DEBUG_STREAM << indent << "ParameterDescription:" << std::dec << std::flush;
	switch(type)
	{
	case typeEmpty:
		DEBUG_STREAM << "empty" << std::flush;
		break;

	case typeRate:
		DEBUG_STREAM << "rate=" << std::flush;
		{
			int
				i,j;

			for(i='A',j=0x10000; i<'Q'; ++i, j<<=1)
			{
				if (data.rate & j)
				{
					DEBUG_STREAM << (char) i << std::flush;
				}
			}
		}
		break;
 
	case typeModeMask:
		DEBUG_STREAM << std::hex << "modeMask=" << data.modeMask << std::dec << std::flush;
		break;
 
	case typeInteger:
		DEBUG_STREAM << "integer=" << data.integer << std::flush;
		break;
 
	case typeColor:
		DEBUG_STREAM << "color=0x" << std::hex << data.color << std::dec << std::flush;
		break;
		 
	case typeScalar:
		DEBUG_STREAM << "scalar=" << data.scalar << std::flush;
		break;
 
	case typeVector:
		DEBUG_STREAM <<
			"vector= (" << data.vector.x <<
			", " << data.vector.y <<
			")";
		break;
		 
	case typeRectangle:
		DEBUG_STREAM <<
			"rectangle= ((" << data.rectangle.bottomLeft.x <<
			", "  << data.rectangle.bottomLeft.y <<
			"),(" << data.rectangle.topRight.x <<
			", "  << data.rectangle.topRight.y <<
			")";
		break;
		 
	case typeAttribute:
		if (data.string == NULL)
		{
			DEBUG_STREAM << "attribute=NULL\n" << std::flush;
		}
		else
		{
			DEBUG_STREAM << "attribute=<" << data.string << ">" << std::flush;
		}
		break;

	case typeString:
		if (data.string == NULL)
		{
			DEBUG_STREAM << "string=NULL\n" << std::flush;
		}
		else
		{
			DEBUG_STREAM << "string=<" << data.string << ">" << std::flush;
		}
		break;

	default:
		DEBUG_STREAM << "ILLEGAL TYPE=" << type << std::flush;
	}
	DEBUG_STREAM << "\n" << std::flush;
	Check_Fpu();
}

void *
	ParameterDescription::ParseAttribute(
		const char *string_pointer,
		Entity *entity
	)
{
	Test_Tell(
		"ParameterDescription::ParseAttribute('" << string_pointer <<
		"', " << entity <<
		")\n"
	);
	Check_Pointer(this);
	Check_Pointer(string_pointer);
	Check(entity);

	Simulation*
		simulation;

	char
		temp_string[80],
		*source,
		*temp_ptr;

	Verify(type == typeAttribute);

	Str_Copy(temp_string, string_pointer, sizeof(temp_string));

	source = temp_string;
	for(temp_ptr = source; *temp_ptr != '\0'; ++temp_ptr)
	{
		if (*temp_ptr == '/')
		{
			*temp_ptr = '\0';

			Test_Tell("Subsystem name=" << source << "\n");
			 
			simulation = (Simulation *) entity->FindSubsystem(source);
			if (simulation == NULL)
			{
				Tell("parseAttribute - subsystem '" << source << "' not found\n");
				Check_Fpu();
				return NULL;
			}
			else
			{
				source = temp_ptr+1; 
				Test_Tell("Subsystem attribute name=" << source << "\n");

				void
					*attribute_pointer = simulation->GetAttributePointer(source);

				if (attribute_pointer == NULL)
				{
					Tell(
						"parseAttribute - attribute '" <<
						string_pointer << "' not found\n"
					);
				}
				Check_Fpu();
				return attribute_pointer;
			}
		}
	}

	Test_Tell("Entity attribute name=" << source << "\n");

	void
		*attribute_pointer = ((Simulation *)entity)->GetAttributePointer(source);

	if (attribute_pointer == NULL)
	{
		Tell(
			"parseAttribute - attribute '" <<
			source << "' not found\n"
		);
	}
	Check_Fpu();
	return attribute_pointer;
}

Logical
	ParameterDescription::Extract(
		GaugeInterpreter *interpreter,
		Warehouse *warehouse_pointer
	)
{
	Test_Tell(
		"ParameterDescription::Extract(" << interpreter <<
		", " << warehouse_pointer <<
		")\n"
	);
	Check_Pointer(this);
	Check(interpreter);
	//
	//----------------------------------------------------------------
	// Choose the appropriate parameter type, attempt to create it
	//----------------------------------------------------------------
	//
	switch(type)
	{
	case typeEmpty:
		Fail("type == empty!");
		break;

	case typeRate:
		Test_Tell("rate? ");
		if (interpreter->GetRate(&data.rate))
		{
			Test_Tell("yes.\n");
			Check_Fpu();
			return True;
		}
		break;
 
	case typeModeMask:
		Test_Tell("modeMask? ");
		if (interpreter->GetModeMask(&data.modeMask))
		{
			Test_Tell("yes.\n");
			Check_Fpu();
			return True;
		}
		break;

	case typeInteger:
		Test_Tell("integer? ");
		if (interpreter->GetInteger(&data.integer))
		{
			Test_Tell("yes.\n");
			Check_Fpu();
			return True;
		}
		break;
 
	case typeColor:
		Test_Tell("color? ");
		if (interpreter->GetInteger(&data.color))
		{
			if (data.color <= 0xFF && data.color >= 0)
			{
				Test_Tell("yes.\n");
				Check_Fpu();
				return True;
			}
		}
		break;
		 
	case typeScalar:
		Test_Tell("scalar? ");
		if (interpreter->GetScalar(&data.scalar))
		{
			Test_Tell("yes.\n");
			Check_Fpu();
			return True;
		}
		break;
 
	case typeVector:
		Test_Tell("vector? ");
		{
			Vector2DOf<int>
				temp_vector;

		if (interpreter->GetVector(&temp_vector))
		{
			data.vector.x = temp_vector.x;
			data.vector.y = temp_vector.y;
			Test_Tell("yes.\n");
			Check_Fpu();
			return True;
		}
		}
		break;

	case typeRectangle:
		Test_Tell("rectangle? ");
		{
			int
				success;

			success = (strcmp(interpreter->GetToken(), "(") == 0);
			success &= interpreter->GetInteger(&data.rectangle.bottomLeft.x);
			success &= (strcmp(interpreter->GetToken(), ",") == 0);
			success &= interpreter->GetInteger(&data.rectangle.bottomLeft.y);
			success &= (strcmp(interpreter->GetToken(), ",") == 0);
			success &= interpreter->GetInteger(&data.rectangle.topRight.x);
			success &= (strcmp(interpreter->GetToken(), ",") == 0);
			success &= interpreter->GetInteger(&data.rectangle.topRight.y);
			success &= (strcmp(interpreter->GetToken(), ")") == 0);

			if (success)
			{
				Test_Tell("yes.\n");
				Check_Fpu();
				return True;
			}
		}
		break;
		 
	case typeAttribute:
		{
			const char
				*token = interpreter->GetToken(); 
			Test_Tell("attribute='");
			Str_Copy(data.string, token, maxStringLength-1);
			Test_Tell(data.string << "'\n");
			Check_Fpu();
		}
		return True;

	case typeString:
		{
			const char
				*token = interpreter->GetToken(); 
			Test_Tell("string='");
			Str_Copy(data.string, token, maxStringLength-1);
			Test_Tell(data.string << "'\n");
			Check_Fpu();
		}
		return True;

	default:
		Fail("Illegal type");
		return False;
	}

	Test_Tell("NO!\n");
	Check_Fpu();
	return False;
}

void
	ParameterDescription::Save(GaugeInterpreter *interpreter)
{
	Test_Tell("ParameterDescription::Save(" << interpreter << ")\n");
	Check_Pointer(this);
	Check(interpreter);

	//
	//----------------------------------------------------------------
	// Choose the appropriate type, write to interpreter table
	//----------------------------------------------------------------
	//
	switch(type)
	{
	case typeEmpty:
		Fail("type == empty!");
		break;

	case typeRate:
		Test_Tell("rate\n");
		interpreter->Insert(&data.rate, sizeof(GaugeRate));
		break;
 
	case typeModeMask:
		Test_Tell("modeMask\n");
		interpreter->Insert(&data.modeMask, sizeof(ModeMask));
		break;
 
	case typeInteger:
		Test_Tell("integer\n");
		interpreter->Insert(&data.integer, sizeof(int));
		break;
 
	case typeColor:
		Test_Tell("color\n");
		interpreter->Insert(&data.color, sizeof(int));
		break;
		 
	case typeScalar:
		Test_Tell("scalar\n");
		interpreter->Insert(&data.scalar, sizeof(Scalar));
		break;
 
	case typeVector:
		Test_Tell("vector\n");
		interpreter->Insert(&data.vector.x, sizeof(int));
		interpreter->Insert(&data.vector.y, sizeof(int));
		break;
		 
	case typeRectangle:
		Test_Tell("rectangle\n");
		interpreter->Insert(&data.rectangle.bottomLeft.x, sizeof(int));
		interpreter->Insert(&data.rectangle.bottomLeft.y, sizeof(int));
		interpreter->Insert(&data.rectangle.topRight.x, sizeof(int));
		interpreter->Insert(&data.rectangle.topRight.y, sizeof(int));
		break;
		 
	case typeAttribute:
		Test_Tell("attribute\n");
		Check_Pointer(data.string);
		interpreter->InsertString(data.string);
		break;

	case typeString:
		Test_Tell("string\n");
		interpreter->InsertString(data.string);
		break;

	default:
		Fail("Illegal type");
		break;
	}
	Check_Fpu();
}

void
	ParameterDescription::Restore(
		GaugeInterpreter *interpreter,
		Entity *entity
	)
{
	Check_Pointer(this);
	Check(interpreter);

	Test_Tell("\nParameterDescription::Restore-");
	//
	//----------------------------------------------------------------
	// Choose the appropriate type, read from interpreter table
	//----------------------------------------------------------------
	//
	switch(type)
	{
	case typeEmpty:
		Fail("type == empty!");
		break;

	case typeRate:
		data.rate = *(GaugeRate *)interpreter->Retrieve(sizeof(GaugeRate));
		Test_Tell("rate=" << std::hex << data.rate << std::dec << "\n");
		break;             
 
	case typeModeMask:
		data.modeMask = *(ModeMask *)
			interpreter->Retrieve(sizeof(ModeMask));
		Test_Tell("modeMask=" << std::hex << data.modeMask << std::dec << "\n");
		break;             
 
	case typeInteger:
		data.integer = *(int *) (interpreter->Retrieve(sizeof(int)));
		Test_Tell("integer=" << data.integer << "\n");
		break;
 
	case typeColor:
		data.color = *(int *) (interpreter->Retrieve(sizeof(int)));
		Test_Tell("color=" << data.color << "\n");
		break;
		 
	case typeScalar:
		data.scalar = *(Scalar *) (interpreter->Retrieve(sizeof(Scalar)));
		Test_Tell("scalar=" << data.scalar << "\n");
		break;
 
	case typeVector:
		data.vector.x = *(int*) interpreter->Retrieve(sizeof(int));
		data.vector.y = *(int*) interpreter->Retrieve(sizeof(int));
		Test_Tell("vector=(" << data.vector.x << "," << data.vector.y << ")\n");
		break;
		 
	case typeRectangle:
		data.rectangle.bottomLeft.x = *(int*) interpreter->Retrieve(sizeof(int));
		data.rectangle.bottomLeft.y = *(int*) interpreter->Retrieve(sizeof(int));
		data.rectangle.topRight.x   = *(int*) interpreter->Retrieve(sizeof(int));
		data.rectangle.topRight.y   = *(int*) interpreter->Retrieve(sizeof(int));
		Test_Tell(
			"rectangle=((" << data.rectangle.bottomLeft.x <<
			"," << data.rectangle.bottomLeft.y <<
			"),(" << data.rectangle.topRight.x <<
			"," << data.rectangle.topRight.y <<
			"))\n"
		);
		break;
		 
	case typeAttribute:
		{
			const char
				*string_pointer = interpreter->RetrieveString();

			Verify(string_pointer != NULL);
			Test_Tell("attribute=" << string_pointer << "\n");
			//--------------------------------------
			// Replace if variable name
			//--------------------------------------
			string_pointer = interpreter->ReplaceVariable(string_pointer);
			//--------------------------------------
			// Change into true attribute pointer
			//--------------------------------------
			Check(entity);
			data.attributePointer = ParseAttribute(string_pointer, entity);
			Verify(data.attributePointer != NULL);
		}
		break;

	case typeString:
		Test_Tell("string\n");
		{
			// Get the string here INSTEAD of inside Str_Copy() because
			// of side effects! (string_pointer is referenced multiple times)
			const char
				*string_pointer = interpreter->RetrieveString();
			//--------------------------------------
			// Replace if variable name
			//--------------------------------------
			string_pointer = interpreter->ReplaceVariable(string_pointer);

			Test_Tell("string=" << string_pointer << "\n");
			Str_Copy(
				data.string,
				string_pointer,
				maxStringLength-1
			);
		}
		break;

	default:
		Fail("Illegal type");
		break;
	}
	Check_Fpu();
}

void
	ParameterDescription::DumpInterpreterEntry(
		GaugeInterpreter *interpreter,
		const char *indent
	)
{
	Check_Pointer(this);
	Check(interpreter);
	//----------------------------------------------------------------
	// Choose the appropriate type, read from interpreter table
	//----------------------------------------------------------------
	DEBUG_STREAM << indent << std::flush;

	switch(type)
	{
	case typeEmpty:
		DEBUG_STREAM << "***EMPTY***\n" << std::flush;
		break;

	case typeRate:
		{
			GaugeRate
				rate = *(GaugeRate *)
					interpreter->Retrieve(sizeof(GaugeRate));
			DEBUG_STREAM << "rate " << rate << "\n" << std::flush;
		}
		break;
 
	case typeModeMask:
		{
			ModeMask
				mask = *(ModeMask *)
					interpreter->Retrieve(sizeof(ModeMask));
			DEBUG_STREAM << "mask " << mask << "\n" << std::flush;
		}
		break;
 
	case typeInteger:
		{
			int
				i = *(int *) (interpreter->Retrieve(sizeof(int)));
			DEBUG_STREAM << std::dec << "int " << i << "\n" << std::flush;
		}
		break;
 
	case typeColor:
		{
			int
				i = *(int *) (interpreter->Retrieve(sizeof(int)));
			DEBUG_STREAM << "color 0x" << i << "\n" << std::flush;
		}
		break;
		 
	case typeScalar:
		{
			Scalar
				s = *(int *) (interpreter->Retrieve(sizeof(Scalar)));
			DEBUG_STREAM << std::dec << "scalar " << s << "\n" << std::flush;
		}
		break;
 
	case typeVector:
		{
			Vector2DOf<int>
				v;

			v.x = *(int *) (interpreter->Retrieve(sizeof(int)));
			v.y = *(int *) (interpreter->Retrieve(sizeof(int)));
			DEBUG_STREAM << std::dec << "vector " << v << "\n" << std::flush;
		}
		break;
		 
	case typeRectangle:
		{
			Rectangle2D
				r;

			r.bottomLeft.x = *(int *) (interpreter->Retrieve(sizeof(int)));
			r.bottomLeft.y = *(int *) (interpreter->Retrieve(sizeof(int)));
			r.topRight.x   = *(int *) (interpreter->Retrieve(sizeof(int)));
			r.topRight.y   = *(int *) (interpreter->Retrieve(sizeof(int)));
			DEBUG_STREAM << std::dec << "rectangle " << r << "\n" << std::flush;
		}
		break;
		 
	case typeAttribute:
		DEBUG_STREAM << "attribute '" << interpreter->RetrieveString() << "'\n" << std::flush;
		break;

	case typeString:
		DEBUG_STREAM << "string '" << interpreter->RetrieveString() << "'\n" << std::flush;
		break;

	default:
		DEBUG_STREAM << "ILLEGAL TYPE=" << type << "!!\n" << std::flush;
		break;
	}
	Check_Fpu();
}

//#############################################################################
// MethodDescription
//#############################################################################
void
	MethodDescription::ShowInstance(char *indent)
{
	Check_Pointer(this);

	DEBUG_STREAM << indent << "MethodDescription:\n" << std::flush;

	char
		temp[80];
	int
		i;

	DEBUG_STREAM << indent << "name   =" << name << "\n" << std::flush;
	DEBUG_STREAM << indent << "execute=" << execute << "\n" << std::flush;

	for(i=0; i<MaximumParameters; ++i)
	{
		if (parameterList[i].type == ParameterDescription::typeEmpty)
		{
			break;
		}

		Verify(strlen(indent)+2 < 80);
		sprintf(temp,"%s%2d:", indent, i);

		parameterList[i].ShowInstance(temp);
	}
	Check_Fpu();
}

void
	MethodDescription::Execute(
		int display_port_index,
		Vector2DOf<int> position,
		Entity *entity,
		GaugeRenderer *renderer
	)
{
	Check_Pointer(this);
	Check(renderer);
	Check(renderer->interpreter);     
	int
		i;
	//-------------------------------------------------------------
	// Restore the parameters from the interpreter table
	//-------------------------------------------------------------
	for (i=0; parameterList[i].type != ParameterDescription::typeEmpty; ++i)
	{
		parameterList[i].Restore(renderer->interpreter, entity);
	}
	//-------------------------------------------------------------
	// Execute the call
	//-------------------------------------------------------------
	Check_Pointer(execute);
#	if DEBUG_LEVEL > 0
		Logical
			result = 	
				(*execute)(
					display_port_index,
					position,
					entity,
					renderer
				);
		Verify(result == True);
#	else
		(*execute)(
			display_port_index,
			position,
			entity,
			renderer
		);
#	endif
	Check_Fpu();
}

//#######################################################################
// GaugeRendererStatistics
//#######################################################################
void
	GaugeRendererStatistics::Clear()
{
	sampleCount = 0;
	sum = (Scalar) 0;
	maximum = (Scalar) 0;
	Check_Fpu();
}

void
	GaugeRendererStatistics::Update(Scalar delta)
{
	++sampleCount;
	sum += delta;
	if (maximum < delta)
	{
		maximum = delta;
	}
	Check_Fpu();
}

Scalar
	GaugeRendererStatistics::CalculateAverage()
{
	Scalar
		average;

	if (sampleCount <= 0)
	{
		average = (Scalar) 0;
	}
	else
	{
		average = (Scalar) (sum/sampleCount);
	}

	Check_Fpu();
	return average;
}

//#############################################################################
// GaugeRenderer
//#############################################################################
GaugeRenderer
	*GaugeRenderer::headGaugeRenderer = NULL;

GaugeRenderer::GaugeRenderer():
	Renderer(
		application->GetApplicationLoopFrameRate(),
		MaxRendererComplexity,								// in renderer.cc (3.0f)
		DefaultRendererPriority,							// in renderer.hh (1)
		GaugeInterestType,									// in interest.hh
		DefaultInterestDepth,								// in interest.hh (1)
		GaugeRendererClassID									// in vdata.hh
	),
	newList(NULL),
	activeList(NULL),
	inactiveList(NULL),
	lampManager(NULL)			// instantiated at topmost level only
{
	Test_Tell("GaugeRenderer::GaugeRenderer()\n");
	Check_Pointer(this);

	int
		i;

	suspended = False;
	previousModeMask = (ModeMask) 0;
	//---------------------------------------------------------------------
	// Ensure that graphicsPort pointers are NULL
	//---------------------------------------------------------------------
	for (i=0; i<maximumGraphicsPorts; ++i)
	{
		graphicsPort[i] = NULL;
	}
	//---------------------------------------------------------------------
	// Register the gauge map item collection objects
	//---------------------------------------------------------------------
	Register_Object(&movingEntities);
	Register_Object(&staticEntities);
	//----------------------------------------------------
	// Add this object to the chain
	//----------------------------------------------------
	nextGaugeRenderer = headGaugeRenderer;
	headGaugeRenderer = this;
	//----------------------------------------------------
	// Initialize the rate index
	//----------------------------------------------------
	rateBitMask = 0;
	rateProfileIndex = 0;
	//----------------------------------------------------
	// Clear the warehouse pointer
	//----------------------------------------------------
	warehousePointer = NULL;
	//----------------------------------------------------
	// Create the interpreter
	//----------------------------------------------------
	interpreter = new GaugeInterpreter();
	Register_Object(interpreter);
	//----------------------------------------------------
	// Clear the gauge alarm manager pointer
	//----------------------------------------------------
	gaugeAlarmManager = NULL;
	//----------------------------------------------------
	// Set up background processing
	//----------------------------------------------------
	taskMode = foreground;
	activeIterator = new SChainIteratorOf<GaugeBase*>(activeList);
	Register_Object(activeIterator);
	//----------------------------------------------------
	// Clear load-balancing data
	//----------------------------------------------------
	for(i=0; i<slotCount; ++i)
	{
		load[i] = (Scalar) 0;
	}
	//----------------------------------------------------
	// Clear profiling data
	//----------------------------------------------------
#	if defined (PROFILE_GAUGES)
		for (i=0; i<slotCount; ++i)
		{
			for (int j=0; j<tierCount; ++j)
			{
				statistics[i][j].Clear();
			}
		}
#	endif
	Check_Fpu();
}

//===========================================================================
// ~GaugeRenderer
//===========================================================================
GaugeRenderer::~GaugeRenderer()
{
	Check(this);

	Test_Tell("GaugeRenderer::~GaugeRenderer()\n");
	//
	//--------------------------------------------------------------------
	// Delete local data structures
	//--------------------------------------------------------------------
	//
	ShutdownImplementation();
	//---------------------------------------------------------------------
	// Delete the interpreter
	//---------------------------------------------------------------------
	Check(interpreter);
	Unregister_Object(interpreter);
	delete interpreter;
	//---------------------------------------------------------------------
	// Delete the gauge alarm manager
	//---------------------------------------------------------------------
	if (gaugeAlarmManager != NULL)
	{
		Check(gaugeAlarmManager);
		Unregister_Object(gaugeAlarmManager);
		delete gaugeAlarmManager;
   }
	//---------------------------------------------------------------------
	// Delete the lamp manager
	//---------------------------------------------------------------------
	if (lampManager != NULL)
	{
		Unregister_Object(lampManager);
		delete lampManager;
	}
	//---------------------------------------------------------------------
	// Delete the active list background iterator
	//---------------------------------------------------------------------
	Unregister_Object(activeIterator);
	delete activeIterator;
	activeIterator = NULL;
	//---------------------------------------------------------------------
	// Unregister the gauge map item collection objects
	//---------------------------------------------------------------------
	Unregister_Object(&movingEntities);
	Unregister_Object(&staticEntities);
	//--------------------------------------------------------------------
	// Unlink this object from the chain
	//--------------------------------------------------------------------
	GaugeRenderer
		*gauge_renderer,
		*previous_gauge_renderer(NULL);

	//
	// Search for 'this' in the chain
	//
	for(
		gauge_renderer = headGaugeRenderer;
		gauge_renderer != NULL;
		gauge_renderer = gauge_renderer->nextGaugeRenderer
		)
	{
		if (gauge_renderer == this)
		{
			//
			// Found! head of list?
			//
			if (previous_gauge_renderer == NULL)
			{
				headGaugeRenderer = nextGaugeRenderer;
			}
			//
			// Not head, remove from chain
			//
			else
			{
				previous_gauge_renderer->nextGaugeRenderer =
					nextGaugeRenderer;
			}
			break;
		}
		//
		// Keep track of 'previous' object
		//
		previous_gauge_renderer = gauge_renderer;
	}

	Check_Fpu();
}

//===========================================================================
// EmergencyShutdown
//===========================================================================
void
	GaugeRenderer::EmergencyShutdown()
{
	Test_Tell("GaugeRenderer::EmergencyShutdown()\n");

	GaugeRenderer
		*gauge_renderer;

	for(
		gauge_renderer = headGaugeRenderer;
		gauge_renderer != NULL;
		gauge_renderer = gauge_renderer->nextGaugeRenderer
		)
	{
		gauge_renderer->LocalEmergencyShutdown();
	}
}

//===========================================================================
// LocalEmergencyShutdown
//===========================================================================
void
	GaugeRenderer::LocalEmergencyShutdown()
{
}

//
//===========================================================================
// TestInstance
//===========================================================================
//
Logical
	GaugeRenderer::TestInstance() const
{
	//--------------------------------------------------------------------
	// Check the base renderer
	//--------------------------------------------------------------------
	return Renderer::TestInstance();
}

//
//===========================================================================
// LinkToEntity
//===========================================================================
//
void
	GaugeRenderer::LinkToEntity(Entity *entity)
{
	Check(this);
	Check(entity);

	Test_Tell("GaugeRenderer::LinkToEntity(" << entity << ")\n");

	//
	//--------------------------------------------------------------------
	// Inform all gauges
	//--------------------------------------------------------------------
	//
	GaugeBase
		*base_pointer;

	if (! suspended)
	{
		{
			SChainIteratorOf<GaugeBase*>
				i(newList);

			while ((base_pointer=i.ReadAndNext()) != NULL)
			{
				Check(base_pointer);
				base_pointer->LinkToEntity(entity);
			}
		}
		{
			SChainIteratorOf<GaugeBase*>
				i(activeList);

			while ((base_pointer=i.ReadAndNext()) != NULL)
			{
				Check(base_pointer);
				base_pointer->LinkToEntity(entity);
			}
		}
		{
			SChainIteratorOf<GaugeBase*>
				i(inactiveList);

			while ((base_pointer=i.ReadAndNext()) != NULL)
			{
				Check(base_pointer);
				base_pointer->LinkToEntity(entity);
			}
		}
	}
	//
	//--------------------------------------------------------------------
	// Call inherited method
	//--------------------------------------------------------------------
	//
	Renderer::LinkToEntity(entity);
	Check_Fpu();
}

//
//===========================================================================
// NotifyOfNewInterestingEntity
//===========================================================================
//
void
	GaugeRenderer::NotifyOfNewInterestingEntity(Entity *entity)
{
	Test_Tell("GaugeRenderer::NotifyOfNewInterestingEntity\n");
	Check(this);
	Check(entity);

	//------------------------------------------------------
	// This method used to update both the movingEntities
	// and staticEntities records.  That functionality has
	// been moved up to the game-specific level (e.g.,
	// RPL4GaugeRenderer) to allow the game to determine
	// what to show.  Note that all descendents MUST chain
	// back to this base method...
	//------------------------------------------------------
	//
	//--------------------------------------------------------------------
	// Inform all gauges
	//--------------------------------------------------------------------
	//
	GaugeBase
		*base_pointer;

	if (! suspended)
	{
		{
			SChainIteratorOf<GaugeBase*>
				i(newList);

			while ((base_pointer=i.ReadAndNext()) != NULL)
			{
				Check(base_pointer);
				base_pointer->NotifyOfNewInterestingEntity(entity);
			}
		}
		{
			SChainIteratorOf<GaugeBase*>
				i(activeList);

			while ((base_pointer=i.ReadAndNext()) != NULL)
			{
				Check(base_pointer);
				base_pointer->NotifyOfNewInterestingEntity(entity);
			}
		}
		{
			SChainIteratorOf<GaugeBase*>
				i(inactiveList);

			while ((base_pointer=i.ReadAndNext()) != NULL)
			{
				Check(base_pointer);
				base_pointer->NotifyOfNewInterestingEntity(entity);
			}
		}
	}
	Check_Fpu();
}


//
//===========================================================================
// NotifyOfBecomingUninterestingEntity
//===========================================================================
//
void
	GaugeRenderer::NotifyOfBecomingUninterestingEntity(Entity *entity)
{
	Test_Tell("GaugeRenderer::NotifyOfBecomingUninterestingEntity\n");
	Check(this);
	Check(entity);
	//------------------------------------------------------
	// This method used to update both the movingEntities
	// and staticEntities records.  That functionality has
	// been moved up to the game-specific level (e.g.,
	// RPL4GaugeRenderer) to allow the game to determine
	// what to show.  Note that all descendents MUST chain
	// back to this base method...
	//------------------------------------------------------
	//
	//--------------------------------------------------------------------
	// Inform all gauges
	//--------------------------------------------------------------------
	//
	GaugeBase
		*base_pointer;

	if (! suspended)
	{
		{
			SChainIteratorOf<GaugeBase*>
				i(newList);

			while ((base_pointer=i.ReadAndNext()) != NULL)
			{
				Check(base_pointer);
				base_pointer->NotifyOfBecomingUninterestingEntity(entity);
			}
		}
		{
			SChainIteratorOf<GaugeBase*>
				i(activeList);

			while ((base_pointer=i.ReadAndNext()) != NULL)
			{
				Check(base_pointer);
				base_pointer->NotifyOfBecomingUninterestingEntity(entity);
			}
		}
		{
			SChainIteratorOf<GaugeBase*>
				i(inactiveList);

			while ((base_pointer=i.ReadAndNext()) != NULL)
			{
				Check(base_pointer);
				base_pointer->NotifyOfBecomingUninterestingEntity(entity);
			}
		}
	}
	Check_Fpu();
}

//
//===========================================================================
// Entity alarms
//===========================================================================
//
void
	GaugeRenderer::StartEntityAlarmImplementation(
		Entity *entity,
		Subsystem *subsystem,
		Enumeration condition,
		ResourceDescription::ResourceID resource_ID
	)
{
	Check(this);

	Check(gaugeAlarmManager);
	gaugeAlarmManager->Activate(
		entity,
		subsystem,
		condition,
		resource_ID
	);
	Check_Fpu();
}
void
	GaugeRenderer::StopEntityAlarmImplementation(
		Entity *entity,
		Subsystem *subsystem,
		Enumeration condition
	)
{
	Check(this);

	Check(gaugeAlarmManager);
	gaugeAlarmManager->Deactivate(
		entity,
		subsystem,
		condition
	);
	Check_Fpu();
}

//
//===========================================================================
// LoadMissionImplementation
//===========================================================================
//
void
	GaugeRenderer::LoadMissionImplementation(Mission */*mission*/)
{
	Tell("GaugeRenderer::LoadMissionImplementation()\n");
	Check(this);


//DEBUG_STREAM << "Mover list has " <<
// 	movingGaugeImages.NumberOfItems() << "items.\n";
//staticGaugeImages.PrintStatistics();


	Check_Fpu();
}

//
//===========================================================================
// ShutdownImplementation
//===========================================================================
//
void
	GaugeRenderer::ShutdownImplementation()
{
	Tell("GaugeRenderer::ShutdownImplementation()\n");
	Check(this);

	//--------------------------------------------------------------------
	// Turn off all gauge alarms
	//--------------------------------------------------------------------
	if (gaugeAlarmManager != NULL)
	{
		Check(gaugeAlarmManager);
		gaugeAlarmManager->RemoveAllAlarms();
	}
	//--------------------------------------------------------------------
	// Delete all remaining gauges BEFORE clearing out the warehouse!
	// ...otherwise the gauges will attempt to reference items which
	// no longer exist in the warehouse...
	//--------------------------------------------------------------------
	Remove(0);
	//--------------------------------------------------------------------
	// Remove all lamps
	//--------------------------------------------------------------------
	if (lampManager != NULL)
	{
		Check(lampManager);
		lampManager->RemoveAllLamps();
	}
	//--------------------------------------------------------------------
	// Clear out the warehouse
	//--------------------------------------------------------------------
	if (warehousePointer != NULL)
	{
		Check(warehousePointer);
		warehousePointer->Purge();
	}
	//--------------------------------------------------------------------
	// Clear auxiliary data structures
	//--------------------------------------------------------------------
	movingEntities.Clear();
	staticEntities.Clear();
	//---------------------------------------------------------------------
	// Destroy all graphicsPort objects
	//---------------------------------------------------------------------
	int
		i;

	for (i=0; i<maximumGraphicsPorts; ++i)
	{
		if (graphicsPort[i] != NULL)
		{
			Unregister_Object(graphicsPort[i]);
			delete graphicsPort[i];
			graphicsPort[i] = NULL;
		}
	}
	Check_Fpu();
}

//
//===========================================================================
// SuspendImplementation
//===========================================================================
//
void
	GaugeRenderer::SuspendImplementation()
{
	Tell("GaugeRenderer::SuspendImplementation()\n");
	Check(this);
	suspended = True;
	Check_Fpu();
}

//
//===========================================================================
// ResumeImplementation
//===========================================================================
//
void
	GaugeRenderer::ResumeImplementation()
{
	Tell("GaugeRenderer::ResumeImplementation()\n");
	Check(this);
	suspended = False;
	Check_Fpu();
}

//
//===========================================================================
// FindGraphicsPort
//===========================================================================
//
int
	GaugeRenderer::FindGraphicsPort(const char * port_name)
{
	Test_Tell("GaugeRenderer::FindGraphicsPort(" << port_name << ")\n");
	if (port_name != NULL)
	{
		for(int i=0; i<maximumGraphicsPorts; ++i)
		{
			if (graphicsPort[i] != NULL)
			{
				Test_Tell(graphicsPort[i]->name << " ");
				if (stricmp(graphicsPort[i]->name, port_name) == 0)
				{
					Test_Tell("<-Found\n");
					Check_Fpu();
					return i;
				}
			}
		}
	}
	Check_Fpu();
	return -1;
}

//
//===========================================================================
// GetGraphicsPort
//===========================================================================
//
GraphicsPort
	*GaugeRenderer::GetGraphicsPort(const char * port_name)
{
	int i(FindGraphicsPort(port_name));

	Check_Fpu();
	if (i >= 0)
	{
		return graphicsPort[i];
	}
	return NULL;
}

GraphicsPort
	*GaugeRenderer::GetGraphicsPort(int port_number)
{
	Check_Fpu();
	if ((port_number >= 0) && (port_number < maximumGraphicsPorts))
	{
		return graphicsPort[port_number];
	}
	else
	{
		return NULL;
	}
}

//
//===========================================================================
// Add
//===========================================================================
//
void
	GaugeRenderer::Add(GaugeBase *new_gauge)
{
	Tell("GaugeRenderer::Add(" << std::hex << new_gauge << std::dec << ")\n");
	Check(this);
	//
	// Don't call Check(new_gauge) here!
	// The Gauge creator calls AddGauge before the gauge is fully built!
	//
	Check_Pointer(new_gauge);
	//-------------------------------------------------------------------------
	// Add to 'new' list
	//-------------------------------------------------------------------------
	newList.Add(new_gauge);
	Check_Fpu();
}

//
//===========================================================================
// Remove
//===========================================================================
//
void
	GaugeRenderer::Remove(unsigned int owner_ID)
{
	Tell("GaugeRenderer::Remove(" << owner_ID << ")\n");
	Check(this);

	GaugeBase
		*the_base;

	//--------------------------------------------------
	// Search active list first
	//--------------------------------------------------
	{
		SChainIteratorOf<GaugeBase*>
			i(activeList);
		//--------------------------------------------------
		// Process all matching gauges
		//--------------------------------------------------
		while ((the_base=i.GetCurrent()) != NULL)
		{
			Check(the_base);

			if ((owner_ID == 0) || (the_base->ownerID == owner_ID))
			{
				//-----------------------------------------------
				// 'Flush' the gauge before deleting it
				//-----------------------------------------------
				the_base->Update(Gauge::gaugeRate_A);
				//-----------------------------------------------
				// Delete it
				//-----------------------------------------------
				i.Remove();
				Tell(the_base->identificationString << "\n" << flush);
				Unregister_Object(the_base);
				delete the_base;
			}
			else
			{
				i.Next();
			}
		}
	}
	//--------------------------------------------------
	// Search inactive list second
	//--------------------------------------------------
	{
		SChainIteratorOf<GaugeBase*>
			i(inactiveList);
		//--------------------------------------------------
		// Process all matching gauges
		//--------------------------------------------------
		while ((the_base=i.GetCurrent()) != NULL)
		{
			Check(the_base);

			if ((owner_ID == 0) || (the_base->ownerID == owner_ID))
			{
				//-----------------------------------------------
				// Delete it
				//-----------------------------------------------
				i.Remove();
				Tell(the_base->identificationString << "\n" << flush);
				Unregister_Object(the_base);
				delete the_base;
			}
			else
			{
				i.Next();
			}
		}
	}
	Check_Fpu();
}

//
//===========================================================================
// Remove
//===========================================================================
//
void
	GaugeRenderer::Inactivate(GaugeBase *the_base)
{
	Tell("GaugeRenderer::Inactivate(" << std::hex << the_base << std::dec << ")\n");
	Check(this);

	GaugeBase
		*the_other_base;

	//--------------------------------------------------
	// Search active list for the base
	//--------------------------------------------------
	SChainIteratorOf<GaugeBase*>
		i(activeList);

	while ((the_other_base=i.GetCurrent()) != NULL)
	{
		Check(the_other_base);

		if (the_base == the_other_base)
		{
			//-----------------------------------------------
			// Remove from this list, place in inactive list
			//-----------------------------------------------
			i.Remove();
			inactiveList.Add(the_base);
			the_base->BecameInactive();
			break;
		}
		else
		{
			i.Next();
		}
	}
	Check_Fpu();
}

GaugeRate
	GaugeRenderer::FindBestFirstTierRate()
{
	return Gauge::gaugeRate_B;		// HACK -stubbed in
}

GaugeRate
	GaugeRenderer::FindBestSecondTierRate()
{
	return Gauge::gaugeRate_D;		// HACK -stubbed in
}

GaugeRate
	GaugeRenderer::FindBestThirdTierRate()
{
	return Gauge::gaugeRate_H;		// HACK -stubbed in
}                           

GaugeRate
	GaugeRenderer::FindBestFourthTierRate()
{
	return Gauge::gaugeRate_P;		// HACK -stubbed in
}

//
//===========================================================================
// ExecuteImplementation
//===========================================================================
//
void
	GaugeRenderer::ExecuteImplementation(
		RendererComplexity /*complexity*/,
		RendererOrigin::InterestingEntityIterator */*iterator*/
	)
{
	SET_GAUGE_RENDERER();
	Check(this);

	if (! suspended)
	{
		if (taskMode == foreground)
		{
			ExecuteForeground();
		}
	}
	Check_Fpu();
	CLEAR_GAUGE_RENDERER();
}

void
	GaugeRenderer::ExecuteForeground()
{

	Check(this);
	Check(activeIterator);

	//-------------------------------------------------------------------
	// Get the current mode mask
	//-------------------------------------------------------------------
	Check(application);
	Check(application->GetModeManager());
	ModeMask
		current_mode_mask = application->GetModeManager()->GetModeMask();
	ModeMask
		previous_mode_mask = application->GetModeManager()->GetPreviousModeMask();
	ModeMask
		change_mode_mask = current_mode_mask ^ previous_mode_mask;       // xor tells me what has changed
	//-------------------------------------------------------------------
	// Update lamp manager
	//-------------------------------------------------------------------
	if (lampManager != NULL)
	{
		Check(lampManager);
		lampManager->Update(current_mode_mask);
	}
	//-------------------------------------------------------------------
	// Move new gauges to active/inactive lists
	//-------------------------------------------------------------------
	{
		SChainIteratorOf<GaugeBase*>
			i(newList);
		GaugeBase
			*base_pointer;

		while ((base_pointer=i.GetCurrent()) != NULL)
		{
			//-------------------------------------
			// Always remove from 'new' list
			//-------------------------------------
			i.Remove();
			//-------------------------------------
			// Place in appropriate list
			//-------------------------------------
			Check(base_pointer);
			if (base_pointer->modeMask & current_mode_mask)
			{

				// If not already flagged,  or gauge's mode mask is always active,
				// or the mode change affects us, place into active list
				if (!(base_pointer->alreadyActivatedFlag)
				  //	|| (base_pointer->modeMask == ModeManager::ModeAlwaysActive)
					|| (base_pointer->modeMask & change_mode_mask))
				{
					base_pointer->alreadyActivatedFlag = True;
					//-------------------------------------
					// Announce new status
					//-------------------------------------
					base_pointer->BecameActive();
					//-------------------------------------
					// Place in active list only if legal
					//-------------------------------------
					if (base_pointer->stayInactive)
					{
						inactiveList.Add(base_pointer);
					}
					else
					{
						activeList.Add(base_pointer);
					}
				}
			}
			else
			{
				inactiveList.Add(base_pointer);
			}
		}
	}
	//---------------------------------------------------------------
	// If the modeMask has changed, update the active/inactive lists.
	//---------------------------------------------------------------
	if (previousModeMask != current_mode_mask)
	{
		previousModeMask = current_mode_mask;

		ActivateGaugeBases(current_mode_mask,change_mode_mask);
		DeactivateGaugeBases(current_mode_mask);
	}
	//---------------------------------------------------------------
	// Restart background processing
	//---------------------------------------------------------------
	taskMode = background;
	activeIterator->First();
	//--------------------------------
	// Reset rate bit mask if needed
	//--------------------------------
	if (rateBitMask == 0)
	{
		rateBitMask = 0x8000;
#		if defined (PROFILE_GAUGES)
			rateProfileIndex = 0;
#		endif
	}
	Check_Fpu();
}

//
//===========================================================================
// ExecuteBackground
//===========================================================================
//
Logical
	GaugeRenderer::ExecuteBackground()
{
	SET_GAUGE_RENDERER();
	Check(this);

	Logical
		result;

   Time start, end;
   int oldTaskMode = taskMode;

	switch(taskMode)
	{
	case foreground:
		result = ExecuteBackgroundDisplayUpdate();	// might as well update
		break;

	case background:
      {
         result = ProcessOneActiveGauge();
		   break;
      }

	case copy:
		result = ExecuteBackgroundDisplayUpdate();
		break;
	}

   if (end.ticks - start.ticks > 100)
   {
      end = start;
   }

	Check_Fpu();
	CLEAR_GAUGE_RENDERER();
	return result;
}

Logical
	GaugeRenderer::ExecuteBackgroundDisplayUpdate()
{
	Check(this);
	return False;
}

//
//===========================================================================
// ActivateGaugeBases
//===========================================================================
//
void
	GaugeRenderer::ActivateGaugeBases(ModeMask current_mode_mask, ModeMask change_mode_mask)
{
	Check(this);
	//-----------------------------------------------------------
	// Test the objects in the 'inactive' list.  If any of them
	// have bits in their modeMask corresponding to the
	// new mode mask, move them to the 'active' list.
	//-----------------------------------------------------------
	SChainIteratorOf<GaugeBase*>
		i(inactiveList);
	GaugeBase
		*base_pointer;

	while ((base_pointer=i.GetCurrent()) != NULL)
	{
		Check(base_pointer);
		//-----------------------------------
		// Became active?
		//-----------------------------------
		if (base_pointer->modeMask & current_mode_mask)
		{
			if (!(base_pointer->alreadyActivatedFlag)
			 //	|| (base_pointer->modeMask == ModeManager::ModeAlwaysActive)
				|| (base_pointer->modeMask & change_mode_mask))
			{
				#if 0
				DEBUG_STREAM << "Activating an inactive (not visible) gauge on inactive list" << endl << std::flush;
				#endif
				//-----------------------------------
				// Inform object of new status
				//-----------------------------------
				base_pointer->BecameActive();
				base_pointer->alreadyActivatedFlag = True;


				//-----------------------------------
				// Move to 'active' list if allowed
				//-----------------------------------
				if (base_pointer->stayInactive)
				{
					i.Next();
				}
				else
				{
					i.Remove();
					activeList.Add(base_pointer);
				}
			}
			else
			{
				i.Next();        
			}
		}
		else
		{
			//-----------------------------------
			// No, try the next one
			//-----------------------------------
			i.Next();
		}
	}
	Check_Fpu();
}

//
//===========================================================================
// DeactivateGaugeBases
//===========================================================================
//
void
	GaugeRenderer::DeactivateGaugeBases(ModeMask current_mode_mask)
{
	Check(this);
	//---------------------------------------------------------------
	// Test the objects in the 'active' list.  If any of them do NOT
	// have bits in their modeMask corresponding to the new mode
	// mask, move them to the 'inactive' list.
	//---------------------------------------------------------------
	SChainIteratorOf<GaugeBase*>
		i(activeList);
	GaugeBase
		*base_pointer;

	while ((base_pointer=i.GetCurrent()) != NULL)
	{
		Check(base_pointer);
		//-----------------------------------
		// Became inactive?
		//-----------------------------------
		if (!(base_pointer->modeMask & current_mode_mask))
		{
			base_pointer->alreadyActivatedFlag = False;
			//-----------------------------------
			// Yes, move to 'inactive' list
			//-----------------------------------
			i.Remove();
			inactiveList.Add(base_pointer);

			base_pointer->BecameInactive();

		}
		else
		{
			//-----------------------------------
			// No, try the next one
			//-----------------------------------
			i.Next();
		}
	}
	Check_Fpu();
}

//
//===========================================================================
// ProcessOneActiveGauge
//===========================================================================
//
Logical
	GaugeRenderer::ProcessOneActiveGauge()
{
	Check(this);
	Check(activeIterator);

	Logical
		result;
	GaugeBase
		*base_pointer = activeIterator->ReadAndNext();

	if (base_pointer == NULL)
	{
		//--------------------------------------------------
		// We're done!
		// Bump the bit mask and index for the next pass
		//--------------------------------------------------
		rateBitMask >>= 1;
#		if defined (PROFILE_GAUGES)
			++rateProfileIndex;
#		endif
		//--------------------------------------------------
		// Inform system that we are finished
		//--------------------------------------------------
		taskMode = copy;
		result = True;		// Don't stop just yet! Go into third phase!
	}
	else
	{
		//--------------------------------------------------
		// Process one gauge
		//--------------------------------------------------
		Check(base_pointer);
#		if defined (PROFILE_GAUGES)
			Scalar
				delta = GetCurrentFramePercentage();

			Logical
				actually_ran =
#		endif
					base_pointer->Update(rateBitMask);

#		if defined (PROFILE_GAUGES)
			delta = GetCurrentFramePercentage() - delta;
			if (delta < (Scalar) 0)
			{
				// Hack - what does it REALLY mean when it's negative?!?
				delta = - delta;
			}

			if (actually_ran)
			{
				base_pointer->UpdateProfile(delta);
			}
			statistics[rateProfileIndex][base_pointer->DiscernTier()]
				.Update(delta);
#		endif
		//--------------------------------------------------
		// Tell renderer manager that we have more to do
		//--------------------------------------------------
		result = True;
	}
	return result;
}

//
//===========================================================================
// GetCurrentFramePercentage
//===========================================================================
//
Scalar
	GaugeRenderer::GetCurrentFramePercentage()
{
	Check(this);
	return (Scalar) 0;
}

enum
{
	average_bar,
	maximum_bar
};

#if defined (PROFILE_GAUGES)
	static Scalar
		draw_bar(
			GaugeRenderer *renderer,
			int bar_width,
			int slot_index,
			int bar_type
		)
	{
		Check(renderer);
		//------------------------------------
		// Show individual tier contributors
		//------------------------------------
		Scalar
			value,
			total_value = (Scalar) 0;
		Scalar
			position = (Scalar) 0;
		int
			tier_index,
			char_position = 0,
			next_char_position;

		for(tier_index=0; tier_index<GaugeRenderer::tierCount; ++tier_index)
		{
			//------------------------------------
			// Choose tier marker to print
			//------------------------------------
			static char
				*tier_number[GaugeRenderer::slotCount] =
					{
						"ABDHP",
						"ABDHQ",
						"ABDIR",
						"ABDIS",
						"ABEJT",
						"ABEJU",
						"ABEKV",
						"ABEKW",
						"ACFLX",
						"ACFLY",
						"ACFMZ",
						"ACFM0",
						"ACGN1",
						"ACGN2",
						"ACGo3",
						"ACGo4",
					};
			char
				tier_marker = tier_number[slot_index][tier_index];
			//------------------------------------
			// Get, clear tier statistics
			//------------------------------------
			switch(bar_type)
			{
			default:
				value=
					renderer->statistics[slot_index][tier_index].CalculateAverage();
				break;

			case maximum_bar:
				value=
					renderer->statistics[slot_index][tier_index].maximum;
				break;
			}
			//------------------------------------
			// Add to total
			// Calculate next bar position
			//------------------------------------
			total_value += value;
			position += bar_width * value;
			//------------------------------------
			// Limit it in case of overflow
			//------------------------------------
			if (position > (Scalar) bar_width)
			{
				position = (Scalar) bar_width;
			}
			//------------------------------------
			// Draw with marker to next position
			//------------------------------------
			next_char_position = (int) position;

			for( ; char_position < next_char_position; ++char_position)
			{
				DEBUG_STREAM << tier_marker << std::flush;
			}
		}
		//------------------------------------
		// Fill unused space in bar
		//------------------------------------
		for( ; char_position < bar_width; ++char_position)
		{
			DEBUG_STREAM << "." << std::flush;
		}

		Check_Fpu();
		return total_value;
	}
#endif


void
	GaugeRenderer::ProfileReport()
{
	Check(this);

#	if defined (PROFILE_GAUGES)
		//--------------------------------------------------------------
		// Show all gauges
		//--------------------------------------------------------------
		{
			SChainIteratorOf<GaugeBase*>
				i(activeList);
			GaugeBase
				*the_base;

		DEBUG_STREAM <<"Active name                      count avg    worst\n" << std::flush;
		DEBUG_STREAM <<"-------------------------------- ----- ------ -----\n" << std::flush;
			while ((the_base=i.ReadAndNext()) != NULL)
			{
				Check(the_base);
				the_base->ReportProfile();
			}
		}
		{
			SChainIteratorOf<GaugeBase*>
				i(inactiveList);
			GaugeBase
				*the_base;

		DEBUG_STREAM <<"Inactive name                    count avg    worst\n" << std::flush;
		DEBUG_STREAM <<"-------------------------------- ----- ------ -----\n" << std::flush;
			while ((the_base=i.ReadAndNext()) != NULL)
			{
				Check(the_base);
				the_base->ReportProfile();
			}
		}
		//--------------------------------------------------------------------
		// Dump profiling data
		//--------------------------------------------------------------------
		int
			slot_index,
			tier_index,
			bar_width = 40;			// total width of bar graph
		char
			buffer[80];
		//------------------------------------
		// Print header bar
		//------------------------------------
		DEBUG_STREAM << "\nSlot|Count|Tier values                             " << std::flush;
		DEBUG_STREAM << "|Total %\n" << std::flush;
		DEBUG_STREAM << "----+-----+" << std::flush;
		{
			for(int i=0; i<bar_width; ++i)
			{
				DEBUG_STREAM << "-" << std::flush;
			}
			DEBUG_STREAM << "+-------\n" << std::flush;
		}

		for(slot_index=0; slot_index<slotCount; ++slot_index)
		{
			//------------------------------------
			// Print slot number header
			//------------------------------------
			sprintf(buffer, "%2d  |", slot_index);
			DEBUG_STREAM << buffer << std::flush;
			//------------------------------------
			// Get total number of samples
			//------------------------------------
			int
				sample_count = 0;
			for(tier_index=0; tier_index<tierCount; ++tier_index)
			{
				sample_count += statistics[slot_index][tier_index].sampleCount;
			}
			//------------------------------------
			// If no data, say so
			//------------------------------------
			if (sample_count <= 0)
			{
				DEBUG_STREAM << "No samples available\n" << std::flush;
			}
			else
			{
				//------------------------------------
				// Show average values
				//------------------------------------
				sprintf(buffer, "%5d|", sample_count);
				DEBUG_STREAM << buffer << std::flush;

				Scalar
					total_average = draw_bar(
						this, bar_width, slot_index, average_bar
					);
				sprintf(buffer, "|%5.2f%%\n", total_average * (Scalar) 100);
				DEBUG_STREAM << buffer << std::flush;
				//------------------------------------
				// Show maximum values
				//------------------------------------
				DEBUG_STREAM << "    |Worst|" << std::flush;

				Scalar
					total_worst = draw_bar(
						this, bar_width, slot_index, maximum_bar
					);
				sprintf(buffer, "|%5.2f%%\n", total_worst * (Scalar) 100);
				DEBUG_STREAM << buffer << std::flush;
				//------------------------------------
				// Clear stats
				//------------------------------------
				for(tier_index=0; tier_index<tierCount; ++tier_index)
				{
					statistics[slot_index][tier_index].Clear();
				}
			}
		}
#	endif

	Check_Fpu();
}

//
//===========================================================================
// Configuration
//===========================================================================
//
void
	GaugeRenderer::BuildConfigurationFile(
		const char *file_name,
		MethodDescription **method_description
	)
{
	Test_Tell(
		"GaugeRenderer::BuildConfigurationFile('" << file_name <<
		"', " << method_description <<
		")\n"
	);
	Check(this);
	Check_Pointer(file_name);
	Check_Pointer(method_description);
	//-----------------------------------------------
	// Initialize the interpreter
	//-----------------------------------------------
	Check(interpreter);
	interpreter->Initialize(file_name, method_description, warehousePointer);
	//-----------------------------------------------
	// Execute app initialization call, if it exists
	//-----------------------------------------------
	Configure("Initialization", NULL);
	Check_Fpu();
}

void
	GaugeRenderer::Configure(
		const char *label,
		Entity *entity
	)
{
	Test_Tell(
		"GaugeRenderer::Configure('" << label <<
		"', " << entity <<
		")\n"
	);
	Check(this);
	Check_Pointer(label);

	Vector2DOf<int>
		position;

	position.x = 0;
	position.y = 0;
	Check(interpreter);
	interpreter->Interpret(label, this, 0, position, entity);

	Check_Fpu();
}
