//===========================================================================//
// 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                         //
//===========================================================================//

#pragma once

#include "Adept.hpp"

namespace Adept {class StateEngine;}

#if !defined(Spew)
	void
		Spew(
			const char* group,
			Adept::StateEngine &state
		);
#endif

namespace Adept {

	class StateEngine__ClassData;
	class StateEngine__StateEntry;
	class Component;

	//##########################################################################
	//###########    StateEngine::FactoryRequest    ##################
	//##########################################################################

	class StateEngine__FactoryRequest
	{
	public:
		StateEngine__FactoryRequest()
			{}
		StateEngine__FactoryRequest(int current_state):
			currentState(current_state)
				{}
		StateEngine__FactoryRequest(const StateEngine__FactoryRequest &request):
			currentState(request.currentState)
				{}

		int
			currentState;

		void
			TestInstance() const
				{}

		class Script
		{
		public:
			StateEngine__ClassData
				*engineClass;
			Stuff::Page
				*instancePage;
			const char
				*stateEngineName;

			void
				TestInstance() const
					{}
		};

		typedef void
			(StateEngine__FactoryRequest::*Factory)(Script *script);
		void
			ConstructFactoryRequest(Script *script);
	};

	//##########################################################################
	//########################    StateEngine    ###############################
	//##########################################################################

	class StateEngine:
		public Stuff::Plug
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

	//##########################################################################
	// Inheritance support
	//
	public:
		typedef StateEngine__ClassData		ClassData;
		typedef StateEngine__StateEntry		StateEntry;
		typedef StateEngine__FactoryRequest	FactoryRequest;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructor
	//
	public:
		StateEngine(
			ClassData *class_data,
			int state_number
		);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		typedef StateEngine*
			(*Factory)(const FactoryRequest *request);

		static StateEngine*
			Make(const FactoryRequest *request);
		void
			Save(FactoryRequest *request);
		void
			Reuse(const FactoryRequest *request);

		~StateEngine();

	protected:
		StateEngine(
			ClassData *class_data,
			const FactoryRequest *request
		);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class data
	//
	public:
		ClassData*
			GetClassData();

		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// State stuff
	//
	public:
		int
			GetState()
				{Check_Object(this); return currentState;}
		int
			GetOldState()
				{Check_Object(this); return oldState;}
		virtual int
			RequestState(
				int new_state,
				void* data = NULL
			);

		enum {
			UninitializedState = 0,
			StateCount
		};

		const StateEntry*
			GetStateEntry(int state);

		void
			TestInstance();

	protected:
		int
			oldState,
			currentState;

		void
			NewState(int new_state);

	protected:
		static const StateEntry
			StateEntries[];

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Stream input/output methods
	//
	public:
		#if !defined(Spew)
			friend void
				::Spew(
					const char* group,
					StateEngine &state
				);
		#endif

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

	//##########################################################################
	//##################    StateEngine::StateEntry    #########################
	//##########################################################################

	class StateEngine__StateEntry
	{
	public:
		int
			stateNumber;
		const char *
			stateName;

		void
			TestInstance() const
				{}
	};

	#define STATE_ENTRY(c,s) {c::s##State, #s##"State"}

	//##########################################################################
	//####################    StateEngine::ClassData    ########################
	//##########################################################################

	class StateEngine__ClassData:
		public Stuff::Plug__ClassData
	{
		friend class StateEngine;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction and Destruction
	//
	public:
		StateEngine__ClassData(
			Stuff::RegisteredClass::ClassID class_id,
			const char *class_name,
			Stuff::Plug::ClassData *parent,
			int count,
			const StateEngine__StateEntry *index_table,
			StateEngine::Factory engine_factory,
			StateEngine::FactoryRequest::Factory request_factory
		);
		~StateEngine__ClassData();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// ClassData Functionality
	//
	protected:
		int
			stateCount;
		StateEngine__StateEntry
			*stateEntries;
		StateEngine::Factory
			engineFactory;
		StateEngine::FactoryRequest::Factory
			requestFactory;

	public:
		int
			GetStateCount()
				{Check_Object(this); return stateCount;}

		const StateEngine__StateEntry*
			GetStateEntry(int state)
				{
					Check_Object(this);
               Verify(state < stateCount);
					return &stateEntries[state];
				}
		const StateEngine__StateEntry*
			FindStateEntry(const char* state_name);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		void
			TestInstance();
	};

	inline StateEngine::ClassData*
		StateEngine::GetClassData()
	{
		Check_Object(this);
		return Cast_Pointer(ClassData*, classData);
	}

	inline const StateEngine::StateEntry*
		StateEngine::GetStateEntry(int state)
	{
		Check_Object(this);
		ClassData *class_data = GetClassData();
		Check_Object(class_data);
		return class_data->GetStateEntry(state);
	}

	inline void
		StateEngine::NewState(int new_state)
	{
		Check_Object(this);
		#if defined(_ARMOR)
			ClassData *class_data = GetClassData();
			Check_Object(class_data);
			Verify(static_cast<unsigned>(new_state) < class_data->GetStateCount());
		#endif
		oldState = currentState;
		currentState = new_state;
	}

}


