#include "munga.h"
#pragma hdrstop

#include "terrain.h"
#include "boxsolid.h"
#include "app.h"
#include "interest.h"

//#############################################################################
//###############################    Terrain    #################################
//#############################################################################

//#############################################################################
// Shared Data Support
//
Derivation* Terrain::GetClassDerivations()
{
	static Derivation classDerivations(Entity::GetClassDerivations(), "Terrain");
	return &classDerivations;
}

Terrain::SharedData
	Terrain::DefaultData(
		Terrain::GetClassDerivations(),
		Terrain::GetMessageHandlers(),
		Terrain::GetAttributeIndex(),
		Terrain::StateCount,
		(Entity::MakeHandler)Terrain::Make
	);

//#############################################################################
// Attribute Support
//
const Terrain::IndexEntry
	Terrain::AttributePointers[]=
{
	{
		Terrain::LocalScaleAttributeID,
		"LocalScale",
		(Entity::AttributePointer)&Terrain::localScale
	}
};

Terrain::AttributeIndexSet& Terrain::GetAttributeIndex()
{
	static Terrain::AttributeIndexSet attributeIndex(ELEMENTS(Terrain::AttributePointers),
		Terrain::AttributePointers,
		Entity::GetAttributeIndex()
	);
	return attributeIndex;
}

//#############################################################################
// Construction and Destruction
//

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Terrain::Terrain(
	Terrain::MakeMessage *creation_message,
	Terrain::SharedData &virtual_data
):
	Entity(creation_message, virtual_data)
{
	localScale = creation_message->localScale;
	SetValidFlag();

	//
	//---------------------------------------------------------------------
	// For now, load in the collision resources into the tree pointed to by
	// this resource
	//---------------------------------------------------------------------
	//
	ResourceFile *res_file = application->GetResourceFile();
	Check(res_file);
	ResourceDescription *res =
		res_file->SearchList(
			resourceID,
			ResourceDescription::BoxedSolidStreamResourceType
		);

	collisionVolumes = NULL;
	if (res)
	{
		Check(res);
		res->Lock();
		InterestManager *interest_mgr =
			application->GetInterestManager();
		Check(interest_mgr);
		InterestZone *zone =
			interest_mgr->GetInterestZone(interestZoneID);
		Check(zone);
		BoxedSolidTree* tree = zone->GetCollisionRoot();
		Check(tree);
		BoxedSolidResource* solids =
			(BoxedSolidResource*)res->resourceAddress;
		int size = res->resourceSize / sizeof(BoxedSolidResource);
		Dump(localOrigin);
		while (size--)
		{
			//
			// Don't forget about scaling...
			//
			BoxedSolidResource rot_box;
			rot_box.Instance(*solids,localOrigin);
			collisionVolumes =
				BoxedSolid::MakeBoxedSolid(&rot_box, this, collisionVolumes);
			Register_Object(collisionVolumes);
			tree->Add(collisionVolumes, rot_box.sliceExtents);
			++solids;
		}
		res->Unlock();
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	Terrain::CreateMakeMessage(
		MakeMessage *creation_message,
		NotationFile *model_file,
		const ResourceDirectories *directories
	)
{
	Check(creation_message);
	Check(model_file);

	if (!Entity::CreateMakeMessage(creation_message, model_file, directories))
	{
		return false;
	}

	creation_message->messageLength = sizeof(MakeMessage);
	creation_message->classToCreate = TerrainClassID;
	creation_message->instanceFlags = HermitInstance|TrappedFlag;

	char *p;
	if ((p = strtok(NULL, " ")) == NULL)
	{
		std::cerr << "Scale missing!\n";
		return false;
	}
	creation_message->localScale = atof(p);
	return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Terrain*
	Terrain::Make(Terrain::MakeMessage *creation_message)
{
	return new Terrain(creation_message);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Terrain::~Terrain()
{
	BoxedSolid *box = collisionVolumes;
	while (box)
	{
		BoxedSolid *next_box = box->GetNextSolid();
		Unregister_Object(box);
		delete box;
		box = next_box;
	}
}

Logical
	Terrain::TestInstance() const
{
	return IsDerivedFrom(*GetClassDerivations());
}

//#############################################################################
//#########################    UnscalableTerrain    ###########################
//#############################################################################

//#############################################################################
// Shared Data Support
//
Derivation* UnscalableTerrain::GetClassDerivations()
{	static Derivation classDerivations(Terrain::GetClassDerivations(), "UnscalableTerrain");
	return &classDerivations;
}


UnscalableTerrain::SharedData
	UnscalableTerrain::DefaultData(
		UnscalableTerrain::GetClassDerivations(),
		UnscalableTerrain::GetMessageHandlers(),
		UnscalableTerrain::GetAttributeIndex(),
		UnscalableTerrain::StateCount,
		(Entity::MakeHandler)UnscalableTerrain::Make
	);

//#############################################################################
// Construction and Destruction
//

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
UnscalableTerrain::UnscalableTerrain(
	UnscalableTerrain::MakeMessage *creation_message,
	UnscalableTerrain::SharedData &virtual_data
):
	Entity(creation_message, virtual_data)
{

	//
	//---------------------------------------------------------------------
	// For now, load in the collision resources into the tree pointed to by
	// this resource
	//---------------------------------------------------------------------
	//
	SetValidFlag();
	ResourceFile *res_file = application->GetResourceFile();
	Check(res_file);
	ResourceDescription *res =
		res_file->SearchList(
			resourceID,
			ResourceDescription::BoxedSolidStreamResourceType
		);
	collisionVolumes = NULL;

	if (res)
	{
		Check(res);
		res->Lock();
		InterestManager *interest_mgr =
			application->GetInterestManager();
		Check(interest_mgr);
		InterestZone *zone =
			interest_mgr->GetInterestZone(interestZoneID);
		Check(zone);
		BoxedSolidTree* tree = zone->GetCollisionRoot();
		Check(tree);
		BoxedSolidResource* solids =
			(BoxedSolidResource*)res->resourceAddress;
		int size = res->resourceSize / sizeof(BoxedSolidResource);
		while (size--)
		{
			BoxedSolidResource rot_box;
			rot_box.Instance(*solids,localOrigin);
			collisionVolumes =
				BoxedSolid::MakeBoxedSolid(&rot_box, this, collisionVolumes);
			Register_Object(collisionVolumes);
			tree->Add(collisionVolumes, rot_box.sliceExtents);
			++solids;
		}
      res->Unlock();
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	UnscalableTerrain::CreateMakeMessage(
		MakeMessage *creation_message,
		NotationFile *model_file,
		const ResourceDirectories *directories
	)
{
	Check(creation_message);
	Check(model_file);

	if (!Entity::CreateMakeMessage(creation_message, model_file, directories))
	{
		return false;
	}

	creation_message->classToCreate = UnscalableTerrainClassID;
	creation_message->instanceFlags = HermitInstance|TrappedFlag;
	return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
UnscalableTerrain*
	UnscalableTerrain::Make(UnscalableTerrain::MakeMessage *creation_message)
{
	return new UnscalableTerrain(creation_message);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
UnscalableTerrain::~UnscalableTerrain()
{
	BoxedSolid *box = collisionVolumes;
	while (box)
	{
		BoxedSolid *next_box = box->GetNextSolid();
		Unregister_Object(box);
		delete box;
		box = next_box;
	}
}

Logical
	UnscalableTerrain::TestInstance() const
{
	return IsDerivedFrom(*GetClassDerivations());
}
