#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>

#include <vector>
#include <list>

#include <functional>

using namespace std;

class ETUD
{
    // nombre d'instances;
    static int compteur;

    int Id;
    string nom;

public:
    ETUD() : Id(++compteur) {};

    ~ETUD()
    {
        cout << "Disparition d'un étudiant (Id=" << Id << ") \n";
    };

    void saisie();
    void affiche();

    static void afficheEnLigneEnTete();
    void afficheEnLigne();

    void lire(ifstream &s);
};

class PROF
{
    // nombre d'instances;
    static int compteur;

    int Id;
    string nom, service;

public:
    PROF() : Id(++compteur) {};
    // passer une variable dans ce constructeur
    // créée un prof "temporaire"
    // cela signifie que son destructeur n'affichera rien
    // dans la console
    PROF(bool) : Id(-1) {};
    ~PROF()
    {
        if (Id == -1)
            return;
        cout << "Disparition d'un prof (Id=" << Id << ")\n";
    }

    void saisie();
    void affiche();

    static void afficheEnLigneEnTete();
    void afficheEnLigne();

    void lire(ifstream &s);

    bool operator==(PROF &p);
};

// initialisation des variables statiques
// sur les structures
// cela permet d'écrire
// : Id(++compteur)
// dans le constructeur
// au lieu de
// {
//   static int compteur = 0;
//   Id = ++compteur;
// }
int PROF::compteur = 0;
int ETUD::compteur = 0;

template <typename T>
int lire_fichier(vector<T> &tab, const string filename)
{
    ifstream file(filename);
    int N;

    if (!file.is_open())
    {
        // code d'erreur de la fonction
        return -1;
    }

    file >> N;
    file.ignore();
    int i = 0;
    while (!file.eof())
    {
        // créer un nouvel étudiant/prof
        // "emplace" pour éviter d'appeller le constructeur lors de la création de l'objet
        // et ensuite lors de la copie dans l'ajout dans le vecteur (destructeur->constructeur)
        tab.emplace_back();
        tab.back().lire(file);
        file.ignore();
    }

    return 0;
}

// Affiche le vecteur via la fonction "affichage" du
// type générique
template <typename T>
void affiche(vector<T> &vec)
{
    for (auto it = vec.begin(); it != vec.end(); ++it)
    {
        (*it).affiche();
    }
}

// Affiche le vecteur en formattage colonne
// En appellant la fonction statique "EnTete"
// Et ensuite ligne par ligne la fonction
// afficheEnLigne
template <typename T>
void affiche_ligne(vector<T> &vec)
{
    T::afficheEnLigneEnTete();
    cout << "\n";
    for (auto &el : vec)
    {
        el.afficheEnLigne();
        cout << "\n";
    }
}

template <typename T>
void saisir_debut(vector<T> &vec)
{
    // créer un objet (constructeur)
    vec.emplace(vec.begin());

    vec.front().saisie();
}

template <typename T>
int recherche(vector<T> &vec)
{
    // passage d'un booléen pour
    // appeller le 2e constructeur
    // d'objet "temporaires" (Id=-1, pas d'appel du déstructeur)
    T p(true);
    p.saisie();
    for (auto it = vec.begin(); it != vec.end(); it++)
    {
        if (p == (*it))
        {
            return it - vec.begin();
        }
    }

    return -1;
}

int menu()
{
    int choix;
    cout << "--Menu--\n"
         << "   1.  Lire fichier PROF + Lire fichier ETUD +Afficher les deux tableaux\n"
         << "   2.  Ajouter un PROF au début du tableau + Afficher\n"
         << "   3.  Ajouter un ETUD au début du tableau + Afficher\n"
         << "   4.  Chercher PROF1 dans le tableau des PROF et le supprimer s'il existe\n"
         << "   5.  Quitter " << endl;
    cout << "Votre choix : ";
    cin >> choix;
    return choix;
}

int main()
{
    vector<ETUD> etudiants;
    etudiants.reserve(20);

    vector<PROF> profs;
    profs.reserve(20);

    // list<ETUD> etudiants;
    // list<PROF> profs;

    bool fichier_lu = false;
    //    int i;

    setlocale(LC_ALL, "");

    while (1)
    {
        switch (menu())
        {
        case 1:
            if (fichier_lu)
            {
                cout << "Le fichier à déjà été lu" << endl;
                break;
            }

            if (lire_fichier(etudiants, "ETUD.txt") != 0)
            {
                cout << "Une erreur est survenue lors de la lecture du fichier ETUD.txt" << endl;
                return 1;
            }

            if (lire_fichier(profs, "PROF.txt") != 0)
            {
                cout << "Une erreur est survenue lors de la lecture du fichier PROF.txt" << endl;
                return 1;
            }

            cout << "-- Liste des étudiants (" << etudiants.size() << ") --" << endl;
            affiche_ligne(etudiants);

            cout << "-- Liste des profs (" << profs.size() << ") --" << endl;
            affiche_ligne(profs);

            fichier_lu = true;

            break;
        case 2:
            saisir_debut(profs);
            affiche_ligne(profs);
            break;

        case 3:
            saisir_debut(etudiants);
            affiche_ligne(etudiants);
            break;
        case 4:
            if (int i = recherche(profs) != -1)
            {
                cout << "Le prof cherché existe en position " << i << " et sera supprimé !" << endl;
                profs.erase(profs.begin() + i);
                affiche_ligne(profs);
            }
            else
            {
                cout << "Le prof n'est pas dans la liste :(" << endl;
            }

            break;
        case 5:
            return 0;
        }
    }
}

void ETUD::saisie()
{
    cin.ignore();
    cout << "Quel est le nom?: ";
    getline(cin, nom);
}

void ETUD::affiche()
{
    cout << "Etudiant ID: " << Id << "\n";
    cout << "Nom: " << nom << "\n";
}

void ETUD::afficheEnLigneEnTete()
{
    cout << "Id        " << " " << "Nom";
}

void ETUD::afficheEnLigne()
{
    cout << left << setw(10) << Id;
    cout << " " << nom;
}

void ETUD::lire(ifstream &i)
{
    i >> nom;
    // std::getline(i, nom, '\n');
}

void PROF::saisie()
{
    cin.ignore();
    cout << "Quel est le nom?: ";
    getline(cin, nom);

    cout << "Quel est le service?: ";
    getline(cin, service);
}

void PROF::affiche()
{
    cout << "Prof ID: " << Id << "\n";
    cout << "Nom: " << nom << "\n";
    cout << "Service: " << service << "\n";
}

void PROF::lire(ifstream &s)
{
    std::getline(s, nom, ';');
    std::getline(s, service, ';');
}

void PROF::afficheEnLigneEnTete()
{
    cout << "Id        " << " Nom     " << " Service";
}

void PROF::afficheEnLigne()
{
    cout << left << setw(10) << Id;
    cout << " " << left << setw(8) << nom;
    cout << " " << service;
}

bool PROF::operator==(PROF &p)
{
    return nom == p.nom && service == p.service;
}