#include <iostream>
#include <set>
#include <functional>
#include <string>
#include <algorithm>
using namespace std;
// Prototypen
template <typename T>
using Func = std::function<T(T)>;
template <class T>
T DatenErfassen(T *result, const char message[]);
template <class T, typename K>
T DatenErfassen(T *result, const char message[], K &&constraint);
void addTier();
float EinnahmenBerechnen(float *tagespreis, int *gewicht);

typedef struct Tier
{
    string tierart;
    int tiernummer;
    float gewicht;
    bool operator<(const Tier &cmp) const { return tiernummer - cmp.tiernummer; }
    bool operator==(const Tier &cmp) const
    {
        return tiernummer == cmp.tiernummer;
    }
    string to_string()
    {
        return ("Tiernummer " + std::to_string(tiernummer) + " ist von der Art " + this->tierart + " und wiegt " + std::to_string(gewicht) + " KG.\n");
    }
} tier_frame;
set<Tier> tiere;
const char *fehler_meldung = "\nEs gab einen Fehler bei der Eingabe.\nBitte erneut eingeben.\n";
int main()
{
    int menu_state = -1;
    cout << "Willkommen auf dem Bauerhof von Bauer Max\n";
    while (true)
    {
        switch (menu_state)
        {
        case 0:
            return 0;
        case 1:
        {
            cout << "Tier anlegen:\n";
            Tier tier;
            DatenErfassen(&tier.tierart, "Tierart: ");
            DatenErfassen(&tier.gewicht, "Gewicht: ");
            DatenErfassen(&tier.tiernummer, "Tiernummer: ");
            tiere.insert(tier);
            menu_state = -1; // Reset
            break;
        }
        case 2:
        {
            int tierid = 0;
            cout << "Tier verkaufen:\n";
            DatenErfassen(&tierid, "Tiernummer:");
            if (tiere.erase(tier_frame{"", tierid, 0}))
            {
                cout << "Tier verkauft\n";
            }
            else
            {
                cout << "Tier wurde nicht gefunden\n";
            }
            menu_state = -1; // Reset
            break;
        }
        case 3:
        {
            cout << "Alle Tiere:\n";
            for (Tier tier : tiere)
            {
                cout << tier.to_string();
            }
            menu_state = -1; // Reset
            break;
        }
        default:
        {
            cout << "\t-	1: Tier anlegen ()\n";
            cout << "\t-	3: Tier anzeigen ()\n";
            cout << "\t-	2: Tier verkaufen (Tiernummer)\n";
            cout << "\t-	0: Programm beenden\n";
            DatenErfassen(&menu_state, "Programm Modul:", [](int *val)
                          { return (bool)(*val >= 0 && *val <= 4); });
        }
        }
    }

    float tagespreis = 0, einnahmen = 0;
    int gewicht = 0;
    cout << "Bitte geben Sie den aktuellen Tagespreis und das Gewicht an.\n ";
    DatenErfassen(&tagespreis, "Tagespreis:");
    DatenErfassen(&gewicht, "Gewicht:");
    einnahmen = tagespreis * gewicht;
    cout << "Die heutigen Einnahmen belaufen sich auf: " << EinnahmenBerechnen(&tagespreis, &gewicht) << " € (" << tagespreis << " x " << gewicht << ")\n";
    return 0;
}

template <class T>
T DatenErfassen(T *result, const char message[])
{
    return DatenErfassen(result, message, [](T *val)
                         { return true; });
}
template <class T, typename K>
T DatenErfassen(T *result, const char message[], K &&constraint)
{
    do
    {
        if (cin.fail())
        {
            cout << fehler_meldung;
            cin.clear();
            cin.ignore();
        }
        cout << message << "\t";
        cin >> *result;
    } while (cin.fail() || !constraint(result));
    return *result;
}

float EinnahmenBerechnen(float *tagespreis, int *gewicht)
{
    return (*tagespreis) * (*gewicht);
}
