#pragma once

#include <psemek/math/affine_transform.hpp>

namespace psemek::math
{

	template <typename T, std::size_t N>
	struct translation
	{
		vector<T, N> v;

		translation();
		translation(vector<T, N> const & v);
		translation(translation const &) = default;

		matrix<T, N, N + 1> affine_matrix() const;
		matrix<T, N, N> linear_matrix() const;
		vector<T, N> translation_vector() const;
		matrix<T, N + 1, N + 1> homogeneous_matrix() const;

		affine_transform<T, N, N> transform() const;

		vector<T, N> operator()(vector<T, N> const & v) const;
		point<T, N> operator()(point<T, N> const & p) const;
	};

	template <typename T, std::size_t N>
	translation(vector<T, N>) -> translation<T, N>;

	template <typename T, std::size_t N>
	translation<T, N>::translation()
		: v{vector<T, N>::zero()}
	{}

	template <typename T, std::size_t N>
	translation<T, N>::translation(vector<T, N> const & v)
		: v{v}
	{}

	template <typename T, std::size_t N>
	matrix<T, N, N + 1> translation<T, N>::affine_matrix() const
	{
		auto result = matrix<T, N, N + 1>::identity();
		for (std::size_t i = 0; i < N; ++i)
			result[i][N] = v[i];
		return result;
	}

	template <typename T, std::size_t N>
	matrix<T, N, N> translation<T, N>::linear_matrix() const
	{
		return matrix<T, N, N>::identity();
	}

	template <typename T, std::size_t N>
	vector<T, N> translation<T, N>::translation_vector() const
	{
		return v;
	}

	template <typename T, std::size_t N>
	matrix<T, N + 1, N + 1> translation<T, N>::homogeneous_matrix() const
	{
		auto result = matrix<T, N + 1, N + 1>::identity();
		for (std::size_t i = 0; i < N; ++i)
			result[i][N] = v[i];
		return result;
	}

	template <typename T, std::size_t N>
	affine_transform<T, N, N> translation<T, N>::transform() const
	{
		return {affine_matrix()};
	}

	template <typename T, std::size_t N>
	vector<T, N> translation<T, N>::operator()(vector<T, N> const & v) const
	{
		return v;
	}

	template <typename T, std::size_t N>
	point<T, N> translation<T, N>::operator()(point<T, N> const & p) const
	{
		return p + v;
	}

	template <typename T, std::size_t N>
	translation<T, N> inverse(translation<T, N> const & t)
	{
		return {-t.v};
	}

}
