#include <print>
#include <map>
#include <string>
#include <utility>

// Adressbuch
// Eine Adresse besteht aus einem Namen, einer Telefonnr.
// und einer EMail-Adresse. Doppelte Namen sind nicht
// zulaessig
 class AddressBook
{
    // Adressdaten, Telefon/Email ohne Name
    using entry = std::pair<std::string, std::string>;
    // Map fuer Adressbuch-Eintraege, Schluessel ist Name
    // Die Nutzdaten sind im pair entry zusammengefasst
    std::map<std::string, entry> theBook;
public:
    // ctor
    AddressBook() = default;
    // dtor
    ~AddressBook() = default;

    // Neue Adresse aufnehmen
    void Insert(std::string_view name, std::string_view phone, std::string_view email)
    {
        // Map benoetigt zum Einfuegen ein entsprechendes pair
        std::pair<std::string, entry> toInsert(name, entry(phone, email));
        // pair mit den Daten einfuegen
        auto success = theBook.insert(toInsert);
        // Da wir nur eine Map haben sind keine doppelten Eintraege erlaubt
        if (!success.second)
            std::println("{} konnte nicht eingefuegt werden!", name);
    }
    // Gibt einzelne Adresse aus
    void PrintAddress(std::string_view name) const
    {
        // Suche nach Namen
        // Falls Name nicht im Adressbuch
        if (auto iter = theBook.find(name.data()); iter == theBook.end())
            std::println("Kein entsprechender Eintrag gefunden!");
        else
        {
            // Sonst Adressdaten ausgeben, Iterator zeigt auf gefunden Eintrag
            std::println("Name: {}\n   Tel.: {}, EMail: {}",
                iter->first, iter->second.first, iter->second.second);
        }
    }
    // Aendert Adressbuch-Eintrag
    bool Update(std::string_view name, std::string_view phone, std::string_view email)
    {
        bool success = false;
        // Eintrag suchen und falls gefunden
        if (auto iter = theBook.find(name.data()); iter == theBook.end())
        {
            std::println("{} nicht im Adressbuch vorhanden!", name);
        }
        else
        {
            // Telefon-Nummer und Email korrigieren
            iter->second.first = phone;
            iter->second.second = email;
            success = true;
        }
        return success;
    }
    // Adresse entfernen
    void Remove(std::string_view name)
    {
        // Eintrag suchen
        if (auto iter = theBook.find(name.data()); iter == theBook.end())
            std::println("{} nicht im Adressbuch vorhanden!", name);
        else
            // Wenn gefunden, dann loeschen
            theBook.erase(iter);
    }
    // Ausgabe des gesamten Buches
    void PrintBook()
    {
        for (auto elem : theBook)
            std::println("Name: {}\n   Tel.: {}, EMail: {}",
                elem.first, elem.second.first, elem.second.second);
    }
};

int main()
{
    // Adressbuch dynamisch anlegen
    AddressBook *pAddr = new AddressBook;

    // Einige Eintraege hinzufuegen
    pAddr->Insert("Emil Maier", "0111/4545", "emai@sonst.net");
    pAddr->Insert("Agathe Maier", "0111/4545", "agma@sonst.net");
    pAddr->Insert("Franzi Lehmann", "08888/1234", "fral@kostnix.de");
    pAddr->Insert("Gustav Schulze", "09999/1111", "gusch@lucky.com");

    // Komplettes Adressbuch ausgeben
    std::println("Inhalt Adressbuch:");
    pAddr->PrintBook();

    // Einen Eintrag abaendern
    std::println("\nAendere Telefon-Nummer von Gustav Schulze:");
    // Und geaenderten Eintrag ausgeben
    if (!pAddr->Update("Gustav Schulze", "09999/7777", "gusch@lucky.com"))
        std::println("Aenderung fehlgeschlagen!");
    else
    {
        std::println("Neuer Eintrag ist:");
        pAddr->PrintAddress("Gustav Schulze");
    }

    // Eintrag entfernen
    std::println("\nEntferne Franzi Xelsbrot:");
    pAddr->Remove("Franzi Xelsbrot");

    // Nochmals komplettes Adressbuch ausgeben
    std::println("\nNeuer Inhalt Adressbuch:");
    pAddr->PrintBook();

    // Adressbuch loeschen
    delete pAddr;
}
