//////////////////////////////////////////////////////////////////////////////
//
// ToolsAVP_Waypoint_Analysis.cpp
//
// Copyright (C) 2007 Rebellion. All Rights Reserved.
//
//////////////////////////////////////////////////////////////////////////////

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

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

// header
#include "Waypointing/ToolsAVP_Waypoint_Analysis.h"

// asura
#include "Core/Asura_Timers.h"
#include "Core/Asura_UserInput.h"
#include "Core/Memory/Asura_Mem.h"
#include "Dynamics/Asura_Collision_Object.h"
#include "Interface/Asura_Dialog.h"
#include "Physics/Asura_Physics.h"
#include "Rendering/Asura_Render.h"
#include "Rendering/Asura_Text_Output.h"

// tools
#include "Misc/Tools_Render.h"
#include "Misc/Tools_Timed_Messages.h"
#include "Waypointing/Tools_Mode_Waypointing.h"
#include "Waypointing/ToolsAVP_Mode_Waypointing.h"
#include "Waypointing/Tools_Waypoint_Selection.h"

//////////////////////////////////////////////////////////////////////////////
//
// ToolsAVP_Waypoint_Analysis
//
//////////////////////////////////////////////////////////////////////////////

bool ToolsAVP_Waypoint_Analysis::s_bIsInterestedInAlienRouteFailure    = true;
bool ToolsAVP_Waypoint_Analysis::s_bIsInterestedInNonAlienRouteFailure = true;

const char* ToolsAVP_Waypoint_Analysis::s_pszPathfinderStrings[ NUM_PATHFINDER_TYPES ] =
{
	"Humanoid",
	"Alien",
	"Predator"
};

const char* ToolsAVP_Waypoint_Analysis::s_pszFunctorStrings[ NUM_FUNCTOR_TYPES ] =
{
	"Humanoid Standard",            
	"Alien Standard",               
	"Predator Standard",            
	"Alien Away From",              
	"Alien Away From In Direction", 
	"Alien Find Cover In Direction",
	"Alien Find Nearest Cover",     
	"Alien Find Wall In Direction", 
	"Alien Find Floor In Direction",
	"Humanoid Combat - Avoid LoF"
};

const ToolsAVP_Waypoint_Analysis::FunctorData ToolsAVP_Waypoint_Analysis::s_axFunctorData[ NUM_FUNCTOR_TYPES ] =
{
//	{ m_bRequiresTwoWPs, m_bRangeValid, m_bDirectionValid }
	{ true,  false, false },
	{ true,  false, false },
	{ true,  false, false },
	{ false, true,  false },
    { false, true,  true  },
	{ false, true,  true  },
	{ false, true,  false },
	{ false, true,  true  },
	{ false, true,  true  },
	{ true, false,  false },
};

ToolsAVP_Waypoint_Analysis::ToolsAVP_Waypoint_Analysis()
: m_xOutputBoundingBox()
, m_pxOrientationOutputArray( NULL )
, m_uPathfinderFlags( AVP_Navigation::AVP_AI_PATHFINDER_FLAG_HUMANOID )
, m_fRange( 30.0f )
, m_xDirection( 1.0f, 0.0f, 0.0f )
, m_pxRouteFindFunctor( NULL )
, m_iPathfinderSelection( PATHFINDER_HUMANOID )
, m_iFunctorSelection( HUMANOID_STANDARD )
, m_bRotatingDirectionLeft( false )
, m_bRotatingDirectionRight( false )
, m_uSelectedAvoidLoFWPIndex(ASURA_INVALID_WAYPOINT_ID)
{
}

