#pragma once

#include <psemek/random/uniform_sphere.hpp>
#include <psemek/random/uniform_real.hpp>

namespace psemek::random
{

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

		uniform_ball_vector_distribution(T r = T{1})
			: sphere_d_{r}
		{}

		uniform_ball_vector_distribution(uniform_ball_vector_distribution const &) = default;

		template <typename RNG>
		auto operator()(RNG && rng)
		{
			result_type v = sphere_d_(rng);
			auto r = uniform_real_distribution<T>{}(rng);
			return v * std::pow(r, T{1} / N);
		}

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

	private:
		uniform_sphere_vector_distribution<T, N> sphere_d_;
	};

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

		uniform_ball_point_distribution(result_type origin, T r = T{1})
			: origin_{origin}
			, vector_d_{r}
		{}

		uniform_ball_point_distribution(uniform_ball_point_distribution const &) = default;

		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_ball_vector_distribution<T, N> vector_d_;
	};

}
