#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

// Struttura atomica del Nodo della Pila
typedef struct Nodo {
  int dato;
  struct Nodo *prossimo;
} Nodo;

// Definizione del tipo Pila come sinonimo di puntatore a Nodo
typedef Nodo *Pila;

// Crea una pila vuota
Pila crea_pila() { return NULL; }

// Controllo stato della pila
bool is_empty_pila(Pila p) { return p == NULL; }

// Operazione PUSH (Inserimento in testa - Tempo Istantaneo)
Pila push(Pila p, int valore) {
  Nodo *nuovo = (Nodo *)malloc(sizeof(Nodo));
  if (nuovo == NULL) {
    fprintf(stderr, "Errore: Memoria esaurita durante l'operazione di push!\n");
    exit(1);
  }
  nuovo->dato = valore;
  nuovo->prossimo = p; // Il nuovo nodo si appoggia sulla vecchia cima
  return nuovo;        // La nuova cima della pila diventa il nuovo nodo
}

// Operazione POP (Rimozione dalla testa con aggiornamento del puntatore - Tempo
// Istantaneo)
bool pop(Pila *p, int *valore_estratto) {
  if (is_empty_pila(*p)) {
    return false; // Underflow
  }

  Nodo *da_eliminare = *p;
  *valore_estratto = da_eliminare->dato;

  *p = (*p)->prossimo; // Sposta la testa di controllo al livello inferiore
  free(da_eliminare);  // Dealloca il frame della pila

  return true;
}

// Operazione PEEK (Ispezione del valore in cima senza rimozione - Tempo
// Istantaneo)
bool peek(Pila p, int *valore_cima) {
  if (is_empty_pila(p)) {
    return false;
  }
  *valore_cima = p->dato;
  return true;
}

// Libera tutta la memoria della pila per prevenire i leak
void libera_pila(Pila p) {
  Nodo *corrente = p;
  while (corrente != NULL) {
    Nodo *succ = corrente->prossimo;
    free(corrente);
    corrente = succ;
  }
}

// Programma di Test
int main(void) {
  Pila mia_pila = crea_pila();

  printf("--- TEST OPERAZIONE PUSH ---\n");
  printf("Inserisco (push) in ordine: 10, 20, 30\n");
  mia_pila = push(mia_pila, 10);
  mia_pila = push(mia_pila, 20);
  mia_pila = push(mia_pila, 30);

  printf("\n--- TEST OPERAZIONE PEEK ---\n");
  int cima;
  if (peek(mia_pila, &cima)) {
    printf("L'elemento attualmente in cima e': %d (Atteso: 30)\n", cima);
  }

  printf("\n--- TEST OPERAZIONE POP (LOGICA LIFO) ---\n");
  int estratto;
  while (pop(&mia_pila, &estratto)) {
    printf("Estratto (pop): %d\n", estratto);
  }
  // L'output deve mostrare l'inversione fisica: 30, poi 20, infine 10.

  if (is_empty_pila(mia_pila)) {
    printf("\nLa pila e' ora vuota con successo!\n");
  }

  // Cleanup protettivo
  libera_pila(mia_pila);
  return 0;
}