#include "MW4Headers.hpp"

#include "Path.hpp"

#include <Adept\EntityClassData.hpp>
#include <Adept\zone.hpp>
#include <Adept\map.hpp>
#include <elementrenderer\GridElement.hpp>

//#############################################################################
//###############################    Path    ##################################
//#############################################################################

Path::ClassData* Path::DefaultData = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Path::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			PathClassID,
			"MechWarrior4::Path",
			Entity::DefaultData,
			0, NULL,
			(Entity::Factory)Make,
			(Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
			ExecutionStateEngine::DefaultData,
			(Entity::GameModel::Factory)GameModel::ConstructGameModel,
			NULL,
			(Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
			(Entity::GameModel::ModelWrite)GameModel::WriteToText,
			(Entity::GameModel::ModelSave)GameModel::SaveGameModel
		);
	Register_Object(DefaultData);
}

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Path* Path::Make(CreateMessage *message,ReplicatorID *base_id)
{
	Check_Object(message);
	gos_PushCurrentHeap(Heap);
	Path *new_entity =
		new Path(DefaultData, message, base_id, NULL);
	gos_PopCurrentHeap();
	Check_Object(new_entity);
	return new_entity;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Path::Path(ClassData *class_data,CreateMessage *message,ReplicatorID *base_id,ElementRenderer::Element *element) :
	Entity(class_data, message, base_id, element),pathPoints()
{
	Check_Pointer(this);
	Check_Object(message);

	//
	//----------------------------------
	//We need to load in the path points
	//----------------------------------
	//
	pathPointsResourceID = message->pathPointsResourceID;

	if(message->pathPointsResourceID != ResourceID::Null)
	{
		Resource stream(message->pathPointsResourceID);
		Verify(stream.DoesResourceExist());
		int num_points;
		stream >> num_points;
		pathPoints.reserve(num_points);
		for(int i=0; i<num_points; i++)
		{
			Point3D point;
			stream >> point;
			pathPoints.push_back(point);
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Path::~Path()
{
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Replicator::CreateMessage* Path::SaveMakeMessage(MemoryStream *stream, ResourceFile *res_file)
{
	Check_Object(this);
	Check_Object(stream);

	//
	//---------------------------------------------------------------------
	// Make sure there is enough room for the factory request on the stream
	//---------------------------------------------------------------------
	//
	stream->AllocateBytes(sizeof(CreateMessage));
	Entity::SaveMakeMessage(stream, res_file);
	CreateMessage *message =
		Cast_Pointer(CreateMessage*, stream->GetPointer());
	message->messageLength = sizeof(*message);

	message->pathPointsResourceID = pathPointsResourceID;

	return message;
}

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

Stuff::Point3D Path::GetNearestPoint (const Stuff::Point3D& pt)
{
	Stuff::Point3D third,toret;
	int i,size,min;
	Stuff::Scalar mindist,dist;

	size = pathPoints.size ();
	Verify (size>0);
	min = 0;
	third.Subtract (pt,pathPoints[0]);
	mindist = third.GetLengthSquared ();
	for (i=1;i<size;i++)
	{
		third.Subtract (pt,pathPoints[i]);
		dist = third.GetLengthSquared ();
		if (dist < mindist)
		{
			mindist = dist;
			min = i;
		}
	}
	return pathPoints[min];
}

int Path::GetNearestIndex (const Stuff::Point3D& pt)
{
	Stuff::Point3D third,toret;
	int i,size,min;
	Stuff::Scalar mindist,dist;

	size = pathPoints.size ();
	Verify (size>0);
	min = 0;
	third.Subtract (pt,pathPoints[0]);
	mindist = third.GetLengthSquared ();
	for (i=1;i<size;i++)
	{
		third.Subtract (pt,pathPoints[i]);
		dist = third.GetLengthSquared ();
		if (dist < mindist)
		{
			mindist = dist;
			min = i;
		}
	}
	return min;
}

void Path::SaveAs2DPoly(Stuff::DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> >& Poly) const
{
	gosASSERT(&Poly);

	Adept::Map& map = *Adept::Map::GetInstance();
/*
	BYTE rows, cols;
	map.GetElement()->GetSize(&rows, &cols);
	
	// Save the MapSize
	Point3D MapSize(rows * c_ZoneSize, 0.0f, cols * c_ZoneSize);
*/
	int i, size;

	size = pathPoints.size ();
	Poly.SetLength(size);
	for(i = 0; i < size; i++)
	{
		Stuff::Vector2DOf<Stuff::Scalar>& d = Poly[(size - 1) - i];
		d.x = pathPoints[i].x;
		d.y = pathPoints[i].z;
		map.WorldToZoneCoords(d.x, d.y);
/*
		d.x += MapSize.x*0.5f;
		d.y += MapSize.z*0.5f;
		d.x *= map.GetColumnZoneScale();
		d.y *= map.GetRowZoneScale();
*/
	}
}

