//////////////////////////////////////////////////////////////////////////////
//
// AVP_Behaviour_GS2Node_RouteTraverse.cpp
//
// Copyright (C) 2008 Rebellion. All Rights Reserved.
//
//////////////////////////////////////////////////////////////////////////////

// I N C L U D E S ///////////////////////////////////////////////////////////

// core
#include "Core/Asura.h"

// header
#include "Behaviour/BehaviourTypes/AVP_Behaviour_GS2Node_RouteTraverse.h"

// asura
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "Entity/Locations/Spline/GamesceneSpline/Asura_ServerNode_GS2Spline.h"

// axon
#include "Behaviour/BehaviourTypes/AVP_Behaviour_GS2Actor.h"
#include "Behaviour/BehaviourTypes/AVP_Behaviour_Types.h"
#include "Core/BrainTypes/AVP_Brain_Actor.h"

// avp
#include "Entity/Locations/OrientedNode/GamesceneNode/AVP_ServerNode_GS2Node.h"

//////////////////////////////////////////////////////////////////////////////
//
// AVP_Behaviour_GS2Node_RouteTraverse
//
//////////////////////////////////////////////////////////////////////////////

AVP_Behaviour_GS2Node_RouteTraverse::AVP_Behaviour_GS2Node_RouteTraverse( AVP_Brain_Actor* pxBrain )
: PARENT( AVP_BEHAVIOUR_TYPE_GS2_NODE_ROUTETRAVERSE, pxBrain )
, m_uLinkToTake( ASURA_GUID_UNREGISTERED )
, m_fRemainingTimeslice( 0.0f )
{
}

void AVP_Behaviour_GS2Node_RouteTraverse::ReadFromChunkStream( Asura_Chunk_Stream& xStream )
{
	u_int uVersion;
	xStream >> uVersion;

	PARENT::ReadFromChunkStream( xStream );

	if ( uVersion == uCURRENT_CHUNK_VERSION )
	{
	}
	else
	{
		Asura_Assertf( false, ( "AVP_Behaviour_GS2Node_RouteTraverse::ReadFromChunkStream - unhandled chunk version (%u)", uVersion ) );
	}
}

void AVP_Behaviour_GS2Node_RouteTraverse::WriteToChunkStream( Asura_Chunk_Stream& xStream ) const
{
	xStream << uCURRENT_CHUNK_VERSION;

	PARENT::WriteToChunkStream( xStream );
}

bool AVP_Behaviour_GS2Node_RouteTraverse::Activate()
{
	const bool bParentOk = PARENT::Activate();

	m_uLinkToTake = ChooseLinkToTake();
	SetFinished();

	return bParentOk;
}

void AVP_Behaviour_GS2Node_RouteTraverse::PerFrameUpdate( const float fTimeslice )
{
	m_fRemainingTimeslice = fTimeslice;

	if ( IsInError() || IsFinished() )
	{
		return;
	}

	PARENT::PerFrameUpdate( fTimeslice );

	m_fRemainingTimeslice = 0.0f;
}

Asura_Guid AVP_Behaviour_GS2Node_RouteTraverse::ChooseLinkToTake()
{
	// Get the waypoint we correspond to.
	const AVP_ServerNode_GS2Node* pxOurNode = AVP_ServerNode_GS2Node::FindEntity( GetGSActorBehaviour()->GetCurrentEntityGuid() );
	if ( !pxOurNode ) { return ASURA_GUID_UNREGISTERED; }
	const u_short usCorrespondingWPID = pxOurNode->GetWaypointID();

	// Find this waypoint on the route.
	const AVP_Navigation::NavData& xNavData = GetActorBrain()->GetNavData();
	for ( u_short usRouteIndex = 0; usRouteIndex < xNavData.m_usRouteLength - 1; ++usRouteIndex )
	{
		if ( xNavData.m_pusRoute[ usRouteIndex ] == usCorrespondingWPID )
		{
			// Determine which link we need to take based on which waypoint we are next heading for.
			const u_short usNextWPID = xNavData.m_pusRoute[ usRouteIndex + 1 ];
			for ( u_int uLinkIndex = 0; uLinkIndex < pxOurNode->GetNumberLinks(); ++uLinkIndex )
			{
				const Asura_ServerNode_GS2Spline* pxLink = Asura_ServerNode_GS2Spline::FindEntity( pxOurNode->GetLink( uLinkIndex ) );
				if ( !pxLink ) { return ASURA_GUID_UNREGISTERED; }

				const AVP_ServerNode_GS2Node* pxTargetNode = AVP_ServerNode_GS2Node::FindEntity( pxLink->GetTargetGuid() );
				if ( !pxTargetNode ) { return ASURA_GUID_UNREGISTERED; }

				if ( pxTargetNode->GetWaypointID() == usNextWPID )
				{
					return pxLink->GetGuid();
				}
			}

			break;
		}
	}

	return ASURA_GUID_UNREGISTERED;
}

AVP_Brain_Actor* AVP_Behaviour_GS2Node_RouteTraverse::GetActorBrain() const
{
	return static_cast< AVP_Brain_Actor* >( GetBrain() );
}

//////////////////////////////////////////////////////////////////////////////
//
// 
//
//////////////////////////////////////////////////////////////////////////////
