//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//
//=============================================================================//
// nav_node.h
// Navigation Nodes are used when generating a Navigation Mesh by point sampling the map
// Author: Michael S. Booth (mike@turtlerockstudios.com), January 2003

#ifndef _NAV_NODE_H_
#define _NAV_NODE_H_

#include "nav.h"

// If DEBUG_NAV_NODES is true, nav_show_nodes controls drawing node positions, and
// nav_show_node_id allows you to show the IDs of nodes that didn't get used to create areas.
#define DEBUG_NAV_NODES 1

//--------------------------------------------------------------------------------------------------------------
/**
 * Navigation Nodes.
 * These Nodes encapsulate world locations, and ways to get from one location to an adjacent one.
 * Note that these links are not necessarily commutative (falling off of a ledge, for example).
 */
class CNavNode
{
public:
	CNavNode( const Vector &pos, const Vector &normal, CNavNode *parent, bool onDisplacement );
	~CNavNode();

	static CNavNode *GetNode( const Vector &pos );					///< return navigation node at the position, or NULL if none exists
	static void CleanupGeneration();

	CNavNode *GetConnectedNode( NavDirType dir ) const;				///< get navigation node connected in given direction, or NULL if cant go that way
	const Vector *GetPosition( void ) const;
	const Vector *GetNormal( void ) const		{ return &m_normal; }
	unsigned int GetID( void ) const			{ return m_id; }

	static CNavNode *GetFirst( void )			{ return m_list; }
	static unsigned int GetListLength( void )	{ return m_listLength; }
	CNavNode *GetNext( void )					{ return m_next; }

	void Draw( void );

	void ConnectTo( CNavNode *node, NavDirType dir, float obstacleHeight, float flObstacleStartDist, float flObstacleEndDist );		///< create a connection FROM this node TO the given node, in the given direction
	CNavNode *GetParent( void ) const;

	void MarkAsVisited( NavDirType dir );							///< mark the given direction as having been visited
	BOOL HasVisited( NavDirType dir );								///< return TRUE if the given direction has already been searched
	BOOL IsBiLinked( NavDirType dir ) const;						///< node is bidirectionally linked to another node in the given direction
	BOOL IsClosedCell( void ) const;								///< node is the NW corner of a bi-linked quad of nodes

	void Cover( void )				{ m_isCovered = true; }			///< @todo Should pass in area that is covering
	BOOL IsCovered( void ) const	{ return m_isCovered; }			///< return true if this node has been covered by an area

	void AssignArea( CNavArea *area );								///< assign the given area to this node
	CNavArea *GetArea( void ) const;								///< return associated area

	void SetAttributes( int bits )		{ m_attributeFlags = bits; }
	int GetAttributes( void ) const		{ return m_attributeFlags; }
	float GetGroundHeightAboveNode( NavCornerType cornerType ) const;	///< return ground height above node in given corner direction (NUM_CORNERS for highest in any direction)
	bool IsBlockedInAnyDirection( void) const;						///< return true if the node is blocked in any direction

	bool IsOnDisplacement( void ) const				{ return m_isOnDisplacement; }

private:
	CNavNode() {}													// constructor used only for hash lookup
	friend class CNavMesh;

	bool TestForCrouchArea( NavCornerType cornerNum, const Vector& mins, const Vector& maxs, float *groundHeightAboveNode );
	void CheckCrouch( void );

	Vector m_pos;													///< position of this node in the world
	Vector m_normal;												///< surface normal at this location
	CNavNode *m_to[ NUM_DIRECTIONS ];								///< links to north, south, east, and west. NULL if no link
	float  m_obstacleHeight[ NUM_DIRECTIONS ];						///< obstacle height (delta from nav node z position) that must be climbed to reach next node in this direction
	float  m_obstacleStartDist[ NUM_DIRECTIONS ];					///< distance along this direction to reach the beginning of the obstacle
	float  m_obstacleEndDist[ NUM_DIRECTIONS ];						///< distance along this direction to reach the end of the obstacle
	unsigned int m_id;												///< unique ID of this node
	int	m_attributeFlags;											///< set of attribute bit flags (see NavAttributeType)

	static CNavNode *m_list;										///< the master list of all nodes for this map
	static unsigned int m_listLength;
	static unsigned int m_nextID;
	CNavNode *m_next;												///< next link in master list
	CNavNode *m_nextAtXY;											///< next link at a particular position

	// below are only needed when generating
	unsigned char m_visited;										///< flags for automatic node generation. If direction bit is clear, that direction hasn't been explored yet.
	CNavNode *m_parent;												///< the node prior to this in the search, which we pop back to when this node's search is done (a stack)
	bool m_isCovered;												///< true when this node is "covered" by a CNavArea
	CNavArea *m_area;												///< the area this node is contained within

	bool m_isBlocked[ NUM_CORNERS ];
	bool m_crouch[ NUM_CORNERS ];
	float m_groundHeightAboveNode[ NUM_CORNERS ];
	bool m_isOnDisplacement;
};

//--------------------------------------------------------------------------------------------------------------
//
// Inlines
//

inline CNavNode *CNavNode::GetConnectedNode( NavDirType dir ) const
{
	return m_to[ dir ];
}

inline const Vector *CNavNode::GetPosition( void ) const
{
	return &m_pos;
}

inline CNavNode *CNavNode::GetParent( void ) const
{
	return m_parent;
}

inline void CNavNode::MarkAsVisited( NavDirType dir )
{
	m_visited |= (1 << dir);
}

inline BOOL CNavNode::HasVisited( NavDirType dir )
{
	if (m_visited & (1 << dir))
		return true;

	return false;
}

inline void CNavNode::AssignArea( CNavArea *area )
{
	m_area = area;
}

inline CNavArea *CNavNode::GetArea( void ) const
{
	return m_area;
}

inline bool CNavNode::IsBlockedInAnyDirection( void ) const
{
	return m_isBlocked[ SOUTH_EAST ] || m_isBlocked[ SOUTH_WEST ] || m_isBlocked[ NORTH_EAST ] || m_isBlocked[ NORTH_WEST ];
}


#endif // _NAV_NODE_H_