void ToolsAVP_Waypoint_Analysis::Update()
{
	PARENT::Update();

	if ( m_bRotatingDirectionLeft || m_bRotatingDirectionRight )
	{
		int iSelectedWaypoint;
		if ( Tools_Waypoint_Selection::GetSelectedWaypoint( iSelectedWaypoint ) )
		{
			const Asura_AI_NavVertex* pxWaypoint = Asura_AI_Navigation_System::GetWaypoint( iSelectedWaypoint );

			if ( m_bRotatingDirectionLeft )
			{
				Asura_Quat xRotation;
				xRotation.FromRotation( Asura_Maths::Pi	* 0.5f * Asura_Timers::GetGameTimeSlice(), pxWaypoint->GetNormal() );
				m_xDirection = xRotation.RotateVector( m_xDirection);
			} 
			else if ( m_bRotatingDirectionRight )
			{
				Asura_Quat xRotation;
				xRotation.FromRotation( Asura_Maths::Pi	* 0.5f * Asura_Timers::GetGameTimeSlice(), pxWaypoint->GetNormal() * -1.0f );
				m_xDirection = xRotation.RotateVector( m_xDirection);
			}
		}

		if ( !Asura_UserInput::KeyPressed( ASURA_KEYID_MOUSEBUTTON1 ) )
		{
			m_bRotatingDirectionLeft = m_bRotatingDirectionRight = false;
		}
	}
}

void ToolsAVP_Waypoint_Analysis::AddOverlayItemsToTabsDialogue( Asura_Tabs_Dialog* pxTabsDialogue, Asura_Vector_2& xOffset )
{
	// Add the option to set our pathfinder flags.
	xOffset.y += Asura_Dialog::LargeSpacing() - Asura_Dialog::DefaultSpacing();

	Asura_Dialog* pxDialogue = new Asura_Dialog( "Pathfinder Flags:", xOffset );
	pxTabsDialogue->AddDialog( pxDialogue );
	xOffset.x += 15.0f;

	Asura_DropDown_List_Dialog* pxDDLDialogue = new Asura_DropDown_List_Dialog( xOffset, s_pszPathfinderStrings, &m_iPathfinderSelection,
		NUM_PATHFINDER_TYPES, NUM_PATHFINDER_TYPES, NULL );
	pxDDLDialogue->SetOnSelectCallback( PathfinderSelectionChanged, reinterpret_cast< int >( this ) );
	pxTabsDialogue->AddDialog( pxDDLDialogue );
	xOffset.x -= 15.0f;
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialogue = new Asura_Dialog( "Route Find Functor:", xOffset );
	pxTabsDialogue->AddDialog( pxDialogue );
	xOffset.x += 15.0f;

	pxDDLDialogue = new Asura_DropDown_List_Dialog( xOffset, s_pszFunctorStrings, &m_iFunctorSelection,
		NUM_FUNCTOR_TYPES, NUM_FUNCTOR_TYPES, NULL );
	pxTabsDialogue->AddDialog( pxDDLDialogue );
	xOffset.x -= 15.0f;
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialogue = new Asura_Numerical_Dialog( "Route Find Range", xOffset, &m_fRange, 0.0f, 1000.0f, 0.25f, "%.2f" );
	pxDialogue->SetIsEnabledFunction( AllowRangeChange, reinterpret_cast< int >( this ) );
	pxTabsDialogue->AddDialog( pxDialogue );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialogue = new Asura_Dialog( "Rotate Direction:", xOffset );
	pxDialogue->SetIsEnabledFunction( AllowDirectionChange, reinterpret_cast< int >( this ) );
	pxTabsDialogue->AddDialog( pxDialogue );
	xOffset.x += 15.0f;

	pxDialogue = new Asura_Function_Dialog( "", xOffset, RotateDirectionLeft, reinterpret_cast< int >( this ) );
	pxDialogue->SetIsEnabledFunction( AllowDirectionChange, reinterpret_cast< int >( this ) );
	pxTabsDialogue->AddDialog( pxDialogue );
	xOffset.x += 5.0f;

	pxDialogue = new Asura_Function_Dialog( "", xOffset, RotateDirectionRight, reinterpret_cast< int >( this ) );
	pxDialogue->SetIsEnabledFunction( AllowDirectionChange, reinterpret_cast< int >( this ) );
	pxTabsDialogue->AddDialog( pxDialogue );
	xOffset.x -= 20.0f;
	xOffset.y += Asura_Dialog::LargeSpacing();

	pxDialogue = new Asura_Function_Dialog("Use Last Selected Waypoint as LoF Test Position", xOffset, SelectLoFAvoidWP, reinterpret_cast< int >( this ) );
	pxDialogue->SetIsEnabledFunction( AllowLoFAvoidWPSelection, reinterpret_cast< int >( this ) );
	pxTabsDialogue->AddDialog( pxDialogue );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialogue = new Asura_Function_Dialog("Clear Waypoint used for LoF Test Position", xOffset, ClearLoFAvoidWP, reinterpret_cast< int >( this ) );
	pxDialogue->SetIsEnabledFunction( AllowLoFAvoidWPSelection, reinterpret_cast< int >( this ) );
	pxTabsDialogue->AddDialog( pxDialogue );
	xOffset.y += Asura_Dialog::LargeSpacing();

	PARENT::AddOverlayItemsToTabsDialogue( pxTabsDialogue, xOffset );
}

