#pragma once

#include <iostream>
#include <cstddef>
#include <stdexcept>
#include "doubly_linked_list.h"

template <typename T>   
class Stack {
   private:
      DoublyLinkedList<T> m_data;

   public:
      Stack()
      : m_data() {}

      Stack(const Stack& stack)
      : m_data(stack.items()) {}

      ~Stack() {
         m_data.clear();
      }

      Stack& operator=(const Stack& rhs) {
         if (&rhs == this)
            return *this;

         m_data = rhs.items();
         return *this;
      }

      void push(const T& item) {
         m_data.push_back(item);
      }

      void pop() {
         if (m_data.size() == 0)
            throw std::out_of_range("stack is empty");

         m_data.remove(m_data.size() - 1);
      }
      
      T& top() {
         if (m_data.size() == 0)
            throw std::out_of_range("stack is empty");

         return m_data[m_data.size() - 1];
      }

      const DoublyLinkedList<T>& items() const {
         return m_data;
      }

      std::size_t size() const {
         return m_data.size();
      }

      void stack_print() const {
         m_data.print();
      }
};