/*=======================================================
  Esempio di gestione di una lista lineare.
  Il puntatore di testa verrà posizionato in una variabile
  di tipo NODO, il cui campo Info potrà essere usato per
  informazioni generali  sulla lista.
  I nodi necessari verranno allocati da memoria Heap.
 ----------------------------------------- 12.12.2005 -*/
#include <stdio.h>
#include <malloc.h>
#include <string.h>

#define LUNGINFO 60           // allineamento a 64 byte
//-----------------------------------------------------
typedef struct Nodo { char        Info[LUNGINFO];   
                      struct Nodo *Next;
                    } NODO;  
//-----------------------------------------------------

int  MenuUtente  ( void   );
void Inserimento ( NODO * );
void Estrazione  ( NODO * );
void Stampa      ( NODO * );
void LiberaLista ( NODO * );

//-----------------------------------------------------
int main (void)
{
  NODO  TestaLista;     // Puntatore di testa della lista
  int   Scelta;         // Operazione chiesta dall'utente;
                        // 0 per Exit
 
  strcpy (TestaLista.Info, "Archivio Clienti 2005");
  TestaLista.Next = NULL;
 
  do
  { Scelta = MenuUtente();
    switch ( Scelta )
    { 
      case 1: Inserimento ( &TestaLista );
              break;
      case 2: Estrazione  ( &TestaLista );
              break;
      case 3: Stampa      ( &TestaLista );
              break;
    }
  }
  while (Scelta);

  LiberaLista ( &TestaLista );
 
  return 0;
}


/*=====================================================
  Elenca tutte le scelte possibili all'utente e
  richiede la scelta di un'opzione.
 -----------------------------------------------------*/
int MenuUtente
( void
)
{ int Scelta;

  printf ("\n--------------------------------------\n");
  printf ("  [1] Inserimento nella lista           \n");
  printf ("  [2] Ricerca ed estrazione dalla lista \n");
  printf ("  [3] Visualizzazione della lista       \n \n");
  printf ("  [0] Chiusura del programma            \n   ");
 
  do Scelta = getc(stdin); while (Scelta<'0' || Scelta>'3');
 
  Scelta -= '0'; // trasforma carattere ASCII in intero

  return Scelta;
}

/*====================================================
  Inserimento ordinato di un nuovo elemento nella Lista.
  Il nodo necessario verrà allocato nella memoria Heap
  con malloc(). 
  Utilizza il valore definito in LUNGINFO per marcare
  con NULL la fine della stringa di informazione,
  nel caso l'utente l'abbia inserita più lunga.
  -----------------------------------------------------*/
void Inserimento
( NODO *Prec   // Puntatore al Nodo di Testa della lista
)
{ char Buffer[200];
  NODO *Succ,
       *Temp;
 
  printf ("\n--------------------------------------\n");
  Temp = (NODO *)malloc( sizeof(NODO) );

  if (Temp)
  { printf ("  Nome nuovo elemento ? ");
    scanf ("%s", Buffer);
    Buffer[LUNGINFO-1] = 0;  //NULL per sicurezza
    strcpy (Temp->Info, Buffer);

    // partendo dal primo elemento dopo il nodo di testa,
    // cerca il primo campo Info maggiore di Buffer.
    // Si ferma comunque in coda lista.
    Succ = Prec->Next;
    while ( Succ && strcmp (Succ->Info, Temp->Info) < 0 )
    { Prec = Succ;
      Succ = Prec->Next;
    } 
  
    Temp->Next = Succ;
    Prec->Next = Temp;
  }
  else
  { printf ("  Memoria Heap Insufficiente !\n");
  }
}

/*==================================================
  Ricerca ed estrazione di un elemento dalla Lista.
  Il nodo inutilizzato verrà rilasciato con free().
  Utilizza il valore definito in LUNGINFO per marcare
  con NULL la fine della stringa di informazione,
  nel caso l'utente l'abbia inserita più lunga.
 -------------------------------------------------*/
void Estrazione
( NODO *Prec  // Puntatore al Nodo di Testa della lista
)
{ char Buffer[200];
  NODO *Succ;
 
  printf ("\n--------------------------------------\n");
  printf ("  Nome elemento da eliminare ? ");
  scanf ("%s", Buffer);
  Buffer[LUNGINFO-1] = 0;  //NULL per sicurezza

  // partendo dal primo elemento dopo il nodo di testa,
  // cerca il campo Info uguale a Buffer.
  // Si ferma comunque in coda lista.
  Succ = Prec->Next;
  while ( Succ && strcmp (Succ->Info, Buffer) )
  { Prec = Succ;
    Succ = Prec->Next;
  }

  if (Succ) // elemento trovato: nodo da eliminare
  { Prec->Next = Succ->Next;
    free (Succ);
  }
  else // elemento NON presente nella lista
  { printf ("  Elemento NON presente in lista.\n");
  }
}

/*========================================================
  Visualizzazione completa dell Lista
 --------------------------------------------------------*/
void Stampa
( NODO *Punt       // Puntatore al Nodo di Testa della lista
)
{ printf ("\n--------------------------------------\n");
  printf ("  %s\n\n", Punt->Info );
 
  while ( Punt->Next)
  { Punt = Punt->Next;
    printf ("  %s\n", Punt->Info );
  }
}

/*==========================================================
  Rilascia tutti i nodi eventalmenta presenti nella Lista
  con free(). Azzera il campo Next nel puntatore di testa.
 ---------------------------------------------------------*/
void LiberaLista
( NODO *Prec   // Puntatore al Nodo di Testa della lista
)
{ NODO *Succ;

  Succ = Prec->Next;

  // sgancia il puntatore di testa dalla lista
  Prec->Next = NULL;

  while ( Succ )
  { Prec = Succ;
    Succ = Prec->Next;
    free ( Prec );
  }
}