#include #include #include #include #include #include using namespace std; /** * \brief ask a question and get a answer. * \tparam T return parameter * \param question the question. * \return the value. */ template T ask_question(const string& question) { cout << question << ": "; T value; cin >> value; return value; } /** * \brief Returns true if answer was 'J'. False if user answered with 'N' * \param question The question for user input. * \return */ bool ask_question(const string& question) { while (true) { const auto answer = ask_question(question + " (J/N)"); if (answer == 'j' || answer == 'J') { return true; } if (answer == 'n' || answer == 'N') { return false; } cout << "Ungueltige Eigabe. Bitte noch einmal versuchen!"; } } /** * \brief Converts a int to string and fill up with '0' at first position. * \param value the integer value. * \param digits Number of digits to fill * \return Formatted integer as string */ string int_to_string(const unsigned int value, const unsigned int digits = 0) { auto str = to_string(value); const auto len = digits > str.length() ? digits - str.length() : 0; for (unsigned int i = 0; i < len; ++i) { str.insert(0, "0"); } return str; } /** * \brief Present a date with day, month and year */ class date final { unsigned short day_; unsigned short month_; unsigned short year_; int day_num_; /** * \brief Get the day number from current day/month/year. * \return Number of days */ int day_number_from_date() const { const auto month = (month_ + 9) % 12; const auto year = year_ - month / 10; return 365 * year + year / 4 - year / 100 + year / 400 + (month * 306 + 5) / 10 + (day_ - 1); } public: date(const unsigned short day, const unsigned short month, const unsigned short year) : day_(day), month_(month), year_(year), day_num_( day_number_from_date()) { } /** * \brief Get day num of current day/month/year * \return Number of days */ int get_day_num() const { return day_num_; } /** * \brief Output operator of date formatted as DD.MM.YYYY * \param ostr output stream * \param date current date * \return output stream */ friend ostream& operator<<(ostream& ostr, const date& date) { ostr << int_to_string(date.day_, 2) << "." << int_to_string(date.month_, 2) << "." << int_to_string(date.year_, 4); return ostr; } }; /** * \brief address containing street, no, postal code and city */ class address final { string street_; string street_no_; string postal_code_; string city_; public: address() = default; address(const string&& street, const string&& street_no, const string&& postal_code, const string&& city) : street_(street), street_no_(street_no), postal_code_(postal_code), city_(city) { } /** * \brief Input operator of address * \param istr output stream * \param address current address * \return output stream */ friend istream& operator>>(istream& istr, address& address) { cout << "Strasse: "; istr >> address.street_; cout << "Hausnummer: "; istr >> address.street_no_; cout << "Postleitzahl: "; istr >> address.postal_code_; cout << "Ort: "; istr >> address.city_; return istr; } /** * \brief Output operator of address * \param ostr output stream * \param address current address * \return output stream */ friend ostream& operator<<(ostream& ostr, const address& address) { ostr << "Strasse: " << address.street_ << endl; ostr << "Hausnummer: " << address.street_no_ << endl; ostr << "Postleitzahl: " << address.postal_code_ << endl; ostr << "Ort: " << address.city_ << endl; return ostr; } }; /** * \brief Incremental raised number as id for customer. */ int next_customer_id; /** * \brief Customer, represented by name, first name, address, phone and year of birth */ class customer final { int id_; string name_; string first_name_; address address_; unsigned short year_of_birth_ = 1900; string phone_no_; bool has_driving_license_ = false; public: customer() : id_(++next_customer_id) { } customer(string&& name, string&& first_name, address&& address, unsigned short&& year_of_birth, string&& phone_no, bool&& has_driving_license) : id_(++next_customer_id), name_(name), first_name_(first_name), address_(address), year_of_birth_(year_of_birth), phone_no_(phone_no), has_driving_license_(has_driving_license) { } /** * \brief Input operator of customer * \param istr input stream * \param customer current address instance * \return output stream */ friend istream& operator>>(istream& istr, customer*& customer) { cout << "Name: "; istr >> customer->name_; cout << "Vorname: "; istr >> customer->first_name_; cout << "Geburtsjahr: "; istr >> customer->year_of_birth_; istr >> customer->address_; cout << "Telefonnumer: "; istr >> customer->phone_no_; customer->has_driving_license_ = ask_question("Fuehrerschein der Klasse A?"); return istr; } /** * \brief Output operator of customer * \param ostr output stream * \param customer current customer instance * \return output stream */ friend ostream& operator<<(ostream& ostr, const customer& customer) { ostr << "Name: " << customer.name_ << endl; ostr << "Vorname: " << customer.first_name_ << endl; ostr << "Geburtsjahr: " << customer.year_of_birth_ << endl; ostr << customer.address_; ostr << "Telefonnummer: " << customer.phone_no_ << endl; ostr << "Fuehrerschein " << (customer.has_driving_license_ ? "" : "nicht ") << "vorhanden." << endl; return ostr; } /** * \brief get name of customer * \return name */ string get_name() const { return name_; } /** * \brief get first name of customer * \return first name */ string get_first_name() const { return first_name_; } /** * \brief get the value, if customer hast driving license * \return True if customer hast driving license. False otherwise. */ bool get_has_driving_license() const { return has_driving_license_; } }; /** * \brief Incremental raised number as id for a reservation. */ int next_reservation_id; /** * \brief Reservation of a motorcycle */ class reservation final { int id_; date start_; date end_; short motorcycle_index_ = -1; // => -1 means nothing reserved customer* customer_; bool canceled_; public: reservation(const date start, const date end, const short motorcycle, customer* customer) : id_(++next_reservation_id), start_(start), end_(end), motorcycle_index_(motorcycle), customer_(customer), canceled_(false) { } /** * \brief get start date of reservation * \return date instance */ date get_start_date() const { return start_; } /** * \brief get end date of reservation * \return date instance */ date get_end_date() const { return end_; } /** * \brief get index of motorcycle array * \return integer value of index */ short get_motorcycle_index() const { return motorcycle_index_; } /** * \brief get pointer of customer, attached to this instance * \return pointer to customer */ customer* get_customer() const { return customer_; } /** * \brief Cancel reservation -> Give Motorcycle to the customer */ void cancel_reservation() { canceled_ = true; } /** * \brief Get Id of the item * \return Auto-incremented id as integer */ int get_id() const { return id_; } /** * \brief get cancellation status of the reservation * \return True is canceled. False otherwise. */ bool get_cancellation() const { return canceled_; } }; /** * \brief All available motorcycles */ string motorcycles[] = { "Suzuki Bandit", "Honda TransAlp", "BMW F 650 GS", "Kawasaki ZZR1400" }; /** * \brief Collection of customer-pointers */ list customers; /** * \brief Collection of reservation pointers. */ list reservations; /** * \brief Creates a new customer, let the user check the input and push it on the list. */ void create_customer(); void create_reservation(); void rent_a_motorcycle(); void export_reservations(); void main_menu(); /** * \brief Main entry method. Starts the main menu. * \return success code */ int main() { main_menu(); return 0; } /** * \brief Let the user choice an option. */ void main_menu() { try { while (true) { system("cls"); cout << "Motorradvermietung (" << reservations.size() << " Reservierungen; " << customers.size() << " Kunden)" << endl << endl; cout << "Bitte w\x84hlen Sie eine Option:" << endl; cout << "1: Neuen Kunden anlegen" << endl; cout << "2: Erstellen einer Reservierung" << endl; cout << "3: Motorrad herausgeben" << endl; cout << "4: Reservierungen exportieren" << endl; cout << endl; cout << "0: Programm beenden" << endl; const auto input = ask_question("Ihre Eingabe"); switch (input) { case 1: create_customer(); break; case 2: create_reservation(); break; case 3: rent_a_motorcycle(); break; case 4: export_reservations(); break; case 0: { return; } default: cout << "Unerlaubte Eingabe" << endl; system("pause"); } } } catch (...) { cout << "Etwas unvorhergesehendes ist passiert. Tut mir leid." << endl; system("pause"); } } /** * \brief Creates a new customer, let the user check the input and push it on the list. */ void create_customer() { while (true) { system("cls"); cout << "Neuen Kunden anlegen" << endl; cout << "------------------------------------" << endl; auto c = new customer; cin >> c; cout << endl << endl; cout << *c; if (ask_question("Angaben korrekt?")) { customers.push_back(c); return; } } } /** * \brief Finds customers by last name * \param name Last name * \return Returns a vector of customers with the same last name */ vector find_customers_by_name(const string& name) { vector result; for (auto customer : customers) { if (customer->get_name() == name) { result.push_back(customer); } } return result; } /** * \brief Find the first customer by first name. * \param filtered_customers A vector of customers with the same last name * \param first_name The first name * \return The first customer with the matching first name. If no customer found, it returns a nullptr */ customer* find_customer_by_first_name(const vector& filtered_customers, const string& first_name) { for (auto c : filtered_customers) { if (c->get_first_name() == first_name) { return c; } } return nullptr; } /** * \brief Gets the validated date * \param question Question to ask the user * \return A date object. */ date get_validated_date(const string&& question) { while (true) { auto date_as_string = ask_question(question + " (tt.mm.jjjj)"); auto day = 0, month = 0, year = 0; const auto res = sscanf_s(date_as_string.c_str(), "%2d.%2d.%4d", &day, &month, &year); if (res == 3 && (month >= 1 && month <= 12) && (day >= 1 && day <= 31) && (year >= 1900 && month <= 2200)) { return date{ static_cast(day), static_cast(month), static_cast(year) }; } cout << "Fehlerhafte Eingabe." << endl; } } /** * \brief * \return */ int select_motorcycle() { while (true) { cout << "Bitte w\x84hlen sie ein Motorrad aus:" << endl; auto index = 0; for (const auto& cycle : motorcycles) { cout << ++index << ": " << cycle << endl; } const auto answer = ask_question("Auswahl"); if (answer > 0 && answer <= index) { return answer - 1; } cout << "Ung\x81ltige Eingabe" << endl << endl; } } bool validate_reservation(reservation* const reservation) { const auto start_sum = reservation->get_start_date().get_day_num(); const auto end_sum = reservation->get_end_date().get_day_num(); for (auto r : reservations) { if (r->get_motorcycle_index() == reservation->get_motorcycle_index()) { if (start_sum < r->get_end_date().get_day_num() && end_sum > r->get_start_date().get_day_num() || end_sum > r->get_start_date().get_day_num() && end_sum < r->get_end_date().get_day_num()) { return false; } } } return true; } customer* get_customer() { const auto name = ask_question("Name des Kunden"); auto customers = find_customers_by_name(name); if (customers.size() > 1) { const auto first_name = ask_question("Vorname des Kunden"); return find_customer_by_first_name(customers, first_name); } if (customers.empty()) { return nullptr; } return customers.front(); } void create_reservation() { system("cls"); const auto current = get_customer(); if (current == nullptr) { cout << "Kunde nicht gefunden" << endl; system("pause"); return; } cout << "Kunde gefunden: " << current->get_first_name() << " " << current->get_name() << endl; if (!current->get_has_driving_license()) { cout << "Der Kunde hat keinen entsprechenden Fuehrerschein." << endl; system("pause"); return; } const auto start_date = get_validated_date("Startdatum"); const auto end_date = get_validated_date("Enddatum"); const auto motorcycle = select_motorcycle(); const auto r = new reservation(start_date, end_date, motorcycle, current); if (validate_reservation(r)) { reservations.push_back(r); } else { cout << "Reservierung konnte nicht angelegt werden." << endl; cout << "Die Zeitperiode ueberschneidet sich mit einer vorhandenen Reservierung" << endl; system("pause"); } } reservation* get_reservation_for_customer(customer* const current_customer) { auto index = 0; vector reservations_of_customer; for (auto reservation : reservations) { if (reservation->get_customer() == current_customer) { cout << ++index << ". " << reservation->get_start_date() << " - " << reservation->get_end_date() << ": " << motorcycles[reservation->get_motorcycle_index()] << endl; reservations_of_customer.push_back(reservation); } } index = ask_question("Waehlen Sie eine Reservierung aus"); return reservations_of_customer[index - 1]; } void rent_a_motorcycle() { system("cls"); const auto current = get_customer(); if (current == nullptr) { cout << "Kunde nicht gefunden" << endl; system("pause"); return; } auto r = get_reservation_for_customer(current); const auto cancel_reservation = ask_question("Motorrad ausgeben?"); cout << endl; if (cancel_reservation) { r->cancel_reservation(); cout << "Motorrad reserviert!" << endl; } else { cout << "Reservierung abgebrochen" << endl; } system("pause"); } string current_date_time() { auto t = time(nullptr); struct tm buf{}; localtime_s(&buf, &t); const auto time = int_to_string(buf.tm_hour, 2) + ":" + int_to_string(buf.tm_min, 2) + ":" + int_to_string(buf.tm_sec, 2); const auto date = int_to_string(buf.tm_mday, 2) + "." + int_to_string(1 + buf.tm_mon, 2) + "." + int_to_string(1900 + buf.tm_year, 4); return date + " " + time; } void export_reservations() { ofstream f; f.open("reservierungen.txt", ios::app); f << "Export (" << current_date_time() << ")" << endl; f << "Id;Motorcycle;Start;End;Name;First_Name;Cancelled" << endl; for (auto reservation : reservations) { f << reservation->get_id() << ";"; f << motorcycles[reservation->get_motorcycle_index()] << ";"; f << reservation->get_start_date() << ";"; f << reservation->get_end_date() << ";"; f << reservation->get_customer()->get_name() << ";"; f << reservation->get_customer()->get_first_name() << ";"; f << (reservation->get_cancellation() ? "True" : "False") << endl; } f << "------------" << endl; f.close(); }