void ToolsAVP_Waypoint_Analysis::RenderWorld()
{
    if ( m_bLinkAnalysisInProgress )
    {
		unsigned int uColour = 0xffffffff;
        m_fLinkAnalysisPlaybackTime += Asura_Timers::GetGameTimeSlice() * m_fLinkAnalysisPlaybackSpeed;
        if ( m_fLinkAnalysisPlaybackTime < 0.0f )
        {
            m_fLinkAnalysisPlaybackTime = 0.0f;
        }
        u_int uIndex = static_cast< u_int >( Asura_Maths::FloatToInt( m_fLinkAnalysisPlaybackTime / Asura_Physics_System::GetTimeStep() ) );
        if ( uIndex >= m_uNumPositionOutputs )
        {
            static const float s_fNumSecondsToHoldAtEnd = 1.0f;
            if ( m_fLinkAnalysisPlaybackTime > ( m_uNumPositionOutputs * Asura_Physics_System::GetTimeStep() ) + s_fNumSecondsToHoldAtEnd )
            {
                m_fLinkAnalysisPlaybackTime = 0.0f;
            }
            uIndex  = m_uNumPositionOutputs - 1;
            uColour = m_bLinkAnalysisSuccessful ? 0xff00ff00 : 0xffff0000;
        }

        Asura_Matrix_3x3 xOrientationMatrix;
        m_pxOrientationOutputArray[ uIndex ].ToMatrix( xOrientationMatrix );
        Asura_Render::RenderBB( m_xOutputBoundingBox, m_pxPositionOutputArray[ uIndex ], xOrientationMatrix, uColour );

		Asura_Matrix_3x3 xInitialOrientation;
		m_pxOrientationOutputArray[ 0 ].ToMatrix( xInitialOrientation );
		const Asura_Vector_3 xInitialForward( xInitialOrientation.e13, xInitialOrientation.e23, xInitialOrientation.e33 );
		const Asura_Vector_3 xCurrentForward( xOrientationMatrix.e13, xOrientationMatrix.e23, xOrientationMatrix.e33 );

		Asura_Render::RenderLine( m_pxPositionOutputArray[ uIndex ],
			m_pxPositionOutputArray[ uIndex ] + xInitialForward * 2.0f, 0xff00ff00 );
		Asura_Render::RenderLine( m_pxPositionOutputArray[ uIndex ],
			m_pxPositionOutputArray[ uIndex ] + xCurrentForward * 2.0f, 0xff0000ff );

		Asura_Text_Output::Print( 20, 20, 0xffffffff, 0, "dot: %f (max %f)", xInitialForward * xCurrentForward, 0.64278760968653932632264340990726f );
    }
    else
    {
        PARENT::RenderWorld();
    }

	int iSelectedWaypoint;
	if ( Tools_Waypoint_Selection::GetSelectedWaypoint( iSelectedWaypoint ) )
	{
		const Asura_AI_NavVertex* pxWaypoint = Asura_AI_Navigation_System::GetWaypoint( iSelectedWaypoint );

		if ( s_axFunctorData[ m_iFunctorSelection ].m_bRangeValid )
		{
			extern void Render_Sphere( const Asura_Vector_3& xCentre, float fRadius, int iColour );
			Render_Sphere( pxWaypoint->GetPosition(), m_fRange, 0xffffffff );
		}
		if ( s_axFunctorData[ m_iFunctorSelection ].m_bDirectionValid )
		{
			const Asura_Vector_3 xBasePosition = pxWaypoint->GetPosition() + pxWaypoint->GetNormal();
			Asura_Render::RenderLine( xBasePosition, xBasePosition + m_xDirection * 5.0f, 0xffffffff );
		}
	}

	if ( m_iFunctorSelection == HUMANOID_COMBAT && m_uSelectedAvoidLoFWPIndex != ASURA_INVALID_WAYPOINT_ID )
	{
		const Asura_AI_NavVertex* pxWaypoint = Asura_AI_Navigation_System::GetWaypoint( m_uSelectedAvoidLoFWPIndex );
		extern void Render_Sphere( const Asura_Vector_3& xCentre, float fRadius, int iColour );
		Render_Sphere( pxWaypoint->GetPosition(), pxWaypoint->GetRadius() + 0.5f, 0xff00ff00 );
	}
}

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

