/*
AUTORE: Manuel Vichi
Esercizio su qsort con array di struct (con spiegazione codice)
*/
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <iomanip>
using namespace std;

typedef struct {
    char nome;
    char cognome;
    int annoDiNascita;
} Persona;

char letteraCasuale() {
    return 'A' + rand() % 26;
}

int annoCasuale() {
    return 1990 + rand() % 21;
}

int confrontaPerCognome(const void* a, const void* b) {
    Persona* p1 = (Persona*)a;
    Persona* p2 = (Persona*)b;
    return p1->cognome - p2->cognome;
}

int confrontaPerAnnoDiNascita(const void* a, const void* b) {
    Persona* p1 = (Persona*)a;
    Persona* p2 = (Persona*)b;
    return p2->annoDiNascita - p1->annoDiNascita;
}

int confrontaPerNomeCognome(const void* a, const void* b) {
    Persona* p1 = (Persona*)a;
    Persona* p2 = (Persona*)b;
    if (p1->nome == p2->nome) {
        return p2->cognome - p1->cognome;
    }
    return p2->nome - p1->nome;
}
void stampaPersone(Persona persone[], int size) {
	cout << "Nome " << " Cognome " << " Anno di Nascita" << endl;
    for (int i = 0; i < size; ++i) {
        cout << setw(2) << persone[i].nome << ". " << setw(6) << persone[i].cognome << ". " << setw(12) << persone[i].annoDiNascita << endl;
    }
}

int main(void) {
    srand((time(NULL)));
    int size = 10;
    Persona persone[size];
    for (int i = 0; i < size; i++) {
        persone[i].nome = letteraCasuale();
        persone[i].cognome = letteraCasuale();
        persone[i].annoDiNascita = annoCasuale();
    }
    cout << "Persone prima dell'ordinamento:" << endl;
    stampaPersone(persone, size);
    qsort(persone, size, sizeof(Persona), confrontaPerCognome);
    cout << endl << "Ordinamento per cognome crescente:" << endl;
    stampaPersone(persone, size);
    qsort(persone, size, sizeof(Persona), confrontaPerAnnoDiNascita);
    cout << endl << "Ordinamento per anno di nascita decrescente:" << endl;
    stampaPersone(persone, size);
    qsort(persone, size, sizeof(Persona), confrontaPerNomeCognome);
    cout << endl << "Ordinamento per nome decrescente ed eventualmente per cognome decrescente:" << endl;
    stampaPersone(persone, size);
    return 0;
}
/*
Spiegazione del codice:

1. Struct Persona:
   La struct contiene tre campi:
   nome: l'iniziale del nome.
   cognome: l'iniziale del cognome.
   annoDiNascita: l'anno di nascita della persona.
   
   Generazione di valori casuali:
   La funzione letteraCasuale() restituisce un carattere casuale tra 'A' e 'Z'.
   La funzione annoCasuale() restituisce un numero casuale tra 1990 e 2010.
   
2. Ordinamento:
   Vengono definiti tre metodi di confronto utilizzabili con qsort:
   confrontaPerCognome() ordina in base al cognome crescente.
   confrontaPerAnnoDiNascita() ordina in base all'anno di nascita decrescente.
   confrontaPerNomeCognome() ordina prima per nome decrescente e, in caso di parità, per cognome decrescente.
   
   Funzione qsort:
   La funzione qsort() di C++ è usata per ordinare l'array di persone. È una funzione standard che richiede:
   Il puntatore all'array da ordinare.
   Il numero di elementi nell'array.
   La dimensione di ogni elemento (in questo caso sizeof(Persona)).
   Una funzione di confronto che stabilisce come ordinare gli elementi.
   
3. Stampa dell'array:
   La funzione stampaPersone() stampa il contenuto dell'array di persone in un formato leggibile.
   
   Dettagli sull'ordinamento:
   
   Ordinamento per cognome crescente:
   qsort utilizza confrontaPerCognome() per confrontare i cognomi delle persone e ordinarle in ordine crescente.
   
   Ordinamento per anno di nascita decrescente:
   qsort utilizza confrontaPerAnnoDiNascita() per confrontare gli anni di nascita e ordinarli in ordine decrescente.
   
   Ordinamento per nome decrescente e, a parità di nome, per cognome decrescente:
   qsort utilizza confrontaPerNomeCognome() per ordinare prima in base al nome in ordine decrescente, e in caso di parità, ordina in base al cognome decrescente.
*/