// =====================================================================================================================
//  fennec, a free and open source game engine
//  Copyright © 2025  Medusa Slockbower
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================

#ifndef FENNEC_CONTAINERS_TUPLE_H
#define FENNEC_CONTAINERS_TUPLE_H

#include <fennec/containers/detail/_tuple.h>
#include <fennec/lang/type_sequences.h>

namespace fennec
{

// TODO: Document

///
/// \brief Tuple, holds a collection of values of different types
/// \tparam TypesT The types to store
template<typename...TypesT> struct tuple;


template<size_t i, typename...TypesT>
constexpr typename tuple<TypesT...>::template elem_t<i>& get(tuple<TypesT...>& x) {
	using elem_t = typename tuple<TypesT...>::template elem_t<i>;
	auto& it = *static_cast<detail::_tuple_leaf<i, elem_t>*>(&x);
	return it.value;
}

template<size_t i, typename...TypesT>
constexpr const typename tuple<TypesT...>::template elem_t<i>& get(const tuple<TypesT...>& x) {
	using elem_t = typename tuple<TypesT...>::template elem_t<i>;
	const auto& it = *static_cast<const detail::_tuple_leaf<i, elem_t>*>(&x);
	return it.value;
}


template<typename ...TypesT>
struct tuple : public detail::_tuple<make_index_sequence_t<sizeof...(TypesT)>, TypesT...>
{
	using base_t = detail::_tuple<make_index_sequence_t<sizeof...(TypesT)>, TypesT...>;

	template<size_t i>
	using elem_t = typename nth_element<i, TypesT...>::type;

	template<typename...ArgsT>
    tuple(ArgsT&&...args)
		: base_t(fennec::forward<ArgsT>(args)...) {
    }

	tuple(const tuple& cpy)
		: base_t(cpy) {
	}

	tuple(tuple&& cpy)
		: base_t(cpy) {
	}
};

// This is needed for
template<typename...TypesT>
tuple(TypesT...) -> tuple<TypesT...>;

}

#endif // FENNEC_CONTAINERS_TUPLE_H