void ToolsAVP_Waypoint_Analysis::AnalyseLink()
{
    int iStartWaypoint, iFinishWaypoint;
    if ( !Tools_Waypoint_Selection::GetFirstTwoSelectedWaypoints( iStartWaypoint, iFinishWaypoint ) ) { return; }

    Asura_AI_NavVertex* pxStartWaypoint  = Asura_AI_Navigation_System::GetWaypoint( iStartWaypoint );
    Asura_AI_NavVertex* pxFinishWaypoint = Asura_AI_Navigation_System::GetWaypoint( iFinishWaypoint );
    if ( !pxStartWaypoint && !pxFinishWaypoint ) { return; }

    const float fDistance = ( pxStartWaypoint->m_xPosition - pxFinishWaypoint->m_xPosition ).Magnitude();
    if ( fDistance > Tools_Mode_Waypointing::GetMaxLinkLength() )
    {
        Tools_Timed_Message_System::AddMessage( Tools_Timed_Message_System::COLOUR_ERROR, "Distance between waypoints too large ( > max link length )" );
        return;
    }

    m_bLinkAnalysisInProgress   = true;
    m_iStartWaypoint            = iStartWaypoint;
    m_iFinishWaypoint           = iFinishWaypoint;
    m_fLinkAnalysisPlaybackTime = 0.0f;

	switch ( m_iPathfinderSelection )
	{
		case PATHFINDER_HUMANOID:
		case PATHFINDER_PREDATOR:
		{
			s_bIsInterestedInAlienRouteFailure	  = false;
			s_bIsInterestedInNonAlienRouteFailure = true;
			break;
		}
		default:
		case PATHFINDER_ALIEN:
		{
			s_bIsInterestedInAlienRouteFailure	  = true;
			s_bIsInterestedInNonAlienRouteFailure = false;
			break;
		}
	}

    ToolsAVP_Mode_Waypointing* pxAVPWaypointing = static_cast< ToolsAVP_Mode_Waypointing* >( Tools_Mode_Waypointing::GetInstance() );
    pxAVPWaypointing->InitialisePhysicsDataForWaypointing();

    u_int uDummyLinkFlags = 0;
    Asura_Vector_3 xStartWaypointNormal = pxStartWaypoint->GetNormal();
    Asura_Vector_3 xEndWaypointNormal = pxFinishWaypoint->GetNormal();
    m_bLinkAnalysisSuccessful = pxAVPWaypointing->CullAndFlagLinkWithPhysics( uDummyLinkFlags,
        pxStartWaypoint->m_xPosition,  xStartWaypointNormal, iStartWaypoint,
        pxFinishWaypoint->m_xPosition, xEndWaypointNormal,   iFinishWaypoint );

	s_bIsInterestedInAlienRouteFailure	  = true;
	s_bIsInterestedInNonAlienRouteFailure = true;

    // Copy the positions and orientations over to our local storage.
    m_uNumPositionOutputs   = Asura_Maths::Min( Tools_Mode_Waypointing::s_uNumPhysicsPositions, static_cast< u_int >( MAX_POSITION_OUTPUTS ) );
    m_pxPositionOutputArray = new Asura_Vector_3[ m_uNumPositionOutputs ];
    if ( m_pxPositionOutputArray )
    {
        Asura_Mem::Copy( m_pxPositionOutputArray, Tools_Mode_Waypointing::s_pxPhysicsPositions, m_uNumPositionOutputs * sizeof( Asura_Vector_3 ) );
    }
    m_pxOrientationOutputArray = new Asura_Quat[ m_uNumPositionOutputs ];
    if ( m_pxOrientationOutputArray )
    {
        Asura_Mem::Copy( m_pxOrientationOutputArray, ToolsAVP_Mode_Waypointing::s_pxPhysicsOrientations, m_uNumPositionOutputs * sizeof( Asura_Quat ) );
    }
    m_xOutputBoundingBox = ToolsAVP_Mode_Waypointing::s_xPhysicsBoundingBox;

    pxAVPWaypointing->ResetPhysicsDataAfterWaypointing();
}

