#ifndef PILHA_INT_H 
#define PILHA_INT_H

/** Representa pilhas de inteiros.
    @invariant 0 <= numero_de_itens <= capacidade and 0 < capacidade. */
class PilhaInt { 
  public: 
    /** Sinónimo de int, serve para simplificar a definição de pilhas de itens
	com tipos diferentes. */
    typedef int Item;
    
    /// Representa condições de memória esgotada.
    class MemoriaEsgotada;


    // Construtores:

    /// Construtor por omissão.  Constrói pilha vazia.
    PilhaInt(); 

    /// Construtor por cópia.  Constrói "clone" de pilha já existente.
    PilhaInt(PilhaInt const& outra_pilha);
    
    /// Destrutor.
    ~PilhaInt(); 
    

    /** @brief Operador de atribuição por cópia.  

        Dada uma pilha (operando esquerdo) torna-a igual à pilha que lhe é
        fornecida como modelo.  Ou seja, faz uma "operação plástica" à
        pilha. 

        Tal como no caso do construtor por cópia, também a versão da
        atribuição por cópia fornecida pelo C++ dá resultados desastrosos,
	fazendo com que a pilha perca partes (a matriz dinâmica) e fique a
	partilhar partes com o modelo.  Digamos que as duas instâncias
	envolvidas são tornadas siamesas pelo cirurgião plástico...  Daí a
	necessidade de fornecer explicitamente este operador. */
    PilhaInt& operator = (PilhaInt const& outra_pilha);
    

    // Inspectores:

    /// Devolve altura da pilha, ou seja, o seu número de itens.
    int altura() const;

    /// Devolve booleano indicando se a pilha está vazia.
    bool estaVazia() const; 

    /// Devolve booleano indicando se a pilha está cheia.
    bool estaCheia() const; 

    /** @brief Devolve item no topo da pilha sem permitir alterá-lo.
	@pre ¬estaVazia(). */
    Item const& topo() const; 
    

    // Modificadores:

    /** @brief Devolve item no topo da pilha permitindo alterá-lo.
	@pre ¬estaVazia(). */
    Item& topo();

    /** @brief Põe novo item no topo da pilha.
	@pre ¬estaCheia(). */
    void poe(Item const& novo_item); 

    /** @brief Tira item do topo da pilha.
	@pre ¬estaVazia(). */
    void tira(); 
    
private: 
    // Qualquer pilha terá esta capacidade inicial:
    static int const capacidade_inicial = 32;

    // A capacidade da pilha em cada instante.  Não é uma capacidade
    // definitiva, pois pode ser aumentada se houver necessidade e se houver
    // memória livre disponível.
    int capacidade; 

    // Ponteiro para o primeiro elemento da matriz dinâmica que guarda os
    // itens da pilha:
    Item* itens; 

    // Guarda o número de itens na pilha.  A matriz dinâmica dos itens está
    // dividida em dois trocos disjuntos.  Os primeiros numero_de_itens
    // elementos guardam itens da pilha.  Os restantes contêm lixo.
    int numero_de_itens; 

    // Devolve booleano indicando se o invariante da classe se cumpre:
    bool cumpreInvariante() const;
};

/// Representa erros de excesso de memória associados à classe PilhaInt.
class PilhaInt::MemoriaEsgotada {
public:
    /// Construtor.  Recebe a dimensão pretendida para a matriz dinâmica.
    MemoriaEsgotada(int dimensao_pretentida);

    /// Inspector da dimensão pretendida para a matriz dinâmica.
    int dimensaoPretendida();

private:
    int dimensao_pretendida; 
}; 

#include "pilha_int_impl.H"

#endif // PILHA_INT_H