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

#include <assert.h>
/*
 * L'inclusione del file assert.h consente di utilizzare una caratteristica relativamente
 * nuova dell'ANSI C, vale a dire le "asserzioni". Per assicurare che in dato punto
 * di un programma sia verificata una proprietÓ (ad esempio, un puntatore p diverso
 * da NULL) basta inserire in quel punto la  chiamata (macro ANSI)
 * assert(<proprietÓ>) (ad esempio, assert(p != NULL)). Se la proprietÓ Ŕ soddisfatta
 * allora l'elaborazione continua normalmente; se invece essa viene violata il 
 * programma si interrompe e viene genarato un opportuno messaggio di errore che
 * segnala la situazione anomala.
 */

#define L 14      /* lunghezza titoli: 13 caratteri + terminatore '\0' */
#define MAX 30    /* max lunghezza nome file */
#define MAXIST 20 /* max lunghezza nome istituto */

typedef char tipotitolo[L];
typedef char tiponomefile[MAX];
typedef char *tiponomeistituto;

typedef int tipodenaro;

struct compenso {
    tiponomeistituto nomeistituto;
    tipodenaro importodovuto;
};

typedef struct compenso tipocompenso;

struct arraycompensi {
    tipocompenso *compensi;
    int dimarray;
};

typedef struct arraycompensi tipoarraycompensi;

void LeggiRiga(FILE *f, tipotitolo tit);
tipodenaro CalcolaImporto(tiponomefile prev, tiponomefile class);
unsigned long int ContaRighe(FILE *f);
tipoarraycompensi CalcolaCompensi(tiponomefile ricev, tiponomefile class);
void Dealloca(tipoarraycompensi *arraycompensi);
int main(void);



void LeggiRiga(FILE *f, tipotitolo tit)
{
    tipodenaro somma;
    assert(fscanf(f, "%13s%d ", tit, &somma) == 2);
    return;
}

tipodenaro CalcolaImporto(tiponomefile prev, tiponomefile class)
{
    FILE *fprev, *fclass;
    tipotitolo titoloprevisione, titoloclassifica;
    tipodenaro importo = 0;
    int i;
    
    fprev = fopen (prev, "r");
    assert(fprev != NULL);
    
    fclass = fopen (class, "r");
    assert(fclass != NULL);
    
    for(i=0; i < 10; i++) {
        LeggiRiga(fprev,titoloprevisione);
        LeggiRiga(fclass,titoloclassifica);
        if(strcmp(titoloprevisione, titoloclassifica) == 0)
            importo += 1000;
    }
    
    fclose(fprev);
    fclose(fclass);
    
    return importo;
}


unsigned long int ContaRighe(FILE *f)
{
    unsigned long int nrighe = 0;
    int  c, /* ultimo carattere letto */ 
        cc; /* penultimo carattere letto */
    
    rewind(f); /* inutile! */
    cc = EOF;
    c = fgetc(f);
    while(!feof(f)) {
        if(c == '\n')
            nrighe++;
        cc = c;
        c = fgetc(f);
    }
    
    if(cc != '\n') /* se il file non termina con '\n' l'ultima riga Ŕ incompleta
                      ma la contiamo lo stesso */
        nrighe++;
    
    rewind(f);
    return nrighe;
}


tipoarraycompensi CalcolaCompensi(tiponomefile ricev, tiponomefile class)
/* si assume che nel file ricev ogni istituto compaia al pi¨ una volta */
{
    tipoarraycompensi ac;
    FILE *fricev;
    tiponomefile prev;
    int i, n;
    
    char nomeistitutotemp[MAXIST];
    
    fricev = fopen (ricev, "r");
    assert(fricev != NULL);
    
    n = ContaRighe(fricev); /* la funzione riposiziona correttamente la posizione
                               di lettura all'inizio del file */
    
    ac.dimarray = n;
    ac.compensi = malloc(n * sizeof(tipocompenso));
    assert(ac.compensi != NULL);
    
    for(i=0; i<n; i++) {
        fscanf(fricev, "%s %s ", prev, nomeistitutotemp);
        (ac.compensi)[i].importodovuto=CalcolaImporto(prev, class);
        (ac.compensi)[i].nomeistituto = malloc(strlen(nomeistitutotemp) + 1);
        assert((ac.compensi)[i].nomeistituto != NULL);
        strcpy((ac.compensi)[i].nomeistituto, nomeistitutotemp);
    }
    
    fclose(fricev);
    return ac;
}

void Dealloca(tipoarraycompensi *arraycompensi)
{
    int i;
    for(i=0; i<arraycompensi->dimarray; i++)
        free((arraycompensi->compensi)[i].nomeistituto);
    free(arraycompensi->compensi);
    
    arraycompensi->dimarray = 0;
    arraycompensi->compensi = NULL;
    return;
}


int main(void)
{
    tiponomefile prev, class, ricev;
    tipodenaro importo;
    tipoarraycompensi arraycompensi;
    int i;
    
    
    puts("Inserisci nome file con previsioni: ");
    gets(prev);
    
    puts("Inserisci nome file con classifica: ");
    gets(class);
    
    importo = CalcolaImporto(prev, class);
    
    printf("L'importo dovuto Ŕ pari a $%d.\n", importo);
    
    puts("Inserisci nome file con elenco di nomi file: ");
    gets(ricev);
    
    arraycompensi = CalcolaCompensi(ricev, class);
    
    printf("Elenco compensi dovuti:\n");
    for(i=0; i<arraycompensi.dimarray; i++)
    /*
     * %-18s visualizza una stringa usando almeno 18 caratteri (riempiendo
     * lo spazio eventualmente in eccedenza con spazi bianchi).
     * Il simbolo '-' serve ad allineare la stringa a sinistra.
     */
        printf("%-18s%6d\n", (arraycompensi.compensi)[i].nomeistituto, 
                            (arraycompensi.compensi)[i].importodovuto); 
    printf("Termine elenco.\n");
    
    printf("Inizio deallocamento... ");
    Dealloca(&arraycompensi);
    printf("fatto. Premi INVIO.\n");
    getchar();
    
    return 0;
}