166 lines
6.0 KiB
C++
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;
|
|
} |