// =====================================================================================================================
//  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/containers/array.h
/// \brief A header containing the definition for a static/stack allocated array
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///


#ifndef FENNEC_CONTAINERS_ARRAY_H
#define FENNEC_CONTAINERS_ARRAY_H

#include <fennec/lang/types.h>
#include <fennec/lang/assert.h>
#include <fennec/lang/metasequences.h>

namespace fennec
{

///
///
/// \brief Data Structure that defines a compile-time allocated array
///
/// \details
/// | Property    | Value       |
/// |:-----------:|:-----------:|
/// | stable      |      ✅     |
/// | dynamic     |      ⛔     |
/// | homogeneous |      ✅     |
/// | distinct    |      ⛔     |
/// | ordered     |      ⛔     |
/// | linear      |      ✅     |
/// | space       | \emph{O(N)} |
/// | access      | \emph{O(1)} |
/// | find        | \emph{O(N)} |
/// | insertion   |      ⛔     |
/// | deletion    |      ⛔     |
///
/// \tparam ValueT value type
/// \tparam N number of elements
template<typename ValueT, size_t N>
struct array {

// Definitions =========================================================================================================
public:

	/// \name Definitions
	/// @{

	using value_t = ValueT; //!< Alias for \emph{ValueT}

	/// @}



// Public Member Variables =============================================================================================
public:

	/// \name Member Variables
	/// @{

	value_t data[N]; //!< Backing c-style array handle

	/// @}



// Properties ==========================================================================================================
public:

	/// \name Properties
	/// @{

	///
	/// \brief Returns the number of elements in the array.
	/// \returns \emph{N}
	///
	/// \par Complexity
	/// \emph{O(1)}
	///
	constexpr size_t size() const { return N; }

	///
	/// \brief Returns \emph{true} when the array is empty
	/// \returns \math{\textbf{ElemV} == 0}
	///
	/// \par Complexity
	/// \emph{O(1)}
	///
	constexpr bool_t is_empty() const { return N == 0; }

	/// @}



// Access ==============================================================================================================
public:

	/// \name Element Access
	/// @{

	///
	/// \details Returns a reference to the element at \c i
	/// \param i index of the element to return
	/// \return reference to the requested element
	///
	/// \par Complexity
	/// \emph{O(1)}
	///
	constexpr value_t& operator[](size_t i) {
		assertd(i < N, "Array Out of Bounds");
		return data[i];
	}

	///
	/// \brief Indexed access
	/// \details Returns a reference to the element at \c i
	/// \param i index of the element to return
	/// \return reference to the requested element
	///
	/// \par Complexity
	/// \emph{O(1)}
	///
	constexpr const value_t& operator[](size_t i) const {
		assertd(i < N, "Array Out of Bounds");
		return data[i];
	}

	///
	/// \returns A reference to \math{\textbf{data}[0]}
	///
	/// \par Complexity
	/// \emph{O(1)}
	///
	constexpr value_t& front() {
		return data[0];
	}

	///
	/// \brief Access the first element
	/// \returns A const-qualified reference to \math{\textbf{data}[0]}
	///
	/// \par Complexity
	/// \emph{O(1)}
	///
	constexpr const value_t& front() const {
		return data[0];
	}

	///
	/// \returns A reference to \math{\textbf{data}[\textbf{N} - 1]}
	///
	/// \par Complexity
	/// \emph{O(1)}
	///
	constexpr value_t& back() {
		return data[N - 1];
	}

	///
	/// \brief Access the last element
	/// \returns A const-qualified reference to \math{\textbf{data}[\textbf{N} - 1]}
	///
	/// \par Complexity
	/// \emph{O(1)}
	///
	constexpr const value_t& back() const {
		return data[N - 1];
	}

	/// @}



// Comparison ==========================================================================================================
public:

	/// \name Comparison Operators
	/// @{

	///
	/// \brief Checks if all elements in the arrays are equal
	///
	/// \par Complexity
	/// \emph{O(N)}
	///
	friend constexpr bool_t operator==(const array& lhs, const array& rhs) {
		return array::_compare(lhs, rhs, make_index_metasequence<N>{});
	}

	///
	/// \brief Checks if any element in the arrays is not equal
	///
	/// \par Complexity
	/// \emph{O(N)}
	///
	friend constexpr bool_t operator!=(const array& lhs, const array& rhs) {
		return not array::_compare(lhs, rhs, make_index_metasequence<N>{});
	}

	/// @}


// Iteration ===========================================================================================================
public:

	/// \name Iteration
	/// @{

	///
	/// \returns A pointer to the first element of the array
	///
	/// \par Complexity
	/// \emph{O(1)}
	///
	constexpr value_t* begin() {
		return data;
	}

	///
	/// \brief C++ Iterator Specification \emph{begin()}
	/// \returns A const-qualified pointer to the first element of the array
	///
	/// \par Complexity
	/// \emph{O(1)}
	///
	constexpr const value_t* begin() const {
		return data;
	}

	///
	/// \returns A pointer to one after the end of the array
	///
	/// \par Complexity
	/// \emph{O(1)}
	///
	constexpr value_t* end() {
		return data + N;
	}

	///
	/// \brief C++ Iterator Specification \emph{end()}
	/// \returns A const-qualified pointer to one after the end of the array
	///
	/// \par Complexity
	/// \emph{O(1)}
	///
	constexpr const value_t* end() const {
		return data + N;
	}

	/// @}


// Private Helpers =====================================================================================================
private:
	template<size_t...i>
	static bool _compare(const array& lhs, const array& rhs, index_metasequence<i...>) {
		return ((lhs[i] == rhs[i]) and ...);
	}
};

}

#endif // FENNEC_CONTAINERS_ARRAY_H
