//////////////////////////////////////////////////////////////////////////////
//
// AVP_Navigation.h
//
// Copyright (C) 2007 Rebellion. All Rights Reserved.
//
//////////////////////////////////////////////////////////////////////////////

// B E G I N   F I L E   W R A P P E R ///////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
#pragma once
#endif

#ifndef __AVP_NAVIGATION_H__
#define __AVP_NAVIGATION_H__ 1

// E N D   F I L E   W R A P P E R ///////////////////////////////////////////

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

// asura
#include "AI/Asura_AI_Navigation.h"
#include "Core/Asura_Maths.h"
#include "Core/Asura_Multithread.h"

// avp
#include "Actor/Vertebrates/Alien/AVP_Alien_JumpHandler.h"

// axon
#include "Core/AVP_Navigation_Types.h"

// F O R W A R D   D E C L A R A T I O N S ///////////////////////////////////

class Asura_Chunk_Stream;
class Asura_Mempool;

//////////////////////////////////////////////////////////////////////////////
//
// AVP_Navigation
//
//////////////////////////////////////////////////////////////////////////////

namespace AVP_Navigation
{
	extern const TestParams s_xTPStandardParams;
	extern const APParams   s_xAPStandardParams;

	extern AlienAStarFunctor		s_xAlienAStarFunctor;
	extern HumanoidAStarFunctor		s_xHumanoidAStarFunctor;
	extern PredatorAStarFunctor		s_xPredatorAStarFunctor;
	extern AlienQueenAStarFunctor	s_xAlienQueenAStarFunctor;

    // Finds the nearest valid waypoint ID to the position given the parameters.
    bool GetNearestWaypointID( const Asura_Vector_3& xPosition, u_short& usNearestWaypointID, const TestParams& xParams = s_xTPStandardParams );
    // Updates the current waypoint
    void UpdateCurrentWaypointID( const Asura_Vector_3& xPosition, u_short& usCurrentWaypointID, const TestParams& xParams = s_xTPStandardParams );
    // Resolves a given position to one inside the waypoint graph and as close as possible to the nearest surface.
    void ResolveToValidPosition( Asura_Vector_3& xPosition, const TestParams& xParams = s_xTPStandardParams );
    // Returns whether this is a valid waypoint ID for the given test parameters.
    bool IsValidWaypointID( const u_short usWaypointID, const TestParams& xParams = s_xTPStandardParams );

    // Returns whether this is a valid link for the given test parameters.
    bool                                 IsValidLinkID( const u_short usWaypointID, const u_char ucLinkIndex, const TestParams& xParams = s_xTPStandardParams );
    LinkTransitionType                   GetLinkTransitionType( const u_short usFromWaypointID, const u_short usToWaypointID );
    AVP_Alien_JumpHandler::AlienJumpType GetJumpTypeFromLinkTransitionType( const LinkTransitionType eLinkTransitionType );
	bool								 IsStandardLink( const u_short usLinkFlags );
    bool                                 IsTransitionLink( const u_short usLinkFlags );
	bool                                 IsGS2Link( const u_short usLinkFlags );
	bool                                 IsEnvHookLink( const u_short usLinkFlags );
    bool                                 IsLowMobilityLink( const u_short usLinkFlags );
    bool                                 IsMedMobilityLink( const u_short usLinkFlags );
    bool                                 IsHighMobilityLink( const u_short usLinkFlags );
	bool								 IsConcaveLink( const Asura_Vector_3& xStartPos, const Asura_Vector_3& xFinishPos, const Asura_Vector_3& xFinishNormal );

    // Returns whether the current position is near enough the destination position given the tolerance parameters.
    bool AtPosition( const Asura_Vector_3& xCurrentPosition, const Asura_Vector_3& xDestinationPosition, const APParams& xParams = s_xAPStandardParams );

    // Gets an A* route using the current WPID, destination position, and destination WPID.
	bool FindRoute( NavData& xNavData, AStarFunctorBase* pxFunctor = NULL, bool bRefineRoute = true );
	// Gets an A* route away using the supplied functor.
	bool FindRouteAwayFrom( NavData& xNavData, AStarFunctorBase* pxFunctor, bool bRefineRoute = true );
	// Copies a route from one nav data to another and fixes up the route start if necessary.
	bool AdoptRoute( NavData& xToNavData, const NavData& xFromNavData, const Asura_Vector_3& xAdopterPosition, AStarFunctorBase* pxFunctor, bool bRefineRoute = true );

	// Does a breadth first search from the start waypoint defined in the functor.
	void SearchWaypoints( const u_int uPathfinderFlags, SearchFunctor* pxSearchFunctor );

    // Removes redundant waypoints from the route.
	void RefineRoute( NavData& xNavData, const TestParams& xParams = s_xTPStandardParams );
    void CalculateRouteAgility( NavData& xNavData );
  
	// returns the distance along the route from a position to the destination - Returns -1.0f if the route isn't valid	 
	float CalculateRouteDistance( const NavData& xNavData, const Asura_Vector_3& xStartPosition, u_short uStartRouteIndex );

