/*############################################
# (\__/)    Programme   : Statistique de Groupe
# ( . .)    Auteur      : Martin Robinson
# c(")(")   Conception  : Aujourd'hui
#		    Description : Plein d'etudian dans
						un fichier et on sort
						des statistiques
###########################################
         (\_/)   directive du pr�processeur
        ( . . ) /
###########################################*/

#include <iostream>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <string.h>

#include "../lib/saisieMR.hpp"
#include "../lib/algoMR.hpp"

using namespace std;

/*       (\_/)   Structure
        ( . . ) /
###########################################*/

struct etudiant{
    char nom[15],       //nom de l'étudiant
         prenom[15];    //prenom de l'étudiant
    float note[10],     //les 10 notes
          noteFinale;   //la note finale
    etudiant()
    {
        nom[0] = 0;
        prenom[0] = 0;
        noteFinale=0;
    }
};

//trie alphabetique croissant des etudiants
//la fonction de la libraire algoMR peut prendre des objects si on lui fourni le comparateur
class cmpAlphaEtu:public sortCmp<etudiant>
{
    public:
        bool operator () (etudiant& a, etudiant& b)
        {
            //les objets vides vont à la fin de la liste
            if (a.nom[0] == 0 || b.nom[0]==0)
                return false;
            //teste les nom
            for (int i=0;i<15;i++)
                if (a.nom[i] == 0)              //si le nom de a est plus court que b alors a<b
                    return true;
                else if (b.nom[i]==0)           //si le nom de b est plus court alors a>b
                    return false;
                else if (a.nom[i] < b.nom[i])   //sinon comparaissont du caractère
                    return true;
                else
                    return false;
            //teste les prenoms pour les étudiant qui on le meme nom
            for (int i=0;i<15;i++)
                if (a.prenom[i] == 0)              //si le nom de a est plus court que b alors a<b
                    return true;
                else if (b.prenom[i]==0)           //si le nom de b est plus court alors a>b
                    return false;
                else if (a.prenom[i] < b.prenom[i])   //sinon comparaissont du caractère
                    return true;
                else
                    return false;
            //dans le cas peut probable ou deux étudiants portent le meme nom et le meme prenom
            return a.noteFinale < b.noteFinale;     //nous testerons la meilleur note des deux
        }
};

/*       (\_/)   Prototype de fonction
        ( . . ) /
###########################################*/

void afficherEnTete();
void lireEtudiant(lecture & entree, etudiant&);
void trier8PremieresNotes(float []);
float calculerNoteFinale(float[]);
template <int qty>
void trierEnOrdreAlphabetique(etudiant listeEtu[]);
void afficherLesEtudiants(etudiant listeEtu[],int);
int calculerNbSuppAMoyenne(etudiant [] ,int , float );
void afficherStatistique(float , int ,etudiant);

/*       (\_/)   Programme Principal
        ( . . ) /
###########################################*/

int main ()
{
	/*  (\_/) initialisation
	___( . . )_/________________*/
	saisie <void> attendre("appuyer sur une touche pour terminer");		//foncteur saisie s�curis� configurer pour faire une pause

	float moyenne = 0;					//moyenne du groupe

	int nbEtudiant = 0,				    //nombre d'etudiants
		nbEchec = 0,					//nombre d'echecs
		nbSupMoy;						//nombre d'�tudiants superieurs � la moyenne.

    etudiant listeEtudiant[20],             //liste des etudiants
             meilleur; //meilleur etudiant

	
	/*  (\_/) ouvrire fichiers
	___( . . )_/________________*/

	lecture entree("Notes.txt");		//ouverture du fichier
	if(!entree)								//en cas d'�chec test fait par l'objet lui meme
	{
	    attendre();     //la sortie de programme en cas d'échec n'est pas déplacable dans une fonction
		return 0;
	}

	for (int i = 0; i<50; i++)		//vider l'ecran
		cout << "\n";
	afficherEnTete();
	
	//lireEtudiant(entree, listeEtudiant[nbEtudiant]);

	/*  (\_/) tant que le fichier n'est pas vide
	___( . . )_/________________*/
	while(entree)					//tant que le fichier n'est pas fini
	{
	    lireEtudiant(entree, listeEtudiant[nbEtudiant]);
		trier8PremieresNotes(listeEtudiant[nbEtudiant].note);
		listeEtudiant[nbEtudiant].noteFinale = calculerNoteFinale(listeEtudiant[nbEtudiant].note);
		moyenne += listeEtudiant[nbEtudiant].noteFinale;                   //accumulation pour la moyenne

		if (meilleur.noteFinale < listeEtudiant[nbEtudiant].noteFinale)	        //trouver le meilleurs etudiant
		    meilleur = listeEtudiant[nbEtudiant];

		nbEtudiant++;				//le nombre d'etudiants augmente
		

	}
	
	moyenne /= nbEtudiant;                                                 //fin du calcul de moyenne
	nbSupMoy = calculerNbSuppAMoyenne(listeEtudiant,nbEtudiant,moyenne);    //nombre d'étudiants superieurs à la moyenne

    trierEnOrdreAlphabetique<20>(listeEtudiant);
    afficherLesEtudiants(listeEtudiant,nbEtudiant);
	afficherStatistique(moyenne, nbSupMoy, meilleur);

	/*  (\_/)  fin
	___( . . )_/________________*/
	entree.fermer();

	cout << "\n\n (\\_/)\n"
		 << "( . .)\n"
		 << "c(\")(\")\n"
		 << "Fin du programme\n";
	attendre();
	return 0;
}

