/* ATTENZIONE:  questo programma  NON riesco  a testarlo!  (La ragione  per
 * chiunque abbia  seguito le lezioni  e' ovvia). Quindi prendetelo  con le
 * molle */

/* Possibile soluzione al compito del 31 gennaio 2000 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 !! */
#include<string.h>



/* dichiarazione struttura dati base (come da testo) */

struct dipendente {
	char nome[20];
	char codice_qualifica[3];
	int stipendio; /* e' chiaro che NON e' portabile */
};

/* non conoscendo a priori il numero di codici qualifica
 * la soluzione piu' pulita per memorizzare il tutto e' una
 * lista allocata dinamicamente, a seguire la sua dichiarazione: */

struct stipendi{
	char codice_qualifica[3];
	long stipendio_totale;
	int numero_dipendenti;
	struct stipendi *next;
} *mylist;
	
/* prototipi delle funzioni */
void inserisci_in_lista(struct dipendente);
void libera_lista(struct stipendi*);
void *Malloc(size_t);
FILE *Fopen(const char *, const char *);


int main(int argc, char **argv){
	
	FILE *dati;
	struct dipendente dato_in_lettura;
	struct stipendi *p; 
	size_t num;
	
	dati=Fopen("dip.dat","r+b");
	
	/* la lista ora e' vuota, non necessariamente il puntatore
	 * al primo elemento sara' NULL, e' quindi opportuno inizializzarlo*/
	mylist=NULL;

	/* ciclo di lettura file e inserimento dati in lista */
	while(!feof(dati)){
		/* leggo un singolo valore */
		num=fread(&dato_in_lettura, sizeof(struct dipendente), 1, dati);
		/* questo e' solo un test di correttezza se l'if
		 * si verifica probabilmente il file in ingresso e' sbagliato */
		if(num!=1) break;
		fprintf(stderr, "%s - %c%c%c - %d\n",dato_in_lettura.nome,dato_in_lettura.codice_qualifica[0],
		    dato_in_lettura.codice_qualifica[1],dato_in_lettura.codice_qualifica[2],
		    dato_in_lettura.stipendio);
                inserisci_in_lista(dato_in_lettura);
	}
	fclose(dati);

	/* ciclo di scrittura dati elaborati, il programma non
	 * specificava il tipo di file, per semplicita' lo facciamo
	 * ASCII */

	dati=Fopen("qual.dat","w+b");
	for(p=mylist;p->next;p=p->next){
		/* KLUDGE */
		fprintf(dati,"codice: %c%c%c numero dipendenti: %d totale emolumenti: %ld\n",
				p->codice_qualifica[0],p->codice_qualifica[1],p->codice_qualifica[2],
				p->numero_dipendenti,
				p->stipendio_totale);
	}
	fclose(dati);



 /* non  necessario  e non  richiesto  dal  compito,  ma io  valuto  sempre
  * positivamente il fatto che si  liberi la memoria allocata dinamicamente
  * prima di uscire dal programma (e comunque e' banale farlo)*/
	libera_lista(mylist);

	return 0;
}


/*************************************************************************/
/*           permette l'inserimento nella lista dei codici               
 * nota: era piu' efficiente il passaggio di un puntatore invece che di
 * una struttura per intero */

void inserisci_in_lista(struct dipendente nuovo){

        /* controllo che la lista sia gia' stata inizializzata
         * nel caso la inizializzo oppure aggiungo semplicemente
         * l'elemento */
        if(mylist==NULL){
                mylist=Malloc(sizeof(struct dipendente));
		/* inizializzo semplicemente i valori e torno */
                mylist->next=NULL;
                memcpy(mylist->codice_qualifica,nuovo.codice_qualifica,3);
		mylist->stipendio_totale=nuovo.stipendio;
		mylist->numero_dipendenti=1;
		return;
        }else{
                struct stipendi *p; /* mi serve per scorrere la lista */
                p=mylist;
                /* ciclo fino a che uno degli elementi contiene lo stesso codice o
                 * fino alla fine della lista */
                while((!strncmp(p->codice_qualifica,nuovo.codice_qualifica,3))||(p->next!=NULL))p=p->next;
		if(!p->next){
			/* sono arrivato alla fine della lista:
			 * stesse operazioni del caso precedente */
                	p->next=Malloc(sizeof(struct stipendi));
			p=p->next;
                	p->next=NULL;
         	       memcpy(p->codice_qualifica,nuovo.codice_qualifica,3);
			p->stipendio_totale=nuovo.stipendio;
			p->numero_dipendenti=1;
			return;
		}
		/* ho trovato un elemento della lista con lo stesso
		 * codice dipendente, non mi serve aggiungere altro,
		 * aggiorno semplicemente i dati */
		p->stipendio_totale+=nuovo.stipendio;
		++p->numero_dipendenti;
        }
	return;
}

void libera_lista(struct stipendi *p){
	if(p->next)libera_lista(p->next);
	free(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;
}