#include "MW4Headers.hpp"
#include "mwmap.hpp"
#include <adept\map.hpp>
#include <ElementRenderer\GridElement.hpp>
#include <ElementRenderer\GroupElement.hpp>
#include <Adept\EntityManager.hpp>

//#############################################################################
//###################################    Map    ###############################
//#############################################################################

MWMap::ClassData*	MWMap::DefaultData = NULL;


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWMap::InitializeClass()
{

	Verify(!DefaultData);
	Check_Object(ExecutionStateEngine::DefaultData);
	DefaultData =
		new ClassData(
			MWMapClassID,
			"MechWarrior4::MWMap",
			Map::DefaultData,
			0, NULL,
			(MWMap::Factory)Make,
			(Map::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
			ExecutionStateEngine::DefaultData,
			(Map::GameModel::Factory)GameModel::ConstructGameModel,
			NULL,
			(Map::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
			(Map::GameModel::ModelWrite)GameModel::WriteToText,
			(Map::GameModel::ModelSave)GameModel::SaveGameModel
		);
	Check_Object(DefaultData);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWMap::TerminateClass()
{
	Check_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWMap* MWMap::Make(const CreateMessage *message,ReplicatorID *base_id)
{
	Check_Object(message);

	Resource model_resource;
	GetGameModelResourceFromDataListID(&model_resource, message->dataListID);
	GameModel *model = Cast_Pointer(GameModel*, model_resource.GetPointer());
	Check_Object(model);
	Resource grid_resource(model->m_gridElementResourceID);
	Check_Object(&grid_resource);
	Verify(grid_resource.DoesResourceExist());

	ElementRenderer::GridElement *grid =
		Cast_Object(
			ElementRenderer::GridElement*,
			ElementRenderer::Element::Create(
				&grid_resource,
				ElementRenderer::ReadERFVersion(&grid_resource)
			)
		);

	MWMap *new_entity = new MWMap(DefaultData, message, base_id, grid);
	Check_Object(new_entity);

	return new_entity;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
#if !defined(NO_MR)
namespace NMissionReview
{
	extern char m_ReviewMapTexture[128];
};
#endif // !defined(NO_MR)

MWMap::MWMap(ClassData *class_data,	const CreateMessage *message,	ReplicatorID *base_id,	ElementRenderer::GridElement *element):
Map(class_data, message, base_id, element, MechWarrior4::ExecutionSlotCount),
	m_executingAIs(NULL)
{
	Check_Pointer(this);
	Check_Object(message);
#if !defined(NO_MR)
	const GameModel *model = GetGameModel ();
	Verify (model);
	Str_Copy (NMissionReview::m_ReviewMapTexture,model->m_HudMap,128);
#endif // !defined(NO_MR)
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWMap::~MWMap()
{
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWMap::AddChild(Entity *entity)
{
	Check_Object(this);
	Check_Object(entity);

	if (entity->IsDerivedFrom (AI::DefaultData))
	{
		AI *ai;
		ai = Cast_Object (AI *,entity);
		m_executingAIs.Add (ai);
		ElementRenderer::Element * element = ai->GetElement ();
		ai->m_GroupElement->AttachChild (element);
		ai->SetInterestMask(SimulationInterestLevel);
	}
	else
		Map::AddChild (entity);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWMap::RemoveChild(Entity *entity)
{
	Check_Object(this);
	Check_Object(entity);

	if (entity->IsDerivedFrom (AI::DefaultData))
	{
		AI *ai;
		ai = Cast_Object (AI *,entity);
		m_executingAIs.Remove (ai);
		ElementRenderer::Element * element = ai->GetElement ();
		ai->m_GroupElement->DetachChild (element);
	}
	else
		Map::RemoveChild (entity);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWMap::PreCollisionExecute(Time till)
{
	Check_Object(this);
	PRECOLLISION_LOGIC("MWMap");

	{
		PRECOLLISION_LOGIC("MWMap::Determine AI Execution");
		ChainIteratorOf<AI*> ais(&m_executingAIs);
		AI *ai;
		while ((ai = ais.ReadAndNext()) != NULL)
		{
			Check_Object(ai);
			if (ai->executionState->GetState () != ExecutionStateEngine::NeverExecuteState)
				ai->DetermineExecution(till);
		}
	}

	Map::PreCollisionExecute (till);

	ChainIteratorOf<AI*> ais2(&m_executingAIs);
	AI *ai;
	while ((ai = ais2.ReadAndNext()) != NULL)
	{
		Check_Object(ai);
		if (ai->executionState->GetState () != ExecutionStateEngine::NeverExecuteState)
		{
			ai->PreCollisionExecute(till);
			Verify(!ai->IsUsingPostCollision() || EntityManager::GetInstance()->IsInPostCollisionExecution(ai));
		}
	}

}

