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

#pragma once

#include "glmSDKAPI.h"
#include "glmVelocitySamplingConfiguration.h"
#include <glmVector2.h>
#include <glmRandomNumberGenerator.h>

namespace glm
{
	/**
	* \defgroup VelocitySampling Velocity sampling
	* \ingroup Navigation
	* \brief Velocity sampling
	*/

	/** 
	* \brief A table of weighted velocities.
	*
	* \ingroup Navigators
	*
	* \author Golaem <dev@golaem.com>
	*/
	class GLM_SDK_API VelocitySampling
	{
	public:

		GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation)

		class GLM_SDK_API Sample
		{
		public:
			Sample();

			Vector2 computeVelocity(const Vector2& desiredVelocity, float maximumVelocityDelta, float rotationCos, float rotationSin) const;

			float getPenalty() const;
			void setPenalty(float penalty);
			const Vector2& getNormalizedVelocityDelta() const;
			void setNormalizedVelocityDelta(const Vector2& normalizedVelocityDelta);

		private:
			Vector2 _normalizedVelocityDelta;
			float _penalty;
		};
	public:
		/** 
		* \brief Default constructor.
		*/
		VelocitySampling(glm::RandomNumberGenerator& rng) ;

		/** 
		* \brief Constructor from a configuration
		*/
		VelocitySampling(const VelocitySamplingConfiguration& configuration, glm::RandomNumberGenerator& rng);

		unsigned int getSampleCount() const;
		const Sample& getSample(unsigned int index) const;
		const VelocitySamplingConfiguration& getConfiguration() const;
		void setConfiguration(const VelocitySamplingConfiguration& configuration, glm::RandomNumberGenerator& rng);

	private:
		void buildTable(glm::RandomNumberGenerator& rng);

		VelocitySamplingConfiguration _configuration;

		glm::Array<Sample> _table;
	};

	//*****************************************************************************
	// VelocitySampling::Sample inline definitions.
	//*****************************************************************************

	//-----------------------------------------------------------------------------
	// getPenalty
	//-----------------------------------------------------------------------------
	inline float VelocitySampling::Sample::getPenalty() const
	{
		return _penalty;
	}

	//-----------------------------------------------------------------------------
	// setPenalty
	//-----------------------------------------------------------------------------
	inline void VelocitySampling::Sample::setPenalty(float penalty)
	{
		_penalty = penalty;
	}

	//-----------------------------------------------------------------------------
	// getNormalizedVelocityDelta
	//-----------------------------------------------------------------------------
	inline const Vector2& VelocitySampling::Sample::getNormalizedVelocityDelta() const
	{
		return _normalizedVelocityDelta;
	}

	//-----------------------------------------------------------------------------
	// setNormalizedVelocityDelta
	//-----------------------------------------------------------------------------
	inline void VelocitySampling::Sample::setNormalizedVelocityDelta(const Vector2& normalizedVelocityDelta)
	{
		_normalizedVelocityDelta = normalizedVelocityDelta;
	}

	//*****************************************************************************
	// VelocitySampling inline definitions.
	//*****************************************************************************

	//-----------------------------------------------------------------------------
	// getSampleCount
	//-----------------------------------------------------------------------------
	inline unsigned int VelocitySampling::getSampleCount() const
	{
		return static_cast<unsigned int>(_table.size());
	}

	//-----------------------------------------------------------------------------
	// getSample
	//-----------------------------------------------------------------------------
	inline const VelocitySampling::Sample& VelocitySampling::getSample(unsigned int index) const
	{
		GLM_DEBUG_ASSERT_MSG(index < _table.size(),"The index #%lu is not valid in this sampling table.", index);
		return _table[index];
	}

	//-----------------------------------------------------------------------------
	// getConfiguration
	//-----------------------------------------------------------------------------
	inline const VelocitySamplingConfiguration& VelocitySampling::getConfiguration() const
	{
		return _configuration;
	}

	//-----------------------------------------------------------------------------
	// setConfiguration
	//-----------------------------------------------------------------------------
	inline void VelocitySampling::setConfiguration(const VelocitySamplingConfiguration& configuration, glm::RandomNumberGenerator& rng)
	{
		if (_configuration != configuration)
		{
			_configuration = configuration;
			buildTable(rng);
		}
	}
}
