/* ATTENZIONE richiede util.c e util.h */
#include<stdio.h>
#include<stdlib.h>
#include"util.h"

#define MAX_MAT 52
#define MAX_FILE 13
#define MAX_VOTO 31

struct esame{
int voto;
char materia[MAX_MAT];
struct esame *prossimo;
struct esame *precedente;
};


int main(int argc, char **argv)
{
FILE *mystream;
char miofile[MAX_FILE];
struct esame *tmp;
struct esame *lista_esami;
char votochar[3];
int numchars;

/* prototipi */
void add_lista_in_ordine(struct esame*, struct esame **);
void stampa_lista(struct esame*);
void calcola_e_stampa_media(struct esame*);
void libera_lista(struct esame*);

for(;;) /* itero */
 {
  /* chiedo un nome di file e continuo finche' non riesco
   * ad aprirlo */
  printf("Inserire il nome del file: ");
  gets(miofile); /* operazione potenzialmente pericolosa */
  if((mystream=fopen(miofile,"r"))==NULL)
   {
    printf("Attenzione: non è possibile aprire il file %s!\n",miofile);
    continue;
   }
  lista_esami=NULL;
  while(!feof(mystream))
   {
    /* alloco un puntatore temporeaneo che serve per contenere i
     * dati via via che sono letti */
    tmp=Malloc(sizeof(struct esame));
    tmp->prossimo=tmp->precedente=NULL;
    /* leggo la materia ed esco se non esiste */
    numchars=fscanf(mystream,"%[^\n]\n",tmp->materia);
    if(!numchars)break;
    /* creo la stringa che contiene il voto letto 
       e' un modo chiaro anche se poco efficiente */
    votochar[0]=fgetc(mystream);
    votochar[1]=fgetc(mystream);
    votochar[2]='\0'; /*questo andrebbe fuori dal ciclo*/
    fgetc(mystream);
    tmp->voto=atoi(votochar);
    add_lista_in_ordine(tmp, &lista_esami);
   }
  /* elimino il nodo fasullo */
  free(tmp);
  tmp=lista_esami->prossimo;
  free(lista_esami);
  lista_esami=tmp;
  lista_esami->precedente=NULL;
  /* ora la lista e' a posto */
  stampa_lista(lista_esami);
  calcola_e_stampa_media(lista_esami);
  libera_lista(lista_esami);
 }
return 0;
}

void stampa_lista(struct esame *jj){
	for(;jj;jj=jj->prossimo)
		printf("Materia: %s, voto: %d\n",jj->materia,jj->voto);
}

void calcola_e_stampa_media(struct esame *jj){
	int somma=0, num_esami=0;

	for(;jj->prossimo->prossimo->prossimo;jj=jj->prossimo);
	for(;jj;jj=jj->precedente){
		somma+=jj->voto;
		++num_esami;
	}
	printf("Media %2.2f\n", ((float)somma)/num_esami);
}

void add_lista_in_ordine(struct esame *nuovo, struct esame **mylist){
	struct esame *count, *ii;

	/* se la lista e' vuota la creo, inserisco un nodo
	 * di testa che contiene dati non validi e metto
	 * nuovo come secondo elemento */
	if (*mylist==NULL){
		*mylist=Malloc(sizeof(struct esame));
		(*mylist)->voto=MAX_VOTO+1;
		(*mylist)->prossimo=nuovo;
		(*mylist)->precedente=NULL;
		return;
	}
	/* scorro la lista per determinare dove
	 * inserire nuovo */
	ii=count=*mylist;
	while(count&&(count->voto>nuovo->voto)){
		ii=count;
		count=count->prossimo;
	}
	/* il trucco della testa fasulla
	 * permette di ridursi a due casi */
	nuovo->precedente=ii;
	if(ii->prossimo!=NULL){
		ii->prossimo->precedente=nuovo;
	        nuovo->prossimo=ii->prossimo;
	}
	ii->prossimo=nuovo;
}
	
void libera_lista(struct esame *nodo){
	if(nodo==NULL)return;
	libera_lista(nodo->prossimo);
	free(nodo);
}