//===========================================================================//
// File:        simulate.cc                                                         //
// Project: MUNGA           Brick: Model Manager                             //
// Contents: Implementation details 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                         //
//===========================================================================//

#include "AdeptHeaders.hpp"
#include "State.hpp"

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

//#############################################################################
// Virtual Data support
//
const StateEngine::StateEntry
	StateEngine::StateEntries[]=
{
	STATE_ENTRY(StateEngine, Uninitialized)
};

StateEngine::ClassData*
	StateEngine::DefaultData = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	StateEngine::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			StateEngineClassID,
			"Adept::StateEngine",
			Plug::DefaultData,
			ELEMENTS(StateEntries), StateEntries,
			Make,
			&StateEngine::FactoryRequest::ConstructFactoryRequest
		);
	Register_Object(DefaultData);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	StateEngine::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateEngine*
	StateEngine::Make(const FactoryRequest *request)
{
	Check_Object(request);
	gos_PushCurrentHeap(g_LibraryHeap);
	StateEngine *engine = new StateEngine(DefaultData, request);
	gos_PopCurrentHeap();
	return engine;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	StateEngine::Save(FactoryRequest *request)
{
	Check_Object(this);
	Check_Object(request);

	request->currentState = currentState;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	StateEngine::Reuse(const FactoryRequest *request)
{
	Check_Object(this);
	Check_Object(request);

	RequestState(request->currentState);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateEngine::~StateEngine()
{
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateEngine::StateEngine(
	ClassData *class_data,
	int state_number
):
	Plug(class_data)
{
	Check_Pointer(this);
	Check_Object(class_data);

	oldState = state_number;
	Verify(static_cast<unsigned>(oldState) < class_data->stateCount);
	currentState = state_number;
	Verify(static_cast<unsigned>(currentState) < class_data->stateCount);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateEngine::StateEngine(
	ClassData *class_data,
	const FactoryRequest *request
):
	Plug(class_data)
{
	Check_Pointer(this);
	Check_Object(class_data);
	Check_Object(request);

	currentState = request->currentState;
	Verify(static_cast<unsigned>(currentState) < class_data->stateCount);
	oldState = UninitializedState;
	Verify(static_cast<unsigned>(oldState) < class_data->stateCount);
}

//#############################################################################
// State stuff
//

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	StateEngine::RequestState(
		int new_state,
		void*
	)
{
	Check_Object(this);
	Check_Object(GetClassData());
	Verify(new_state < GetClassData()->stateCount);

	oldState = currentState;
	return currentState = new_state;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
#if !defined(Spew)
	void
		Spew(
			const char* group,
			StateEngine &state_indicator
		)
	{
		Check_Object(&state_indicator);
		const StateEngine::StateEntry *state =
			state_indicator.GetStateEntry(state_indicator.GetState());
		Check_Pointer(state);
		SPEW((group, "%s+", state->stateName));
	}
#endif

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	StateEngine::TestInstance()
{
	Verify(IsDerivedFrom(DefaultData));
}

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateEngine__ClassData::StateEngine__ClassData(
	RegisteredClass::ClassID class_id,
	const char* name,
	Plug::ClassData *parent,
	int count,
	const StateEngine::StateEntry index_table[],
	StateEngine::Factory engine_factory,
	StateEngine::FactoryRequest::Factory request_factory
):
	Plug__ClassData(class_id, name, parent),
	engineFactory(engine_factory),
	requestFactory(request_factory)
{
	Check_Pointer(this);
	//
	//------------------------------
	// Only the root can be empty...
	//------------------------------
	//
	stateCount = 0;
	stateEntries = NULL;
	StateEngine__ClassData *inheritance = NULL;
	int i;
	if (parent != Plug::DefaultData)
	{
		Check_Object(parent);
		inheritance = Cast_Pointer(StateEngine__ClassData *, parent);
		Check_Object(inheritance);
		if (!count)
		{
			stateCount = inheritance->stateCount;
			goto Skip_Mix;
		}
	}

	//
	//-------------------------------------------------------
	// Find out the highest message type we have to deal with
	//-------------------------------------------------------
	//
	for (i=0; i<count; ++i)
	{
		if (index_table[i].stateNumber > stateCount)
		{
			stateCount = index_table[i].stateNumber;
		}
	}
	++stateCount;
	if (inheritance)
	{
		Check_Object(inheritance);
		Verify(inheritance->stateCount + count == stateCount);
		#if defined(_ARMOR)
			i = inheritance->stateCount;
			goto Check_Table;
		#endif
	}
	else
	{
		Verify(stateCount == count);
		#if defined(_ARMOR)
			i = 0;
Check_Table:
			while (i < stateCount)
			{
				int j;
				for (j=0; j<count; ++j)
				{
					if (index_table[j].stateNumber == i)
					{
						break;
					}
				}
				if (j == count)
				{
					break;
				}
				++i;
			}
			Verify(i == stateCount);
		#endif
	}

	//
	//-----------------------------------------------------------------------
	// Allocate the memory for the new handler set, and copy the inherited
	// handlers to the new table.  We are guaranteed to have enough space for
	// the inherited table
	//-----------------------------------------------------------------------
	//
Skip_Mix:
	stateEntries = new StateEngine::StateEntry[stateCount];
	Register_Pointer(stateEntries);
	i = 0;
	if (inheritance)
	{
		for (; i<inheritance->stateCount; ++i)
		{
			stateEntries[i] = inheritance->stateEntries[i];
		}
	}

	//
	//----------------------------------------------------------------------
	// Step through the new table supplied, placing each handler in the slot
	// determined by the message type
	//----------------------------------------------------------------------
	//
	for (i=0; i<count; ++i)
	{
		Verify(!inheritance || index_table[i].stateNumber >= inheritance->stateCount);
		stateEntries[index_table[i].stateNumber] = index_table[i];
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateEngine__ClassData::~StateEngine__ClassData()
{
	if (stateEntries)
	{
		Unregister_Pointer(stateEntries);
		delete[] stateEntries;
	}
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const StateEngine::StateEntry*
	StateEngine__ClassData::FindStateEntry(const char* state_name)
{
	Check_Object(this);
	Check_Pointer(state_name);

	for (int state=0; state<stateCount; ++state)
	{
		if (!_stricmp(state_name, stateEntries[state].stateName))
		{
			return &stateEntries[state];
		}
	}
	return NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	StateEngine__ClassData::TestInstance()
{
	Verify(IsDerivedFrom(StateEngine::DefaultData));
}
