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

#include <fstream>
#include <iostream>
#include "book.h"
#include "utils.h"
using namespace std;

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

void book::new_entry()
{
   cout << "Neuer Eintrag\n";

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

   if (name.empty())
   {
      cout << "Abbruch 'neuer Eintrag', da Name leer\n";
      return;
   }

   string lower_name(to_lower(name));
   if (entries_.count(lower_name) > 0)
   {
      cout << "Abbruch 'neuer Eintrag', da Name schon vorhanden\n";
      return;
   }

   entry& e = entries_[lower_name];
   e.input(name);
}

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

void book::edit_entry()
{
   string name;
   cout << "Bearbeiten von: ";
   getline(cin, name);

   if (name.empty())
   {
      cout << "- Abbruch\n";
      return;
   }

   string lower_name(to_lower(name));
   auto fit = entries_.find(lower_name);
   if (fit == cend(entries_))
   {
      cout << "- Name nicht vorhanden => Abbruch\n";
      return;
   }

   fit->second.edit();
   string new_lower_name(to_lower(fit->second.name()));
   if (new_lower_name != lower_name)
   {
      entries_.insert({new_lower_name, fit->second});
      entries_.erase(fit);
   }
}

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

void book::remove_entry()
{
   string name;
   cout << "Loeschen von: ";
   getline(cin, name);

   if (name.empty())
   {
      cout << "- Abbruch => nichts geloescht\n";
      return;
   }

   string lower_name(to_lower(name));
   auto fit = entries_.find(lower_name);
   if (fit == cend(entries_))
   {
      cout << "- Name nicht vorhanden => nichts geloescht\n";
      return;
   }

   if (ask_yes_no("Wollen Sie den Eintrag loeschen?"))
   {
      entries_.erase(fit);
      cout << "- Eintrag geloescht, noch " << entries_.size() << " Eintraege vorhanden.\n";
   }
}

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

void book::print() const
{
   cout << entries_.size() << " Eintraege:\n";
   for (auto& [name, numbers] : entries_)
   {
      numbers.print();
   }
}

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

void book::find_and_print() const
{
   string pattern;
   cout << "Suchen nach: ";
   getline(cin, pattern);

   string lower_pattern(to_lower(pattern));

   auto lower = entries_.lower_bound(lower_pattern);
   auto eit = cend(entries_);

   if (lower == eit || !starts_with(lower->first, lower_pattern))
   {
      cout << "\nKein Name im Telefonbuch beginnt mit \"" << pattern << "\".\n";
      return;
   }

   cout << "\nGefunden:\n";
   for (; lower != eit; ++lower)
   {
      if (!starts_with(lower->first, lower_pattern)) break;
      lower->second.print();
   }
}

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

void book::load(const string& filename)
{
   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;
   }

   int line = 0;
   do
   {
      entry e;
      e.load(in, line);
      if (in.fail()) break;
      string lower_name(to_lower(e.name()));
      entries_.insert({ lower_name, e });
   } while (!in.fail());
   if (!in.eof())
   {
      cout << "- Problem beim Lesen der Zeile " << line << '\n';
   }

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

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

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

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

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

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