#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)

CSemiPatrolData::CSemiPatrolData (MW4AI::CRailGraph *graph,MoverAI *owner) : CMoveData (graph,owner)
{
	m_PatrolType = PATROL_UNDEF;
	m_List.clear ();
	m_CurRequest = 0;
	m_NodeListDirty = false;
	m_PathID = -1;
	m_StartPoint = 0;
	m_MoveType = MOVE_SEMIPATROL;
	m_PathWorking = false;
}

CSemiPatrolData::~CSemiPatrolData (void)
{
}

void CSemiPatrolData::Save (MemoryStream *stream)
{
	stlport::vector<Stuff::Point3D>::iterator iter1;

	*stream << m_NodeListDirty;
	*stream << m_PathID;
	*stream << m_StartPoint;
	*stream << m_CurRequest;
	*stream << m_PathWorking;
	*stream << m_List.size ();
	for (iter1 = m_List.begin ();iter1 != m_List.end ();iter1++)
	{
		*stream << *iter1;
	}

	CMoveData::Save (stream);
}

void CSemiPatrolData::Load (MemoryStream *stream)
{
	AutoHeap local_heap (g_MoverAIHeap);

	int i,size;

	*stream >> m_NodeListDirty;
	*stream >> m_PathID;
	*stream >> m_StartPoint;
	*stream >> m_CurRequest;
	*stream >> m_PathWorking;
	*stream >> size;
	for (i=0;i<size;i++)
	{
		Point3D temp;
		*stream >> temp;
		m_List.push_back (temp);
	}

	CMoveData::Load (stream);
}

void CSemiPatrolData::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 CSemiPatrolData::InsertObject (Entity *who)
{
	inherited::InsertObject (who);
}

void CSemiPatrolData::StartExecuting (MoverAI *ai,Stuff::Time till)
{

	inherited::StartExecuting (ai,till);
	m_PathWorking = false;

	m_CurRequest = m_StartPoint;
}

void CSemiPatrolData::PathDone (MoverAI *ai,Stuff::Time till,bool failed)
{

	inherited::PathDone (ai,till,failed);

	if (failed)
		return;

	Verify (ai->m_Vehicle);

	Stuff::Point3D temploc;
	const Vehicle__GameModel *model=NULL;
	if (ai->m_Vehicle)
		model = static_cast<const Vehicle__GameModel *> (ai->m_Vehicle->GetGameModel ()) ;
	if (ai->m_Vehicle)
		temploc = (Stuff::Point3D) ai->m_Vehicle->GetLocalToWorld ();

	CurRequest (CurRequest ()+1);
	if (CurRequest () < RequestSize ())
	{
		Verify (m_PathWorking);
		m_PathWorking = false;
	}
	else
	{
		switch (m_PatrolType)
		{
			case PATROL_SINGLE:
				Done (true);
				ai->SetMoveHead (Point3D (-1,-1,-1),0);
				break;
			case PATROL_LOOP:
				Executing (false);
				m_StartPoint = 0;
				CreateRequests (temploc,MW4AI::ConvertTypetoUsage (model->moveTypeFlag));
				StartExecuting (ai,till);
				break;
			case PATROL_SEESAW:
				Executing (false);
				m_StartPoint = 0;
				ReversePatrolList ();
				CreateRequests (temploc,MW4AI::ConvertTypetoUsage (model->moveTypeFlag));
				StartExecuting (ai,till);
				break;
		}
//				Done (true);
	}
}

MW4AI::CPathRequest *CSemiPatrolData::NeedPathRequest (const Point3D& loc,int usageflags)
{
	CPathRequest *toret;
	if (!Executing ())
		return NULL;

	if (Done ())
		return NULL;
	m_PathWorking = true;
	Verify (m_CurRequest>=0);
	Verify (m_CurRequest<m_List.size ());
	toret = g_PathManager->AddRequest (gos_GetElapsedTime (),m_Graph,loc,m_List[m_CurRequest],usageflags,m_AI,m_AI->AllowTenMeter ());
	return toret;
}

void CSemiPatrolData::UpdatePathRequest (const Point3D& loc,MW4AI::CPathRequest *req)
{
	if (!Executing ())
		return;
	Verify (req);
	Verify (m_CurRequest>=0);
	Verify (m_CurRequest<m_List.size ());
	m_PathWorking = true;
	req->UpdateSrcDest (loc,m_List[m_CurRequest]);
}

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

void CSemiPatrolData::CreateRequests (const Stuff::Point3D& start,int usageflags)
{
	Point3D loc,third,fred;
	AutoHeap local_heap (g_MoverAIHeap);

	inherited::CreateRequests (start,usageflags);
}
bool CSemiPatrolData::operator== (const CSemiPatrolData& p1)
{
	if (!inherited::operator== ((inherited)p1))
		return false;
	if (m_PathID != p1.m_PathID)
		return false;
	return true;
}

Stuff::Point3D CSemiPatrolData::Location (int id)
{
	Verify (id>=0);
	if (id >= m_List.size ())
		return Point3D (-1,-1,-1);

	return m_List[id];
}

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

void CSemiPatrolData::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 CSemiPatrolData::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]);
	}
}

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

	if (m_PathWorking)
		return;

	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_CurRequest);
	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 (LocationSize () > (m_CurRequest+1))
		{
			m_CurRequest+=1;
		}
		else
		{
			ai->PathDone (till,false);
		}
	}
	ai->SetMoveHead (Location (m_CurRequest),Speed (),Location (m_CurRequest+1));
}

