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

using namespace std;

class Poule;
class Oeuf;

template <class C>
void affiche_cont(C& cont) {
	for (auto& volaille : cont) {
		volaille.affiche();
		cout << endl;
	}
}

class Coq {
	string Nom;
	int Age;

public:
	void saisie();
	void affiche();

	Oeuf Cocorico(Poule p);

	bool operator<(Coq& c2) {
		return Age < c2.Age;
	}

	template <class C>
	void CocoricoPoules(C&c) {
		vector<Oeuf> oeufs;
		oeufs.reserve(c.size());
		for (auto poule : c) {
			oeufs.push_back(Cocorico(poule));
		}
		affiche_cont(oeufs);
	}
};

class Poule {
	string Nom;
	int Poids;

	friend Coq;

protected:
	void set_poids(int poids) { Poids = poids; }

public:
	void saisie();
	void affiche();

	float get_poids() {
		return Poids;
	}

	bool operator<(Poule& c2) {
		return Poids < c2.Poids;
	}
};

class Oeuf : public Poule {
	char Qualite;

public:
	Oeuf(int poids) {
		set_poids(poids);

		cout << "L'oeuf a bien ete pondu et pese : "<<poids<<"(gr)" << endl;
	}

	void saisie();
	void affiche();
};

template <class C, class T>
void saisie(C& cont, const string nom) {
	int n;

	cout << "Combien de " << nom << " ? : ";
	cin >> n; cin.ignore();

	while (n-- > 0) {
		T p;
		p.saisie();
		cont.insert(cont.begin(), p);
	}
}



int poids_poules(list<Poule> poules) {
	int S = 0;
	for (Poule& p : poules) {
		S += p.get_poids() / 1000;
	}
	return S;
}

pair<Poule, Coq> couple(list<Poule> poules, vector<Coq> coqs) {
	auto poule = max_element(poules.begin(), poules.end());
	auto coq = min_element(coqs.begin(), coqs.end());

	if (poule == poules.end() || coq == coqs.end()) {
		cout << "Aucun couple n'a pu être formé";
		exit(1);
	}

	cout << "Le couple formé est ";
	coq->affiche();
	cout << " et ";
	poule->affiche();
	cout << endl;

	return make_pair(*poule, *coq);
}

Coq plus_vieux_coq(vector<Coq> coqs) {
	auto coq = max_element(coqs.begin(), coqs.end());
	if (coq == coqs.end()) {
		cout << "Il n'y a pas de coq!";
		exit(1);
	}
	return *coq;
}

// Faut-il effacer l'unique élément si le conteneur ne contient qu'un seul élément ?
// Supprimer la première moitié? que vaut la moitié pour 1 élement.
template <class C>
void effacer_moitie(C& c) {
	auto it = c.begin();
	for (int i = 0; i < c.size() / 2; i++) it++;

	c.erase(c.begin(), it);
}

int menu() {
	int c;

	cout << "1) Saisir_Clav 1 List de Poule(s) (insertion au début) + Affichage" << endl
		<< "2) Saisir_Clav 1 Vector de Coq(s) (insertion au début) + Affichage" << endl
		<< "3) Calculer et afficher la Somme des poids en Kg : Sp" << endl
		<< "4) Le plus jeune des Coqs épouse la Poule la plus lourde" << endl
		<< "5) Le Coq fait Cocorico et toutes les Poules pondent + Affichage" << endl
		<< "6) Effacer la première moitié de List et de Vector + Affichage" << endl
		<< "Votre choix : ";

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

int main() {
	list<Poule> poules;
	vector<Coq> coqs;

	float Sp;

	setlocale(LC_ALL, "");

	while (true) {
		switch (menu()) {
		case 1:
			saisie<list<Poule>, Poule>(poules, "Poules");
			affiche_cont(poules);
			break;
		
		case 2:
			saisie<vector<Coq>, Coq>(coqs, "Coqs");
			affiche_cont(coqs);
			break;

		case 3:
			Sp = poids_poules(poules);
			cout << "Somme de Poids des poules en Kg : " << Sp;

			break;
		case 4:
			couple(poules, coqs);

			break;

		// Cocorico
		case 5:
			plus_vieux_coq(coqs).CocoricoPoules(poules);
			break;
		case 6:
			effacer_moitie(coqs);
			effacer_moitie(poules);

			affiche_cont(coqs);
			affiche_cont(poules);

			break;

		default:
			return 0;
		}
	}

	return 0;
}

void Poule::saisie() {
	cout << "Le nom ? : ";
	getline(cin, Nom);
	cout << "Le poids ? : ";
	cin >> Poids; cin.ignore();
}

void Coq::saisie() {
	cout << "Le nom ? : ";
	getline(cin, Nom);
	cout << "L' age ? : ";
	cin >> Age; cin.ignore();
}

void Poule::affiche() {
	cout << Nom << "(" << Poids << ") ";
}

void Coq::affiche() {
	cout << Nom << "(" << Age << ") ";
}

void Oeuf::affiche() {
	cout << Qualite << "(" << get_poids()  << "gr)";
}

void Oeuf::saisie() {
	cout << "Saisir qualité de l'oeuf (A, B ou C) ? : ";
	cin >> Qualite;
}

Oeuf Coq::Cocorico(Poule p) {
	Oeuf oeuf(p.get_poids() / 10);

	oeuf.saisie();

	return oeuf;
}