#include <iostream>
#include <vector>
#include <string>
using namespace std;

/* 
 CONSTAT : c'est encore mieux (on a amélioré le français), mais :
   3) Généricité : on ne peut faire que de la fondue ; pourquoi pas autre chose ? facile ?

mineurs/plus tard:
   4) rendre la saisie plus robuste : do-while
*/

// ==== Type de données =============================

struct Mot {
  string mot;
  string pluriel; // "" pour les invariables, suffixe sur 1 char ou mot entier sinon
  bool feminin; // ou masculin (false)
};

typedef double Quantite;

struct Ingredient
{
  string nom;
  Quantite qtt;
  Mot unite;
};

struct Recette {
  Mot nom;
  unsigned int nb_personnes;
  vector<Ingredient> ingredients; // liste et quantités
};

typedef vector<Recette> Menu;

// ==== Fonctions ===================================

unsigned int demander_nb_convives()
{
  unsigned int nb_convives(0);
  do {
    cout << "Entrez le nombre de personnes invitées : ";
    cin >> nb_convives;
  } while (nb_convives < 1);
  return nb_convives;
}

// --------------------------------------------------

const Recette& choisir(Menu const& liste)
{
  cout << "Quelle recette souhaitez-vous faire ?" << endl;
  for (size_t i(0); i < liste.size(); ++i) {
    cout << i+1 << " - un";
    if (liste[i].nom.feminin) cout << 'e';
    cout << " " << liste[i].nom.mot << endl;
  }
  size_t choix(0);
  bool ok(false);
  do {
    cin >> choix;
    if ((choix == 0) or (choix > liste.size())) {
      cout << "Entre 1 et " << liste.size() <<", SVP." << endl;
    } else {
      ok = true;
    }
  } while (not ok);
  return liste[choix-1];
}

// --------------------------------------------------

Recette adapter(Recette const& r, unsigned int nb_convives) 
{
  Recette retour(r);
  
  // Mise à jour des quantités en fonction du nombre de convives :

  double ratio(nb_convives); // Notez le 'double' ici...
  ratio /= r.nb_personnes;   // ... pour éviter une division entière.

  for (auto& ingredient : retour.ingredients) { // ATTENTION ! n'oubliez pas le & ici !
    ingredient.qtt *= ratio;
  }

  retour.nb_personnes = nb_convives;

  return retour;
}

// --------------------------------------------------

bool est_voyelle(char c) {
  return "aeiouyAEIOUY"s.find(c) != string::npos;
  // pour les caractères accentués, c'est franchement plus compliqué (encodage)
}

// --------------------------------------------------

// Pensez à MODULARISER : faire aussi un affiche() pour Mot !!

void afficher(Mot const& m, bool pluriel = false)
{
  if (pluriel and not m.pluriel.empty()) {
    if (m.pluriel.size() == 1) {
      cout << m.mot << m.pluriel;
    } else {
      cout << m.pluriel;
    }
  } else {
    // singulier
    cout << m.mot;
  }
}

void afficher(Ingredient const & ing)
{
  cout << ing.qtt << ' ';
  afficher(ing.unite, ing.qtt > 1.0);
  if (not ing.nom.empty()) {
    if (est_voyelle(ing.nom.front())) {
      cout << " d'";
    } else {
      cout << " de ";
    }
    cout << ing.nom;
  }
}

void afficher(Recette const & rec)
{
  cout << "Pour faire un";
  if (rec.nom.feminin) cout << 'e';
  cout << " " << rec.nom.mot << " pour " << rec.nb_personnes << " personne";
  if (rec.nb_personnes > 1) cout << 's';
  cout << "," << endl;
  cout << "il vous faut : " << endl;
  for (auto const& ingredient : rec.ingredients) {
    cout << " - ";
    afficher(ingredient);
    cout << endl;
  }
}

// ==== Main ========================================

int main()
{
  // Quelques unités utiles
  const Mot gramme   ({ "gr"    , "" , false });
  const Mot decilitre({ "dl"    , "" , false });
  const Mot gousse   ({ "gousse", "s", true  });

  // Le menu
  Menu carte({

     { { "fondue fribourgeoise", "fondues fribourgeoises", true },
       4,
       { { "Vacherin fribourgeois", 800.0, gramme },
         { "eau"                  ,   2.0, decilitre },
         { "ail"                  ,   2.0, gousse },
         { "pain"                 , 400.0, gramme }
       }
     },
     {
       { "choucroute garnie", "choucroutes garnies", true },
       6,
       { { "chou fermenté cru", 900.0, gramme     },
         { "Edelzwicker"      ,   5.0, decilitre  },
         { "kassler fumé"     , 750.0, gramme     },
         { "lard fumé"        , 300.0, gramme     },
         { "lard salé"        , 300.0, gramme     },
         { ""                 , 12,    { "pomme de terre", "pommes de terre", true } },
         { ""                 , 12,    { "knack", "s", true } },
         { ""                 ,  3,    { "saucisse Lorraine", "saucisses Lorraines", true } },
         { ""                 ,  6,    { "Leverknepfle", "Leverknepfles", false } }
      }
    }
   });

  const Recette& plat(choisir(carte));
  afficher(adapter(plat, demander_nb_convives()));
 
  return 0;
}

