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

#pragma once

#include "glmTrianglePartition.h"

namespace glm
{
	/** 
	* \brief Specialization of TrianglePartition allowing edges and vertices to be tagged by additionnal informations.
	*
	* \ingroup spatialDataStructures
	*
	* \author Golaem <dev@golaem.com>
	*
	* \param VertexTag The type used for vertices tags (default is int).
	* \param EdgeTag The type used for edges tags (default is int).
	*/
	template <class VertexTag=int, class EdgeTag=int>
	class TaggedTrianglePartition : public TrianglePartition
	{
		typedef TaggedTrianglePartition<VertexTag, EdgeTag> ThisTaggedTrianglePartition;
	public:

		GLM_CLASS_STAT_ID( glm::MemoryStatIds::GolaemShared)

		/** 
		* \name Construction/Destruction
		*/
		//@{
		TaggedTrianglePartition();

		//TaggedTrianglePartition(const TaggedTrianglePartition<VertexTag,EdgeTag> & partition);

		virtual ~TaggedTrianglePartition();

		//TaggedTrianglePartition<VertexTag,EdgeTag> & operator=(const TaggedTrianglePartition<VertexTag,EdgeTag> & partition);

		/**
		* \brief Initialize
		* \param vertices The vertices.
		* \param verticesTags The vertices tags.
		* \param edges The edges as pair of vertex id.
		* \param edgesTags The edges tags.
		* \param cellsEdges The cells defined using their edges.
		* \return True if the partition has been successfully initialized
		*/
		bool init(
			glm::Array<Vector2 > vertices
			, glm::Array< VertexTag > verticesTags
			, glm::Array< std::pair<VertexId,VertexId> > edges
			, glm::Array< EdgeTag > edgesTags
			, glm::Array< IndexTriplet<EdgeId> > cellsEdges
			, bool& cancel
			);

		/**
		* \brief Clear the data structure.
		*/
		virtual void clear();
		//@}

		/** 
		* \name Tags
		*/
		//@{
		const VertexTag & getVertexTag(const VertexId & id) const;

		void setVertexTag(const VertexId & id, const VertexTag & tag);

		const EdgeTag & getEdgeTag(const EdgeId & id) const;

		void setEdgeTag(const EdgeId & id, const EdgeTag & tag);
		//@}

		// for unit tests only
        bool operator==(const TaggedTrianglePartition<VertexTag, EdgeTag>& partition) const;

    private:
	
		TaggedTrianglePartition( const TaggedTrianglePartition<VertexTag,EdgeTag>& ) ;
		void operator=( const TaggedTrianglePartition<VertexTag,EdgeTag>& ) ;
        bool operator!=(const TaggedTrianglePartition<VertexTag, EdgeTag>&)
        {
            GLM_EXIT("TaggedTrianglePartition operator != not implemented.");
        }

    protected:

		glm::Array<VertexTag> _verticesTags ;

		glm::Array<EdgeTag> _edgesTags ;
	} ;

	//*****************************************************************************
	// TaggedTrianglePartition inline definitions
	//*****************************************************************************

	//-----------------------------------------------------------------------------
	// constructor
	//-----------------------------------------------------------------------------
	template <class VertexTag, class EdgeTag>
	TaggedTrianglePartition<VertexTag,EdgeTag>::TaggedTrianglePartition()
		:TrianglePartition()
		,_verticesTags()
		,_edgesTags()
	{
	}

	//-----------------------------------------------------------------------------
	// destructor
	//-----------------------------------------------------------------------------
	template <class VertexTag, class EdgeTag>
	TaggedTrianglePartition<VertexTag,EdgeTag>::~TaggedTrianglePartition()
	{
		clear();
	}

	//-----------------------------------------------------------------------------
	// initialize
	//-----------------------------------------------------------------------------
	template <class VertexTag, class EdgeTag>
	bool TaggedTrianglePartition<VertexTag,EdgeTag>::init(
		glm::Array< Vector2 > vertices
		, glm::Array< VertexTag > verticesTags
		, glm::Array< std::pair<VertexId,VertexId> > edges
		, glm::Array< EdgeTag > edgesTags
		, glm::Array< IndexTriplet<EdgeId> > cellsEdges
		, bool& cancel
		)
	{
		GLM_DEBUG_ASSERT(verticesTags.size() == vertices.size());
		GLM_DEBUG_ASSERT(edges.size() == edgesTags.size());
		_verticesTags = verticesTags;
		_edgesTags = edgesTags;

		return TrianglePartition::init(vertices,edges,cellsEdges, cancel);
	}

	//-----------------------------------------------------------------------------
	// clear
	//-----------------------------------------------------------------------------
	template <class VertexTag, class EdgeTag>
	void TaggedTrianglePartition<VertexTag,EdgeTag>::clear()
	{
		_verticesTags.clear();
		_edgesTags.clear();
		TrianglePartition::clear();
	}

	//-----------------------------------------------------------------------------
	// getTag (Vertex)
	//-----------------------------------------------------------------------------
	template <class VertexTag, class EdgeTag>
	const VertexTag & TaggedTrianglePartition<VertexTag,EdgeTag>::getVertexTag(const VertexId & id) const
	{
		return _verticesTags[id] ;
	}

	//-----------------------------------------------------------------------------
	// setTag (Vertex)
	//-----------------------------------------------------------------------------
	template <class VertexTag, class EdgeTag>
	void TaggedTrianglePartition<VertexTag,EdgeTag>::setVertexTag(const VertexId & id, const VertexTag & tag)
	{
		_verticesTags[id] = tag ;
	}

	//-----------------------------------------------------------------------------
	// getTag (Edge)
	//-----------------------------------------------------------------------------
	template <class VertexTag, class EdgeTag>
	const EdgeTag & TaggedTrianglePartition<VertexTag,EdgeTag>::getEdgeTag(const EdgeId & id) const
	{
		return _edgesTags[id] ;
	}

	//-----------------------------------------------------------------------------
	// setTag (Edge)
	//-----------------------------------------------------------------------------
	template <class VertexTag, class EdgeTag>
	void TaggedTrianglePartition<VertexTag,EdgeTag>::setEdgeTag(const EdgeId & id, const EdgeTag & tag)
	{
		_edgesTags[id] = tag ; 
	}

	//-----------------------------------------------------------------------------
	// operator==
	//-----------------------------------------------------------------------------
	template <class VertexTag, class EdgeTag>
	bool TaggedTrianglePartition<VertexTag,EdgeTag>::operator==(const TaggedTrianglePartition<VertexTag,EdgeTag> & partition) const
	{
		if (_edgesTags != partition._edgesTags)
		{
			return false;
		}
		else if (_verticesTags != partition._verticesTags)
		{
			return false;
		}
		else
		{
			return TrianglePartition::operator ==(partition);
		}
	}
}

