/* possibile soluzione alla verifica del 31.5.2000 */

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

/* lunghezza codice ISBN 10 caratteri +1 di fine stringa*/
#define LISBN 10+1
#define LBUFF 100

/* nodo dell'albero binario di ricerca */
struct nodo{
  char isbn[LISBN];
  char *titolo;
  unsigned char scaffale;
  struct nodo *maggiori, *minori;
};

/* prototipi funzioni */
void *Malloc(size_t); 
FILE *Fopen(const char *, const char *);
void *Realloc(void *, size_t);
struct nodo *leggi_riga(FILE *);
struct nodo *inserisci_in_albero(struct nodo *, struct nodo *);
struct nodo *ricerca_libro(struct nodo *, char *);


int main(int argc, char **argv){

 /* un puntatore per dati temporanei e uno per
  * la radice dell'albero */
 struct nodo *tmp;
 struct nodo *albero_libri=NULL;
 /* file handler per lettura */
 FILE *dati;
 /* codice ISBN da ricercare */
 char code[LISBN];
 /* puntatore a dati libri ricercati */
 struct nodo *p;
	
 /* PRIMA PARTE: leggo e interpreto libri.txt */
 dati=Fopen("libri.txt","r");
 while(1){

  /* chiamo una funzione che legge una  riga del file spezzandola in codice
   * ISBN, titolo e scaffale. Questa  funzione ritorna NULL qualora siamo a
   * fondo file in questo caso esco dal ciclo */
  tmp=leggi_riga(dati);
  if(!tmp)break;

  /* inserisco i dati nell'albero binario */
  albero_libri=inserisci_in_albero(albero_libri, tmp);
 }

 /* SECONDA PARTE: iterativamente chiedo un codice ISBN
  * e cerco e stampo lo scaffale relativo */
 while(1){
  printf("Inserisci un codice ISBN: ");
  fgets(code, LISBN+1, stdin);

  /* elimino l'invio */
  code[LISBN-1]='\0';
  printf("Sto ricercando %s\n", code);
  p=ricerca_libro(albero_libri, code);
  if(!p)
   printf("Libro non presente !\n");
  else
   printf("Libro ``%s'' presente nello scaffale %d\n", p->titolo, (int)p->scaffale);
 }
 return EXIT_SUCCESS;
}

/* questa funzione legge codice ISBN, titolo e scaffale dal file passato se
 * non riesce a leggere ritorna NULL */
struct nodo *leggi_riga(FILE *a){
 struct nodo *letto;
 int nb,np;
 char c;
 char *t;

 /* alloco struttura per dati */
 letto=Malloc(sizeof(struct nodo));

 /* provo a leggere dal file il codice*/
 /* nb=fscanf(a, "%[^&]\n",letto->isbn);*/
 t=fgets(letto->isbn,LISBN,a);

 /* se e' riuscito a leggere il codice t deve puntare
  * a letto->isbn altrimenti e' NULL */
 if(!t){
  free(letto);
  return NULL;
 }

 /* inizio a leggere il titolo con
  * una lettura bufferizzata */
 nb=1;
 np=0;
 letto->titolo=Malloc(LBUFF*sizeof(char));
 getc(a); /* ignoro ``&'' */
 c=(char)getc(a);
 /* leggo carattere a carattere fino 
  * fino alla prossima '&' */
 while(c!='&'){
  letto->titolo[np++]=c;
  if(np==LBUFF)
   letto->titolo=Realloc(letto->titolo,LBUFF*sizeof(char)*++nb);
  c=(char)getc(a);
 }

 /* termino la stringa che contiene il titolo */
 letto->titolo[np]='\0';

 /* leggo il codice scaffale, inizialmente lo metto in nb */
 fscanf(a,"%d\n",&nb);
 letto->scaffale=(unsigned char)nb;
 return letto;
}


/* questa funzione inserisce  i dati in un albero binario  e restituisce la
 * radice, il codice ISBN e' usato come chiave */

struct nodo *inserisci_in_albero(struct nodo *tree, struct nodo *new){
 int confronto;

 /* se l'albero non esiste il primo nodo e'
  * sicuramente la radice */
 if(!tree)return new;

 /* confronto i codici per capire come
  * spostarmi lungo i rami */
 confronto=strcmp(tree->isbn,new->isbn);

 /* se confronto e' nullo ho una chiave duplicata ! */
 if(!confronto){
  fprintf(stderr, "Errore chiave duplicata!\n");
  exit(EXIT_FAILURE);
 }

 /* se confronto  e' <  0 allora la  chiave del nuovo  nodo e'  maggiore di
  * quella del nodo con cui lo stiamo confrontando:
  *
  * se esiste il sottoalbero richiamo ricorsivamente la funzione altrimenti 
  * inserisco direttamente */

 if(confronto<0){
  if(tree->maggiori)
   tree->maggiori=inserisci_in_albero(tree->maggiori, new);
  else{
   tree->maggiori=new;
  }
 }else{
  if(tree->minori)
   tree->minori=inserisci_in_albero(tree->minori, new);
  else{
   tree->minori=new;
  }
 }

 return tree;
}

/* questa procedura ricerca nell'albero binario il libro
 * tramite il codice ISBN
 * e ne restituisce l'indirizzo in memoria
 * se non la trova rende NULL */
struct nodo *ricerca_libro(struct nodo *a, char *c){
 int confronto;

 /* se il sottoalbero di ricerca non esiste ritorno
  * NULL */
 if(!a)return NULL;

 /* utilizzo strcmp per confrontare chiave del nodo
  * e chiave che sto cercando */
 confronto=strcmp(a->isbn,c);

 /* a seconda del risultato ho trovato la chiave o
  * devo continuare la ricerca */
 if(!confronto) return a;
 if(confronto<0) return ricerca_libro(a->maggiori, c);
 return ricerca_libro(a->minori, c);
}

/* solite procedure utilizzate durante il corso */

void *Malloc(size_t size)
{
 void *genericp;
 if((genericp=malloc(size))==NULL)
  {
   perror("Malloc");
   exit(1);
  }
  return genericp;
}

/*************************************************************************/

FILE *Fopen(const char *nome, const char *modo)
{
FILE *tmp;

 if((tmp=fopen(nome, modo))==NULL)
  {
   fprintf(stderr, "Non riesco ad aprire il file %s in maniera %s\n",nome, modo);
   perror("Fopen");
   exit(1);
  }
 return tmp;
}

/*************************************************************************/

void *Realloc(void *ptr, size_t size)
{
 void *genericp;
 if((genericp=realloc(ptr, size))==NULL)
  {
   perror("Realloc");
   exit(1);
  }
  return genericp;
}