#pragma once

#include <psemek/random/uniform_sphere.hpp>

namespace psemek::random
{

	template <typename T, std::size_t N>
	struct uniform_hemisphere_vector_distribution
	{
		using result_type = math::vector<T, N>;

		uniform_hemisphere_vector_distribution(math::vector<T, N> const & n, T r = T{1})
			: d_{r}
			, n_{n}
		{}

		uniform_hemisphere_vector_distribution(uniform_hemisphere_vector_distribution const &) = default;

		template <typename RNG>
		auto operator()(RNG && rng)
		{
			result_type v = d_(rng);
			if (dot(v, n_) < 0)
				v = -v;
			return v;
		}

		T radius() const { return d_.radius(); }

	private:
		uniform_sphere_vector_distribution<T, N> d_;
		math::vector<T, N> n_;
	};

	template <typename T, std::size_t N>
	struct uniform_hemisphere_point_distribution
	{
		using result_type = math::point<T, N>;

		uniform_hemisphere_point_distribution(result_type origin, math::vector<T, N> const & n, T r = T{1})
			: origin_{origin}
			, vector_d_{n, r}
		{}

		template <typename RNG>
		auto operator()(RNG && rng)
		{
			return origin_ + vector_d_(rng);
		}

		result_type origin() const { return origin_; }

		T radius() const { return vector_d_.radius(); }

	private:
		result_type origin_;
		uniform_hemisphere_vector_distribution<T, N> vector_d_;
	};

}