void ToolsAVP_Waypoint_Analysis::StopLinkAnalysis()
{
    PARENT::StopLinkAnalysis();

    delete [] m_pxOrientationOutputArray;
    m_pxOrientationOutputArray = NULL;
}

void ToolsAVP_Waypoint_Analysis::AnalyseRouteFind()
{
	int iStartWaypoint = ASURA_INVALID_WAYPOINT_ID;
	int iFinishWaypoint = ASURA_INVALID_WAYPOINT_ID;
	Asura_AI_NavVertex* pxStartWaypoint = NULL;
	Asura_AI_NavVertex* pxFinishWaypoint = NULL;

	if ( s_axFunctorData[ m_iFunctorSelection ].m_bRequiresTwoWPs )
	{
		if ( !Tools_Waypoint_Selection::GetFirstTwoSelectedWaypoints( iStartWaypoint, iFinishWaypoint ) ) { return; }

		pxStartWaypoint  = Asura_AI_Navigation_System::GetWaypoint( iStartWaypoint );
		pxFinishWaypoint = Asura_AI_Navigation_System::GetWaypoint( iFinishWaypoint );
		if ( !pxStartWaypoint && !pxFinishWaypoint ) { return; }
	}
	else
	{
		if ( !Tools_Waypoint_Selection::GetSelectedWaypoint( iStartWaypoint ) ) { return; }

		pxStartWaypoint = Asura_AI_Navigation_System::GetWaypoint( iStartWaypoint );
		if ( !pxStartWaypoint ) { return; }
	}

	switch ( m_iFunctorSelection )
	{
		default: Asura_Assert( false, "ToolsAVP_Waypoint_Analysis::AnalyseRouteFind - unhandled functor type" ); // fallthrough
		case HUMANOID_STANDARD:				m_pxRouteFindFunctor = new AVP_Navigation::HumanoidAStarFunctor; break;
		case ALIEN_STANDARD:				m_pxRouteFindFunctor = new AVP_Navigation::AlienAStarFunctor;	 break;
		case PREDATOR_STANDARD:				m_pxRouteFindFunctor = new AVP_Navigation::PredatorAStarFunctor; break;
		case ALIEN_AWAY_FROM:				m_pxRouteFindFunctor = new AVP_Navigation::AlienAwayFromFunctor( pxStartWaypoint->GetPosition(), m_fRange ); break;
		case ALIEN_AWAY_FROM_IN_DIRECTION:  m_pxRouteFindFunctor = new AVP_Navigation::AlienAwayFromInDirFunctor( pxStartWaypoint->GetPosition(), m_fRange, m_xDirection ); break;
		case ALIEN_FIND_COVER_IN_DIRECTION: m_pxRouteFindFunctor = new AVP_Navigation::AlienFindCoverInDirFunctor( static_cast< u_short >( iStartWaypoint ), static_cast< u_short >( iStartWaypoint ), m_fRange, m_xDirection ); break;
		case ALIEN_FIND_NEAREST_COVER:		m_pxRouteFindFunctor = new AVP_Navigation::AlienFindCoverInRangeFunctor( static_cast< u_short >( iStartWaypoint ), static_cast< u_short >( iStartWaypoint ), 0.0f, m_fRange ); break;
		case ALIEN_FIND_WALL_IN_DIRECTION:  m_pxRouteFindFunctor = new AVP_Navigation::AlienFindWallInDirFunctor( static_cast< u_short >( iStartWaypoint ), m_fRange, m_xDirection ); break;
		case ALIEN_FIND_FLOOR_IN_DIRECTION: m_pxRouteFindFunctor = new AVP_Navigation::AlienFindFloorInDirFunctor( static_cast< u_short >( iStartWaypoint ), m_fRange, m_xDirection ); break;
		case HUMANOID_COMBAT:				
		{
			if ( m_uSelectedAvoidLoFWPIndex != ASURA_INVALID_WAYPOINT_ID )
			{
				const Asura_AI_NavVertex* pxWaypoint = Asura_AI_Navigation_System::GetWaypoint( m_uSelectedAvoidLoFWPIndex );
				m_pxRouteFindFunctor = new AVP_Navigation::HumanoidCombatAStarFunctor( pxWaypoint->GetPosition() );
			}
			else
			{
				Tools_Timed_Message_System::AddMessage( Tools_Timed_Message_System::COLOUR_ERROR, "No Test Waypoint Selected, Test Position will be world Origin (0, 0, 0) ");
				m_pxRouteFindFunctor = new AVP_Navigation::HumanoidCombatAStarFunctor( Asura_Vector_3( 0.0f, 0.0f, 0.0f ) );
			}
		}
	}

	m_pusRoute = new unsigned short[ MAX_ANALYSIS_ROUTE_LENGTH ];
	if ( !m_pusRoute ) { return; }
	m_bRouteFindInProgress = true;
	m_bRouteFindFinished   = false;
	m_iStartWaypoint       = iStartWaypoint;
	m_iFinishWaypoint      = iFinishWaypoint;
	m_iRouteLength         = 0;

	if ( s_axFunctorData[ m_iFunctorSelection ].m_bRequiresTwoWPs )
	{
		Asura_AI_Navigation_System::PreAStarSearch( static_cast< unsigned short >( m_iStartWaypoint ),
			static_cast< unsigned short >( m_iFinishWaypoint ),
			Asura_AI_Navigation_System::DefaultGoalCostEstimateFunction,
			NULL );
	} 
	else
	{
		Asura_AI_Navigation_System::PreAStarSearch( static_cast< unsigned short >( m_iStartWaypoint ),
			Asura_AI_Navigation_System::DefaultGoalCostEstimateFunction,
			NULL );
	}
}

