207 lines
5.6 KiB
C++
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";
|
|
}
|
|
}
|