TalTech_cpp/CT1/booking/booking.cpp

207 lines
5.6 KiB
C++

#include <iostream>
#include <vector>
#include <cstdint>
#include <limits>
#include <sstream>
#define RESET "\033[0m"
#define RED "❌ \033[31m"
#define GREEN "✅ \033[32m"
#define BOLDWHITE "\033[1m\033[37m"
constexpr const char* MENU_MSG = "=== Ticket Booking System ===\n1. Configure>\n2. Reserve\n3. Cancel\n4. Check\n5. Exit\n";
constexpr const char* REWRITE_WARNING_MSG = "WARNING: all reservations will be lost. Do you wish to continue? (0/1)\n";
constexpr const char* CURSOR_MSG = "> ";
using seat_num = uint64_t;
using uiBool = bool;
class BookingException : public std::exception {
public: const char* what() const noexcept override {
return "Internal exception!";
}
};
class AlreadyReserved : public BookingException {
const char* what() const noexcept override {
return "Already reserved!";
}
};
class NotReserved : public BookingException {
const char* what() const noexcept override {
return "Not reserved!";
}
};
class InvalidSeat : public BookingException {
const char* what() const noexcept override {
return "Invalid seat number!";
}
};
class InvalidArgument : public BookingException {
const char* what() const noexcept override {
return "Invalid argument!";
}
};
class NotConfigured : public BookingException {
const char* what() const noexcept override {
return "Not configured!";
}
};
enum class MenuState {
MENU,
SETUP = 1,
RESERVE = 2,
CANCEL = 3,
CHECK = 4,
EXIT = 5,
};
std::istream& operator>>(std::istream& is, MenuState& state) {
int a;
if (!(is >> a)) {
is.clear();
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
throw InvalidArgument();
}
state = static_cast<MenuState>(a);
return is;
}
template <class T>
T getInput(std::istream& is) {
T n;
if (!(is >> n) || n < 0) {
is.clear();
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
throw InvalidSeat();
}
return n;
}
template <>
uiBool getInput<uiBool>(std::istream& is) {
uint64_t n;
if (!(is >> n) || (n != 1 && n != 0)) {
is.clear();
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
throw InvalidArgument();
}
return n == 1;
}
class Seat { //TODO jmeno rezervace
private:
bool reserved;
public:
Seat() : reserved(false) {}
bool getState() {
return reserved;
}
bool setState(bool s) {
reserved = s;
return true;
}
};
class Booker {
public:
Booker() : inUse(false), configured(false) {};
Booker(seat_num capacity) : seats(capacity), inUse(false), configured(true) {}
~Booker() = default;
bool getSeatState(seat_num seat) {
if (!configured) throw NotConfigured();
if (seat >= seats.size()) throw InvalidSeat();
return seats.at(seat).getState();
}
bool reserveSeat(seat_num seat) {
if (!configured) throw NotConfigured();
if (seat >= seats.size()) throw InvalidSeat();
if (seats.at(seat).getState()) throw AlreadyReserved();
inUse = true;
return seats.at(seat).setState(true);
}
bool cancelSeat(seat_num seat) {
if (!configured) throw NotConfigured();
if (seat >= seats.size()) throw InvalidSeat();
if (!seats.at(seat).getState()) throw NotReserved();
return seats.at(seat).setState(false);
}
bool getInUse() { return inUse; }
private:
std::vector<Seat> seats;
bool inUse;
bool configured;
};
int main(int ragc, char* argv[]) {
std::ostream& os = std::cout;
std::istream& is = std::cin;
MenuState state = MenuState::MENU;
Booker h;
for (;;) {
try {
seat_num seat;
os << BOLDWHITE << MENU_MSG << RESET;
is >> state;
switch (state) {
case MenuState::SETUP :
if (h.getInUse()) {
os << REWRITE_WARNING_MSG << CURSOR_MSG;
if (!getInput<uiBool>(is)) break;
}
os << "Enter a number of avaliable seats: \n" << CURSOR_MSG;
seat = getInput<seat_num>(is);
h = Booker(seat);
os << GREEN << "New avaliable seat count: " << seat << "\n" << RESET;
break;
case MenuState::RESERVE :
os << "Seat to be reserved: ";
seat = getInput<seat_num>(is);
h.reserveSeat(seat);
os << GREEN << "Seat " << seat << " reserved\n" << RESET;
break;
case MenuState::CANCEL :
os << "Seat to be cancelled: ";
seat = getInput<seat_num>(is);
h.cancelSeat(seat);
os << GREEN << "Seat " << seat << " cancelled\n" << RESET;
break;
case MenuState::CHECK :
os << "Seat to be checked: ";
seat = getInput<seat_num>(is);
if (h.getSeatState(seat))
os << RED << "Seat " << seat << " is reserved\n" << RESET;
else
os << GREEN << "Seat " << seat << " is avaliable\n" << RESET;
break;
case MenuState::EXIT :
os << "Exiting...\n";
return EXIT_SUCCESS;
break;
case MenuState::MENU :
default:
throw InvalidArgument();
}
} catch (BookingException& e) {
os << RED << e.what() << RESET;
// return EXIT_FAILURE;
}
state = MenuState::MENU;
os << "\n\n";
}
}