void ToolsAVP_Waypoint_Analysis::StopRouteFindAnalysis()
{
	delete m_pxRouteFindFunctor;
	m_pxRouteFindFunctor = NULL;

	m_bRouteFindInProgress = false;
	m_bRouteFindFinished   = false;
	m_iStartWaypoint       = ASURA_INVALID_WAYPOINT_ID;
	m_iFinishWaypoint      = ASURA_INVALID_WAYPOINT_ID;
	m_iRouteLength         = 0;
	delete [] m_pusRoute;
	m_pusRoute = NULL;
}

void ToolsAVP_Waypoint_Analysis::NextRouteFindStep()
{
    m_bRouteFindFinished = Asura_AI_Navigation_System::AStarSearchIncremental( m_pusRoute, m_iRouteLength, MAX_ANALYSIS_ROUTE_LENGTH,
																			   m_uPathfinderFlags, m_pxRouteFindFunctor,
																			   AVP_Navigation::FunctorGoalCostFunction,
																			   AVP_Navigation::FunctorTraversalCostFunction,
																			   AVP_Navigation::FunctorGoalAchievedFunction,
																			   AVP_Navigation::FunctorLinkFlagsTestFunction );
    if ( m_bRouteFindFinished )
    {
		OnRouteFindFinished();
    }
}

