#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
#include <iomanip>
#include <string>
#include <fstream>

using namespace std;

class ETUD {
	int Id;
	string nom;

public:
	ETUD() { static int i = 0; Id = ++i; }
	~ETUD() { cout << "Disparition de l'étudiant ID=" << Id << endl; }

	void saisie(string ligne) { nom = ligne.substr(0, ligne.find(';')); };
	void affiche() { cout << setw(4) << Id << left << setw(2) << nom; }
	void saisie() { cout << "Nom :"; cin.ignore(); getline(cin, nom); }

	string getNom() { return nom; }
};

class PROF {
	int Id;
	string nom, service;

public:
	PROF() { static int i = 0; Id = ++i; }
	~PROF() { cout << "Disparition du prof ID=" << Id << endl; }

	void saisie(string ligne) { int i = ligne.find(';'); nom = ligne.substr(0, i); service = ligne.substr(i + 1, ligne.find(';', i+1) - i - 1); };
	void affiche() { cout << left << setw(4) << Id << left << setw(8) << nom << "  " << left << setw(8) << service; }
	void saisie() { cout << "Nom :"; cin.ignore(); getline(cin, nom); cout << "Service :"; cin.ignore(); getline(cin, service); }

	string getNom() { return nom; }
};

int menu() {
	int choix;
	cout << "Entrez votre choix : \n"
		<< "   1.  Lire fichier PROF et stocker les données dans un Vector + Affichage\n"
		<< "   2.  Lire fichier ETUDB et stocker les données dans une List + Affichage\n"
		<< "   3.  Ajouter un PROF au début du Vector + Afficher\n"
		<< "   4.  Ajouter un ETUD au début de List   + Afficher\n"
		<< "   5.  Supprimer le PROF et ETUD au début de Vector et List + Affichage\n"
		<< "   6.  Créer une List2 contenant uniquement les noms des ETUD et PROF \n"
		<< "   7.  Quitter " << endl;
	cin >> choix;
	return choix;
}

// template <class C, class O>
template <class C>
void lire(C& c, string nomfichier) {
	ifstream fichier(nomfichier);
	int N;
	string ligne;

	if (!fichier) {
		cout << "Une erreur est survenue lors de la lecture du fichier" << endl;
		return;
	}

	fichier >> N;
	fichier.ignore();
	while (N-- > 0) {
		getline(fichier, ligne);
		// O o;
		// o.saisie(ligne);
		// c.insert(c.end(), o);
		
		// https://cplusplus.com/reference/vector/vector/emplace/
		// https://cplusplus.com/reference/list/list/emplace/
		c.emplace(c.end())->saisie(ligne);
	}
}

template <class C>
void affiche(C& conteneur) {
	cout << "Ce conteneur contient" << endl;
	for (auto& o : conteneur) {
		cout << endl;
		o.affiche();
	}
	cout << endl;
}

template <class C>
void lire_puis_affiche(C& conteneur, string nomfichier) {
	lire(conteneur, nomfichier);
	affiche(conteneur);
}

// template <class C, class O>
template <class C>
void ajoutdebut_affiche(C& conteneur) {
	conteneur.emplace(conteneur.begin())->saisie();
	affiche(conteneur);
}

template <class C>
void supprimedebut_affiche(C& conteneur) {
	conteneur.erase(conteneur.begin());
	affiche(conteneur);
}

template <class C>
void remplirliste_nom(C& c, list<string>& l) {
	for (auto& o : c) {
		l.push_back(o.getNom());
	}
}

void affiche(list<string>& l) {
	cout << "Voici la liste des noms des etudiants et des PROFs" << endl;
	for (auto& o : l) {
		cout << endl << o;
	}
	cout << endl;
}

int main() {
	setlocale(LC_ALL, "");

	list<ETUD> etuds;
	vector<PROF> profs;
	
	list<string> list2;

	profs.reserve(10);

	int choix;

	while ((choix = menu()) != 7) {
		switch (choix) {
		case 1:
			//lire<vector<PROF>, PROF>(profs, "PROF.txt");
			lire_puis_affiche(profs, "PROF.txt");
			break;

		case 2:
			//lire<list<ETUD>, ETUD>(etuds, "ETUDB.txt");
			lire_puis_affiche(etuds, "ETUDB.txt");
			break;

		case 3:
			ajoutdebut_affiche(profs);
			break;

		case 4:
			ajoutdebut_affiche(etuds);
			break;

		case 5:
			supprimedebut_affiche(etuds);
			supprimedebut_affiche(profs);
			break;

		case 6:
			remplirliste_nom(etuds, list2);
			remplirliste_nom(profs, list2);
			affiche(list2);
			break;
		}
	}


	return 0;
}

/*
template <class Conteneur, class T>
void fonction_template(Conteneur& conteneur) {
	T monobjet;

	conteneur.push_back(monobjet);
}

void exemple_template() {
	list<PROF> profs;
	profs.push_back
	
	int varI = 0;

	fonction_template<list<PROF>, PROF>(profs);

	fonction_template<list<PROF>, string>(profs);

	fonction_template<int, string>(varI);
}
*/
/*
// expand la fonction template comme ceci
void fonction_template(list<PROF>& conteneur) {
	PROF monobjet;

	conteneur.push_back(monobjet);
}
 
// expand la fonction template comme ceci (avec le 2e)
void fonction_template(list<PROF>& conteneur) {
	string monobjet;

	conteneur.push_back(monobjet);
}

// expand la fonction template comme ceci (avec le 3e)
void fonction_template(int& conteneur) {
	string monobjet;

	conteneur.push_back(monobjet);
}*/