#pragma once

#if defined(TRACE_GUAUGE_RENDERER)
	extern BitTrace Gauge_Renderer;
	#define SET_GUAGE_RENDERER()	Gauge_Renderer.Set()
	#define CLEAR_GUAGE_RENDERER()	Gauge_Renderer.Clear()
#else
	#define SET_GAUGE_RENDERER()
	#define CLEAR_GAUGE_RENDERER()
#endif

class GaugeSymbol;
class GaugeSymbolTable;
class GaugeInterpreter;
struct ParameterDescription;
struct MethodDescription;
class GaugeRenderer;
class LampManager;

#include <fstream>
#include "renderer.h"
#include "gaugalrm.h"
#include "resource.h"
#include "gaugmap.h"
#include "gauge.h"
#include "lamp.h"
#include "wrhous.h"

struct LookupTable
{
	const
		char *typeString;
	int
		value;

	int
		Search(const char *string);
};

//#######################################################################
// Interpreter
//#######################################################################
typedef unsigned char GaugeInterpreterCommand;
typedef int GaugeInterpreterOffset;

class GaugeSymbol SIGNATURED
{
	friend class GaugeSymbolTable;
	friend class GaugeInterpreter;
public:
	~GaugeSymbol();	// WARNING - do NOT destroy individual entries!
							// This implementation assumes that once a symbol
							// is defined, it exists until ALL symbols are
							// destroyed: this allows a very simple singly-
							// linked-list structure.
							// Deleting an entry WILL corrupt the list.
	Logical
		TestInstance() const;
protected:
	GaugeSymbol(
		GaugeSymbol **head_pointer,
		const char *label,
		GaugeInterpreterOffset offset,
		Logical resolved
	);

	char
		label[32];
	GaugeInterpreterOffset
		offset;
	Logical
		resolved;
	GaugeSymbol
		*nextSymbol;
};

class GaugeSymbolTable SIGNATURED
{
	friend class GaugeInterpreter;
public:
	enum
	{
		errUnresolvedForwardReference = -2,
		errUndefinedSymbol = -3
	};

	~GaugeSymbolTable();
	Logical
		TestInstance() const;
protected:
	GaugeSymbolTable(char *table_pointer);

	void
		Add(const char *label, GaugeInterpreterOffset offset);
	GaugeInterpreterOffset
		Refer(const char *label, GaugeInterpreterOffset offset);
	GaugeInterpreterOffset
		Get(const char *label);
	const char *
		LabelFromValue(GaugeInterpreterOffset offset);
	Logical
		UnresolvedForwardReferences();

	GaugeSymbol
		*head;
	char
		*tablePointer;
};

class GaugeInterpreter SIGNATURED
{
	friend struct MethodDescription;
	friend class GaugeRenderer;
public:
	~GaugeInterpreter();
	Logical
		TestInstance() const;
	const char *
		GetToken();
	void
		UngetPreviousToken();
	Logical
		GetInteger(int *int_pointer);
	Logical
		GetScalar(Scalar *scalar_pointer);
	Logical
		GetVector(Vector2DOf<int> *vector);
	Logical
		GetRate(GaugeRate *rate);
	Logical
		GetModeMask(ModeMask *mode_mask_pointer);
	const char *
		ReplaceVariable(const char *possible_variable_name);
	void
		DumpTable();

protected:
	GaugeInterpreter();

	void
		Initialize(
			const char *file_name,
			MethodDescription **method_list,
			Warehouse *warehouse_pointer
		);

	void
		GetProcedureBody(
			MethodDescription **method_list,
			Warehouse *warehouse_pointer
		);

	void
		ReportParsingError(
			const char *string
		);

	Logical
		ParsePrimitive(
			const char *name,
			MethodDescription **method_list,
			Warehouse *warehouse_pointer
		);

public:
	void
		Insert(const void *value, int size_in_chars);
	void *
		Retrieve(int size_in_chars);
	void
		InsertString(const char *string);
	const char *
		RetrieveString();

protected:
	void
		Interpret(
			const char *label,
			GaugeRenderer *renderer,
			int display_port_index,
			Vector2DOf<int> position,
			Entity *entity
		);

