161 lines
5.2 KiB
C++
161 lines
5.2 KiB
C++
#include <iostream>
|
|
#include <limits> // streamsize::max
|
|
#include "booking.cpp"
|
|
|
|
/* declaring X(option) generates:
|
|
- Ordered menu message entry
|
|
- Ordered Menu::State::option symbol
|
|
*/
|
|
#define MENU_ENTRIES \
|
|
X(RESERVE), \
|
|
X(CANCEL), \
|
|
X(CHECK), \
|
|
X(BREAK), \
|
|
X(FILTER_AVALIABLE), \
|
|
X(FILTER_RESERVED), \
|
|
X(FILTER_BROKEN), \
|
|
X(EXIT)
|
|
|
|
#include "menugen.cpp"
|
|
|
|
namespace Menu {
|
|
// generate enum
|
|
#define X(entry) entry
|
|
enum class State : StateType{
|
|
MENU = 0, // default state
|
|
MENU_ENTRIES,
|
|
COUNT // number of menu entries
|
|
};
|
|
#undef X
|
|
|
|
// generate menu message
|
|
constexpr auto generateMenuMessage() {
|
|
constexpr char menuMsg[] = "=== Ticket Booking System ===";
|
|
constexpr char dot[] = ". ";
|
|
constexpr char nl[] = "\n";
|
|
constexpr auto str = concat( nl, nl, menuMsg, nl,
|
|
#define X(entry) NumToString<static_cast<StateType>(State::entry)>::value, dot, #entry, nl
|
|
MENU_ENTRIES
|
|
#undef X
|
|
);
|
|
return str;
|
|
}
|
|
}
|
|
|
|
constexpr auto MENU_MSG = Menu::generateMenuMessage();
|
|
|
|
std::istream& operator>>(std::istream& is, Menu::State& state) {
|
|
if (!(is >> reinterpret_cast<Menu::StateType&>(state))) throw Booking::InvalidArgument();
|
|
return is;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os, Booking::seat_range r) {
|
|
if (r.second == r.first) os << " seat " << r.first << " is ";
|
|
else os << " seats " << r.first << "-" << r.second << " are ";
|
|
return os;
|
|
}
|
|
|
|
std::pair<int, int> getRange(std::istream& is) {
|
|
auto isEnd = [](char c) { return c == '\n' || c == EOF; };
|
|
try {
|
|
std::pair<Booking::seat_num, Booking::seat_num> output;
|
|
if (!(is >> output.first) || output.first < 1 || output.first > Booking::SEAT_CAPACITY)
|
|
throw Booking::InvalidSeat();
|
|
output.second = output.first;
|
|
while (!std::isdigit(is.peek())) {
|
|
char c = is.get();
|
|
if (c == '-') break;
|
|
if (isEnd(c)) return output;
|
|
if (!std::iswspace(c)) throw Booking::InvalidSeat();
|
|
}
|
|
if (!(is >> output.second) || output.second < 1 || output.second > Booking::SEAT_CAPACITY)
|
|
throw Booking::InvalidSeat();
|
|
char c = is.peek();
|
|
if (isEnd(c)) {
|
|
is.get(); // clear newline or eof
|
|
if (output.first > output.second)
|
|
std::swap(output.first, output.second);
|
|
return output;
|
|
}
|
|
while (std::iswspace(c - is.get())) if (isEnd(c)) return output;
|
|
throw Booking::InvalidSeat(); // unexpected character
|
|
} catch(...) {
|
|
throw Booking::InvalidSeat();
|
|
}
|
|
}
|
|
|
|
int main(int ragc, char* argv[]) {
|
|
std::ostream& os = std::cout;
|
|
std::istream& is = std::cin;
|
|
Menu::State state = Menu::State::MENU;
|
|
Booking::Booker h;
|
|
Booking::seat_range range;
|
|
|
|
for (;;) try {
|
|
state = Menu::State::MENU;
|
|
os << Menu::BOLDWHITE << MENU_MSG << Menu::RESET << Menu::CURSOR; is >> state;
|
|
|
|
switch (state) {
|
|
|
|
case Menu::State::RESERVE:
|
|
os << "Seat(s) to be reserved:\n" << Menu::CURSOR;
|
|
range = getRange(is);
|
|
// for (Booking::seat_num i = range.first; i <= range.second; ++i) h.reserveSeat(i);
|
|
h.reserveSeat(range);
|
|
os << Menu::GREEN << range << "reserved\n" << Menu::RESET;
|
|
break;
|
|
|
|
case Menu::State::CANCEL:
|
|
os << "Seat(s) to be cancelled:\n" << Menu::CURSOR;
|
|
range = getRange(is);
|
|
h.cancelSeat(range);
|
|
os << Menu::GREEN << range << "cancelled\n" << Menu::RESET;
|
|
break;
|
|
|
|
case Menu::State::BREAK:
|
|
os << "Seat(s) to be broken:\n" << Menu::CURSOR;
|
|
range = getRange(is);
|
|
h.breakSeat(range, os, Menu::RED);
|
|
os << Menu::RESET << range << "broken";
|
|
break;
|
|
|
|
case Menu::State::CHECK:
|
|
os << "Seat(s) to be checked:\n" << Menu::CURSOR;
|
|
range = getRange(is);
|
|
h.print(range, os);
|
|
break;
|
|
|
|
|
|
case Menu::State::FILTER_BROKEN:
|
|
os << "Avaliable seats are: ";
|
|
h.filter([](const Booking::Seat& s) -> bool { return s.s == Booking::Seat::Status::BROKEN; }, os);
|
|
break;
|
|
|
|
case Menu::State::FILTER_AVALIABLE:
|
|
os << "Avaliable seats are: ";
|
|
h.filter([](const Booking::Seat& s) -> bool { return s.s == Booking::Seat::Status::AVALIBLE; }, os);
|
|
break;
|
|
|
|
case Menu::State::FILTER_RESERVED:
|
|
os << "Reserved seats are: ";
|
|
h.filter([](const Booking::Seat& s) -> bool { return s.s == Booking::Seat::Status::RESERVED; }, os);
|
|
break;
|
|
|
|
case Menu::State::EXIT:
|
|
os << "Exiting...\n";
|
|
return EXIT_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
throw Booking::InvalidArgument();
|
|
}
|
|
} catch (Booking::BookingException& e) {
|
|
os << Menu::RED << e.what() << Menu::RESET << "\n";
|
|
is.clear();
|
|
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
|
// return EXIT_FAILURE;
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|