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

#pragma once

#include "glmSDKAPI.h"
#include "glmAbstractNavigationMesh3Creator.h"
#include "glmVoxelNavigationMesh2.h"
#include "glmNavigationMesh3CreatorParameters.h"

namespace glm
{
	struct RecastData;
	class ComputeSharedEdgesWorkerThread;
	class ComputeOverlappingCellsWorkerThread;

	/**
	* \brief Compute Navigation Mesh functor from voxels
	*
	* \ingroup NavMesh3
	*
	* \author Golaem <dev@golaem.com>
	*/
	class GLM_SDK_API VoxelNavigationMesh3Creator : public AbstractNavigationMesh3Creator
	{
		friend class ComputeSharedEdgesWorkerThread;
		friend class ComputeOverlappingCellsWorkerThread;

	public:
		typedef int ComponentId;

		VoxelNavigationMesh3Creator() ;
		virtual ~VoxelNavigationMesh3Creator() ;

		int _nbTilesX;
		int _nbTilesY;

		float _voxelWidth;
		float _voxelHeight;

		/**
		* \brief The Recast data from which to build the navigation mesh
		*/
		RecastData* _recastData;

		NavigationMesh3CreatorParameters _parameters;

	protected:

		/**
		* \brief The Navigation Mesh 2D components.
		*/
		glm::PODArray<VoxelNavigationMesh2*> _components;

		glm::Array<std::pair<int, int> > _componentIds; // used to test if tiles are neighbors

		/**
		* \brief CellId to component cell id association.
		*/
		glm::Array<std::pair<ComponentId, NavigationMeshCellId> > _cellId2ComponentCellId;

		/**
		* \brief EdgeId to component edge id association.
		*/
		glm::Array<glm::GlmMap<ComponentId, NavigationMeshEdgeId> > _edgeId2ComponentEdgeId;

		/**
		* \brief Computes the Navigation Mesh.
		*/
		bool doComputation(bool& cancel);

	private:
		/**
		* \brief copy constructor, declared but not defined to disallow copying this object
		*/
		VoxelNavigationMesh3Creator( const VoxelNavigationMesh3Creator& ) ;

		/**
		* \brief assignment operator, declared but not defined to disallow copying this object
		*/
		const VoxelNavigationMesh3Creator& operator=( const VoxelNavigationMesh3Creator& ) ;

		/**
		* \brief Computes the Navigation Mesh 2D components.
		*/
		bool computeComponents(Progress::SP progress);

		/**
		* \brief Computes the 3d cells to 2d cells associations
		*/
		bool computeCellsAssociations(Progress::SP progress);

		/**
		* \brief Computes the shared edges
		*/
		std::pair<VoxelNavigationMesh3Creator::ComponentId, NavigationMeshEdgeId>
			computeSharedEdge(std::pair<VoxelNavigationMesh3Creator::ComponentId, NavigationMeshEdgeId> currentEdge) const;

		bool computeSharedEdges(
			glm::GlmMap<std::pair<ComponentId, NavigationMeshEdgeId>, std::pair<ComponentId, NavigationMeshEdgeId> >& sharedEdges, 
			Progress::SP progress, unsigned int threadCount = 0);

		/**
		* \brief Computes the edges
		*/
		bool computeEdges(
			const glm::GlmMap<std::pair<ComponentId, NavigationMeshEdgeId>, std::pair<ComponentId, NavigationMeshEdgeId> >& sharedEdges, 
			Progress::SP progress);

		/**
		* \brief Computes the cells that overlap in 2d
		*/
		bool computeOverlappingCells(Progress::SP progress, unsigned int threadCount = 0);

		/**
		* \brief Filter cells based on their surface
		*/
		bool filterCells(Progress::SP progress);

		bool componentsAreNeighbors(int tile1X, int tile1Y, int tile2X, int tile2Y) const;

		bool*	_cancel;
	} ;
}
