#pragma once

#include <memory>

namespace gelib_impl
{

	template <const size_t N>
	class Indexed
	{
	protected:
		std::unique_ptr<std::array<int, N>> m_indices;

	public:

		Indexed(std::array<int, N>& indices);

		Indexed* set_index(size_t at, int val);

		int operator[](size_t index)
		{
			return (*this)[index];
		}

		virtual std::array<int, N>& get_indices() const;

		void reorder(std::array<size_t, N> const& order);

		Indexed();

	};

	template <const size_t N>
	Indexed<N>::Indexed()
	{
		m_indices = std::move(std::make_unique<std::array<int, N>>(std::array<int, N>()));
	}

	template <const size_t N>
	Indexed<N>::Indexed(std::array<int, N>& indices)
	{
		std::array<int, N> new_indices;
		std::copy(indices.begin(), indices.end(), new_indices.begin());
		m_indices = std::move(std::make_unique<std::array<int, N>>(new_indices));

	}

	template <const size_t N>
	Indexed<N>* Indexed<N>::set_index(size_t at, int val)
	{
		(*m_indices)[at] = val;
		return this;
	}

	template <const size_t N>
	std::array<int, N>& Indexed<N>::get_indices() const
	{
		return *m_indices;
	}

	template<size_t N>
	void Indexed<N>::reorder(std::array<size_t, N> const& order)
	{
		std::array<int, N> new_indices;
		for (size_t i = 0; i < N; ++i)
			new_indices[i] = (*m_indices)[order[i]];
		std::copy(new_indices.begin(), new_indices.end(), m_indices->begin());
	}

}