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

#pragma once

#include "glmMutex.h"
#include "glmNoGround.h"

namespace glm
{
	/**
	* \defgroup ground
	* \brief Ground functions.
	*/
	/**
	* \brief Abstract class defining a group.
	*
	* \ingroup ground
	*
	* \author Golaem <dev@golaem.com>
	*/
	class GLM_SDK_API GroundManager
	{
	public:

		struct GLM_SDK_API RegisteredGround
		{
		public:

			GLM_CLASS_STAT_ID( glm::MemoryStatIds::GolaemShared)

			RegisteredGround();
			RegisteredGround(int minLod, AbstractGround* ground);
			int _minLod; //!< The minimum lod level to which this ground applies.
			AbstractGround* _ground; //!< The ground.
			bool operator<(const RegisteredGround& ground) const; //!< Compare two RegisteredGround based on their minLod
			bool operator==(const RegisteredGround& ground) const; //!< Compare two RegisteredGround based on their minLod
		};

	public:

		GLM_CLASS_STAT_ID( glm::MemoryStatIds::GolaemShared)

		/**
		* \name Construction/Destruction
		*/
		//@{
		GroundManager();
		~GroundManager();
		//@}

		// used for serialization
		GroundManager( const GroundManager& other );
		GroundManager& operator=( const GroundManager& other );

		/**
		* \name init/update/finish
		*/
		//@{
		void init();
		void update(Time dt);
		void finish();
		void reset();
		//@}

		/**
		* \name Grounds
		*/
		//@{
		/**
		* \note If no ground has been provided, this method returns the default ground (an instance of NoGround).
		* \note If grounds has been provided, the manager must be initialized before grounds are retrieved (initialization orders the grounds).
		*/
		const AbstractGround& getGround(int lod, bool checkBeforeInit = true) const;
		/**
		* \note If no ground has been provided, this method will assert.
		* \note If grounds has been provided, the manager must be initialized before grounds are touched (initialization orders the grounds).
		*/
		AbstractGround& touchGround(int lod);
		void setGround(int lodLowerBound, AbstractGround* ground);
		const glm::Array< RegisteredGround >& getGrounds() const;
		void setGrounds(const glm::Array< RegisteredGround >& grounds);
		bool hasGround(int lod) const;

		/**
		* \brief Removes a ground without destroying it
		*/
		void removeGround(AbstractGround* ground);

		/**
		* \brief Removes all grounds without destroying them
		*/
		void removeGrounds();

		bool isRunning() const
		{
			return _running;
		}
		//@}
	protected:

		/**
		* \brief Delete the existing grounds.
		*/
		void clearGrounds();

		/**
		* \brief Sort the grounds using their minimal LOD.
		*/
		void sortGrounds();

		bool _running;

		/**
		* \brief Registered grounds.
		*
		* The vector is sorted incrementally using the minimal LOD.
		*/
		glm::Array< RegisteredGround > _grounds;

		NoGround	_defaultGround;
	};
}


