/***************************************************************************
*                                                                          *
*  Copyright (C) Golaem S.A.  All Rights Reserved.                         *
*                                                                          *
***************************************************************************/

#pragma once

#include "glmSDKAPI.h"
#include "glmRoadmapNode.h"
#include "glmRoadmapArc.h"

//golaem core includes
#include <glmOrientedGraph.h>
#include <glmMatrix4.h>

namespace glm
{
	class IRoadmapCosts;
	class Segment3;

	/**
	* \defgroup Roadmap Roadmap
	*
	* \ingroup Environment
	*
	* \brief Roadmaps over navigation meshes.
	*
	* \section roadmap_roadmap A roadmap on top of a navigation mesh
	* The path spatial environment provides roadmaps on top of the \ref NavMesh "navigation meshes" in order to compute paths.
	* The roadmap is an oriented graph gathering:
	* \li Nodes representing the waypoints, each belongs to a navigation mesh edge;
	* \li Oriented arcs joining two nodes, each belongs to a single navigation mesh cell.
	* 
	* Two nodes are joined by an arc if their edges belong to the same cell and if the distance
	* between the segment they form and obstacles is less than the minimum radius given at creation. 
	*
	* \image html "Roadmap.png" Roadmap (free navigation mesh edges are grey, obstacles are red, the roadmap is orange)
	*
	* Usually, each of the navigation mesh edges gets a roadmap node. Edges identified as steps are given two:
	* one to go up, the other to go down. This separation is usefull to detect when a path is going up the stairs or 
	* going down.
	*
	* \image html "RoadmapStairs.png" Stairs steps in a roadmap
	*
	* \section roadmap_classes Classes description
	* IRoadmap is part of the Path spatial environment framework, it defines the interface to use a roadmap.
	* \li Nodes are instances of \ref RoadmapNode they are identified in their roadmap using \ref RoadmapNodeId.
	* \li Arcs are instances of \ref RoadmapArc they are identified in their roadmap using \ref RoadmapArcId.
	*
	* RoadmapImpl is the provided implementation of IRoadmap.
	*
	* AbstractRoadmapCreator, RoadmapCreator, RoadmapGseLoader, RoadmapGseSaver, RoadmapCreatorParameters and RoadmapStitcher
	* should not be used directly, they are used during the \ref PSSpatialEnvironmentCreator "creation", the 
	* \ref PSSpatialEnvironmentGseSaver "saving" and the \ref PSSpatialEnvironmentGseLoader "loading" processes of 
	* the spatial environment.
	*/

	/**
	* \brief Interface defining the spatial environment roadmaps.
	*
	* \ingroup Roadmap
	*
	* \author Golaem <dev@golaem.com> 
	*
	* \see \ref roadmap_roadmap "Roadmaps general principles"
	*/
	class GLM_SDK_API Roadmap
	{
	public:

		GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation)

		~Roadmap();

		/** 
		* \brief Nodes
		*/
		//@{
		/**
		* \brief Retrieve the position of the given node.
		* \pre The given node identifier must be \ref isNodeIdValid "valid" within this roadmap.
		*/
		Vector3 getNodePositionLocal(const RoadmapNodeId& nodeId) const;
		//@}

		/** 
		* \brief Arcs
		*/
		//@{		
		/**
		* \brief Retrieve the segment of the given arc.
		* \pre The given arc identifier must be \ref isArcIdValid "valid" within this roadmap.
		*/
		void getArcSegmentLocal(Segment3& arcSegment, const RoadmapArcId& arcId) const;
		//@}

		/** 
		* \name GraphicInfos
		*/
		//@{
		/**
		* \brief Compute a 3D multisegment representing the roadmap.
		* \param[out] geometry The geometry.
		* \param[in] addArrows If true, arrows are added to the arcs segment to show their orientation (default is true).
		*/
		void computeGeometry(glm::Array<Segment3>& geometry, bool addArrows = true) const;
		//@}

		/**
		* \name Edition
		*/
		//@{
#if GLM_ROADMAP_ERASE_SUPPORT_ENABLE
		void eraseCell(const NavigationMeshCellId& cellId);
#endif
		//@}

		/// The navigation mesh
		const NavigationMesh3* _navigationMesh;

		/// The graph
		OrientedGraph _graph;

		/// The arcs associated to each cell
		glm::PODArrayOfArray<RoadmapArcId> _cellArcs;

		/// The waypoints associated to each edge
		glm::PODArrayOfArray<RoadmapNodeId> _edgeNodes;
		
		// used for dynamic navigation meshes : use inverse on input position, and applyw worlMat on output
		Matrix4 _worldTransformMatrix;
		Matrix4 _worldTransformMatrixInverse;

	private:

		GLM_DISALLOW_COPY_AND_ASSIGN( Roadmap );

#if GLM_ROADMAP_ERASE_SUPPORT_ENABLE
		/**
		* \brief Erases an arc
		*/
		void eraseArc(const RoadmapArcId& arcId);

		/**
		* \brief Erases a node
		*/
		void eraseNode(const RoadmapNodeId& nodeId);
#endif

		/**
		* \brief Constructor
		*/
		Roadmap(const NavigationMesh3& navigationMesh);

		friend class AbstractRoadmapCreator;
	};
}
