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

using namespace std;

class Base {
	string nom;
	vector<string> ing;
public:
	string getNom() const { return nom; }
	vector<string> getIng() { return ing; }

	bool operator=(Base b) { return b.nom == nom; }
	bool operator<(Base b) const { return nom < b.nom; }

	void lecture(ifstream& f);
	void saisie();
	void affichage();
};

class Pizza : public Base {
public:
	bool contient_allergene(string allergene);
	float getPrix();
};

class Client : public Base {
public:
	bool est_allergique(Pizza p);
};



template <class C, class T>
void lecture(C& c, const string name) {
	ifstream f(name);

	if (!f.is_open()) {
		cout << "Erreur lors de la lecture du fichier" << endl;
		exit(1);
	}

	int N;
	f >> N; f.ignore();
	while ((N--) > 0) {
		T t;
		t.lecture(f);
		c.push_back(t);
		f.ignore();
	}
}

void Base::lecture(ifstream& f) {
	getline(f, nom, ';');
	int N;
	f >> N; f.ignore();
	while ((N--) > 0) {
		string t;
		getline(f, t, ';');
		ing.push_back(t);
	}
}

template <class T>
void afficher(T t, int w) {
	cout << left << setw(w) << t << " ";
}

void Base::affichage() {
	cout << nom << " : ";
	
	cout << "(";
	for (int i = 0; i < ing.size()-1; i++) {
		cout << ing[i] << ", ";
	}
	if (ing.size() > 0)
		cout << ing[ing.size()-1];
	cout << ")";
}

void Base::saisie() {
	cout << "Nom : ";
	getline(cin, nom);
	int N;
	cout << "Nbr ing : ";
	cin >> N; cin.ignore();
	for (int i = 0; i < N; i++) {
		string s;
		cout << "Ing" << (i + 1) << " : ";
		getline(cin, s);
		ing.push_back(s);
	}
}

float Pizza::getPrix() {
	return getIng().size() * 2.0;
}


template <class C>
void affichage(C c) {
	for (auto a : c) {
		a.affichage();
		cout << endl;
	}
	cout << endl;
}

bool Client::est_allergique(Pizza p) {
	for (string ing : getIng()) {
		if (p.contient_allergene(ing))
			return true;
	}
	
	return false;
}

bool Pizza::contient_allergene(string ing) {
	for (string i : getIng()) {
		if (ing == i)
			return true;
	}
	return false;
}

void pizza_alergenes(multimap<Client, Pizza>& mp, vector<Pizza> pizzas, list<Client> clients) {
	for (Client c : clients) {
		for (Pizza p : pizzas) {
			if (c.est_allergique(p))
				continue;
			mp.insert(make_pair(c, p));
		}
	}
}

void affiche_map(multimap<Client, Pizza> mp, list<Client> clients) {
	/* auto it = mp.begin();
	 while (it != mp.end()) {
		Client c = it->first;
		cout << c.getNom() << " : " << endl;
		int i = 1;
		while (it != mp.end() && it->first.getNom() == c.getNom()) {
			cout << "   ";
			cout << "(" << i << ") : ";
			it->second.affichage();
			cout << endl;
			it++; i++;
		}
		cout << endl;
	} */
	clients.sort();
	for (Client c : clients) {
		cout << c.getNom() << " : " << endl;
		int i = 0;
		auto r = mp.equal_range(c);
		for (; r.first != r.second; r.first++) {
			cout << "   ";
			cout << "(" << i << ") : ";
			r.first->second.affichage();
			cout << endl;
			i++;
		}
	}
}

void ajout_pizza(vector<Pizza>& pizzas) {
	Pizza p;
	char c;
	cout << "Ajout au début (O/N) : ";
	cin >> c; cin.ignore();
	auto it = c == 'O' ? pizzas.begin() : pizzas.end();

	p.saisie();

	pizzas.insert(it, p);

	cout << "Prix calculé de cette pizza = " << p.getPrix() << " euros" << endl;
}

void del_pizza(vector<Pizza>& pizzas) {
	string ing;
	cout << "Ingr_allergie : ";
	getline(cin, ing);
	
	auto it = pizzas.begin();
	while (it != pizzas.end()) {
		if (it->contient_allergene(ing)) {
			it = pizzas.erase(it);
		}
		it++;
	}

	cout << "Il reste : ";
	for (int i = 0; i < pizzas.size()-1; i++) {
		cout << pizzas[i].getNom() << ", ";
	}
		
	if (pizzas.size() > 0) {
		cout << pizzas[pizzas.size() - 1].getNom();
	}

	cout << endl;
}

int menu() {
	int c;

	cout << "1. Lire Pizza(s)" << endl
		<< "2. Lire Client(s)" << endl
		<< "3. Créer multimap<client, pizza>" << endl
		<< "4. Ajouter (début ou fin) pizza + prix (2euros/ing.)" << endl
		<< "5. Supprimer toutes les pizzas" << endl;

	cout << "Choix : ";

	cin >> c; cin.ignore();
	return c;
}

int main() {
	vector<Pizza> pizzas;
	list<Client> clients;

	multimap<Client, Pizza> mp;
	

	setlocale(LC_ALL, "");

	while (true) {
		switch (menu()) {
		case 1:
			lecture<vector<Pizza>, Pizza>(pizzas, "PIZZA_4.txt");
			affichage(pizzas);
			
			break;
		case 2:
			lecture<list<Client>, Client>(clients, "CLIENT.txt");
			affichage(clients);

			break;
		case 3:
			pizza_alergenes(mp, pizzas, clients);
			affiche_map(mp, clients);

			break;
		case 4:
			ajout_pizza(pizzas);
			affichage(pizzas);

			break;
		case 5:
			del_pizza(pizzas);
			affichage(pizzas);

			break;
		default:
			return 0;
		}
	}
}