//PROBLEMA N. 6: BANCA DATI STUDENTI
//Assegnato a: BACCIU MARIA GIOVANNA
//SCRIVERE UN PROGRAMMA PER GESTIRE I DATI RELATIVI AGLI STUDENTI DEL CORSO DI
//LAUREA IN INFORMATICA. PER CIASCUN STUDENTE I DATI SONO: nome, cognome, numero
//di matricola, data di nascita, anno di immatricolazione, esami sostenuti
//(con voto e data), e anno di corso(I,II,III).
//DEVE ESSERE POSSIBILE AVERE I DATI STAMPATI O VISUALIZZATI IN RIFERIMENTO
//AD UNO STUDENTE, AD UN CORSO, AD UN ANNO, AD UN ESAME SOSTENUTO.
////////////////////////////////////////////////////////////////////////////////
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_NOME_ES 40
#define MAX_NOME_STUD 50
#define MAX_ESAMI 29
#define MAX_STUD 20
#include <time.h>
typedef enum{false,true} bool;
typedef struct data{
    int giorno;
    int mese;
    int anno;
}data;
typedef struct esami
{
    char nomeEs[MAX_NOME_ES];
    int voto;
    data dataEsame;
}tipo_esami;
typedef struct student
{
    char nome[MAX_NOME_STUD];
    char cognome[MAX_NOME_STUD];
    int matricola;
    data data_nascita;
    data dataEsame;
    int anno_immatricolazione;
    int num_esami;
    tipo_esami esame[MAX_ESAMI];
    int annoCorso;
}studente;
//procedura per memorizzare l'array studente su file binario
void write_on_file(studente tmp[],int n)
{
    int i; FILE *fp;
    if (n!=0)
    {
        //tenta di aprire in scrittura il file N_studenti.txt
        if((fp=fopen("N_studenti.txt","wb"))!=NULL)
        {
            //se l'apertura riesce, scrive su file il valore di n (che corrisponde a count, che indica quanti studenti sono salvati)
            fprintf(fp,"%d",n);
            fclose(fp);
            //chiude il file N_studenti.txt e tenta l'apertura in scrittura del file binario STUDENTS.dat
            if((fp=fopen("STUDENTS.dat","wb"))!=NULL)
            {
                //la fwrite scrive l'intero array di studenti sul file binario, ma non scrive gli esami sostenuti.
                fwrite(tmp,sizeof(studente),n,fp);
                fclose(fp);
                //chiude fp ed apre in scrittura il file binario EXAMS.dat per ovviare al problema di cui sopra
                if((fp=fopen("EXAMS.dat","wb"))!=NULL)
                {
                    for(i=0; i<n; i++)
                        //scorre l'array di studenti e per ognuno di essi scrive su file binario il singolo array di esami sostenuti.
                        fwrite(tmp[i].esame, sizeof(tipo_esami),tmp[i].num_esami,fp);
                    fclose(fp);//chiude il puntatore al file
                }
                else
                {
                    //controllo sull'apertura del file EXAMS.dat: se fallisce allora termina forzatamente il programma
                    printf("Errore nella scrittura dei dati degli esami.\n");
                    exit(EXIT_FAILURE);
                }
            }
            else
            {
                //controllo sull'apertura del file STUDENTS.dat: se fallisce allora termina forzatamente il programma
                printf("Errore nella scrittura dei dati degli studenti.\n");
                exit(EXIT_FAILURE);
            }
        }
        else
            //controllo sull'apertura del file N_studenti.txt: se fallisce non salva su file
            printf("Errore: impossibile memorizzare i dati. \n");
    }
}
void read_from_file(studente tmp[], int *n)
{
    int i;
    FILE *fp;
    //tenta di aprire in lettura il file N_studenti.txt per sapere quanti studenti dovrà caricare nell'array
    if((fp=fopen("N_studenti.txt","rb"))!=NULL)
    {
        fscanf(fp,"%d",n);
        fclose(fp);
        //chiude il puntatore e apre in lettura il file STUDENTS.dat
        if((fp=fopen("STUDENTS.dat","rb"))!=NULL)
        {
            //conoscendo quanti studenti deve caricare(n) la fwrite preleva i valori dal file e li carica nel buffer di record
            fread(tmp,sizeof(studente),*n,fp);
            fclose(fp);
            //ora tenta di aprire il file EXAMS.dat per caricare gli esami dei singoli studenti, con un procedimento analogo
            //a quella utilizzata dalla procedura write_on_file(), solo utilizzando la fread per la lettura
            if((fp=fopen("EXAMS.dat","rb"))!=NULL)
            {
                for(i=0; i<*n; i++)
                    fread(tmp[i].esame, sizeof(tipo_esami),tmp[i].num_esami,fp);
                fclose(fp);
            }
            //controllo sull'apertura di EXAMS.dat: se fallisce termina forzatamente il programma
            else
            {
                printf("Errore nella lettura dei dati degli esami.\n");
                exit(EXIT_FAILURE);
            }
        }
        //controllo sull'apertura di STUDENTS.dat: se fallisce termina forzatamente il programma
        else
        {
            printf("Errore nella lettura dei dati degli studenti.\n");
            exit(EXIT_FAILURE);
        }
    }
    //controllo sull'apertura di N_studenti.txt: se fallisce avvia il programma senza caricare gli studenti.
    else
        printf("Nessun salvataggio presente. \n");
}
void inserisci_studente(studente tmp[],data datanascita, int count, data dataEsame)
{
    int i;
    system("cls");                      //per pulire lo schermo
    printf("\n==== Inserimento dati anagrafici degli studenti =========");
    printf("\n=========================================================\n");
    // inserimento matricola
    printf("\n\n\tInserire i dati del %d studente: ", count+1);
    printf("\nMatricola.........: ");
    scanf("%d",&tmp[count].matricola);
    fflush(stdin);
    // inserimento nome
    printf("\nNome..............: ");
    scanf("%s",&tmp[count].nome);
    fflush(stdin);
    // inserimento cognome
    printf("\nCognome...........: ");
    scanf("%s",&tmp[count].cognome);
    //inserimento data di nascita
    printf("\nData di nascita...: ");
    printf("\nInserisci il giorno: ");
    scanf("%d", &tmp[count].data_nascita.giorno);
    printf("Inserisci il mese: ");
    scanf("%d", &tmp[count].data_nascita.mese);
    printf("Inserisci il anno: ");
    scanf("%d", &tmp[count].data_nascita.anno);
    //inserimento data di immatricolazione
    printf("\nAnno di immatricolazione...: ");
    scanf("%d", &tmp[count].anno_immatricolazione);
    //inserimento esami sostenuti
    printf("Quanti esami hai sostenuto?: ");
    scanf("%d", &tmp[count].num_esami);
    for(i=0;i<tmp[count].num_esami;i++)
    {
        printf("Esame: ");
        scanf("%s",&tmp[count].esame[i].nomeEs);
        fflush(stdin);
        do{
            printf("Voto: ");
            scanf("%d", &tmp[count].esame[i].voto);
        }while(!((tmp[count].esame[i].voto>17) && (tmp[count].esame[i].voto<31 )));
        printf("\nData esame sostenuto...: ");
        printf("\nInserisci il giorno (GG): ");
        scanf("%d", &tmp[count].esame[i].dataEsame.giorno);
        printf("Inserisci il mese (MM): ");
        scanf("%d", &tmp[count].esame[i].dataEsame.mese);
        printf("Inserisci l'anno (AAAA): ");
        scanf("%d", &tmp[count].esame[i].dataEsame.anno);
    }
    ////inserimento anno di corso
    do{
        printf("\nInserisci l'anno di corso... \n(Digita 1 per il I, 2 per il II, e 3 per il III: \n");
        scanf("%d", &tmp[count].annoCorso);
    }while((tmp[count].annoCorso<1)||(tmp[count].annoCorso)>3);
}
void visualizza_studenti( studente tmp[],data datanascita, int count,  data dataEsame)
{
    int i,j;
    system("cls");
    printf("\n===== Visualizzazione dati anagrafici degli studenti =====\n");
    printf("==========================================================\n");
    printf(" Matricola:     Cognome:      Nome:         DataNascita:     Anno Immatricolazione:   Corso:");
    printf("\n=========================================================\n");
    for (i=0; i<count; i++)
    {
        printf(" %5d          ",tmp[i].matricola);
        printf("%13s ",&tmp[i].cognome);
        printf("%13s ",&tmp[i].nome);
        printf("%2d/%2d/%4d       ",tmp[i].data_nascita.giorno,tmp[i].data_nascita.mese,tmp[i].data_nascita.anno);
        printf("%4d                      ", tmp[i].anno_immatricolazione);
        printf("%d", tmp[i].annoCorso);
        printf(" \n\tEsami sostenuti:");
    for(j=0;j<tmp[i].num_esami;j++)
    {
        printf("\n  %s",&tmp[i].esame[j].nomeEs);
        printf("\t%d",tmp[i].esame[j].voto);
        printf("\t%2d-%2d-%4d",tmp[i].esame[j].dataEsame.giorno,tmp[i].esame[j].dataEsame.mese,tmp[i].esame[j].dataEsame.anno);
        printf("\n");
    }
}
printf("\n\n***Stampa completata!***\n\n");
}
void ricerca_studente(studente tmp[],data datanascita, int count,  data dataEsame)
{
    int i,j, matr;
    bool trovato;
    trovato = false;
    printf("\nInserisci la matricola dello studente: ");
    scanf("%d", &matr);
    fflush(stdin);
    for (i=0; i<count && trovato == false; i++)
        if (matr == tmp[i].matricola)
            trovato = true;
    if (trovato == true)
    {
        printf("\n=========================================================\n");
        printf("         INFORMAZIONI SULLO STUDENTE RICERCATO: \n");
        printf("\n=========================================================\n");
        printf("MATRICOLA: %d\n", tmp[i-1].matricola);
        printf("NOME: %s\n", tmp[i-1].nome);
        printf("COGNOME: %s\n", tmp[i-1].cognome);
        printf("     %2d-%2d-%4d",tmp[i-1].data_nascita.giorno,tmp[i-1].data_nascita.mese,tmp[i-1].data_nascita.anno);
        printf("       %4d", tmp[i-1].anno_immatricolazione);
        printf("   %d", tmp[i-1].annoCorso);
        printf(" \n\tEsami sostenuti:");
        printf("\n=========================================================\n");
        for(j=0;j<tmp[i-1].num_esami;j++)
        {
            printf("\n  %s",&tmp[i-1].esame[j].nomeEs);
            printf("\t%d",tmp[i-1].esame[j].voto);
            printf("\t%2d-%2d-%4d",tmp[i-1].esame[j].dataEsame.giorno,tmp[i-1].esame[j].dataEsame.mese,tmp[i-1].esame[j].dataEsame.anno);
            printf("\n");
        }
        printf("\n=========================================================\n");
    }
    else printf("informazioni non presenti in archivio\n");
}
void ricerca_corso(studente tmp[],data datanascita, int count,  data dataEsame)
{
    int i=0,j,cnt=0, anno;
    bool trovato;
    trovato = false;
    printf("\nInserisci l'anno di corso: ");
    scanf("%d", &anno);
    printf("\n=========================================================\n");
    printf("\n\nSTUDENTI APPARTENENTI AL %d anno di corso: \n", anno);
    printf("\n=========================================================\n");
    do{
    if (anno == tmp[i].annoCorso)
    trovato = true;
    if (trovato == true)
    {
        cnt++;
        printf("MATRICOLA: %d\n", tmp[count].matricola);
        printf("NOME: %s\n", tmp[i].nome);
        printf("COGNOME: %s\n", tmp[i].cognome);
        printf("DATA DI NASCITA: %2d-%2d-%4d\n",tmp[i].data_nascita.giorno,tmp[i].data_nascita.mese,tmp[i].data_nascita.anno);
        printf("ANNO DI IMMATRICOLAZIONE %4d\n", tmp[i].anno_immatricolazione);
        printf(" \n\tEsami sostenuti:");
        for(j=0;j<tmp[i].num_esami;j++)
        {
            printf("\nESAME:  %s",&tmp[i].esame[j].nomeEs);
            printf("\tVOTO:%d",tmp[i].esame[j].voto);
            printf("\tDATA:%2d-%2d-%4d",tmp[i].esame[j].dataEsame.giorno,tmp[i].esame[j].dataEsame.mese,tmp[i].esame[j].dataEsame.anno);
            printf("\n");
        }
        printf("\n=========================================================\n");
        trovato=false;
    }
    i++;
}  while(i<count);
if(cnt==0)
    printf("Nessun risultato trovato\n");
}
void ricerca_anno_immatr(studente tmp[],data datanascita, int count,  data dataEsame)
{
    int i=0,j, anno;
    bool trovato;
    trovato = false;
    printf("\nInserisci l'anno di immatricolazione: ");
    scanf("%d", &anno);
    printf("\n\nSTUDENTI ISCRITTI AL CORSO DI LAUREA NEL %d: \n", anno);
    do{
    if (anno == tmp[i].anno_immatricolazione)
    trovato = true;
    if (trovato == true)
    {
        printf("MATRICOLA: %d\n", tmp[count].matricola);
        printf("NOME: %s\n", tmp[i].nome);
        printf("COGNOME: %s\n", tmp[i].cognome);
        printf("DATA DI NASCITA: %2d-%2d-%4d\n",tmp[i].data_nascita.giorno,tmp[i].data_nascita.mese,tmp[i].data_nascita.anno);
        printf("ANNO DI CORSO%4d\n", tmp[i].annoCorso);
        printf(" \n\tEsami sostenuti:");
        for(j=0;j<tmp[i].num_esami;j++)
        {
            printf("\nESAME:  %s",&tmp[i].esame[j].nomeEs);
            printf("\tVOTO:%d",tmp[i].esame[j].voto);
            printf("\tDATA:%2d-%2d-%4d",tmp[i].esame[j].dataEsame.giorno,tmp[i].esame[j].dataEsame.mese,tmp[i].esame[j].dataEsame.anno);
            printf("\n");
        }
    }  else printf("informazioni non presenti in archivio\n");
        i++;
    }  while(i<count);
}
void ricerca_esame(studente tmp[],data datanascita, int count,  data dataEsame)
{
    int i=0,j,k;
    char esame[20];
    bool trovato;
    trovato = false;
    printf("\nINSERISCI IL NOME DELL'ESAME: ");
    gets(esame);
    printf("\n\nSTUDENTI CHE ANNO SOSTENUTO L'ESAME: %s\n", esame);
    do{
        for(k=0; k<tmp[i].num_esami; k++)
            if (strcmp(esame, &tmp[i].esame[k].nomeEs)==0){
                trovato = true;
                break;
                }
    if (trovato == true)
    {
        printf("MATRICOLA: %d\n", tmp[count].matricola);
        printf("NOME: %s\n", tmp[i].nome);
        printf("COGNOME: %s\n", tmp[i].cognome);
        printf("DATA DI NASCITA: %2d-%2d-%4d\n",tmp[i].data_nascita.giorno,tmp[i].data_nascita.mese,tmp[i].data_nascita.anno);
        printf("ANNO DI CORSO%4d\n", tmp[i].annoCorso);
        printf(" \n\tEsami sostenuti:");
        for(j=0;j<tmp[i].num_esami;j++)
        {
            printf("\tVOTO:%d",tmp[i].esame[j].voto);
            printf("\tDATA:%2d-%2d-%4d",tmp[i].esame[j].dataEsame.giorno,tmp[i].esame[j].dataEsame.mese,tmp[i].esame[j].dataEsame.anno);
            printf("\n");
        }
    }
        i++;
    }  while(i<count);
    if(trovato==false)
     printf("informazioni non presenti in archivio\n");
}
//a seconda del parametro passato scrive su un file di testo un report delle operazioni effettuate dall'utente
void write_report(int n)
{
    FILE *fp;
    time_t rawtime;
    struct tm *timeinfo;
    char buffer[80];
    //memorizza la data e l'ora attuali nella struct timeinfo
    time(&rawtime);
    timeinfo = localtime(&rawtime);
    //tenta di aprire il file REPORT.txt in scrittura: se fallisce termina il programma
    if((fp = fopen("REPORT.txt","a"))==NULL){
        printf("Errore: impossibile salvare su file di LOG\n");
        exit(EXIT_FAILURE);
    }
    //prepara il messaggio a seconda del parametro n
    switch(n){
        case 0:
        strftime (buffer, 80, "Esecuzione programma il %d/%m/%y alle %H:%M\n", timeinfo);
        break;
        case 1:
        strftime (buffer, 80, "Inserimento studente il %d/%m/%y alle %H:%M\n", timeinfo);
        break;
        case 2:
        strftime (buffer, 80, "Visualizzazione elenco studenti effettuata il %d/%m/%y alle %H:%M\n", timeinfo);
        break;
        case 3:
        strftime (buffer, 80, "Ricerca per matricola effettuata il %d/%m/%y alle %H:%M\n", timeinfo);
        break;
        case 4:
        strftime (buffer, 80, "Ricerca per anno di corso effettuata il %d/%m/%y alle %H:%M\n", timeinfo);
        break;
        case 5:
        strftime (buffer, 80, "Ricerca per anno di immatricolazione effettuata il %d/%m/%y alle %H:%M\n", timeinfo);
        break;
        case 6:
        strftime (buffer, 80, "Ricerca per esame effettuata il %d/%m/%y alle %H:%M\n", timeinfo);
        break;
    }
    //scrive il report su file
    fprintf(fp,"%s",buffer);
    fclose(fp);
}
void main(){
    int scelta, count=0;
    studente tmp[MAX_STUD];
    data datanascita;
    data dataEsame;
    bool trovato;
    write_report(0);
    read_from_file(tmp,&count);
    do{
        printf("\n=========================================================\n");
        printf("\n1 Inserisci nuovo studente");
        printf("\n2 Visualizza Studenti  ");
        printf("\n3 Visualizza Scheda Studente singolo");
        printf("\n4 Visualizza per corso ");
        printf("\n5 Visualizza per anno di immatricolazione ");
        printf("\n6 Visualizza per esame sostenuto");
        printf("\n7 Fine ");
        printf("\n=========================================================\n");
        printf("\nInserisci la tua scelta ---> ");
        scanf("%d",&scelta);
        fflush(stdin);
        trovato = false;
        switch(scelta)
        {
            case 1:
            inserisci_studente(tmp,datanascita,count,dataEsame);
            count++;
            printf("\n\nHai inserito %d studenti..\n", count);
            write_report(1);
            break;
            case 2:
            visualizza_studenti(tmp,datanascita,count,dataEsame );
            write_report(2);
            break;
            case 3:
            ricerca_studente(tmp,datanascita,count,dataEsame);
            write_report(3);
            break;
            case 4:
            ricerca_corso(tmp,datanascita,count,dataEsame);
            write_report(4);
            break;
            case 5:
            ricerca_anno_immatr(tmp,datanascita,count,dataEsame);
            write_report(5);
            break;
            case 6:
            ricerca_esame(tmp,datanascita,count,dataEsame);
            write_report(6);
            break;
            case 7:
            write_on_file(tmp,count);
            printf("Salvataggio effettuato con successo\n");
            exit(EXIT_SUCCESS);
            break;
            default:
            printf("\nScelta non valida!\n");
        }
}while(scelta != 7);
}