	void
		InterpretFromOffset(
			GaugeInterpreterOffset offset,
			GaugeRenderer *renderer,
			int display_port_index,
			Vector2DOf<int> position,
			Entity *entity
		);

	enum
	{
		endMarker=0,
		returnCommand,
		setPortIndexCommand,
		addOffsetCommand,
		callCommand,
		enableCommand,
		disableCommand,
		attributeVariableCommand,
		nextAvailableCommand
	};

	enum
	{
		// The original (RP) value 46864 is too small for BattleTech's larger
		// gauge config: as more BT gauge widgets are registered, more of
		// L4GAUGE.CFG resolves into interpreter bytecode instead of being
		// parse-skipped, overflowing the fixed table.  The Insert() bounds guard
		// is a Verify() that compiles out at DEBUG_LEVEL 0, so the overflow was
		// a SILENT heap corruption (detected later in mission bitmap loading).
		// Sized generously for BT's full config.  (was 46864)
		interpreterTableSize = 262144
	};

	enum
	{
		maxVariableNameArrayIndex = 10
	};

	std::filebuf file;
	char currentToken[64];
	Logical tokenNotTaken;
	int lineNumber;

	GaugeSymbolTable *symbolTable;
	MethodDescription **primitiveTable;
	int primitiveCount;
	char *interpreterTable;
	GaugeInterpreterOffset currentOffset;
	const char *attributeNameArray[maxVariableNameArrayIndex];
};

//#######################################################################
// ParameterDescription
//#######################################################################
#	define PARAMETER_DESCRIPTION_END \
	{ ParameterDescription::typeEmpty, NULL }
struct ParameterDescription
{
	enum ParameterType
	{
		typeEmpty = 0,
		typeRate,
		typeModeMask,
		typeInteger,
		typeColor,
		typeScalar,
		typeVector,
		typeRectangle,
		typeAttribute,
		typeString
	};

	ParameterType
		type;
	enum
	{
		maxStringLength=64
	};

	union
	{
		// 'nextMethodList' is used to chain to the next method list...
		MethodDescription **nextMethodList;
		GaugeRate rate;
		ModeMask modeMask;
		int integer;
		int color;
		Scalar scalar;
		BitMap          *bitmap;
		PixelMap8       *pixelmap;
		Palette8        *palette;
		void            *attributePointer;

		// can't use Vector2DOf<int> because constructor not allowed here!
		struct
		{
			int x, y;
		}
		vector;

		// can't use Rectangle2D because constructor not allowed here!
		struct
		{
			struct
			{
				int x, y;
			}
			bottomLeft;

			struct
			{
				int x, y;
			}
			topRight;
		}
		rectangle;

		char string[maxStringLength];
	}
	data;

	~ParameterDescription();

	void
		ShowInstance(char *indent);
	void
		CheckIt(int type);
	void
		Save(GaugeInterpreter *interpreter);
	void
		Restore(
			GaugeInterpreter *interpreter,
			Entity *entity
		);
	void
		DumpInterpreterEntry(
			GaugeInterpreter *interpreter,
			const char *indent
		);
	void *
		ParseAttribute(const char *string_pointer, Entity *entity);
	Logical
		Extract(
			GaugeInterpreter *interpreter,
			Warehouse *warehouse_pointer
		);
};

//#######################################################################
// MethodDescription
//#######################################################################
#	define METHOD_DESCRIPTION_CHAIN(pointer) \
	{NULL, NULL, {{ ParameterDescription::typeEmpty, pointer }}}

struct MethodDescription
{
	enum
	{
		MaximumParameters = 16
	};

	char
		*name;

	Logical
		(*execute)(
			int display_port_index,
			Vector2DOf<int> position,
			Entity *entity,
			GaugeRenderer *renderer
		);

	ParameterDescription
		parameterList[MaximumParameters];

