//=============================================================================

#include <map>
#include <vector>
#include <string>
#include <limits>
#include <iostream>
#include <fstream>
using namespace std;

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

using numbers_type = vector<string>;
using book_type = map<string, numbers_type>;
using book_entry = book_type::value_type;

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

const string filename("telefonbuch3.txt");

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

bool starts_with(const string& src, const string& pattern)
{
   if (src.length() < pattern.length())
   {
      return false;
   }
   return src.substr(0, pattern.length()) == pattern;
}

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

void print_entry(const book_entry& entry)
{
   cout << "* " << entry.first << " => ";
   for (const string& no : entry.second)
   {
      cout << '(' << no << ") ";
   }
   cout << '\n';
}

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

void list_entries(const book_type& book)
{
   cout << book.size() << " Eintraege:\n";
   for (const auto& entry : book)
   {
      print_entry(entry);
   }
}

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

void search_entries(const book_type& book)
{
   string s;
   cout << "Suchen nach: ";
   getline(cin, s);

   auto lower = book.lower_bound(s);
   if (lower == cend(book) || !starts_with(lower->first, s))
   {
      cout << "\nKein Name im Telefonbuch beginnt mit \"" << s << "\".\n";
      return;
   }

   cout << "\nGefunden:\n";
   auto eit = cend(book);
   for (; lower != eit; ++lower)
   {
      if (!starts_with(lower->first, s)) break;
      print_entry(*lower);
   }
}

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

void new_entries(book_type& book)
{
   cout << "Neuer Eintrag\n";

   string name;
   cout << "> Name: ";
   getline(cin, name);

   if (name.empty())
   {
      cout << "Abbruch 'neuer Eintrag', da leerer Name\n";
      return;
   }
   if (book.count(name) > 0)
   {
      cout << "Abbruch 'neuer Eintrag', da Name schon vorhanden\n";
      return;
   }

   numbers_type& numbers = book[name];
   for (string no;;)
   {
      cout << "> Nr.: ";
      getline(cin, no);
      if (no.empty()) break;
      numbers.push_back(no);
   }
}

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

bool save_entries(const book_type& book)
{
   cout << "Sichere Daten in die Datei \"" << filename << "\"...\n";

   ofstream out(filename);
   if (out.fail())
   {
      cout << "- Probleme beim Oeffnen der Datei.\n";
      return false;
   }

   for (const auto& [name, numbers] : book)
   {
      out << name << '\n';
      for (const auto& name : numbers)
      {
         out << name << '\n';
      }
      out << '\n';
      if (out.fail())
      {
         cout << "- Probleme beim Schreiben in die Datei.\n";
         return false;
      }
   }

   cout << "- fertig\n";
   return true;
}

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

void load_entries(book_type& book)
{
   cout << "Lade Daten aus der Datei \"" << filename << "\"...\n";

   ifstream in(filename);
   if (in.fail())
   {
      cout << "- Probleme beim Oeffnen der Datei.\n- 0 Eintraege geladen.\n";
      return;
   }

   string s;
   int line = 0;
   do
   {
      ++line;
      getline(in, s);
      if (in.fail()) break;
      numbers_type& numbers = book[s];

      for (;;)
      {
         ++line;
         getline(in, s);
         // Bei s.empty() Schleife beenden, da eine Leerzeile 
         // das Ende der Telefon-Nummern anzeigt.
         if (in.fail() || s.empty()) break;
         numbers.push_back(s);
      }
   } while (!in.fail());
   if (!in.eof())
   {
      cout << "- Problem beim Lesen der Zeile " << line << '\n';
   }

   cout << "- " << book.size() << " Eintrage geladen.\n";
}

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

int main()
{
   cout << "Aufg_13_07_Telefonbuch_3\n\n";

   book_type book;
   load_entries(book);

   for (string s;;)
   {
      cout << "\nBitte waehlen Sie eine Aktion: \n"
         << "- e : Programmende\n"
         << "- l : Alle Eintraege auflisten\n"
         << "- s : Nach Eintrag suchen\n"
         << "- n : Neuen Eintrag eingeben\n"
         << "> ";
      getline(cin, s);
      if (s.length() != 1) continue;
      cout << '\n';

      switch (s[0])
      {
      case 'e':
         if (save_entries(book))
         {
            cout << "\nAuf Wiedersehen\n";
            return 0;
         }
         break;
      case 'l':
         list_entries(book);
         break;
      case 's':
         search_entries(book);
         break;
      case 'n':
         new_entries(book);
         break;
      }
   }
}
