#include <print>
#include <queue>
#include <string>
#include <tuple>
using namespace std::string_literals;

// Synonym fuer Queue mit std:string
using PData = std::queue<std::string>;
// enum fuer die Frischwaren-Gruppen
enum Produkt {BUTTER, KAESE, MILCH};
// Dekodieren der Produktgruppen
const std::string prodName[] {"Butter"s, "Kaese"s, "Milch"s};

// Funktion zum Einlagern einer Ware
// lag: Feld mit den Lager fuer Frischwaren
// prod: Produkt
// anzPal: Anzahl der Paletten
// ware: Einzulagernde Ware
void Einlagern(PData lag[], enum Produkt prod, int anzPal, std::string ware)
{
    // Paletten mit Ware in entsprechende Lagerlinie einlagern
    for (int index=0; index<anzPal; index++)
        lag[prod].emplace(ware);
    std::println("  Eingelagert {} Paletten {} '{}'",
        anzPal, prodName[prod], ware);
}

// Funktion zum Abholen einer Ware
// lag: Feld mit den Lager fuer Frischwaren
// prod: Frischwaren-Gruppe
// anzPal: Anzahl Paletten
void Abholen(PData lag[], enum Produkt prod, int anzPal)
{
    // Solange Lager nicht leer und noch Paletten
    // ausgelagert werden sollen
    while ((!lag[prod].empty()) && (anzPal != 0))
    {
        std::println("  Hole 1 Palette '{}' aus Lager {}",
            lag[prod].front(), prodName[prod]);
        lag[prod].pop();
        anzPal--;
    }
}

int main()
{
    // Lager mit 3 Linien fuer die 3 verschiedenen
    // Frischwaren-Gruppen
    std::queue<std::string> lager[MILCH+1];

    // Die erste Lieferung von Waren
    // Produkt, Anzahl Palettte, Warenbezeichnung
    std::tuple<Produkt,int,std::string> lieferungen[]
    {
        std::tuple{MILCH, 3, "Weideglueck"s},
        std::tuple{KAESE, 1, "Berghof"s},
        std::tuple{MILCH, 2, "Von der Alm"s},
        std::tuple{BUTTER,2, "Landgold"s},
        std::tuple{KAESE, 2, "Zartschmelz"s},
        std::tuple{BUTTER,2, "Die Streichzarte"s},
    };

    // Gesamte Lieferung ins Lager uebernehmen
    for (auto [prod, paletten, ware]: lieferungen)
        Einlagern(lager, prod, paletten, ware);

    // Tagesbegin, Ware aus Lager holen
    std::println("\nHole 2 Paletten Kase aus Lager:");
    Abholen(lager, KAESE, 2);
    std::println("Hole 4 Paletten Milch aus Lager:");
    Abholen(lager, MILCH, 4);
    std::println("Hole 3 Paletten Butter aus Lager");
    Abholen(lager, BUTTER, 3);

    std::println("\nNeue Lieferung: 3 Paletten Butter \"Unsere Beste\"");
    Einlagern(lager, BUTTER, 3, "Unsere Beste"s);

    std::println("\nAlles muss raus:");
    Abholen(lager,BUTTER,INT_MAX);
    Abholen(lager,KAESE,INT_MAX);
    Abholen(lager,MILCH,INT_MAX);
}