/*       (\_/)   fonction
        ( . . ) /
###########################################*/
//affichage
void afficherEnTete()
{
	cout << right << setw(50) << "Liste des �tudiants" << endl
		 << right << setw(50) << "===================" << endl << endl
		 << left << setw(50) << "Nom"
		 << left << setw(20) << "Note Finale" << endl
		 << left << setw(50) << "========================"
		 << left << setw(20) << "===========" << endl;
}
//lecture du fichier
void lireEtudiant(lecture & entree, etudiant &etuCourant)
{
	//lire etudiant ... c'est un foncteur avec validation automatique
	entree >> etuCourant.nom >> etuCourant.prenom;
	for (int i=0;i<10;i++)
	    entree >> etuCourant.note[i];
}
//trie les huits premieres notes , utilise une liste heap
void trier8PremieresNotes(float note[])
{
    float tableau[8];                       //tableau de trie temporaire
    minCmp <float> minHeap;                 //direction du trie
	heap <float,8> triage(minHeap,tableau); //objet de triage par heap (arbre binaire)
	for (int i=0; i<8;i++)      //injecter les notes dans la structure de trie
		triage.push(note[i]);
	for (int i=0; i<8; i++)     //resortire les notes trié de la structure (HeapSort)
		note[i] = triage.pop();

}
//un commentaire
float calculerNoteFinale(float note[])
{
	int pond[7] = {5,5,5,5,5,25,50};      //ponderation
	float noteF = 0;                      //accumulateur , noteFinale
	for(int i=3;i<10;i++)
		noteF += note[i] * pond[i-3] / 100;

	return noteF;
}

//trier en ordre Alphabetique
template <int qty>
void trierEnOrdreAlphabetique(etudiant listeEtu[])
{
    cmpAlphaEtu croissant;
    selectSort<etudiant,qty>(listeEtu, &croissant);
}

//afficher l'etudiant;
void afficherEtudiant(etudiant etuCourrant)
{
	cout << left << setw(15) << etuCourrant.nom
		 << left << setw(25) << etuCourrant.prenom
		 << right << setw(19) << fixed << setprecision(0) << etuCourrant.noteFinale << " %\n";
}

//afficher les étudiants
void afficherLesEtudiants(etudiant listeEtu[],int qty)
{
    for (int i=0;i<qty;i++)
        afficherEtudiant(listeEtu[i]);
}

//calculer le nb d'etudiant supp�rieurs � la moyenne
int calculerNbSuppAMoyenne(etudiant liste[],int nbEtudiant, float moyenne)
{
	int nbSupMoy=0;	//nombre d'etudiant sup�rieurs � la moyenne
	
	for (int i = 0; i<nbEtudiant;i++)			//pour tout les etudiants
	{
		if (moyenne < liste[i].noteFinale)					//si plus grand que la moyennes
			nbSupMoy++;							//il y a un �tudiant de plus supp�rieurs � la moyenne
	}
	return nbSupMoy;
}
//un commentaire
void afficherStatistique(float moyenne, int nbSupMoy, etudiant meilleur)
{
	cout << endl << left << setw(30) << "Moyenne du groupe:  "
		 << fixed << setprecision(1) << setw(5) << moyenne << "%\n"
		 << left << setw(30) << "Nb sup�rieur � la moy: "
		 << setw(7) << nbSupMoy << endl
		 << left << setw(30) << "Meilleur r�sultat:"
		 << meilleur.prenom[0] << ". "
		 << meilleur.nom << endl;
}

/*       (\_/)   fini
        ( . . ) /
###########################################*/
