#include "MW4Headers.hpp"
#include "Adept\AdeptHeaders.hpp"

#include "mw4.hpp"
#include "moverai.hpp"
#include "Adept\Interface.hpp"
#include "Adept\Application.hpp"
#include "Adept\player.hpp"
#include "torso.hpp"

#include "aimovedata.hpp"

using namespace MechWarrior4;
using namespace MW4AI;
#pragma warning (push)
#include <algorithm>
#pragma warning (pop)

CRigidPatrolData::CRigidPatrolData (MW4AI::CRailGraph *graph,MoverAI *owner) : CMoveData (graph,owner)
{
	m_PatrolType = PATROL_UNDEF;
	m_List.clear ();
	m_InMove = 0;
	m_InMoveDir = 1;
	m_NodeListDirty = false;
	m_PathID = -1;
	m_StartPoint = 0;
	m_MoveType = MOVE_RIGIDPATROL;
}

CRigidPatrolData::~CRigidPatrolData (void)
{
}
void CRigidPatrolData::Save (MemoryStream *stream)
{
	*stream << ((int) m_PatrolType);
	*stream << m_NodeListDirty;
	*stream << m_PathID;
	*stream << m_StartPoint;
	*stream << m_InMove;
	*stream << m_InMoveDir;
	*stream << m_List.size ();
	stlport::vector<Stuff::Point3D>::iterator iter;
	for (iter = m_List.begin ();iter != m_List.end ();iter++)
	{
		*stream << *iter;
	}

	CMoveData::Save (stream);
}

void CRigidPatrolData::Load (MemoryStream *stream)
{
	int size,i;
	Point3D pt;

	AutoHeap local_heap (g_MoverAIHeap);
	*stream >> size;
	m_PatrolType = (Patrol_Type) size;
	*stream >> m_NodeListDirty;
	*stream >> m_PathID;
	*stream >> m_StartPoint;
	*stream >> m_InMove;
	*stream >> m_InMoveDir;
	*stream >> size;
	for (i=0;i<size;i++)
	{
		*stream >> pt;
		m_List.push_back (pt);
	}
	CMoveData::Load (stream);
}

void CRigidPatrolData::InsertPoint (const Stuff::Point3D& loc)
{
	Point3D temp;

	AutoHeap local_heap (g_MoverAIHeap);
	temp = loc;
	ConvertPointToGrid (temp);
	inherited::InsertPoint (temp);
	if (m_List.size ())
		if (temp == m_List[m_List.size ()-1])
			return;
	m_List.push_back (temp);
	m_NodeListDirty = true;
}
void CRigidPatrolData::InsertObject (Entity *who)
{
	inherited::InsertObject (who);
}

void CRigidPatrolData::StartExecuting (MoverAI *ai,Stuff::Time till)
{
	inherited::StartExecuting (ai,till);

	m_InMove = m_StartPoint;
	m_InMoveDir = 1;
}
void CRigidPatrolData::PathDone (MoverAI *ai,Stuff::Time till,bool failed)
{
	inherited::PathDone (ai,till,failed);

	if (failed)
		return;

	switch (PatrolType ())
	{
		case PATROL_SINGLE:
			Done (true);
			break;
		case PATROL_LOOP:
			m_InMove = 0;
			m_InMoveDir = 1;
			break;
		case PATROL_SEESAW:
			m_InMoveDir *= -1;
			m_InMove += m_InMoveDir;
			break;
	}
}

void CRigidPatrolData::CreatePlaneRequests (const Stuff::Point3D& start)
{
	inherited::CreatePlaneRequests (start);
}

void CRigidPatrolData::CreateRequests (const Stuff::Point3D& start,int usageflags)
{
	inherited::CreateRequests (start,usageflags);

}
bool CRigidPatrolData::operator== (const CRigidPatrolData& p1)
{
	if (!inherited::operator== ((inherited)p1))
		return false;
	if (m_PathID != p1.m_PathID)
		return false;
	return true;
}

void CRigidPatrolData::Execute (MoverAI *ai,Stuff::Time till)
{
	inherited::Execute (ai,till);

	Point3D loc(0,0,0),head(0,0,0),destloc,extra;

	Verify (ai);
	Verify (ai->m_Vehicle);
	loc = (Point3D) ai->m_Vehicle->GetLocalToWorld ();

	const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (ai->m_Vehicle->GetGameModel ()) ;

	Stuff::Scalar speed,dist,move;

	speed = ai->m_Vehicle->speedDemand;
	loc.y = 0;

	destloc = Location (m_InMove);
	destloc.y = 0;
	extra.Subtract (destloc,loc);
	dist = extra.GetLengthSquared ();
	move = (float) (speed * model->maxSpeed);		// use one second buffer
	move *= move;

	if ((dist<25.0) || (dist < move))
	{
		if ((m_InMoveDir > 0) && (LocationSize () > (m_InMove+m_InMoveDir)))
		{
			m_InMove+=m_InMoveDir;
		}
		else if ((m_InMoveDir < 0) && ((m_InMove+m_InMoveDir) > 0))
		{
			m_InMove+= m_InMoveDir;
		}
		else
		{
			ai->PathDone (till,false);
		}
	}
	ai->SetMoveHead (Location (m_InMove),Speed ());
}

Stuff::Point3D CRigidPatrolData::Location (int id)
{
	Verify (id>=0);
	Verify (id<m_List.size ());
	return m_List[id];
}

int CRigidPatrolData::LocationSize (void) const
{
	return m_List.size ();
}

void CRigidPatrolData::ReversePatrolList (void)
{
	stlport::vector<Stuff::Point3D>::iterator first,last;

	AutoHeap local_heap (g_MoverAIHeap);
	first = m_List.begin ();
	last = m_List.end ();
	stlport::reverse (first,last);
}

void CRigidPatrolData::SetupPath (Path *path)
{
	Check_Object (path);
	m_PathID = path->objectID;

	int size,i;
	size = path->pathPoints.size ();
	for (i=0;i<size;i++)
	{
		InsertPoint (path->pathPoints[i]);
	}
}
