#pragma once #include #include #include #include #include #include #include #include #include "menugen.cpp" namespace Booking { using seat_num = int64_t; using seat_range = std::pair; using uiBool = bool; class BookingException : public std::exception { public: const char* what() const noexcept override { return "Internal exception!"; } }; #define EXCEPTION(INTERNAL, EXTARNAL) \ class INTERNAL : public BookingException { \ const char* what() const noexcept override { return EXTARNAL; } \ }; EXCEPTION(AlreadyReserved, "Already reserved!") EXCEPTION(NotReserved, "Not reserved!") EXCEPTION(InvalidSeat, "Invalid seat number!"); EXCEPTION(InvalidArgument, "Invalid argument!") struct Seat { enum class Status { AVALIBLE, RESERVED, BROKEN }; enum class Type { VIP, REGULAR, CHEAP }; Status s = Status::AVALIBLE; Type t; std::string reservation_name; Seat(Type t) : t(t) {} }; class Booker { private: std::map< seat_num, Seat > seats; std::map< Seat::Type, std::stack< seat_num > > avaliables = {{Seat::Type::VIP, {}}, {Seat::Type::REGULAR, {}}, {Seat::Type::CHEAP, {}}}; std::map< Seat::Type, std::queue< std::string > > queues = {{Seat::Type::VIP, {}}, {Seat::Type::REGULAR, {}}, {Seat::Type::CHEAP, {}}}; std::stack< std::pair< seat_num, std::string > > cancellations; mutable std::shared_mutex m; public: Booker() { for (seat_num i = 0; i < 100; ++i) { seats.emplace(seats.size() + 1, Seat::Type::REGULAR); avaliables[Seat::Type::REGULAR].emplace(seats.size()); } for (seat_num i = 0; i < 1; ++i) { seats.emplace(seats.size() + 1, Seat::Type::VIP); avaliables[Seat::Type::VIP].emplace(seats.size()); } for (seat_num i = 0; i < 2; ++i) { seats.emplace(seats.size() + 1, Seat::Type::CHEAP); avaliables[Seat::Type::CHEAP].emplace(seats.size()); } } void reserveSeat(Seat::Type t, const std::string& name, std::ostream& os) { m.lock(); if (avaliables[t].size()) { seat_num s = avaliables[t].top(); avaliables[t].pop(); seats.at(s).s = Seat::Status::RESERVED; seats.at(s).reservation_name = name; os << "Seat " << s << " it now reserved" << std::endl; } else { queues[t].push(name); os << "All seats of this type occupied, youre " << queues[t].size() << " in queue" << std::endl; } m.unlock(); } void cancelSeat(std::ostream& os, std::string name) { m.lock(); bool c = false; for (auto& i : seats) { Seat& s = i.second; if (s.reservation_name != name) continue; c = true; cancellations.emplace(i.first, name); // check for waiting if (queues[s.t].empty()) { s.s = Seat::Status::AVALIBLE; s.reservation_name.clear(); avaliables[s.t].emplace(i.first); os << Menu::GREEN << "Reservation at " << i.first << " cancelled, noboady is waiting\n" << Menu::RESET << std::flush; } else { auto c = queues[s.t].front(); queues[s.t].pop(); s.reservation_name = c; os << Menu::GREEN << "Reservation at " << i.first << " cancelled" << Menu::RESET << ", " << c << " got the seat" << std::endl; } } if (!c) os << Menu::RED << "No reservation at this name found!\n" << Menu::RESET << std::flush; m.unlock(); } void print(std::ostream& os) const { m.lock_shared(); for (const auto& i : seats) { const Seat& s = i.second; seat_num n = i.first; std::string type; switch (s.t) { case Seat::Type::VIP: type = "VIP"; break; case Seat::Type::REGULAR: type = "Regular"; break; case Seat::Type::CHEAP: type = "Cheap"; break; } switch (s.s) { case Seat::Status::AVALIBLE: os << Menu::GREEN << type << " seat " << n << " is avaliable\n" << Menu::RESET << std::flush; break; case Seat::Status::RESERVED: os << Menu::YELLOW << type << " seat " << n << " is reserved" << Menu::RESET << " by \"" << s.reservation_name << "\"\n" << std::flush; break; case Seat::Status::BROKEN: os << Menu::RED << type << " seat " << n << " is broken\n" << Menu::RESET << std::flush; break; default: break; } } std::stack tmp = cancellations; os << "past cancellations:" << std::endl; while (tmp.size()) { auto i = tmp.top(); tmp.pop(); os << "seat " << i.first << " by " << i.second << std::endl; } m.unlock_shared(); } std::pair calculateSeatStatistics() const; std::vector getSortedClients() const; std::pair getHighestSeatReservation() const; void displaySeatsReversed(std::ostream& os) const; size_t countBookingsByClient(const std::string& name) const; size_t replaceClientName(const std::string& oldName, const std::string& newName); std::vector getVipClients() const; }; } std::ostream& operator<<(std::ostream& os, const Booking::Booker& b) { b.print(os); return os; }