void ToolsAVP_Waypoint_Analysis::NextRouteFindSteps()
{
    int iStepsLeft = m_iRouteFindStepIncrement;
    while ( iStepsLeft-- && !m_bRouteFindFinished )
    {
        m_bRouteFindFinished = Asura_AI_Navigation_System::AStarSearchIncremental( m_pusRoute, m_iRouteLength, MAX_ANALYSIS_ROUTE_LENGTH,
																				   m_uPathfinderFlags, m_pxRouteFindFunctor,
																				   AVP_Navigation::FunctorGoalCostFunction,
																				   AVP_Navigation::FunctorTraversalCostFunction,
																				   AVP_Navigation::FunctorGoalAchievedFunction,
																				   AVP_Navigation::FunctorLinkFlagsTestFunction );
    }

    if ( m_bRouteFindFinished )
    {
		OnRouteFindFinished();
    }
}

void ToolsAVP_Waypoint_Analysis::OnRouteFindFinished()
{
	if ( m_iRouteLength == 0 )
	{
		Tools_Timed_Message_System::AddMessage( Tools_Timed_Message_System::COLOUR_ERROR, "Route find failed!" );
	}
	else
	{
		Tools_Timed_Message_System::AddMessage( Tools_Timed_Message_System::COLOUR_DEFAULT, "Route find succeeded!" );
	}
}

void ToolsAVP_Waypoint_Analysis::PathfinderSelectionChanged( int iThis )
{
	ToolsAVP_Waypoint_Analysis* pxThis = reinterpret_cast< ToolsAVP_Waypoint_Analysis* >( iThis );
	switch ( pxThis->m_iPathfinderSelection )
	{
		case PATHFINDER_HUMANOID:
		{
			pxThis->m_uPathfinderFlags = AVP_Navigation::AVP_AI_PATHFINDER_FLAG_HUMANOID;
			break;
		}

		case PATHFINDER_ALIEN:
		{
			pxThis->m_uPathfinderFlags = AVP_Navigation::AVP_AI_PATHFINDER_FLAG_ALIEN_HIGH_MOBILITY;
			break;
		}

		case PATHFINDER_PREDATOR:
		{
			pxThis->m_uPathfinderFlags = AVP_Navigation::AVP_AI_PATHFINDER_FLAG_PREDATOR;
			break;
		}

		default: break;
	}
}

bool ToolsAVP_Waypoint_Analysis::AllowedToAnalyseRouteFind()
{
	ToolsAVP_Waypoint_Analysis* pxThis = reinterpret_cast< ToolsAVP_Waypoint_Analysis* >( s_pxThis );

	if ( pxThis->m_bRouteFindInProgress )
	{
		return false;
	}

	const int iNumSelectedWPs = Tools_Waypoint_Selection::IsEnabled() ? Tools_Waypoint_Selection::GetNumSelectedWaypoints() : 0;
	if ( pxThis->s_axFunctorData[ m_iFunctorSelection ].m_bRequiresTwoWPs )
	{
		return ( iNumSelectedWPs == 2 );
	}
	else
	{
		return ( iNumSelectedWPs == 1 );
	}
}

