// =====================================================================================================================
//  fennec, a free and open source game engine
//  Copyright © 2025 - 2026  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/>.
// =====================================================================================================================

///
/// \file fennec/lang/ranges.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///

#ifndef FENNEC_LANG_RANGES_H
#define FENNEC_LANG_RANGES_H

#include <fennec/lang/types.h>
#include <fennec/lang/type_traits.h>

namespace fennec
{

///
/// \brief C++ Iterator Specification \emph{begin()}
/// \tparam ContainerT the container type
/// \param c the container to iterate on
/// \returns an iterator at the start of the container
template<typename ContainerT>
inline constexpr auto begin(ContainerT& c) noexcept(noexcept(c.begin())) -> decltype(c.begin()) {
	return c.begin();
}

///
/// \brief C++ Iterator Specification \emph{begin()}
/// \tparam ContainerT the container type
/// \param c the container to iterate on
/// \returns an iterator at the start of the container
template<typename ContainerT>
inline constexpr auto begin(const ContainerT& c) noexcept(noexcept(c.begin())) -> decltype(c.begin()) {
	return c.begin();
}

///
/// \brief C++ Iterator Specification \emph{begin()}
/// \tparam T the element type
/// \tparam N the bounds of the array
/// \param arr a bounded array to iterate on
/// \returns an iterator at the start of the array
template<typename T, size_t N>
inline constexpr T* begin(T (&arr)[N]) noexcept {
	return arr;
}


///
/// \brief C++ Iterator Specification \emph{end()}
/// \tparam ContainerT the container type
/// \param c the container to iterate on
/// \returns an iterator at the end of the container
template<typename ContainerT>
inline constexpr auto end(ContainerT& c) noexcept(noexcept(c.end())) -> decltype(c.end()) {
	return c.end();
}

///
/// \brief C++ Iterator Specification \emph{end()}
/// \tparam ContainerT the container type
/// \param c the container to iterate on
/// \returns an iterator at the end of the container
template<typename ContainerT>
inline constexpr auto end(const ContainerT& c) noexcept(noexcept(c.end())) -> decltype(c.end()) {
	return c.end();
}

///
/// \brief C++ Iterator Specification \emph{end()}
/// \tparam T the element type
/// \tparam N the bounds of the array
/// \param arr a bounded array to iterate on
/// \returns an iterator at the end of the array
template<typename T, size_t N>
inline constexpr T* end(T (&arr)[N]) noexcept {
	return arr + N;
}

///
/// \brief Range for array types.
/// \tparam TypeT The base type.
///
/// \note Operates on the range \emph{[first, last)}.
template<typename TypeT>
struct range {
	TypeT* first; //!< The first element
	TypeT* last;  //!< The last element

	///
	/// \brief C++ Iterator Specification \emph{begin()}
	/// \returns A pointer to the start of the array
	TypeT* begin() const {
		return first;
	}

	///
	/// \brief C++ Iterator Specification \emph{end()}
	/// \returns A pointer to the start of the array
	TypeT* end() const {
		return last;
	}
};

///
/// \brief Range for iterators.
/// \tparam IteratorT The iterator type.
///
/// \note Operates on the range \emph{[first, last)}.
template<typename IteratorT> requires(is_iterable_v<IteratorT>)
struct range<IteratorT> {
	IteratorT first; //!< The first element
	IteratorT last;  //!< The last element

	///
	/// \brief C++ Iterator Specification \emph{begin()}
	/// \returns A pointer to the start of the array
	IteratorT& begin() const {
		return first;
	}

	///
	/// \brief C++ Iterator Specification \emph{end()}
	/// \returns A pointer to the start of the array
	IteratorT& end() const {
		return last;
	}
};


///
/// \brief Proxy Struct for fulfilling the C++ 11 Iterator Specification
template<typename ScalarT>
struct counter {
	ScalarT val; //!< The held value

	///
	/// \brief Pre-Increment
	/// \returns A reference to \emph{this} after incrementing \emph{val}.
	counter& operator++() {
		++val;
		return *this;
	}

	///
	/// \brief Post-Increment
	/// \returns A counter with the previously held value.
	counter operator++(int) {
		++val;
		return { val - 1 };
	}

	///
	/// \brief Equality Operator
	/// \param ctr The counter to compare with
	/// \returns \math{{val}_{this} = {val}_{ctr}}
	bool operator==(const counter& ctr) const {
		return val == ctr.val;
	}

	///
	/// \brief Equality Operator
	/// \param ctr The counter to compare with
	/// \returns \math{{val}_{this} \neq {val}_{ctr}}
	bool operator!=(const counter& ctr) const {
		return val != ctr.val;
	}

	///
	/// \brief Dereference Operator
	/// \returns \emph{val}
	ScalarT operator*() const {
		return val;
	}
};


///
/// \brief Range for scalar types.
/// \tparam ScalarT The scalar type.
///
/// \note Operates on the range \emph{[first, last)}.
template<typename ScalarT> requires(is_scalar_v<ScalarT>)
struct range<ScalarT> {
	ScalarT first; //!< The starting value
	ScalarT last;  //!< The last value

	///
	/// \brief C++ Iterator Specification \emph{begin()}
	/// \returns A `fennec::counter` containing \emph{first}
	counter<ScalarT> begin() const {
		return { first };
	}

	///
	/// \brief C++ Iterator Specification \emph{begin()}
	/// \returns A `fennec::counter` containing \emph{last}
	counter<ScalarT> end() const {
		return { last };
	}
};

}

#endif // FENNEC_LANG_RANGES_H