/* Possibile soluzione al compito del 20 settembre 1999 per coloro che dovevano sostenere 
 * l'esame di FONDAMENTI DI INFORMATICA 2 
 * 
 * ATTENZIONE: dato che questo programma e' stato sviluppato a fini didattici
 * risulta eccessivamente pieno di commenti. NON prendetelo ad esempio dal
 * punto di vista dei commenti!!! */

#include<stdio.h>
#include<stdlib.h> /* molti di voi si dimenticano di includere stdlib
                    * che pero' e' necessaria per le funzioni di 
                    * allocazione dinamica della memoria !! */

/* definizione struttura dati per il nodo dell'albero binario */

struct elemento{
	int codice;
	int giacenza;
	int valid; 
	struct elemento *maggiori;
	struct elemento *minori;
} *mytree;

struct elemento *mylist=NULL;

/* prototipi delle funzioni */
void *Malloc(size_t); 
FILE *Fopen(const char *, const char *);
void inserisci_in_albero(struct elemento);
void libera_albero(struct elemento*);
void visita_albero(FILE *,struct elemento*);
struct elemento *trova_punto_di_inserzione(struct elemento *, int);
struct elemento *ricerca_in_albero(struct elemento *, int);


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

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

FILE *dati;
struct elemento elemento_tmp; /* struttura temporanea per dati in lettura */
struct elemento *p; /* puntatore al nodo ricercato */


/* prima fase: leggo il file e man mano inserisco gli elementi
 * nella lista */
dati=Fopen("giacenze.dat","r");
while(!feof(dati)){
  fscanf(dati, "%d;%d\n", &elemento_tmp.codice,&elemento_tmp.giacenza);
  /* ora posso inserire nella lista */
  inserisci_in_albero(elemento_tmp);
 }
fclose(dati);

/* seconda fase: leggo il secondo file e aggiorno l'albero */
dati=Fopen("ordini.dat","r");
while(!feof(dati)){
  fscanf(dati, "%d;%d\n", &elemento_tmp.codice,&elemento_tmp.giacenza);
  /* ricerco il nodo che contiene il dato con lo stesso codice */
  p=ricerca_in_albero(mytree, elemento_tmp.codice);
  /* aggiorno il dato giacenza */
  p->giacenza-=elemento_tmp.giacenza;
 }
fclose(dati);

/* terza fase: aggiorno il primo file */
dati=Fopen("giacenze.dat","w");
/* visito l'albero (la modalita' non importa) */
visita_albero(dati, mytree);
fclose(dati);

/* la liberazione della memoria 
 * e' banale usando una funzione ricorsiva */
libera_albero(mytree);

return 0;
}

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

void libera_albero(struct elemento *o){
	if(!o)return;
	libera_albero(o->maggiori);
	libera_albero(o->minori);
	free(o);
}


/*************************************************************************/
void visita_albero(FILE *scrivo, struct elemento *o){
	if(!o)return;
	fprintf(scrivo,"%d;%d\n",o->codice,o->giacenza);
	visita_albero(scrivo, o->maggiori);
	visita_albero(scrivo, o->minori);
}



/*************************************************************************/
/* ricerca nell'albero l'elemento di codice a. Sfrutto la ricorsione */
struct elemento *ricerca_in_albero(struct elemento *p, int a){
	
	/* suppongo che NON ci siano errori nei file !!! 
	 * chiaramente e' un'ipotesi critica ! */
	
	if(p->codice==a)return p;

	if(p->codice>a)return ricerca_in_albero(p->minori,a);
	else return ricerca_in_albero(p->maggiori,a);
}

/*************************************************************************/
/* inserisce un elemento in un albero binario di ricerca. Il testo non lo
 * dice ma e' evidente che l'albero sara' ordinato usando il codice */

void inserisci_in_albero(struct elemento nuovo){
	struct elemento *p; /* punto di inserzione */
	
	if(mytree==NULL){ /* e' il primo elemento */
		p=mytree=Malloc(sizeof(struct elemento));
	}else{ /* dovro' trovare dove inserire */
		p=trova_punto_di_inserzione(mytree, nuovo.codice);
		if(p->codice>nuovo.codice){
			p->minori=Malloc(sizeof(struct elemento));
			p=p->minori;
		}else{
			p->maggiori=Malloc(sizeof(struct elemento));
			p=p->maggiori;
		}
	}
	/* a questo punto comunque sia p e' il nodo da usare: copio i dati */
	p->maggiori=NULL;
	p->minori=NULL;
	p->codice=nuovo.codice;
	p->giacenza=nuovo.giacenza;
}

/*************************************************************************/
/* restituisce il nodo sotto cui inserire un elemento di chiave a */
struct elemento *trova_punto_di_inserzione(struct elemento *p, int a){
	if(p->codice>a){
		if(p->minori)return trova_punto_di_inserzione(p->minori,a);
		else return p;
	}
	/* suppongo non ci siano errori nei file e quindi e' chiaro
	 * che a questo punto p->codice<a */
	if(p->maggiori)return trova_punto_di_inserzione(p->maggiori,a);
	else return p;

}

/*************************************************************************/
/* da qui in poi sono semplici funzioni di utilita' gia' viste a lezione */
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;
}