//===========================================================================//
// File:	model.hpp                                                           //
// Project: MUNGA           Brick: Model Manager                             //
// Contents: Interface specification of model class                          //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 01/25/95  JMA  Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. All Rights reserved //
//                      PROPRIETARY AND CONFIDENTIAL                         //
//===========================================================================//

#if !defined(SIMULATE_HPP)
#	define SIMULATE_HPP

#	if !defined(STATE_HPP)
#		include <state.hpp>
#	endif

#	if !defined(RECEIVER_HPP)
#		include <receiver.hpp>
#	endif

#	if !defined(TIME_HPP)
#		include <time.hpp>
#	endif

#	if !defined(RESOURCE_HPP)
#		include <resource.hpp>
#	endif

	class Simulation__SharedData;
	class Simulation__IndexData;
	class Simulation__IndexEntry;
	class Simulation__AttributeIndexSet;
	class MemoryStream;

	//##########################################################################
	//#################    Simulation::UpdateRecord    #########################
	//##########################################################################

	struct Simulation__UpdateRecord
	{
	public:
		size_t recordLength;
		Word subsystemID;
		Word recordID;
		Time timeStamp;
		Enumeration simulationState;
	};

	//##########################################################################
	//#######################    Simulation    #################################
	//##########################################################################

	class Simulation:
		public Receiver
	{
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Shared Data Support
	//
	public:
		typedef Simulation__SharedData SharedData;
		SharedData*
			GetSharedData();

		static Derivation ClassDerivations;

		static SharedData DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction and Destruction Support
	//
	protected:
		Simulation(
			ClassID class_ID,
			SharedData &shared_data
		);

	public:
		~Simulation();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Attribute Support
	//
	public:
		typedef Enumeration							AttributeID;
		typedef Simulation__IndexData				IndexData;
		typedef Simulation__IndexEntry			IndexEntry;
		typedef Simulation__AttributeIndexSet	AttributeIndexSet;
		typedef int Simulation::*AttributePointer;

		enum {
			AnyAttributeID = 0,
			SimulationStateAttributeID,
			NextAttributeID
		};

		static const AttributePointer NullAttribute;

		void*
			GetAttributePointer(AttributeID attribute);
		void*
			GetAttributePointer(const char* attribute_name);

	private:
		static const IndexEntry AttributePointers[];

	protected:
		static AttributeIndexSet	AttributeIndex;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Simulation Support
	//
	public:
		typedef void
			(Simulation::*Performance)(Scalar time_slice);
		typedef void
			(Simulation::*Encore)();
		typedef Simulation__UpdateRecord UpdateRecord;

		void
			SetPerformance(Performance performance)
				{Check(this); activePerformance = performance;}
		void
			Perform(Scalar time_slice)
				{
					Check(this);
					(this->*activePerformance)(time_slice);
				}

		virtual void
			PerformAndWatch(
				const Time& till,
				MemoryStream *update_stream
			);

		void
			DoNothingOnce(Scalar time_slice);
		void
			DoNothing(Scalar time_slice);

		void
			SetLastPerformance(const Time& when)
				{Check(this); Check(&when); lastPerformance = when;}
		void
			RequestEncore(Encore encore);

		virtual void
			ReadUpdateRecord(UpdateRecord *message);
		virtual void
			WriteUpdateRecord(
				UpdateRecord *message,
				int update_model
			);
		void
			WriteSimulationUpdate(MemoryStream *update_stream);

		enum {
			DefaultUpdateModelBit=0,
			NextUpdateModelBit
		};

		enum {
			DefaultUpdateModelFlag = 1<<DefaultUpdateModelBit
		};

		void
			ForceUpdate(Word model=DefaultUpdateModelFlag)
				{Check(this); updateModel |= model;}

	protected:
		Time
			lastPerformance;
		Time
			lastUpdate;
		Word
			updateModel;

		Performance
			activePerformance;

	//##########################################################################
	// Flag Support
	//
	public:
		enum {
			DelayWatchersBit,
			DontExecuteBit,
			NextBit
		};
		enum {
			DelayWatchersFlag		= 1<<DelayWatchersBit,
			DontExecuteFlag		= 1<<DontExecuteBit
		};

		LWord simulationFlags;

		void
			SetWatcherDelay()
				{Check(this); simulationFlags |= DelayWatchersFlag;}
		void
			ClearWatcherDelay()
				{Check(this); simulationFlags &= ~DelayWatchersFlag;}
		Logical
			AreWatchersDelayed()
				{Check(this); return (simulationFlags & DelayWatchersFlag) != 0;}

		void
			NeverExecute()
				{Check(this); simulationFlags |= DontExecuteFlag;}
		void
			ExecuteOnUpdate()
				{Check(this); simulationFlags |= DontExecuteFlag;}
		void
			AlwaysExecute()
				{Check(this); simulationFlags &= ~DontExecuteFlag;}
		Logical
			IsReplicantExecutable()
				{
					Check(this);
					return
						(simulationFlags&DontExecuteFlag) == 0
						 || lastUpdate >= lastPerformance;
				}
		Logical
			IsNonReplicantExecutable()
				{Check(this); return (simulationFlags&DontExecuteFlag) == 0;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// State support
	//
	public:
		enum {
			DefaultState = 0,
			StateCount
		};

		unsigned
			GetSimulationState()
				{Check(this); return simulationState.GetState();}
		unsigned
			GetOldSimulationState()
				{Check(this); return simulationState.GetOldState();}
		void
			SetSimulationState(unsigned new_state)
				{Check(this); simulationState.SetState(new_state);}

		StateIndicator
			simulationState;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Watcher Support
	//
	public:
		void
			AddAudioWatcher(Component *watcher)
				{Check(&audioWatcherSocket);audioWatcherSocket.Add(watcher);}
		void
			AddVideoWatcher(Component *watcher)
				{Check(&videoWatcherSocket);videoWatcherSocket.Add(watcher);}
		void
			AddGaugeWatcher(Component *watcher)
				{Check(&gaugeWatcherSocket);gaugeWatcherSocket.Add(watcher);}

		void
			AddEffectWatcher(Component *watcher)
			{Check(&effectWatcherSocket); effectWatcherSocket.Add(watcher);}

		void
			ExecuteWatchers();

	private:
		SChainOf<Component*>
			audioWatcherSocket;
		SChainOf<Component*>
			videoWatcherSocket;
		SChainOf<Component*>
			gaugeWatcherSocket;
		SChainOf<Component*>
			effectWatcherSocket;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		Logical
			TestInstance() const;
		static Logical
			TestClass();
	};

	//##########################################################################
	//###################    Simulation::IndexEntry    #########################
	//##########################################################################

	struct Simulation__IndexEntry
	{
		Enumeration
			entryID;
		const char *
			entryName;
		Simulation::AttributePointer
			entryAddress;
	};

	#define ATTRIBUTE_ENTRY(class,name,attribute)\
		{\
			class::name##AttributeID,\
			#name,\
			(Simulation::AttributePointer) &class::attribute\
		}

	//##########################################################################
	//#################    Simulation::AttributeIndexSet    ####################
	//##########################################################################

	class Simulation__AttributeIndexSet:
		public Receiver::InheritanceSet
	{
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction and Destruction
	//
	public:
		Simulation__AttributeIndexSet(
			Simulation::AttributeID count,
			const Simulation::IndexEntry index_table[],
			const Simulation::AttributeIndexSet &inheritance
		)
			{Build(count, index_table, &inheritance);}

		Simulation__AttributeIndexSet(
			Simulation::AttributeID count,
			const Simulation::IndexEntry index_table[]
		)
			{Build(count, index_table, NULL);}

		Simulation__AttributeIndexSet()
			{attributeIndex = NULL; entryCount = 0;}

		~Simulation__AttributeIndexSet();

	protected:
		void
			Build(
				Simulation::AttributeID count,
				const Simulation::IndexEntry index_table[],
				const Simulation::AttributeIndexSet *inheritance
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// AttributeIndexSet Functionality
	//
	protected:
		Simulation::IndexEntry
			*attributeIndex;

	public:
		Simulation::AttributePointer
			Find(Simulation::AttributeID attribute) const
				{
					Check(this);
               Verify(attribute > 0);
					if (attribute<=entryCount)
						return attributeIndex[attribute-1].entryAddress;
					else
						return Simulation::NullAttribute;
				}
		Simulation::AttributePointer
			Find(const char* attribute_name) const;
		const Simulation::IndexEntry*
			FindEntry(const char* attribute_name) const;

		static const Simulation::AttributeIndexSet
			NullSet;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		static Logical
			TestClass();
	};

	//##########################################################################
	//###################    Simulation::SharedData    #########################
	//##########################################################################

	class Simulation__SharedData:
		public Receiver::SharedData
	{
	public:
		Simulation__SharedData(
			Derivation& derivation,
			Receiver::MessageHandlerSet &message_handlers,
			Simulation::AttributeIndexSet &attribute_index,
			int state_count
		):
			Receiver::SharedData(derivation, message_handlers),
			activeAttributeIndex(&attribute_index),
			stateCount(state_count)
				{}

		Simulation::AttributeIndexSet*	activeAttributeIndex;
		int stateCount;
	};

	inline Simulation::SharedData*
		Simulation::GetSharedData()
			{return Cast_Object(SharedData*,sharedData);}

#endif
