#include #include // 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(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(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 getRange(std::istream& is) { auto isEnd = [](char c) { return c == '\n' || c == EOF; }; try { std::pair 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); 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::max(), '\n'); // return EXIT_FAILURE; } return EXIT_SUCCESS; }