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

using namespace std;

class Papillon {
	string Nom;
	char couleur;
public:
	Papillon() {};
	Papillon(char couleur) : couleur(couleur) {};

	void saisie(ifstream& f);
	void saisie();
	void afficher();

	string nomcouleur() {
		return couleur == 'J' ? "Jaune" : "Bleu";
	}

	char getcouleur() {
		return couleur;
	}

	string getnom() {
		return Nom;
	}

	bool operator<(Papillon b) {
		return Nom > b.Nom; /* tri décroissant */
	}

	bool operator==(Papillon p) {
		return Nom == p.Nom && couleur == p.couleur;
	}
};

template <class T>
void lecture(T& cont, const string name) {
	ifstream f(name);
	
	if (!f.is_open()) {
		cout << "Erreur lors de l'ouverture du fichier" << endl;
		exit(1);
	}

	int n;

	f >> n; f.ignore();

	while (!f.eof()) {
		Papillon p;
		
		p.saisie(f);
		f.ignore();
		cont.insert(cont.begin(), p);
	}
}

template <class T>
void afficher_el(T& el) {
	el.afficher();
}

void afficher_el(string el) {
	cout << el;
}

template <class T>
void afficher(T cont) {
	for (auto el : cont) {
		// el.afficher(); 
		afficher_el(el);
		cout << endl;
	}
	cout << endl;
}

template <class T>
void tri_affichage(T& cont) {
	sort(cont.begin(), cont.end());

	afficher(cont);
}

// spécialisation de template
template <class A>
void tri_affichage(list<A>& cont) {
	cont.sort(); afficher(cont);
}

Papillon saisie_papillon() {
	Papillon p;
	p.saisie();
	return p;
}

template <class A>
bool effacer_papillon(A& cont, Papillon rec) {
	auto it = find(cont.begin(), cont.end(), rec);

	if (it == cont.end()) {
		return false;
	}

	cont.erase(it);

	return true;
}

void effacer_papillon(list<Papillon>& cont1, vector<Papillon>& cont2) {
	Papillon p = saisie_papillon();

	if (!effacer_papillon(cont1, p)) {
		cout << "Papillon non trouvé dans la liste jaune"<<endl;
	}

	if(!effacer_papillon(cont2, p)) {
		cout << "Papillon non trouvé dans le vecteur bleu" << endl;
	}

	afficher(cont1);
	afficher(cont2);
}

template <class T>
void remplir_set(T cont, set<string>& s) {
	for (auto a : cont) {
		s.insert(a.getnom());
	}
}

int menu() {
	int c;

	cout << "1) Lire PapJ.txt(Papillon Jaune) et stocker les données dans List" << endl
		<< "2) Lire PapB.txt(Papillon Bleu) et stocker les données dans Vector" << endl
		<< "3) Tri par ordre décroissant selon le nom + Affichage" << endl
		<< "4) Ajout d’1 Papillon dans List ou Vector selon sa couleur + Affichage" << endl
		<< "5) Cherche la position d’1 Papillon dans List et Vector et l’efface" << endl
		<< "6) Construit un SET avec les noms de tous les Papillons de List et Vector + Affichage" << endl;

	cout << "Choix : ";
	cin >> c; cin.ignore();
	return c;
}

int main() {
	list<Papillon> j;
	vector<Papillon> b;

	set<string> noms;

	Papillon p;

	while (true) {
		switch (menu()) {
		case 1:
			lecture(j, "PapJ.txt");
			afficher(j);
			break;
		case 2:
			lecture(b, "PapB.txt");
			afficher(b);
			break;

		case 3:
			tri_affichage(j);
			tri_affichage(b);

			break;
		case 4:
			p = saisie_papillon();
			if (p.getcouleur() == 'J') {
				j.push_back(p);
				afficher(j);
			}
			else {
				b.push_back(p);
				afficher(b);
			}

			break;

		case 5:
			effacer_papillon(j, b);
			break;

		case 6:
			noms.clear();
			remplir_set(j, noms);
			remplir_set(b, noms);
			afficher(noms);

			break;
		default:

			return 0;
		}
	}
}

void Papillon::saisie(ifstream& f) {
	getline(f, Nom, ';');
	f >> couleur; f.ignore();
}

void Papillon::afficher() {
	cout << left << setw(8) << Nom << " " << nomcouleur();
}

void Papillon::saisie() {
	cout << "Nom : ";
	getline(cin, Nom);

	couleur = '\0';
	while (couleur != 'J' && couleur != 'B') {
		cout << "Couleur (J/B) : ";
		cin >> couleur; cin.ignore();
		couleur = toupper(couleur);
	}
}