bool ToolsAVP_Waypoint_Analysis::AllowRangeChange( int iThis )
{
	ToolsAVP_Waypoint_Analysis* pxThis = reinterpret_cast< ToolsAVP_Waypoint_Analysis* >( iThis );
	return pxThis->s_axFunctorData[ pxThis->m_iFunctorSelection ].m_bRangeValid;
}

bool ToolsAVP_Waypoint_Analysis::AllowDirectionChange( int iThis )
{
	ToolsAVP_Waypoint_Analysis* pxThis = reinterpret_cast< ToolsAVP_Waypoint_Analysis* >( iThis );
	return pxThis->s_axFunctorData[ pxThis->m_iFunctorSelection ].m_bDirectionValid;
}

void ToolsAVP_Waypoint_Analysis::RotateDirectionLeft( int iThis )
{
	ToolsAVP_Waypoint_Analysis* pxThis = reinterpret_cast< ToolsAVP_Waypoint_Analysis* >( iThis );
	pxThis->m_bRotatingDirectionLeft = true;
	pxThis->m_bRotatingDirectionRight = false;
}

void ToolsAVP_Waypoint_Analysis::RotateDirectionRight( int iThis )
{
	ToolsAVP_Waypoint_Analysis* pxThis = reinterpret_cast< ToolsAVP_Waypoint_Analysis* >( iThis );
	pxThis->m_bRotatingDirectionLeft = false;
	pxThis->m_bRotatingDirectionRight = true;
}

bool ToolsAVP_Waypoint_Analysis::AllowLoFAvoidWPSelection( int iThis )
{
	ToolsAVP_Waypoint_Analysis* pxThis = reinterpret_cast< ToolsAVP_Waypoint_Analysis* >( iThis );
	
	if ( pxThis->m_iFunctorSelection == HUMANOID_COMBAT )
	{
		return true;
	}
	else
	{
		return false;
	}
}

void ToolsAVP_Waypoint_Analysis::SelectLoFAvoidWP( int iThis )
{
	ToolsAVP_Waypoint_Analysis*					pxThis				= reinterpret_cast< ToolsAVP_Waypoint_Analysis* >( iThis );
	Tools_Waypoint_Selection::SelectionData*	pxSelectionArray	= Tools_Waypoint_Selection::GetSelectionArray();
	int											iNumSelected		= Tools_Waypoint_Selection::GetNumSelectedWaypoints();

	int iBestIndex = -1;
	int iBestWPIndex = ASURA_INVALID_WAYPOINT_ID;

	if (pxSelectionArray && iNumSelected > 0)
	{
		for ( int i = 0; i < Asura_AI_Navigation_System::GetNumberOfWaypoints(); ++i )
		{
			if ( pxSelectionArray[ i ].m_bIsSelected && pxSelectionArray[ i ].m_iSelectionIndex >= iBestIndex )
			{
				iBestIndex = pxSelectionArray[ i ].m_iSelectionIndex;
				iBestWPIndex = i;
			}
		}

		if ( iBestWPIndex != ASURA_INVALID_WAYPOINT_ID )
		{
			pxThis->m_uSelectedAvoidLoFWPIndex = iBestWPIndex;
			Tools_Waypoint_Selection::ClearSelection();
		}
	}
}

void ToolsAVP_Waypoint_Analysis::ClearLoFAvoidWP( int iThis )
{
	ToolsAVP_Waypoint_Analysis*	pxThis = reinterpret_cast< ToolsAVP_Waypoint_Analysis* >( iThis );

	pxThis->m_uSelectedAvoidLoFWPIndex = ASURA_INVALID_WAYPOINT_ID;
}

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