/****************************************************** possibile soluzione
 * alla  verifica   del  14   aprile  2000   mediante  l'utilizzo   di  una
 * rappresentazione concatenata  e allocazione  dinamica della  memoria, il
 * file in ingresso ha una sintassi  rigida e quindi la lettura e' agevole,
 * in generale NON e' cosi' per negli esami */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define D_LEN 51 /* massima lunghezza da testo
                  * e carattere fine stringa */
/* si e' scelto di usare una rappresentazione concatenata
 * con testa fasulla al fine di evitare l'utilizzo
 * di variabili globali */
struct nodo{
 char descrizione[D_LEN];
 long prezzo;
 int num_pezzi;
 struct nodo *prossimo;
};

/* prototipi funzioni */

void *Malloc(size_t); 
FILE *Fopen(const char *, const char *);
struct nodo *inizializza_lista(void);
struct nodo *leggi_dati(FILE*);
void inserisci_in_lista(struct nodo*, struct nodo*);
void stampa_lista_in_file(struct nodo*, FILE*);
void calcola_totale(struct nodo*, unsigned long int*);
void libera_lista(struct nodo *);


int main(int argc, char **argv){
 struct nodo *mialista, *nodotmp;
 FILE *archivio;
 unsigned long int totale;

 /* apro file in ingresso */
 archivio=Fopen("totali.txt","r");

 /* creo la lista, visto che devo ordinare opto
  * per una lista con testa fasulla e insertion
  * sort */
 mialista=inizializza_lista();

 /* leggo i dati e li metto in lista */
 while((nodotmp=leggi_dati(archivio))!=NULL)
  inserisci_in_lista(mialista, nodotmp);

 fclose(archivio);
 
 archivio=Fopen("ris.txt","w");

 /* stampo la lista, mi devo ricordare che il primo nodo
  * e' fasullo */
 stampa_lista_in_file(mialista->prossimo, archivio);

 /* ripercorro la lista e computo il totale */
 totale=0;
 calcola_totale(mialista->prossimo, &totale);

 fprintf(archivio, "\nTOTALE: %ld\n", totale);

 fclose(archivio);

 /* libero memoria */
 libera_lista(mialista);
 return 0;
}

/* creo la lista con un nodo iniziale fasullo
 * in cui non metto dati */
struct nodo *inizializza_lista(void){
 struct nodo *testa;
 testa=Malloc(sizeof(struct nodo));
 testa->prossimo=NULL;
 /* restituisco indirizzo*/
 return testa;
}

struct nodo *leggi_dati(FILE* a){
 struct nodo *tmp;
 int ris;

 tmp=Malloc(sizeof(struct nodo));
 tmp->prossimo=NULL;

 /* la sintassi del file e' rigida (negli esami non avviene mai)
  * e' comodo l'utilizzo di scanf e parenti */
 ris=fscanf(a, "%ld#%d#%[^\n]",&tmp->prezzo,&tmp->num_pezzi,tmp->descrizione);

 /* se non sono stati letti tre elementi o c'e'
  * un errore nel file o sono in fondo */
 if(ris<3){
  free(tmp);
  tmp=NULL;
 }

 return tmp;
}

void inserisci_in_lista(struct nodo* lista, struct nodo* nuovo){
 struct nodo *p;

 p=lista; /* primo nodo */
 /* cerco il punto di inserzione */
 while((p->prossimo!=NULL)&&(p->prossimo->prezzo<nuovo->prezzo))
  p=p->prossimo;
 
 /* inserisco */
 nuovo->prossimo=p->prossimo;
 p->prossimo=nuovo;
}

void stampa_lista_in_file(struct nodo* p, FILE* a){
 if(p==NULL)return; 
 stampa_lista_in_file(p->prossimo, a);
 fprintf(a, "%s\n", p->descrizione);
}

void calcola_totale(struct nodo* p, unsigned long int* t){
 if(p==NULL)return; 
 *t+=p->prezzo*p->num_pezzi;
 calcola_totale(p->prossimo, t);
}

void libera_lista(struct nodo *p){
 if(p==NULL)return; 
 libera_lista(p->prossimo);
 free(p);
}

/* funzioni 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;
}