/* File: assicura.c */
/* Time-stamp: "2002-06-06 14:22:34 calvanes" */
/* Scopo: soluzione esercizio 1 compito esame di Fondamenti di Informatica del
          14/10/2000 */

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


/* ******* SOLUZIONE PUNTO 1 ******* */

typedef int bool;
#define TRUE 1
#define FALSE 0

#define LUNGTARGA 7
#define MERITOMAX 20
#define LUNGNOME  20

typedef char TipoTarga[LUNGTARGA + 1];
typedef char TipoNome[LUNGNOME + 1];

typedef char TipoData[9];          /* formato: GGMMAAAA */
typedef char TipoResponsabilita;   /* valori ammessi: 'S' o 'N' */


struct nodoLista {
  TipoTarga targa;
  int num_incidenti;
  struct nodoLista *next;
};
typedef struct nodoLista NodoLista;
typedef NodoLista *TipoLista;


/* ******* SOLUZIONE PUNTO 2 ******* */

/* ALGORITMO costruisci una lista con il numero di incidenti per ogni targa,
             leggendo le informazioni da un file di incidenti
     inizializza la lista alla lista vuota
     APRI il file in lettura
     WHILE il file non e` finito
     DO leggi dal file i dati per un incidente (targa, data, responsabilita)
        IF la responsabilita` e` 'S'
        THEN cerca la targa nella lista
             IF la targa compare
             THEN incrementa di 1 il numero di incidenti associato
             ELSE aggiungi un nuovo elemento in testa alla lista con numero di
                  incidenti pari ad 1
     chiudi il file
     restituisci il puntatore alla lista costruita
*/

TipoLista CercaTarga(char *t, TipoLista lis)
  /* Cerca il veicolo con targa t in lis e restituisce il puntatore
     all'elemento trovato, se questo esiste, NULL altrimenti.
     Usata al punto 2 per verificare se una targa e` gia` presente nella lista,
        ed al punto 3 per trovare il numero di incidenti. */
{
  TipoLista ris = NULL;
  bool trovato = FALSE;

  while (lis != NULL && !trovato)
    if (strcmp(lis->targa, t) == 0) {
      trovato = TRUE;
      ris = lis;
    }
    else
      lis = lis->next;

  return ris;
}  /* CercaTarga */


TipoLista ContaIncidenti(char *nomefile)
  /* In base alle informazioni contenute nel file di nome nomefile,
     costruisce una lista di coppie <t,n>, dove t e` la targa di un autoveicolo
     nel file, ed n e` il numero di incidenti di cui l'autoveicolo e` stato
     responsabile. */
{
  FILE *finc;
  TipoTarga targa;
  TipoData data;
  TipoResponsabilita resp;
  TipoLista lis_incidenti = NULL, punt;

  if ((finc = fopen(nomefile, "r")) == NULL) {
    printf("Errore in apertura in lettura di %s\n", nomefile);
    return NULL;
  }

  /* lettura degli incidenti e aggiornamento della lista */

  fscanf(finc, "%7s %8s %c", targa, data, &resp);
  while (!feof(finc)) {
    if (resp == 'S') {
      punt = CercaTarga(targa, lis_incidenti);
      if (punt == NULL) {   /* inserisci un nuovo record in testa alla lista */
        punt = malloc(sizeof(NodoLista));
        strcpy(punt->targa, targa);
        punt->num_incidenti = 1;
        punt->next = lis_incidenti;
        lis_incidenti = punt;
      } else         /* aggiorna il numero di incidenti associato alla targa */
        punt->num_incidenti++;
    }
    fscanf(finc, "%7s %8s %c", targa, data, &resp);
  }

  fclose(finc);
  return lis_incidenti;
}  /* ContaIncidenti */


/* ******* SOLUZIONE PUNTO 3 ******* */

/* ALGORITMO crea un file di polizze aggiornando le classi di merito in base
             alle informazioni contenute in una lista di incidenti
     apri il file di polizze in lettura
     apri un nuovo file di polizze in scrittura
     WHILE il file di polizze non e` finito
     DO leggi i dati relativi ad un polizza dal file (targa, classe, cognome)
        cerca la targa nella lista di incidenti
        IF la targa non e` presente
        THEN il numero di incidenti e` zero
        ELSE estrai il numero di incidenti dall'elemento della lista
        aggiorna la classe di merito in base al numero di incidenti
        scrivi sul nuovo file di polizze i dati aggiornati
     chiudi il file di polizze
     chiudi il nuovo file di polizze
*/

void AggiornaClasse(int *classe, int ninc)
  /* Aggiorna la classe di merito in base al numero di incidenti. */
{
  if (ninc == 0) {
    if (*classe > 0)
      (*classe)--;
  } else
    if (*classe + ninc * 2 > MERITOMAX)
      *classe = MERITOMAX;
    else
      *classe += ninc * 2;
}  /* AggiornaClasse */


void AggiornaPolizze(char *nomefile, TipoLista lis_incidenti)
{
  FILE *fpolizze, *fappoggio;
  TipoTarga targa;
  int classe;
  TipoNome nome;
  TipoLista punt;
  int ninc;

  /* apertura del file di polizze e di un file di appoggio su cui scrivere le
     polizze aggiornate */

  if ((fpolizze = fopen(nomefile, "r")) == NULL) {
    printf("Errore in apertura in lettura di %s\n", nomefile);
    return;
  }

  if ((fappoggio = fopen("appoggio.dat", "w")) == NULL) {
    printf("Errore in apertura in scritture di %s\n", nomefile);
    return;
  }

  /* lettura delle polizze, aggiornamento e scrittura sul file di appoggio */
  fscanf(fpolizze, "%7s %d %20s", targa, &classe, nome);
  while (!feof(fpolizze)) {
    punt = CercaTarga(targa, lis_incidenti);
    if (punt == NULL)
      ninc = 0;
    else
      ninc = punt->num_incidenti;
    AggiornaClasse(&classe, ninc);
    fprintf(fappoggio, "%s %2d %s\n", targa, classe, nome);
    fscanf(fpolizze, "%7s %d %20s", targa, &classe, nome);
  }

  fclose(fpolizze);
  fclose(fappoggio);

  /* rinomina il file di polizze in modo da non perderlo;
     non richiesto nella specifica */
  rename(nomefile, "polizze-orig.dat");

  /* rinomina il file di appoggio */
  rename("appoggio.dat", nomefile);
}  /* AggiornaPolizze */

/* ******* PARTE NON RICHIESTA DAL TESTO ******* */

void CancellaLista(TipoLista *lis)
  /* Pone lis uguale alla lista vuota e rende disponibile la memoria occupata.
     Versione iterativa. */
{
  TipoLista paux;

  while (*lis != NULL) {
    paux = *lis;
    *lis = (*lis)->next;
    free(paux);
  }
}  /* CancellaLista */


int main(void)
{
  char nome_file_incidenti[256], nome_file_polizze[256];
  TipoLista lis;

  printf("Immetti il nome di un file di incidenti: ");
  scanf("%256s", nome_file_incidenti);
  printf("Immetti il nome di un file di polizze: ");
  scanf("%256s", nome_file_polizze);
  lis = ContaIncidenti(nome_file_incidenti);
  AggiornaPolizze(nome_file_polizze, lis);
  CancellaLista(&lis);

  return 0;
}  /* Assicurazione */