	void
		ShowInstance(char *indent);
	void
		Execute(
			int display_port_index,
			Vector2DOf<int> position,
			Entity *entity,
			GaugeRenderer *renderer
		);
};

//#######################################################################
// GaugeRenderer
//#######################################################################
struct GaugeRendererStatistics
{
	int
		sampleCount;
	Scalar
		sum,
		maximum;

	void
		Clear(),
		Update(Scalar delta);
	Scalar
		CalculateAverage();
};


class GaugeRenderer:
	public Renderer
{
	friend class Gauge;
	friend class GaugeInterpreter;
	friend Scalar draw_bar(
		GaugeRenderer *renderer,
		int bar_width,
		int slot_index,
		int bar_type
	);
public:
	enum
	{
		maximumGraphicsPorts = 16
	};
	//--------------------------------------------------------------------
	// Construction, Destruction, Testing
	//--------------------------------------------------------------------
	GaugeRenderer();
	~GaugeRenderer();

	static void
		EmergencyShutdown();

	virtual void
		LocalEmergencyShutdown();

	Logical
		TestInstance() const;

	LampManager*
		GetLampManager()
			{
				Check(this);
				Check_Fpu();
				return lampManager;
			}

	//--------------------------------------------------------------------
	// Entity-related methods
	//
	// These are virtual functions defined by the Renderer class.
	// Derived classes call these methods if the derived class
	// doesn't do anything special about the entity.
	//--------------------------------------------------------------------
	void
		LinkToEntity(Entity *entity);
	void
		NotifyOfNewInterestingEntity(Entity *entity);
	void
		NotifyOfBecomingUninterestingEntity(Entity *entity);
	void
		StartEntityAlarmImplementation(
			Entity *entity,
			Subsystem *subsystem,
			Enumeration condition,
			ResourceDescription::ResourceID resource_ID
		);
	void
		StopEntityAlarmImplementation(
			Entity *entity,
			Subsystem *subsystem,
			Enumeration condition
		);
	//--------------------------------------------------------------------
	// LoadMissionImplementation
	//	ShutdownImplementation
	//	SuspendImplementation
	//	ResumeImplementation
	//
	// These are virtual functions defined by the Renderer class.
	// Derived classes must call these methods.
	//--------------------------------------------------------------------
	void
		LoadMissionImplementation(Mission *mission);
	void
		ShutdownImplementation();
	void
		SuspendImplementation();
	void
		ResumeImplementation();


	//--------------------------------------------------------------------
	// Video effects
	//  HACK!!!!!!!!
	// Quick and dirty hack to allow calling L4GaugeRenderer::SpecialEffect
	// from non L4 level.   GDU 2/28/96
	//--------------------------------------------------------------------
public:
	enum VideoEffectType
	{
		scrambleVideo
	};

	virtual void
		SpecialEffect(VideoEffectType type, Scalar duration) {};

	//
	//--------------------------------------------------------------------
	// GetGraphicsPort
	//--------------------------------------------------------------------
	//
	int
		FindGraphicsPort(const char * port_name);

	GraphicsPort
		*GetGraphicsPort(const char *port_name);

	GraphicsPort
		*GetGraphicsPort(int port_number);

	//
	//--------------------------------------------------------------------
	// GaugeEntityList operations
	//--------------------------------------------------------------------
	//
	int
		GetMovingEntities(
			GaugeEntityList *destination_list
		)
			{
				return movingEntities.CopyEntities(
					destination_list
				);
			}

	int
		GetMovingEntitiesWithinBounds(
			GaugeEntityList *destination_list,
			Scalar minX,
			Scalar minY,
			Scalar minZ,
			Scalar maxX,
			Scalar maxY,
			Scalar maxZ
		)
			{
				return movingEntities.CopyEntitiesWithinBounds(
					destination_list,
					minX, minY, minZ,
					maxX, maxY, maxZ
				);
			}

	int
		GetStaticEntities(
			GaugeEntityList *destination_list
		)
			{
				return staticEntities.CopyEntities(
					destination_list
				);
			}
	int
		GetStaticEntitiesWithinBounds(
			GaugeEntityList *destination_list,
			Scalar minX,
			Scalar minY,
			Scalar minZ,
			Scalar maxX,
			Scalar maxY,
			Scalar maxZ
		)
			{
				return staticEntities.CopyEntitiesWithinBounds(
					destination_list,
					minX, minY, minZ,
					maxX, maxY, maxZ
				);
			}
	void
		GetStaticBounds(
			Scalar *min_x,
			Scalar *min_y,
			Scalar *min_z,
			Scalar *max_x,
			Scalar *max_y,
			Scalar *max_z
		)
			{
				staticEntities.GetBounds(
					min_x, min_y, min_z,
					max_x, max_y, max_z
				);
			}
	//
	//--------------------------------------------------------------------
	// Configure
	//--------------------------------------------------------------------
	//
	virtual void
		Configure(
			const char *configuration_name,
			Entity *entity
		);

	int
		parseConfigurationLine(
			const char *entry,
			char *buffer,
			char **item_pointer,
			int max_items
		);

	//--------------------------------------------------------------------
	// Gauge methods
	//--------------------------------------------------------------------
	void
		Add(GaugeBase *new_base),
		Remove(unsigned int ownerID),
		Inactivate(GaugeBase *the_base);

	GaugeRate
		FindBestFirstTierRate(),
		FindBestSecondTierRate(),
		FindBestThirdTierRate(),
		FindBestFourthTierRate();
	//--------------------------------------------------------------------
	// ExecuteImplementation
	//--------------------------------------------------------------------
protected:
	void
		ExecuteImplementation(
			RendererComplexity complexity_update,
			RendererOrigin::InterestingEntityIterator *iterator
		);

public:
	Logical
		ExecuteBackground();

protected:
	void
		ActivateGaugeBases(ModeMask current_mode_mask, ModeMask change_mode_mask),
		DeactivateGaugeBases(ModeMask current_mode_mask);
	Logical
		ProcessOneActiveGauge();
	virtual void
		ExecuteForeground();
	virtual Logical
		ExecuteBackgroundDisplayUpdate();
	//--------------------------------------------------------------------
	// Profiling support
	//--------------------------------------------------------------------
protected:
	virtual Scalar
		GetCurrentFramePercentage();
public:
	void
		ProfileReport();
	//--------------------------------------------------------------------
	// Configuration parsing methods
	//--------------------------------------------------------------------
protected:
	void
		BuildConfigurationFile(
			const char *file_name,
			MethodDescription **method_description
		);
	//--------------------------------------------------------------------
	// Public data
	//--------------------------------------------------------------------
public:
	Warehouse
		*warehousePointer;
	GaugeInterpreter
		*interpreter;

   int GetTaskMode() { return taskMode; }
	//--------------------------------------------------------------------
	// Protected data
	//--------------------------------------------------------------------
protected:
	GraphicsPort *graphicsPort[maximumGraphicsPorts];
	GaugeEntityList movingEntities;
	GaugeEntityArray staticEntities;
	LampManager *lampManager;
	GaugeAlarmManager *gaugeAlarmManager;

	enum
	{
		foreground,
		background,
		copy
	}
	taskMode;

private:
	//
	//--------------------------------------------------------------------
	// Private data
	//--------------------------------------------------------------------
	//
	ModeMask
		previousModeMask;
	SChainOf<GaugeBase*>
		newList,
		activeList,
		inactiveList;
	SChainIteratorOf<GaugeBase*>
		*activeIterator;
	Logical
		suspended;
	GaugeRate
		rateBitMask;
	int
		rateProfileIndex;
	static GaugeRenderer
		*headGaugeRenderer;
	GaugeRenderer
		*nextGaugeRenderer;
	//-----------------------------------
	// Load-balancing data and profiling
	//-----------------------------------
	enum
	{
		slotCount = 16,
		tierCount=5
	};

	Scalar
		load[slotCount];
	GaugeRendererStatistics
		statistics[slotCount][tierCount];
};
