TalTech_cpp/CT4/booking.cpp

166 lines
6.0 KiB
C++

#pragma once
#include <cstdint>
#include <ostream>
#include <algorithm>
#include <functional>
#include <map>
#include <queue>
#include <stack>
#include <shared_mutex>
#include "menugen.cpp"
namespace Booking {
using seat_num = int64_t;
using seat_range = std::pair<seat_num, seat_num>;
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<size_t, size_t> calculateSeatStatistics() const;
std::vector<std::string> getSortedClients() const;
std::pair<seat_num, std::string> 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<std::string> getVipClients() const;
};
}
std::ostream& operator<<(std::ostream& os, const Booking::Booker& b) {
b.print(os);
return os;
}