    // Finds the nearest point on the route to the current position, with an optional look ahead distance to project the result along the route if required.
    // Returns whether the nearest position has reached the end of the route or not.
    bool FindNearestPointOnRoute( const NavData& xNavData, const Asura_Vector_3& xCurrentPosition, float fLookAheadDistance,
                                  Asura_Vector_3& xNearestPosition, u_short& usNearestRouteSegmentIndex );

	// Finds the nearest point on the route to the current position ignoring hight differences, with an optional look ahead distance (also in horizonal plane) to project the result along the route if required.
	// Returns whether the nearest position has reached the end of the route or not.
	bool FindNearestPointOnRouteHorizontal( const NavData& xNavData, const Asura_Vector_3& xCurrentPosition, float fLookAheadDistance,
		Asura_Vector_3& xNearestPosition, u_short& usNearestRouteSegmentIndex );

	// used to find the nearest position to the passed in current position on somebody elese route.
	void FindNearestPointOnOtherRoute( const NavData& xNavData, const Asura_Vector_3& xCurrentPosition, Asura_Vector_3& xNearestPosition, u_short& usNearestRouteSegmentIndex );

	// Glue functions that get the AStarFunctorBase in the pUserData void pointer.
	float FunctorTraversalCostFunction( const int iWaypointIndex, const int iLinkIndex, u_int uPathfinderFlags, void* pUserData );
	bool FunctorLinkFlagsTestFunction( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags, void* pUserData );
	float FunctorGoalCostFunction( const int iWaypointIndex, void* pUserData );	
	bool FunctorGoalAchievedFunction( const int iWaypointIndex, void* pUserData );

	bool IsRouteBlocked(const  NavData& xNavData);

    // Route debug info.
#ifndef ASURA_NO_DEBUG_OUTPUT
    void RenderRoute( const NavData& xNavData );

    int GetDebugNumRoutesAllocated();
    extern int s_iDbgTotalRoutesAllocated;
    extern int s_iDbgNumShortRoutesAllocated;
    extern int s_iDbgNumMedRoutesAllocated;
    extern int s_iDbgNumLongRoutesAllocated;
#endif

    // Route storage.
    void     InitialiseRouteMempools();
    void     ShutdownRouteMempools();
    u_short* CreateRouteBuffer( const u_int uRouteLength );
    void     DestroyRouteBuffer( u_short*& pusRouteBuffer );
    int      GetWorkingRouteBufferLength();
    u_short* GetWorkingRouteBuffer();
    enum { LONGEST_ROUTE_ALLOWED = 256 };
    extern Asura_Mempool* s_pxShortRouteMempool;
    extern Asura_Mempool* s_pxMedSmallRouteMempool;
	extern Asura_Mempool* s_pxMedRouteMempool;
	extern Asura_Mempool* s_pxMedLongRouteMempool;
    extern Asura_Mempool* s_pxLongRouteMempool;
    extern u_short        s_ausWorkingRouteBuffer[ LONGEST_ROUTE_ALLOWED ];
#ifndef ASURA_NO_DEBUG_OUTPUT
    extern u_short        s_usPreLength;
    extern u_short        s_ausPreRouteBuffer[ LONGEST_ROUTE_ALLOWED ];
    extern u_short        s_usPostLength;
    extern u_short        s_ausPostRouteBuffer[ LONGEST_ROUTE_ALLOWED ];
#endif
};

//////////////////////////////////////////////////////////////////////////////
//
// Asura_Job_RouteFind
// Putting this in here for now as it's only a test.
//
//////////////////////////////////////////////////////////////////////////////

class AVP_RouteFind
{
public:
	// Assumption: These functions are only ever called from one thread.
	// Assumption: Each simultaneous request uses a separate nav data structure.
	static Asura_Handle RequestRouteFind( AVP_Navigation::NavData& xNavData );
	static void			CancelRouteFind( Asura_Handle& iHandle );
	static bool			RouteFindFinished( const Asura_Handle& iHandle );
	static bool			GetRouteFindResults( Asura_Handle& iHandle, AVP_Navigation::NavData& xNavData );

private:
	friend class Axon_Project_System;
	static void Initialise();
	static void Reset();
	static void ThreadUpdateFunction( const void* pUserData );
	static void Shutdown();

	static void FindRoute( AVP_Navigation::NavData& xNavData );
	static void CancelAllRouteFinds();

private:
	enum { MAX_SIMULTANEOUS_JOBS = 32 };
	static struct Request
	{
		Request() : m_xNavData(), m_eState( FREE ) {}

		//## todo - We don't need all of this structure.
		AVP_Navigation::NavData m_xNavData;
		enum State
		{
			FREE,
			PENDING,
			FINISHED,
			CANCELLING
		} m_eState;
	}				       s_axRequests[ MAX_SIMULTANEOUS_JOBS ];
	// The number of request slots that have valid data in them (!FREE).
	static int			   s_iNumUsedRequests;
	// The number of request slots that still need processing by the thread update function (PENDING/CANCELLING).
	static int			   s_iNumActiveRequests;
    static Asura_Mutex     s_xRequestMutex;
	static Asura_SyncEvent s_xStopThread;
};

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

#endif //__AVP_Navigation_H__
