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

#pragma once

#include "glmOrientedGraph.h"

namespace glm
{
	/** 
	* \brief An extended oriented graph, allowing to plan paths to and from points outside an existing graph, by linking them to this graph
	*
	* \ingroup graphs
	*
	* \see glm::graphs::IOrientedGraph
	*
	* \author Golaem <dev@golaem.com>
	*/
	class GLM_SDK_API ExtendedOrientedGraph : public IOrientedGraph
	{
	public:

		GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation);

		/** 
		* \brief Constructor from another oriented graph
		* \warning The given base graph should not be modified during the lifetime of the Oriented graph.
		*/
		explicit ExtendedOrientedGraph(const OrientedGraph& baseGraph);

		/**
		* \brief Destructor.
		*/
		virtual ~ExtendedOrientedGraph();

		/**
		* \brief Clears all the additional nodes/arcs, but does not clear the underlying graph.
		*/
		void clearExtension();

		int findIndexOfModifiedNodeId(const int & nodeId) const;

		/** 
		* \name Nodes
		*/
		//@{
		unsigned int getNbNodeIds() const;
		bool hasNode(const int & nodeId) const;
		int addNode(const RoadmapNode& data);

		/**
		* \warning Only nodes added to the extended graph can be removed, as the base graph can not be modified.
		*/
		const RoadmapNode & getNode(const int& nodeId) const;
		const glm::PODArray<int>& getNodeSuccessors(const int & nodeId) const;
		const glm::PODArray<int>& getNodePredecessors(const int & nodeId) const;
		void addModifiedNode( int nodeId );
		//@}

		/** 
		* \name Arcs
		*/
		//@{		
		unsigned int getNbArcIds() const;
		bool hasArc(const int & arcId) const;
		int addArc(const int& origin, const int& extremity, const RoadmapArc & data);
		/**
		* \warning Only arcs added to the extended graph can be removed, as the base graph can not be modified.
		*/
				const RoadmapArc & getArc(const int& arcId) const;
		int getArcOrigin(const int & arcId) const;
		int getArcExtremity(const int & arcId) const;
		int retrieveArc(const int & origin, const int & extremity) const;
		//@}

		/**
		* \brief set the baseGraph to use during current operations (used in multithread by roadmapquery, to use thread safe graphs instances );
		*/
		void setBaseGraph( const OrientedGraph& baseGraph );

		/**
		* \brief get the baseGraph currently in use
		*/
		const OrientedGraph& getBaseGraph( ) const;

	private:
		
		GLM_DISALLOW_COPY_AND_ASSIGN( ExtendedOrientedGraph );

		glm::Array<RoadmapNode> _additionalNodeData;
		glm::Array<OrientedGraph::ArcData> _additionalArcData;
		
		// we may add successors or predecessors to baseGraph nodes, need nodeId information. added nodes will be handles as basegraph nodes for this case.
		glm::Array< int > _modifiedNodeIds; // keep key in another array for faster sortings
		glm::Array< glm::PODArray<int> > _modifiedPredecessors; // these arrays are kept allocated, their inner array are cleared when adding a new modified node to avoid reallocating it each time.
		glm::Array< glm::PODArray<int> > _modifiedSuccessors;	// these arrays are kept allocated, their inner array are cleared when adding a new modified node to avoid reallocating it each time.
		
		/// The base graph
		const OrientedGraph* _baseGraph;
	};
}
