#ifndef CORE_STACK_HPP
#define CORE_STACK_HPP

#include "core/data/ArrayList.hpp"
#include "core/data/List.hpp"
#include "core/utils/Error.hpp"

namespace Core {
    namespace Internal {
        template<typename T, typename S>
        class BaseStack final {
            S data{};

        public:
            template<typename... Args>
            BaseStack& push(Args&&... args) {
                data.add(Core::forward<Args>(args)...);
                return *this;
            }

            void clear() {
                data.clear();
            }

            void pop() {
                assert(data.getLength() > 0);
                data.removeBySwap(data.getLength() - 1);
            }

            bool isEmpty() const {
                return data.getLength() == 0;
            }

            T& peek() {
                assert(data.getLength() > 0);
                return data[data.getLength() - 1];
            }

            const T& peek() const {
                assert(data.getLength() > 0);
                return data[data.getLength() - 1];
            }

            void toString(BufferString& s) const {
                s.append(data);
            }
        };
    }

    template<typename T>
    using ListStack = Internal::BaseStack<T, List<T>>;

    template<typename T, size_t N>
    using ArrayStack = Internal::BaseStack<T, ArrayList<T, N>>;
}

#endif