Summary Files Commits Branches @commit @diff @stats
path: root / Year 1 / Object-oriented Programming / Project 1 / src
diff options
context:
space:
mode:
Commit24bdf39e6c21ab846f6c86803761d78a094e05c0 (patch)
Author
 Syndamia <kamen.d.mladenov@protonmail.com>
2022-05-26 20:31:26 +0300
Committer
 Syndamia <kamen.d.mladenov@protonmail.com>
2022-05-26 20:31:26 +0300
Files1b2077b088098cc7ae6afc946b10a4d680110294 /Year 1/Object-oriented Programming/Project 1/src
uni-projects-24bdf39e6c21ab846f6c86803761d78a094e05c0.tar
uni-projects-24bdf39e6c21ab846f6c86803761d78a094e05c0.tar.gz
uni-projects-24bdf39e6c21ab846f6c86803761d78a094e05c0.zip
Parentcbe944835cc0951a946d01f034b4d28ff9874a4e (diff)
Added files from project 1 (mirror)
28 files changed, 2881 insertions, 0 deletions
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Command.cpp24
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Command.h27
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Menu.cpp135
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Menu.h46
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Toolbox.cpp223
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Toolbox.hpp115
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Generic/Date/Date.cpp174
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Generic/Date/Date.h59
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Generic/List/List.hpp345
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Generic/List/OrderedList.hpp55
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Generic/String/String.cpp169
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Generic/String/String.h56
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Models/Event.cpp153
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Models/Event.h63
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Models/Hall.cpp76
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Models/Hall.h47
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Models/Reservation.cpp79
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Models/Reservation.h50
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Models/Ticket.cpp71
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Models/Ticket.h41
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Services/EventService.cpp369
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Services/EventService.h65
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Services/HallService.cpp42
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Services/HallService.h30
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/Services/StatusCode.h35
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/UserInterface/FMITicketSystemConsoleUI.cpp295
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/UserInterface/FMITicketSystemConsoleUI.h14
-rw-r--r--Year 1/Object-oriented Programming/Project 1/src/main.cpp23
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Command.cpp b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Command.cpp
new file mode 100644
index 0000000..c14bcc8
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Command.cpp
@@ -0,0 +1,24 @@
+#include "Command.h"
+#include <cstring>
+
+Command::Command() : Command("", nullptr) {}
+
+/*! \param nameInMenu C-style string, class stores at most 255 characters (last character is always terminating zero)
+ * \param exec Function pointer that will be executed when run() is called. Can be nullptr.
+ */
+Command::Command(const char* nameInMenu, void (*exec)()) {
+ strncpy(this->nameInMenu, nameInMenu, 255);
+ this->nameInMenu[255] = '\0';
+ this->exec = exec;
+}
+
+/*! Executes the stored function pointer, when it's not nullptr. Otherwise does nothing.
+ */
+void Command::run() const {
+ if (exec != nullptr)
+ exec();
+}
+
+const char* Command::get_nameInMenu() const {
+ return nameInMenu;
+}
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Command.h b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Command.h
new file mode 100644
index 0000000..f1eb55b
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Command.h
@@ -0,0 +1,27 @@
+#ifndef HEADER_CONSOLEINTERFACE_COMMAND
+#define HEADER_CONSOLEINTERFACE_COMMAND
+
+/*! \file Command.h
+ * \brief Stores the declaration of class Command
+ */
+
+/*! \brief Stores a 256 character name and a function pointer to be executed when calling run()
+ *
+ * Menu uses this class for a more generic implementation of it's navigate function.
+ */
+class Command {
+ char nameInMenu[256];
+ void (*exec)();
+
+public:
+ //! Leaves name empty and exec function pointer to nullptr
+ Command();
+ //! Copies contents of nameInMenu and stores exec
+ Command(const char* nameInMenu, void (*exec)());
+ //! Executes the stored function pointer
+ void run() const;
+
+ const char* get_nameInMenu() const;
+};
+
+#endif
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Menu.cpp b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Menu.cpp
new file mode 100644
index 0000000..3ab857e
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Menu.cpp
@@ -0,0 +1,135 @@
+#include "Menu.h"
+#include "Toolbox.hpp"
+#include <cstring>
+
+Menu::Menu() : Menu("Menu", false, false) {}
+
+/*! \param title C-style string, class stores at most 255 characters (last character is always terminating zero)
+ * \param backExistsApp Flag whether or not to list the 0-th option as "Exit", rather than "Go Back"
+ * \param isSubMenu Flag whether or not to show the title as a subTitle or not
+ */
+Menu::Menu(const char* title, bool backExistsApp, bool isSubMenu) : menuOptions() {
+ this->backExistsApp = backExistsApp;
+ this->isSubMenu = isSubMenu;
+ strncpy(this->title, title, 255);
+ this->title[255] = '\0';
+}
+
+/*! \param title C-style string, class stores at most 255 characters (last character is always terminating zero)
+ * \param backExistsApp Flag whether or not to list the 0-th option as "Exit", rather than "Go Back"
+ * \param isSubMenu Flag whether or not to show the title as a subTitle or not
+ * \param commands Pointer to an array of Command instances
+ * \param commandCount Number of elements that "commands" points to
+ */
+Menu::Menu(const char* title, bool backExistsApp, bool isSubMenu, const Command* commands, unsigned commandCount) {
+ this->backExistsApp = backExistsApp;
+ this->isSubMenu = isSubMenu;
+ menuOptions = List<Command>(commands, commandCount);
+ strncpy(this->title, title, 255);
+ this->title[255] = '\0';
+}
+
+void Menu::addCommand(const Command& command) {
+ menuOptions.add(command);
+}
+
+enum MessageType {
+ NoPrint,
+ Success,
+ Warning,
+ Error,
+};
+const char* msg;
+MessageType msgType;
+
+/*! \param message C-style string, saves to pointer for later reuse when showing the message.
+ *
+ * Stores the message pointer in a global variable (in the cpp file) and
+ * sets it's type as an Error in another global variable (in the cpp file).
+ *
+ * The next time the whole Menu is shown, the message will appear below the title.
+ */
+void Menu::registerError(const char* message) const {
+ msg = message;
+ msgType = Error;
+}
+
+/*! \param message C-style string, saves to pointer for later reuse when showing the message.
+ *
+ * Stores the message pointer in a global variable (in the cpp file) and
+ * sets it's type as a Warning in another global variable (in the cpp file).
+ *
+ * The next time the whole Menu is shown, the message will appear below the title.
+ */
+void Menu::registerWarning(const char* message) const {
+ msg = message;
+ msgType = Warning;
+}
+
+/*! \param message C-style string, saves to pointer for later reuse when showing the message.
+ *
+ * Stores the message pointer in a global variable (in the cpp file) and
+ * sets it's type as Success in another global variable (in the cpp file).
+ *
+ * The next time the whole Menu is shown, the message will appear below the title.
+ */
+void Menu::registerSuccess(const char* message) const {
+ msg = message;
+ msgType = Success;
+}
+
+/*!
+ * Prints the title, then an Error/Warning/Sucess message (if set),
+ * prints all command names as an ordered list (starting from 1),
+ * waits for user input to select one of those commands (by list number)
+ * and finally executes the appropriate command's run() function.
+ *
+ * After the run() function exists, everything is reprinted.
+ * The 0 list index is always "Go Back"/"Exit" and it always stops the reprinting loop.
+ *
+ * If there are no commands, prints "Menu is empty!".
+ * If user input doesn't correspond to any command, registers an error message and reprints.
+ */
+void Menu::navigate() const {
+ if (menuOptions.get_count() == 0) {
+ printLine("Menu is empty!");
+ return;
+ }
+
+ unsigned buffer = 1; // We immedeately read the value of buffer, so this is fine
+
+ while (buffer != 0) {
+ clear();
+ if (isSubMenu)
+ subTitleBox(title);
+ else
+ titleBox(title);
+
+ switch(msgType) {
+ case Error: errorBox(msg); msgType = NoPrint; break;
+ case Warning: warningBox(msg); msgType = NoPrint; break;
+ case Success: successBox(msg); msgType = NoPrint; break;
+ case NoPrint: printLine(""); break;
+ }
+ printLine("");
+
+ resetOrderedList(0);
+ if (backExistsApp)
+ printOrderedListElem("Exit");
+ else
+ printOrderedListElem("Go Back");
+
+ for (unsigned i = 0; i < menuOptions.get_count(); i++)
+ printOrderedListElem(menuOptions[i].get_nameInMenu());
+
+ _printInputBoxLabel("Execute No [0-");
+ print(menuOptions.get_count());
+ print("]: ");
+ read(buffer);
+
+ if (buffer > menuOptions.get_count())
+ registerError("Invalid menu option!");
+ else if (buffer > 0)
+ menuOptions[buffer - 1].run();
+ }
+}
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Menu.h b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Menu.h
new file mode 100644
index 0000000..e0ea685
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Menu.h
@@ -0,0 +1,46 @@
+#ifndef HEADER_CONSOLEINTERFACE_MENU
+#define HEADER_CONSOLEINTERFACE_MENU
+
+/*! \file Menu.h
+ * \brief Stores the declaration of class Menu
+ */
+
+#include "Command.h"
+#include "../List/List.hpp"
+
+/*! \brief Handles navigation between multiple commands
+ *
+ * Shows the title, then below it an Error/Warning/Success message if set,
+ * lists all command options as an enumerated list, takes command index
+ * and calls the chosen command's run() function.
+ */
+class Menu {
+ char title[256];
+ List<Command> menuOptions;
+
+ bool backExistsApp;
+ bool isSubMenu;
+
+public:
+ //! Sets name as "Menu", leaves all flags to false and creates an empty Command list
+ Menu();
+ //! Copies title, saves flags and creates and empty Command list
+ Menu(const char* title, bool backExistsApp, bool isSubMenu);
+ //! Copies title, saves flags and copies commands
+ Menu(const char* title, bool backExistsApp, bool isSubMenu, const Command* commands, unsigned commandCount);
+
+ //! Adds a command to the internal Command list
+ void addCommand(const Command& command);
+
+ //! Tell Menu to show an error message next time it prints
+ void registerError(const char* message) const;
+ //! Tell Menu to show a warning message next time it prints
+ void registerWarning(const char* message) const;
+ //! Tell Menu to show a success message next time it prints
+ void registerSuccess(const char* message) const;
+
+ //! Lists commands and after user input executes an appropriate command run() function
+ void navigate() const;
+};
+
+#endif
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Toolbox.cpp b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Toolbox.cpp
new file mode 100644
index 0000000..ca83b3b
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Toolbox.cpp
@@ -0,0 +1,223 @@
+#include "Toolbox.hpp"
+
+/*!
+ * Erases display and moves cursor to top left corner via ANSI escape sequences: \c ESC[2J \c ESC[1;1H
+ *
+ * \warning Not all terminals support any or all ANSI escape sequences
+ *
+ * \note Source: https://stackoverflow.com/a/52895729/12036073
+ */
+void clear() {
+ std::cout << u8"\033[2J\033[1;1H";
+}
+
+/*!
+ * Sub boxes are like normal boxes, but indented with 4 spaces.
+ */
+void _printSubBoxSpacing() {
+ std::cout << " ";
+}
+
+/* Title boxes */
+
+/*! \param title C-style string, there are no size checks so it could wrap
+ *
+ * Prints the title, surrounded by "===".
+ */
+void titleBox(const char* title) {
+ std::cout << std::endl << "=== " << title << " ===" << std::endl;
+}
+
+/*! \param title C-style string, there are no size checks so it could wrap
+ *
+ * Prints the title, surrounded by "---".
+ */
+void subTitleBox(const char* title) {
+ std::cout << std::endl << "--- " << title << " ---" << std::endl;
+}
+
+/* Status boxes */
+
+/*! \param message C-style string, there are no size checks so it could wrap
+ *
+ * Success boxes start with "<S>" and print the message.
+ *
+ * \remark Success/Warning/Error boxes start with "<C>" where C is an appropriate character.
+ */
+void successBox(const char* message) {
+ std::cout << "<S> " << message << std::endl;
+}
+
+/*!
+ * \copydetails successBox()
+ * \sa _printSubBoxSpacing()
+ */
+void successSubBox(const char* message) {
+ _printSubBoxSpacing();
+ successBox(message);
+}
+
+/*! \param message C-style string, there are no size checks so it could wrap
+ *
+ * Warning boxes start with "<W>" and print the message.
+ *
+ * \remark Success/Warning/Error boxes start with "<C>" where C is an appropriate character.
+ */
+void warningBox(const char* message) {
+ std::cout << "<W> " << message << std::endl;
+}
+
+/*!
+ * \copydetails warningBox()
+ * \sa _printSubBoxSpacing()
+ */
+void warningSubBox(const char* message) {
+ _printSubBoxSpacing();
+ warningBox(message);
+}
+
+/*! \param message C-style string, there are no size checks so it could wrap
+ *
+ * Error boxes start with "<E>" and print the message.
+ *
+ * \remark Success/Warning/Error boxes start with "<C>" where C is an appropriate character.
+ */
+void errorBox(const char* message) {
+ std::cout << "<E> " << message << std::endl;
+}
+
+/*!
+ * \copydetails errorBox()
+ * \sa _printSubBoxSpacing()
+ */
+void errorSubBox(const char* message) {
+ _printSubBoxSpacing();
+ errorBox(message);
+}
+
+/* Input line boxes */
+
+/*! \param label C-style string, there are no size checks so it could wrap
+ *
+ * Prints "(+)" and then the given label.
+ * It doesn't create spacing after label, so it should exist in the label itself.
+ *
+ * \remark Semi-internal means the function is defined in the header out of necessity (for templated functions)
+ */
+void _printInputBoxLabel(const char* label) {
+ std::cout << "(+) " << label;
+}
+
+void __inputLineBoxGetInput(char* output, unsigned maxWidth, bool ignore) {
+ if (ignore)
+ std::cin.ignore();
+ std::cin.getline(output, maxWidth);
+}
+
+/*! \param label C-style string, there are no size check so it could wrap
+ * \param output Pointer to a char array
+ * \param maxWidth Maximum count of characters to read from user input. output MUST be able to hold that many characters!
+ * \param ignore Whether or not to ignore the first new-line delimiter.
+ * true by default, should be set to false only when an inputLineBox/SubBox has been issued directly prior or when it's the very first issued box command.
+ *
+ * Prints "(+)" before the label.
+ */
+void inputLineBox(const char* label, char* output, unsigned maxWidth, bool ignore) {
+ _printInputBoxLabel(label);
+ __inputLineBoxGetInput(output, maxWidth, ignore);
+}
+
+/*!
+ * \copydetails inputLineBox()
+ * \sa _printSubBoxSpacing()
+ */
+void inputLineSubBox(const char* label, char* output, unsigned maxWidth, bool ignore) {
+ _printSubBoxSpacing();
+ _printInputBoxLabel(label);
+ __inputLineBoxGetInput(output, maxWidth, ignore);
+}
+
+/*! \param ignore Whether or not to ignore the first new-line delimiter.
+ * true by default, should be set to false only when an inputLineBox/SubBox has been issued directly prior or when it's the very first issued box command.
+ *
+ * Prints a "Press enter to continue" message and waits for the user
+ */
+void pressEnterToContinue(bool ignore) {
+ char tmp;
+ inputLineBox("[Press enter to continue]", &tmp, 1, ignore);
+}
+
+/* Ordered list */
+
+int orderedListIndex = 1;
+
+/*!
+ * Prints the latests ordered list index, surrounded by square brackets, and increments the ordered list index.
+ *
+ * \remark There are no size checks, so list index could overflow.
+ *
+ * \remark Semi-internal means the function is defined in the header out of necessity (for templated functions)
+ */
+
+void _printOrderedListBeginning() {
+ std::cout << "[" << orderedListIndex++ << "] ";
+}
+
+/*! \param starter Sets the starting number by which ordered list will enumerate
+ *
+ * \remark Although starter can be a negative number, ordered list will always increment up the number.
+ */
+void resetOrderedList(int starter) {
+ orderedListIndex = starter;
+}
+
+/* Table */
+
+void __printTableHeaderNumber(unsigned number) {
+ std::cout << ":" << ((number < 100) ? " " : "") << number << ((number < 10) ? " " : "");
+}
+
+void __printTableColumnHeader(unsigned start, unsigned count) {
+ std::cout << ": ";
+ for (unsigned i = 0; i < count; i++)
+ __printTableHeaderNumber(start++);
+ std::cout << ":" << std::endl;
+
+ for (unsigned i = 0; i <= count; i++)
+ std::cout << "====";
+ std::cout << "=" << std::endl;
+}
+
+void __printTableLine(unsigned columns) {
+ std::cout << ":===";
+ for (unsigned i = 0; i < columns; i++)
+ std::cout << "+---";
+ std::cout << ":" << std::endl;
+}
+
+/*! \param startNumber The number by which column and row enumeration begins
+ * \param columns How many columns the table should have
+ * \param items C-style string, each cell is a single character from the string
+ *
+ * Prints a string as a grid/table of characters from top to bottom, left to right.
+ * The first character is on the top left, the last one is on the bottom right.
+ *
+ * Table is printed until a terminating zero is encountered.
+ * The rows are "calculated" from the columns count and the items length.
+ */
+void table(unsigned startNumber, unsigned columns, const char* items) {
+ __printTableColumnHeader(startNumber, columns);
+
+ __printTableHeaderNumber(startNumber);
+ for (unsigned i = 0, colInd = 0, rowInd = 0; items[i] != '\0'; i++, (++colInd) %= columns) {
+ if (colInd == 0 && i != 0) {
+ std::cout << ":" << std::endl;
+ __printTableLine(columns);
+ __printTableHeaderNumber((++rowInd) + startNumber);
+ }
+
+ std::cout << ((colInd == 0) ? "║ " : "| ") << items[rowInd * columns + colInd] << " ";
+ }
+ std::cout << ":" << std::endl;
+}
+
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Toolbox.hpp b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Toolbox.hpp
new file mode 100644
index 0000000..91306cb
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Toolbox.hpp
@@ -0,0 +1,115 @@
+#ifndef HEADER_CONSOLEINTERFACE_TOOLBOX
+#define HEADER_CONSOLEINTERFACE_TOOLBOX
+
+#include <iostream>
+
+/*! \file Toolbox.hpp
+ * \brief Stores a wide range of functions for simpler/more automated printing.
+ *
+ * Adds a lot of functions for printing.
+ *
+ * \remark iostream is included by necessity (templated functions), you should only use the provided functions, if you can.
+ */
+
+#define MAX_LINE_WIDTH 1024
+
+//! Clears the console screen
+void clear();
+//! Prints a title box
+void titleBox(const char* title);
+//! Prints a title sub box
+void subTitleBox(const char* title);
+
+//! Prints a success box
+void successBox(const char* message);
+//! Prints a success box as a sub box
+void successSubBox(const char* message);
+//! Prints a warning box
+void warningBox(const char* message);
+//! Prints a warning box as a sub box
+void warningSubBox(const char* message);
+//! Prints an error box
+void errorBox(const char* message);
+//! Prints an error box as a sub box
+void errorSubBox(const char* message);
+
+//! Prints label, gets a whole line of input and stores it to output
+void inputLineBox(const char* label, char* output, unsigned maxWidth, bool ignore = true);
+//! Prints label as a sub box, gets a whole line of input and stores it to output
+void inputLineSubBox(const char* label, char* output, unsigned maxWidth, bool ignore = true);
+//! Waits for user to press enter
+void pressEnterToContinue(bool ignore = true);
+
+//! Resets the ordered list starting number
+void resetOrderedList(int starter = 1);
+
+//! Prints a string as a table
+void table(unsigned startNumber, unsigned columns, const char* items);
+
+//! Semi-internal function that prints the spacing for sub boxes
+void _printSubBoxSpacing();
+//! Semi-internal function that prints the label of an input box
+void _printInputBoxLabel(const char* label);
+//! Semi-internal function that prints the latest ordered list index
+void _printOrderedListBeginning();
+
+//! Reads user input and stores it
+template <typename T>
+void read(T* storage) {
+ std::cin >> storage;
+}
+
+//! Reads user input and stores it
+template <typename T>
+void read(T& storage) {
+ std::cin >> storage;
+}
+
+//! Prints given item
+template <typename T>
+void print(const T* item) {
+ std::cout << item;
+}
+
+//! Prints given item
+template <typename T>
+void print(const T& item) {
+ std::cout << item;
+}
+
+//! Prints given item and an endline character
+template <typename T>
+void printLine(const T* item) {
+ std::cout << item << std::endl;
+}
+
+//! Prints given item and an endline character
+template <typename T>
+void printLine(const T& item) {
+ std::cout << item << std::endl;
+}
+
+//! Prints the element as the latest list item
+template <typename T>
+void printOrderedListElem(const T& elem) {
+ _printOrderedListBeginning();
+ printLine(elem);
+}
+
+//! Prints a label and then reads user input and stores it
+template <typename T>
+void inputBox(const char* label, T* output) {
+ _printInputBoxLabel(label);
+ std::cin >> *output;
+}
+
+//! Prints a label with sub box spacing and then reads user input and stores it
+//! \sa _printSubBoxSpacing()
+template <typename T>
+void inputSubBox(const char* label, T* output) {
+ _printSubBoxSpacing();
+ _printInputBoxLabel(label);
+ std::cin >> *output;
+}
+
+#endif
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/Date/Date.cpp b/Year 1/Object-oriented Programming/Project 1/src/Generic/Date/Date.cpp
new file mode 100644
index 0000000..7c8f4d9
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/Date/Date.cpp
@@ -0,0 +1,174 @@
+#include "Date.h"
+#include <cstring>
+
+/* Private */
+
+bool Date::isLeapYear() {
+ // Implements https://en.wikipedia.org/wiki/Leap_year#Gregorian_calendar
+ return year % 400 == 0 || year % 100 != 0 || year % 4 == 0;
+}
+
+unsigned short Date::daysInMonth() {
+ if (month == 2)
+ return 28 + isLeapYear();
+ if (month <= 7)
+ return 30 + month % 2;
+ return 31 - month % 2;
+}
+
+/* Public */
+
+Date::Date() : Date(01, 05, 2022) {}
+
+/*! \param str C-style string
+ *
+ * Values are initialized with zeroes. Then it parses the string:
+ *
+ * Skips spaces, saves day with atoi, skips two characters,
+ * skips spaces, saves month with atoi, skips two characters,
+ * skips spaces, saves year with atoi.
+ *
+ * Values are validated with setters.
+ * You should always have spaces between day, month and year and no non-numeric characters between them.
+ *
+ * \remark If there are non-numeric characters, as per atoi() spec, the appropriate property is zero.
+ */
+Date::Date(const char* str) : Date(0, 0, 0) {
+ while (*str == ' ' && *str != '\0') str++;
+ set_day(atoi(str));
+ str += 2;
+ while (*str == ' ' && *str != '\0') str++;
+ set_month(atoi(str));
+ str += 2;
+ while (*str == ' ' && *str != '\0') str++;
+ set_year(atoi(str));
+}
+
+/*!
+ * Initializes values with zeroes and then uses setters to save the function arguments.
+ */
+Date::Date(unsigned short day, unsigned short month, unsigned short year) {
+ this->day = this->month = this->year = 0;
+ set_day(day);
+ set_month(month);
+ set_year(year);
+}
+
+unsigned short Date::get_day() const {
+ return day;
+}
+
+/*! \return Whether newDay was saved or not
+ *
+ * If newDay is equal to 0, or is more than the appropriate days in the month, the day isn't set.
+ */
+bool Date::set_day(unsigned short newDay) {
+ if (newDay == 0 || newDay > daysInMonth())
+ return false;
+ day = newDay;
+ return true;
+}
+
+unsigned short Date::get_month() const {
+ return month;
+}
+
+/*! \return Whether newMonth was saved or not
+ *
+ * If newMonth is equal to 0 or is more than 12, the month isn't set.
+ */
+bool Date::set_month(unsigned short newMonth) {
+ if (newMonth == 0 || newMonth > 12)
+ return false;
+ month = newMonth;
+ return true;
+}
+
+unsigned short Date::get_year() const {
+ return year;
+}
+
+/*! \return Whether year was saved or not
+ *
+ * Year isn't set when newYear is zero
+ */
+bool Date::set_year(unsigned short newYear) {
+ if (newYear == 0)
+ return false;
+ year = newYear;
+ return true;
+}
+
+int digitToChar(unsigned digit) {
+ if (digit <= 9)
+ return '0' + digit;
+ return ' ';
+}
+
+/*! \return String object in the format "day.month.year"
+ *
+ * \note Currently there isn't any way to change the formatting
+ */
+String Date::createString() const {
+ String out;
+ return ((((out += day) += ".") += month) += ".") += year;
+}
+
+/*! \param istr An input stream
+ *
+ * Directly reads bytes from stream (calls read() function).
+ *
+ * \remark Doesn't alter the stream in any other way.
+ * \note Best used with binary ifstream
+ */
+void Date::read(std::istream& istr) {
+ istr.read((char*)&day, sizeof(day));
+ istr.read((char*)&month, sizeof(month));
+ istr.read((char*)&year, sizeof(year));
+}
+
+/*! \param ostr An output stream
+ *
+ * Directly writes bytes to stream (calls write() function).
+ *
+ * \remark Doesn't alter the stream in any other way.
+ * \note Best used with binary ofstream
+ */
+void Date::write(std::ostream& ostr) {
+ ostr.write((char*)&day, sizeof(day));
+ ostr.write((char*)&month, sizeof(month));
+ ostr.write((char*)&year, sizeof(year));
+}
+
+/*! \returns -1 if this < other, 1 if this > other, 0 if this == other
+ */
+int Date::compare(const Date& other) const {
+ if (year < other.year || month < other.month || day < other.day)
+ return -1;
+ return year > other.year || month > other.month || day > other.day;
+}
+
+
+/* Outside of class */
+
+/*!
+ * Uses the stream's >> operator to read and parse the day, month and year.
+ *
+ * \note Best used with std::cin or text std::ifstream
+ */
+std::istream& operator>>(std::istream& istr, Date& dt) {
+ unsigned short d, M, y;
+ istr >> d >> M >> y;
+ dt = Date(d, M, y);
+ return istr;
+}
+
+/*!
+ * Uses the stream's << operator to write the date in the format "day.month.year"
+ *
+ * \note Best used with std::cout or text std::ofstream
+ */
+std::ostream& operator<<(std::ostream& ostr, const Date& dt) {
+ ostr << dt.get_day() << "." << dt.get_month() << "." << dt.get_year();
+ return ostr;
+}
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/Date/Date.h b/Year 1/Object-oriented Programming/Project 1/src/Generic/Date/Date.h
new file mode 100644
index 0000000..89cc89c
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/Date/Date.h
@@ -0,0 +1,59 @@
+#ifndef HEADER_DATE
+#define HEADER_DATE
+
+/*! \file Date.h
+ * \brief Stores the declaration of class Date
+ */
+
+#include <istream>
+#include <ostream>
+#include "../String/String.h"
+
+/*! \brief Stores a day, month and year
+ */
+class Date {
+ unsigned short day;
+ unsigned short month;
+ unsigned short year;
+
+ bool isLeapYear();
+ unsigned short daysInMonth();
+
+public:
+ //! Sets date as 01 May 2022
+ Date();
+ //! Parses string
+ Date(const char* str);
+ //! Sets day, month and year
+ Date(unsigned short day, unsigned short month, unsigned short year);
+
+ //! Returns the day
+ unsigned short get_day() const;
+ //! Sets the day
+ bool set_day(unsigned short day);
+ //! Returns the month
+ unsigned short get_month() const;
+ //! Sets the month
+ bool set_month(unsigned short month);
+ //! Returns the year
+ unsigned short get_year() const;
+ //! Sets the year
+ bool set_year(unsigned short year);
+
+ //! Returns the date as a String object
+ String createString() const;
+
+ //! Reads date from stream
+ void read(std::istream& istr);
+ //! Writes date to stream
+ void write(std::ostream& ostr);
+ //! Compares two dates
+ int compare(const Date& other) const;
+};
+
+//! Reads date from stream with >> operator
+std::istream& operator>>(std::istream& istr, Date& dt);
+//! Writes date to stream with << operator
+std::ostream& operator<<(std::ostream& ostr, const Date& dt);
+
+#endif
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/List/List.hpp b/Year 1/Object-oriented Programming/Project 1/src/Generic/List/List.hpp
new file mode 100644
index 0000000..0b53033
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/List/List.hpp
@@ -0,0 +1,345 @@
+#ifndef HEADER_LIST
+#define HEADER_LIST
+
+/*! \file List.hpp
+ * \brief Stores declaration and definition of templated class List
+ */
+
+#include <istream>
+#include <ostream>
+
+/*! \brief Templated class that stores an array of elements in dynamic memory
+ *
+ * \warning findIndex(), contain(), read(), write(), operator<<() and operator>>() require the type to have defined a couple of functions.
+ * \sa findIndex()
+ * \sa contain()
+ * \sa read()
+ * \sa write()
+ * \sa operator<<()
+ * \sa operator>>()
+ */
+template <typename T>
+class List {
+protected:
+ T* elements;
+ unsigned length;
+ unsigned count;
+
+ void resize();
+ void free();
+ void copyFrom(const List& other);
+
+public:
+ //! Copies all elements in given array
+ List(const T* elements, unsigned elementsCount);
+ //! Adds an element
+ void add(const T& element);
+ //! Inserts element at given index
+ void insertAt(const T& element, unsigned index);
+ //! Removes element at index
+ bool removeAt(unsigned index);
+ //! Finds the index of element
+ unsigned findIndex(const T& element) const;
+ bool contain(const T& element) const;
+ //! Returns reference to element at index
+ T& operator[](unsigned index);
+ //! Returns constant reference to element at index
+ const T& operator[](unsigned index) const;
+
+ //! Appends elements from other list
+ List<T>& operator+=(const List<T> other);
+
+ //! Reads from stream
+ std::istream& read(std::istream& istr);
+ //! Writes to stream
+ std::ostream& write(std::ostream& ostr) const;
+
+ //! Returns the length
+ unsigned get_length() const;
+ //! Returns the count
+ unsigned get_count() const;
+
+ List();
+ List& operator=(const List& other);
+ List(const List& other);
+ ~List();
+
+ List(List&& other);
+ List& operator=(List&& other);
+};
+
+//! Reads List from stream with >> operator
+template <typename T>
+std::istream& operator>>(std::istream& istr, List<T>& obj);
+//! Writes List to stream with << operator
+template <typename T>
+std::ostream& operator<<(std::ostream& ostr, const List<T>& obj);
+
+/* Private */
+
+template <typename T>
+void List<T>::resize() {
+ length = (length == 0) ? 8 : length << 1;
+ T* temp = new T[length];
+ for (int i = 0; i < count; i++)
+ temp[i] = elements[i];
+ delete[] elements;
+ elements = temp;
+}
+
+template <typename T>
+void List<T>::free() {
+ delete[] elements;
+}
+
+template <typename T>
+void List<T>::copyFrom(const List& other) {
+ elements = new T[other.length];
+ for (int i = 0; i < other.count; i++)
+ elements[i] = other.elements[i];
+ length = other.length;
+ count = other.count;
+}
+
+/* Public */
+
+template <typename T>
+List<T>::List(const T* elements, unsigned elementsCount) {
+ length = 8;
+ count = elementsCount;
+ this->elements = new T[length];
+ for (unsigned i = 0; i < count; i++)
+ this->elements[i] = elements[i];
+}
+
+/*!
+ * Resizes internal array if there is no space for additional elements.
+ */
+template <typename T>
+void List<T>::add(const T& element) {
+ if (length == count) resize();
+
+ elements[count++] = element;
+}
+
+/*!
+ * If index is after the last element, the element is just added.
+ * Otherwise all elements after the index are shifted right and element is put in place.
+ *
+ * Resizes internal array if there is no space for additional elements.
+ */
+template <typename T>
+void List<T>::insertAt(const T& element, unsigned index) {
+ if (index >= count) {
+ add(element);
+ return;
+ }
+ if (length == count) resize();
+
+ for (unsigned i = count; i > index; i--)
+ elements[i] = elements[i - 1];
+
+ elements[index] = element;
+ count++;
+}
+
+/*! \returns Wether element could be removed
+ *
+ * If index is after that of the last element, nothing is done and false is returned.
+ * Otherwise elements after index are shifted right and count is reduced.
+ */
+template <typename T>
+bool List<T>::removeAt(unsigned index) {
+ if (index >= count) return false;
+
+ for (int i = index; i < count; i++)
+ elements[i] = elements[i + 1];
+ count--;
+ return true;
+}
+
+/*! \returns Index of element. If element isn't found, returns the count of element.
+ *
+ * \warning The function depends on the type having a function "compare" defined, which takes two elements and returns a number <0 if elem1 < elem2, >0 if elem1 > elem2, 0 if elem1 == elem2
+ * \note Searching is done linearly
+ */
+template <typename T>
+unsigned List<T>::findIndex(const T& element) const {
+ unsigned ind = 0;
+ while (ind < count && elements[ind].compare(element) != 0)
+ ind++;
+ return ind;
+}
+
+/*! \returns Whether the element is contained in the current List
+ *
+ * \warning Function depends on findIndex(), which means the same "compare" function must be defined in the type
+ * \sa findIndex()
+ */
+template <typename T>
+bool List<T>::contain(const T& element) const {
+ return findIndex(element) < count;
+}
+
+template <typename T>
+T& List<T>::operator[](unsigned index) {
+ return elements[index];
+}
+
+template <typename T>
+const T& List<T>::operator[](unsigned index) const {
+ return elements[index];
+}
+
+template <typename T>
+List<T>& List<T>::operator+=(const List<T> other) {
+ for (unsigned i = 0; i < other.length; i++)
+ add(other[i]);
+ return *this;
+}
+
+/*! \param istr An input stream
+ *
+ * Directly reads bytes from stream (calls read() function).
+ * Any stored values are deleted and replaced with those from the stream.
+ *
+ * \warning The function depends on the type having a function "read" defined, which takes an std::istream& and writes it's data to it. Return type doesn't matter.
+ * \remark Doesn't alter the stream in any other way.
+ * \note Best used with binary ifstream
+ */
+template <typename T>
+std::istream& List<T>::read(std::istream& istr) {
+ istr.read((char*)&length, sizeof(length));
+ istr.read((char*)&count, sizeof(count));
+
+ delete[] elements;
+ elements = new T[length];
+
+ for (int i = 0; i < count; i++)
+ elements[i].read(istr);
+
+ return istr;
+}
+
+/*! \param ostr An output stream
+ *
+ * Directly writes bytes to stream (calls write() function).
+ *
+ * \warning The function depends on the type having a function "write" defined, which takes an std::ostream& and writes it's data to it. Return type doesn't matter.
+ * \remark Doesn't alter the stream in any other way.
+ * \note Best used with binary ofstream
+ */
+template <typename T>
+std::ostream& List<T>::write(std::ostream& ostr) const {
+ ostr.write((const char*)&length, sizeof(length));
+ ostr.write((const char*)&count, sizeof(count));
+
+ for (int i = 0; i < count; i++)
+ elements[i].write(ostr);
+
+ return ostr;
+}
+
+/*!
+ * Length is the size of the underlying array (allocated memory).
+ */
+template <typename T>
+unsigned List<T>::get_length() const {
+ return length;
+}
+
+/*!
+ * Count is the amount of elements that are stored.
+ */
+template <typename T>
+unsigned List<T>::get_count() const {
+ return count;
+}
+
+// Rule of 4
+
+template <typename T>
+List<T>::List() : List(nullptr, 0) {}
+
+template <typename T>
+List<T>& List<T>::operator=(const List& other) {
+ if (this != &other) {
+ free();
+ copyFrom(other);
+ }
+ return *this;
+}
+
+template <typename T>
+List<T>::List(const List& other) {
+ copyFrom(other);
+}
+
+template <typename T>
+List<T>::~List() {
+ free();
+}
+
+// Move semantics
+
+template <typename T>
+List<T>::List(List&& other) {
+ length = other.length;
+ count = other.count;
+ elements = other.elements;
+ other.elements = nullptr;
+}
+
+template <typename T>
+List<T>& List<T>::operator=(List&& other) {
+ if (this != &other) {
+ free();
+ length = other.length;
+ count = other.count;
+ elements = other.elements;
+ other.elements = nullptr;
+ }
+ return *this;
+}
+
+/* Outside of class */
+
+/*!
+ * Uses the stream's >> operator to read and parse the elements.
+ * The first item in the stream should be the count.
+ *
+ * \warning The function depends on the type having the operator >> defined, which takes an std::istream& and writes it's data to it. Return type doesn't matter.
+ * \note Best used with std::cin or text std::ifstream
+ */
+template <typename T>
+std::istream& operator>>(std::istream& istr, List<T>& obj) {
+ List<T> newObj;
+ unsigned count;
+ istr >> count;
+
+ T temp;
+ for (int i = 0; i < count; i++) {
+ istr >> temp;
+ obj.add(temp);
+ }
+
+ return istr;
+}
+
+/*!
+ * Uses the stream's << operator to write the count and then all objects.
+ *
+ * \warning The function depends on the type having the operator << defined, which takes an std::ostream& and writes it's data to it. Return type doesn't matter.
+ * \note Best used with std::cout or text std::ofstream
+ */
+template <typename T>
+std::ostream& operator<<(std::ostream& ostr, const List<T>& obj) {
+ ostr << obj.get_count() << std::endl;
+ for (int i = 0; i < obj.get_count(); i++)
+ ostr << obj[i];
+
+ return ostr;
+}
+
+
+#endif
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/List/OrderedList.hpp b/Year 1/Object-oriented Programming/Project 1/src/Generic/List/OrderedList.hpp
new file mode 100644
index 0000000..8d13a5d
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/List/OrderedList.hpp
@@ -0,0 +1,55 @@
+#ifndef HEADER_ORDEREDLIST
+#define HEADER_ORDEREDLIST
+
+/*! \file OrderedList.hpp
+ * \brief Stores declaration and definition of templated class OrderedList
+ */
+
+#include "List.hpp"
+
+/*! \brief Inherits List, but contains it's elements in a sorted manner
+ *
+ * \warning Outside those defined in List, insert() requires the type to have defined a "compare" of functions.
+ * \sa insert()
+ */
+template <typename T>
+class OrderedList : public List<T> {
+public:
+ OrderedList();
+ OrderedList(const T* elements, unsigned elementsCount);
+
+ /*! \brief \warning Function is deleted, use insert() instead
+ * \sa insert()
+ */
+ void add(T element) = delete;
+ /*! \brief \warning Function is deleted, use insert() instead
+ * \sa insert()
+ */
+ void insertAt(T element, unsigned index) = delete;
+
+ //! Inserts an element at a sorted position
+ void insert(T element);
+};
+
+template <typename T>
+OrderedList<T>::OrderedList() : OrderedList(nullptr, 0) {}
+
+template <typename T>
+OrderedList<T>::OrderedList(const T* elements, unsigned elementsCount) : List<T>::List(elements, elementsCount) {}
+
+/*!
+ * \warning The function depends on the type having a function "compare" defined, which takes two elements and returns a number <0 if elem1 < elem2, >0 if elem1 > elem2, 0 if elem1 == elem2
+ * \note Insertion is done linearly
+ */
+template <typename T>
+void OrderedList<T>::insert(T element) {
+ if (List<T>::length == List<T>::count) List<T>::resize();
+
+ unsigned insertionInd = 0;
+ while (insertionInd < List<T>::count && List<T>::elements[insertionInd].compare(element) < 0)
+ insertionInd++;
+
+ List<T>::insertAt(element, insertionInd);
+}
+
+#endif
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/String/String.cpp b/Year 1/Object-oriented Programming/Project 1/src/Generic/String/String.cpp
new file mode 100644
index 0000000..9d61999
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/String/String.cpp
@@ -0,0 +1,169 @@
+#include "String.h"
+#include <cstring>
+
+/* Private */
+
+void String::free() {
+ delete[] str;
+}
+
+void String::copyFrom(const String& other) {
+ str = new char[other.length + 1];
+ strncpy(str, other.str, other.length + 1);
+ length = other.length;
+}
+
+/* Public */
+
+/*!
+ * Allocated with length + 1 size, so there is a terminating zero at the end.
+ */
+String::String(unsigned length) {
+ this->length = length;
+ str = new char[length + 1];
+ str[length] = '\0';
+}
+
+/*! \params str C-style string
+ */
+String::String(const char* str) {
+ length = strlen(str);
+ this->str = new char[length + 1]; // capture terminating zero
+ strncpy(this->str, str, length + 1);
+}
+
+const char* String::get_cstr() const {
+ return str;
+}
+
+unsigned String::get_length() const {
+ return length;
+}
+
+char& String::operator[](unsigned index) {
+ return str[index];
+}
+
+/*! \params str C-style string
+ */
+String& String::operator+=(const char* str) {
+ unsigned strLen = strlen(str);
+ char* newStr = new char[length + strLen + 1];
+ strncpy(newStr, this->str, length + 1);
+ strncat(newStr, str, strLen + 1);
+
+ delete[] this->str;
+ this->str = newStr;
+ length += strLen;
+
+ return *this;
+}
+
+/*!
+ * Converts the number to a C-style string and then uses += to append it.
+ */
+String& String::operator+=(unsigned number) {
+ unsigned tempLen = 0;
+ for (unsigned tmp = number; tmp > 0 || tempLen == 0; tmp /= 10)
+ tempLen++;
+
+ char* tmp = new char[tempLen + 1];
+ tmp[tempLen] = '\0';
+ for (unsigned i = tempLen - 1; i < tempLen; i--, number /= 10)
+ tmp[i] = number % 10 + '0';
+
+ *this += tmp;
+ delete[] tmp;
+ return *this;
+}
+
+String::String() : String("") {}
+
+String::String(const String& other) {
+ copyFrom(other);
+}
+
+String& String::operator=(const String& other) {
+ if (this != &other) {
+ free();
+ copyFrom(other);
+ }
+ return *this;
+}
+
+String::~String() {
+ free();
+}
+
+String::String(String&& other) {
+ str = other.str;
+ other.str = nullptr;
+ length = other.length;
+}
+
+String& String::operator=(String&& other) {
+ if (this != &other) {
+ delete[] str;
+ str = other.str;
+ other.str = nullptr;
+ length = other.length;
+ }
+ return *this;
+}
+
+/*! \param istr An input stream
+ *
+ * Directly reads bytes from stream (calls read() function).
+ * First reads the string length, then the underlying C-style string (including terminating zero).
+ *
+ * \remark Doesn't alter the stream in any other way.
+ * \note Best used with binary ifstream
+ */
+void String::read(std::istream& istr) {
+ istr.read((char*)&length, sizeof(length));
+ delete[] str;
+ str = new char[length + 1];
+ istr.read(str, sizeof(char) * (length + 1));
+}
+
+/*! \param ostr An output stream
+ *
+ * Directly writes bytes to stream (calls write() function).
+ * First writes the string length, then the underlying C-style string (including terminating zero).
+ *
+ * \remark Doesn't alter the stream in any other way.
+ * \note Best used with binary ofstream
+ */
+void String::write(std::ostream& ostr) const {
+ ostr.write((char*)&length, sizeof(length));
+ ostr.write(str, sizeof(char) * (length + 1));
+}
+
+/*! \params other C-style string
+ * \returns strcmp between underlying C-style string and "other"
+ */
+int String::compare(const String& other) const {
+ return strcmp(str, other.str);
+}
+
+/*!
+ * Uses the stream's getline function to read the data.
+ *
+ * \warning It takes at most 1024 characters from the stream!
+ * \note Best used with std::cin or text std::ifstream
+ */
+std::istream& operator>>(std::istream& istr, String& event) {
+ istr.getline(event.str, 1024);
+ event.length = strlen(event.str);
+
+ return istr;
+}
+
+/*!
+ * Uses the stream's << operator to write the underlying C-style string
+ *
+ * \note Best used with std::cout or text std::ofstream
+ */
+std::ostream& operator<<(std::ostream& ostr, const String& event) {
+ return ostr << event.str;
+}
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/String/String.h b/Year 1/Object-oriented Programming/Project 1/src/Generic/String/String.h
new file mode 100644
index 0000000..84fbe9c
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/String/String.h
@@ -0,0 +1,56 @@
+#ifndef HEADER_STRING
+#define HEADER_STRING
+
+/*! \file String.h
+ * \brief Stores declaration of class String
+ */
+
+#include <istream>
+#include <ostream>
+
+class String {
+ char* str;
+ unsigned length;
+
+ void free();
+ void copyFrom(const String& other);
+
+public:
+ //! The underlying array is allocated with length (+ 1) size
+ String(unsigned length);
+ //! Copies str
+ String(const char* str);
+ //! Returns internal C-style string
+ const char* get_cstr() const;
+ //! Returns number of characters in string
+ unsigned get_length() const;
+ //! Returns a character reference (from the underlying C-style string) at the given index
+ char& operator[](unsigned index);
+
+ //! Appends a C-style string
+ String& operator+=(const char* str);
+ //! Appends a number
+ String& operator+=(unsigned number);
+
+ String();
+ String(const String& other);
+ String& operator=(const String& other);
+ ~String();
+
+ String(String&& other);
+ String& operator=(String&& other);
+
+ //! Reads String from stream
+ void read(std::istream& istr);
+ //! Writes String to stream
+ void write(std::ostream& ostr) const;
+ //! Compares two strings
+ int compare(const String& other) const;
+
+ //! Reads String from stream with >> operator
+ friend std::istream& operator>>(std::istream& istr, String& event);
+ //! Writes String to stream with << operator
+ friend std::ostream& operator<<(std::ostream& ostr, const String& event);
+};
+
+#endif
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Models/Event.cpp b/Year 1/Object-oriented Programming/Project 1/src/Models/Event.cpp
new file mode 100644
index 0000000..c4557b7
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Models/Event.cpp
@@ -0,0 +1,153 @@
+#include "Event.h"
+#include "Reservation.h"
+
+Event::Event() : hall(), name(), date() {}
+
+Event::Event(const Hall& hall, String name, Date date) : tickets(), reservations() {
+ this->hall = hall;
+ this->name = name;
+ this->date = date;
+}
+
+OrderedList<Ticket>& Event::get_tickets() {
+ return tickets;
+}
+
+const OrderedList<Ticket>& Event::get_tickets() const {
+ return tickets;
+}
+
+OrderedList<Reservation>& Event::get_reservations() {
+ return reservations;
+}
+
+const OrderedList<Reservation>& Event::get_reservations() const {
+ return reservations;
+}
+
+const Hall& Event::get_hall() const {
+ return hall;
+}
+
+const String& Event::get_name() const {
+ return name;
+}
+
+const Date& Event::get_date() const {
+ return date;
+}
+
+/*! \param istr An input stream
+ *
+ * Directly reads bytes from stream (calls read() function).
+ * Stored types must have defined a read() function.
+ *
+ * \remark Doesn't alter the stream in any other way.
+ * \note Best used with binary ifstream
+ */
+void Event::read(std::istream& istr) {
+ hall.read(istr);
+ name.read(istr);
+ date.read(istr);
+ tickets.read(istr);
+ reservations.read(istr);
+}
+
+/*! \param ostr An output stream
+ *
+ * Directly writes bytes to stream (calls write() function).
+ * Stored types must have defined a read() function.
+ *
+ * \remark Doesn't alter the stream in any other way.
+ * \note Best used with binary ofstream
+ */
+void Event::write(std::ostream& ostr) {
+ hall.write(ostr);
+ name.write(ostr);
+ date.write(ostr);
+ tickets.write(ostr);
+ reservations.write(ostr);
+}
+
+/*! \return compare of halls, or if they are equal, compare of dates
+ */
+int Event::compare(const Event& other) {
+ if (hall.compare(other.hall) == 0)
+ return date.compare(other.date);
+ return hall.compare(other.hall);
+}
+
+/*!
+ * Uses the stream's >> operator to read and parse all internal values.
+ * Stored types must have defined operator >>.
+ *
+ * \note Best used with std::cin or text std::ifstream
+ */
+std::istream& operator>>(std::istream& istr, Event& event) {
+ Hall newHall;
+ String newString;
+ Date newDate;
+ OrderedList<Ticket> newTickets;
+ OrderedList<Reservation> newReservation;
+
+ istr >> newHall >> newString >> newDate >> newTickets >> newReservation;
+ event = Event(newHall, newString, newDate);
+ event.get_tickets() = newTickets;
+ event.get_reservations() = newReservation;
+
+ return istr;
+}
+
+unsigned insertionOpSet = 0;
+
+/*! \param setting A number, defining the different options. It's best if it is passed as binary number.
+ *
+ * Sets a configuration setting for how operator<< should behave. Setting is stored as a global variable in the cpp file, so it's independent of Event instance.
+ *
+ * Each bit in the number is a certain setting. Each bit from left to right represents one of these options, from top to bottom:
+ * 1. Write count of bought tickets (available only if 5. is set)
+ * 2. Write count of reserved tickets (available only if 5. is set)
+ * 3. Write reservations
+ * 4. Write bought tickets
+ * 5. Write Hall information
+ *
+ * \par Example
+ * To configure printing the Hall information, bought tickets count and the bought tickets themselves, you would do:
+ * \code{.cpp}
+ * configureEventInsertionOp(0b10011);
+ * \endcode
+ */
+void configureEventInsertionOp(unsigned setting) {
+ insertionOpSet = setting;
+}
+
+/*!
+ * Uses the stream's << operator to write all internal data, following setting from configureEventInsertionOp()
+ * Stored types must have defined operator <<.
+ *
+ * \note Best used with std::cout or text std::ofstream
+ */
+std::ostream& operator<<(std::ostream& ostr, const Event& event) {
+ if (insertionOpSet & 1) {
+ ostr << "| Hall: " << event.get_hall().get_number() << " | Name: " << event.get_name() << " | Date: " << event.get_date();
+
+ if (insertionOpSet & 8)
+ ostr << " || Tickets Count: " << event.get_tickets().get_count();
+ if (insertionOpSet & 16)
+ ostr << " || Reservations Count: " << event.get_reservations().get_count();
+ ostr << std::endl;
+ }
+ if (insertionOpSet & 2) {
+ ostr << "Bought tickets: ";
+ for (unsigned i = 0; i < event.get_tickets().get_count(); i++)
+ ostr << "[" << event.get_tickets()[i] << "] ";
+ ostr << std::endl;
+ }
+ if(insertionOpSet & 4) {
+ ostr << "Reserved tickets: ";
+ for (unsigned i = 0; i < event.get_reservations().get_count(); i++)
+ ostr << "[" << event.get_reservations()[i] << "] ";
+ ostr << std::endl;
+ }
+ return ostr;
+}
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Models/Event.h b/Year 1/Object-oriented Programming/Project 1/src/Models/Event.h
new file mode 100644
index 0000000..1162b8f
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Models/Event.h
@@ -0,0 +1,63 @@
+#ifndef HEADER_MODEL_EVENT
+#define HEADER_MODEL_EVENT
+
+/*! \file Event.h
+ * \brief Stores the declaration of class Event
+ */
+
+#include "../Generic/List/OrderedList.hpp"
+#include "../Generic/Date/Date.h"
+#include "../Generic/String/String.h"
+#include "Hall.h"
+#include "Ticket.h"
+#include "Reservation.h"
+#include <istream>
+#include <ostream>
+
+/*! \brief Stores an event's hall, name, date, bought tickets and reservations
+ */
+class Event {
+ Hall hall;
+ String name;
+ Date date;
+ OrderedList<Ticket> tickets;
+ OrderedList<Reservation> reservations;
+
+public:
+ //! Calls default constructors on data
+ Event();
+ //! Copies given hall and sets name and date
+ Event(const Hall& hall, String name, Date date);
+
+ //! Returns constant reference Hall in which event will be held
+ const Hall& get_hall() const;
+ //! Returns constant reference to name of event
+ const String& get_name() const;
+ //! Returns constant reference to date on which event will be held
+ const Date& get_date() const;
+
+ //! Returns reference to bought tickets
+ OrderedList<Ticket>& get_tickets();
+ //! Returns constant reference to bought tickets
+ const OrderedList<Ticket>& get_tickets() const;
+ //! Returns reference to reservations
+ OrderedList<Reservation>& get_reservations();
+ //! Returns constant reference to reservations
+ const OrderedList<Reservation>& get_reservations() const;
+
+ //! Reads Event from stream
+ void read(std::istream& istr);
+ //! Writes Event to stream
+ void write(std::ostream& ostr);
+ //! Compares two events
+ int compare(const Event& other);
+};
+
+//! Reads Event from stream with >> operator
+std::istream& operator>>(std::istream& istr, Event& event);
+//! Configures how Event should be shown, when written to stream with << operator
+void configureEventInsertionOp(unsigned setting);
+//! Writes Event to stream with << operator
+std::ostream& operator<<(std::ostream& ostr, const Event& event);
+
+#endif
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Models/Hall.cpp b/Year 1/Object-oriented Programming/Project 1/src/Models/Hall.cpp
new file mode 100644
index 0000000..feacdac
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Models/Hall.cpp
@@ -0,0 +1,76 @@
+#include "Hall.h"
+
+Hall::Hall() : Hall(0, 0, 0) {}
+
+Hall::Hall(int number) : Hall(number, 0, 0) {}
+
+Hall::Hall(int number, unsigned rows, unsigned seatsPerRow) {
+ this->number = number;
+ this->rows = rows;
+ this->seatsPerRow = seatsPerRow;
+}
+
+int Hall::get_number() const {
+ return number;
+}
+unsigned Hall::get_rows() const {
+ return rows;
+}
+
+unsigned Hall::get_seatsPerRow() const {
+ return seatsPerRow;
+}
+
+/*! \param istr An input stream
+ *
+ * Directly reads bytes from stream (calls read() function).
+ *
+ * \remark Doesn't alter the stream in any other way.
+ * \note Best used with binary ifstream
+ */
+void Hall::read(std::istream& istr) {
+ istr.read((char*)&number, sizeof(number));
+ istr.read((char*)&rows, sizeof(rows));
+ istr.read((char*)&seatsPerRow, sizeof(seatsPerRow));
+}
+
+/*! \param ostr An output stream
+ *
+ * Directly writes bytes to stream (calls write() function).
+ *
+ * \remark Doesn't alter the stream in any other way.
+ * \note Best used with binary ofstream
+ */
+void Hall::write(std::ostream& ostr) const {
+ ostr.write((char*)&number, sizeof(number));
+ ostr.write((char*)&rows, sizeof(rows));
+ ostr.write((char*)&seatsPerRow, sizeof(seatsPerRow));
+}
+
+/*! \return -1 if number < other.number, 1 if number > other.number, 0 if number == other.number
+ */
+int Hall::compare(const Hall& other) const {
+ return (number > other.get_number()) - (number < other.get_number());
+}
+
+/*!
+ * Uses the stream's >> operator to read and parse all internal values.
+ *
+ * \note Best used with std::cin or text std::ifstream
+ */
+std::istream& operator>>(std::istream& istr, Hall& hall) {
+ int number;
+ unsigned rows, seatsPerRow;
+ istr >> number >> rows >> seatsPerRow;
+ hall = Hall(number, rows, seatsPerRow);
+ return istr;
+}
+
+/*!
+ * Uses the stream's << operator to write all internal data.
+ *
+ * \note Best used with std::cout or text std::ofstream
+ */
+std::ostream& operator<<(std::ostream& ostr, const Hall& hall) {
+ return ostr << hall.get_number() << " " << hall.get_rows() << " "<< hall.get_seatsPerRow();
+}
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Models/Hall.h b/Year 1/Object-oriented Programming/Project 1/src/Models/Hall.h
new file mode 100644
index 0000000..c567c75
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Models/Hall.h
@@ -0,0 +1,47 @@
+#ifndef HEADER_MODEL_HALL
+#define HEADER_MODEL_HALL
+
+/*! \file Hall.h
+ * \brief Stores the declaration of class Hall
+ */
+
+#include <istream>
+#include <ostream>
+
+/*! \brief Each hall contains a number, rows and seats per row
+ */
+class Hall {
+ int number;
+ unsigned rows;
+ unsigned seatsPerRow;
+
+public:
+ //! Sets values to 0
+ Hall();
+ //! Sets values, except number, to 0
+ Hall(int number);
+ //! Sets values
+ Hall(int number, unsigned rows, unsigned seatsPerRow);
+
+ //! Returns a Hall's number
+ int get_number() const;
+ //! Returns a Hall's row count
+ unsigned get_rows() const;
+ //! Return a Hall's seats per row count
+ unsigned get_seatsPerRow() const;
+
+ //! Reads Hall from stream
+ void read(std::istream& istr);
+ //! Writes Hall to steam
+ void write(std::ostream& ostr) const;
+ //! Compare two Halls
+ int compare(const Hall& other) const;
+
+};
+
+//! Reads Hall from stream with >> operator
+std::istream& operator>>(std::istream& istr, Hall& hall);
+//! Writes Hall to stream with << operator
+std::ostream& operator<<(std::ostream& ostr, const Hall& hall);
+
+#endif
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Models/Reservation.cpp b/Year 1/Object-oriented Programming/Project 1/src/Models/Reservation.cpp
new file mode 100644
index 0000000..002ba29
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Models/Reservation.cpp
@@ -0,0 +1,79 @@
+#include "Reservation.h"
+#include <cstring>
+
+Reservation::Reservation() : Reservation(Ticket(), "", "") {}
+
+Reservation::Reservation(const Ticket& ticket) : Reservation(ticket, "", "") {}
+
+Reservation::Reservation(const Ticket& ticket, const char* password, const char* note) {
+ this->ticket = ticket;
+ strncpy(this->password, password, PASSWORD_LEN);
+ strncpy(this->note, note, NOTE_LEN);
+}
+
+const Ticket& Reservation::get_ticket() const {
+ return ticket;
+}
+
+const char* Reservation::get_password() const {
+ return password;
+}
+
+const char* Reservation::get_note() const {
+ return note;
+}
+
+/*! \param istr An input stream
+ *
+ * Directly reads bytes from stream (calls read() function).
+ * Uses ticket's read() function.
+ *
+ * \remark Doesn't alter the stream in any other way.
+ * \note Best used with binary ifstream
+ */
+void Reservation::read(std::istream& istr) {
+ ticket.read(istr);
+ istr.read(password, sizeof(password));
+ istr.read(note, sizeof(note));
+}
+
+/*! \param ostr An output stream
+ *
+ * Directly writes bytes to stream (calls write() function).
+ * Uses ticket's write() function.
+ *
+ * \remark Doesn't alter the stream in any other way.
+ * \note Best used with binary ofstream
+ */
+void Reservation::write(std::ostream& ostr) const {
+ ticket.write(ostr);
+ ostr.write(password, sizeof(password));
+ ostr.write(note, sizeof(note));
+}
+
+/*! \return Compares tickets
+ */
+int Reservation::compare(const Reservation& other) const {
+ return ticket.compare(other.ticket);
+}
+
+/*!
+ * Uses the stream's >> operator to read and parse the ticket.
+ * Password and note are left blank.
+ *
+ * \note Best used with std::cin or text std::ifstream
+ */
+std::istream& operator>>(std::istream& istr, Reservation& reservation) {
+ strncpy(reservation.password, "", PASSWORD_LEN);
+ strncpy(reservation.note, "", NOTE_LEN);
+ return istr >> reservation.ticket;
+}
+
+/*!
+ * Uses the stream's << operator to write the ticket only.
+ *
+ * \note Best used with std::cout or text std::ofstream
+ */
+std::ostream& operator<<(std::ostream& ostr, const Reservation& reservation) {
+ return ostr << reservation.ticket;
+}
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Models/Reservation.h b/Year 1/Object-oriented Programming/Project 1/src/Models/Reservation.h
new file mode 100644
index 0000000..10035b9
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Models/Reservation.h
@@ -0,0 +1,50 @@
+#ifndef HEADER_MODEL_RESERVATION
+#define HEADER_MODEL_RESERVATION
+
+/*! \file Reservation.h
+ * \brief Stores the declaration of class Reservation
+ */
+
+#include "Ticket.h"
+#include <istream>
+#include <ostream>
+
+#define PASSWORD_LEN 8
+#define NOTE_LEN 32
+
+/*! \brief Each Reservations contains a ticket, a password and a note
+ */
+class Reservation {
+ Ticket ticket;
+ char password[PASSWORD_LEN];
+ char note[NOTE_LEN];
+
+public:
+ //! Sets ticket as default value and leaves password and note blank
+ Reservation();
+ //! Sets ticket and leaves password and note blank
+ Reservation(const Ticket& ticket);
+ //! Sets ticket, password and note
+ Reservation(const Ticket& ticket, const char* password, const char* note);
+
+ //! Returns constant reference to ticket
+ const Ticket& get_ticket() const;
+ //! Returns constant C-style string to password
+ const char* get_password() const;
+ //! Returns constant C-style string to note
+ const char* get_note() const;
+
+ //! Reads Reservation from stream
+ void read(std::istream& istr);
+ //! Writes Reservation to stream
+ void write(std::ostream& ostr) const;
+ //! Compares two Reservations
+ int compare(const Reservation& other) const;
+
+ //! Reads Reservation from stream with >> operator
+ friend std::istream& operator>>(std::istream& istr, Reservation& reservation);
+ //! Writes Reservation to stream with << operator
+ friend std::ostream& operator<<(std::ostream& ostr, const Reservation& reservation);
+};
+
+#endif
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Models/Ticket.cpp b/Year 1/Object-oriented Programming/Project 1/src/Models/Ticket.cpp
new file mode 100644
index 0000000..bc8ef84
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Models/Ticket.cpp
@@ -0,0 +1,71 @@
+#include "Ticket.h"
+
+Ticket::Ticket() : Ticket(0, 0) {}
+
+Ticket::Ticket(unsigned row, unsigned seat) {
+ this->row = row;
+ this->seat = seat;
+}
+
+unsigned Ticket::get_row() const {
+ return row;
+}
+
+unsigned Ticket::get_seat() const {
+ return seat;
+}
+
+/*! \param istr An input stream
+ *
+ * Directly reads bytes from stream (calls read() function).
+ *
+ * \remark Doesn't alter the stream in any other way.
+ * \note Best used with binary ifstream
+ */
+void Ticket::read(std::istream& istr) {
+ istr.read((char*)&row, sizeof(row));
+ istr.read((char*)&seat, sizeof(seat));
+}
+
+/*! \param ostr An output stream
+ *
+ * Directly writes bytes to stream (calls write() function).
+ *
+ * \remark Doesn't alter the stream in any other way.
+ * \note Best used with binary ofstream
+ */
+void Ticket::write(std::ostream& ostr) const {
+ ostr.write((const char*)&row, sizeof(row));
+ ostr.write((const char*)&seat, sizeof(seat));
+}
+
+/*! \return If rows are equal, -1 if seat < other.seat, 1 if seat > other.seat, 0 if seat == other.seat, else the same, but for rows
+ */
+int Ticket::compare(const Ticket& other) const {
+ if (row == other.row)
+ return (seat > other.seat) - (seat < other.seat);
+ return (row > other.row) - (row < other.row);
+}
+
+/* Outside of class */
+
+/*!
+ * Uses the stream's >> operator to read and parse row and seat.
+ *
+ * \note Best used with std::cin or text std::ifstream
+ */
+std::istream& operator>>(std::istream& istr, Ticket& ticket) {
+ unsigned row, seat;
+ istr >> row >> seat;
+ ticket = Ticket(row, seat);
+ return istr;
+}
+
+/*!
+ * Uses the stream's << operator to write row and seat, separated by a space.
+ *
+ * \note Best used with std::cout or text std::ofstream
+ */
+std::ostream& operator<<(std::ostream& ostr, const Ticket& ticket) {
+ return ostr << ticket.get_row() << " " << ticket.get_seat();
+}
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Models/Ticket.h b/Year 1/Object-oriented Programming/Project 1/src/Models/Ticket.h
new file mode 100644
index 0000000..06b4571
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Models/Ticket.h
@@ -0,0 +1,41 @@
+#ifndef HEADER_HEADER_TICKET
+#define HEADER_HEADER_TICKET
+
+/*! \file Ticket.h
+ * \brief Stores the declaration of class Ticket
+ */
+
+#include <istream>
+#include <ostream>
+
+/*! \brief Each Ticket contains a row and a seat number
+ */
+class Ticket {
+ unsigned row;
+ unsigned seat;
+
+public:
+ //! Sets row and seat to zeroes
+ Ticket();
+ //! Sets row and seat
+ Ticket(unsigned row, unsigned seat);
+
+ //! Returns row
+ unsigned get_row() const;
+ //! Returns seat
+ unsigned get_seat() const;
+
+ //! Reads Ticket from stram
+ void read(std::istream& istr);
+ //! Writes Ticket to stream
+ void write(std::ostream& ostr) const;
+ //! Compares two Tickets
+ int compare(const Ticket& other) const;
+};
+
+//! Reads Ticket from stream with >> operator
+std::istream& operator>>(std::istream& istr, Ticket& ticket);
+//! Writes Ticket to stream with << operator
+std::ostream& operator<<(std::ostream& ostr, const Ticket& ticket);
+
+#endif
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Services/EventService.cpp b/Year 1/Object-oriented Programming/Project 1/src/Services/EventService.cpp
new file mode 100644
index 0000000..7ee757e
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Services/EventService.cpp
@@ -0,0 +1,369 @@
+#include "EventService.h"
+#include "StatusCode.h"
+#include <cstring>
+#include <fstream>
+
+/* Private */
+
+unsigned EventService::indexOfEvent(const char* name, const Date& date) {
+ for (unsigned i = 0; i < events.get_count(); i++) {
+ if (events[i].get_date().compare(date) == 0 && events[i].get_name().compare(name) == 0)
+ return i;
+ }
+ return events.get_count();
+}
+
+bool correctReservationPassword(const Reservation& res, const char* password) {
+ return strcmp(res.get_password(), password) == 0;
+}
+
+/* Public */
+
+EventService::EventService(const HallService* hs) {
+ this->hs = hs;
+ events = OrderedList<Event>();
+}
+
+EventService::EventService(const HallService* hs, const Event* events, unsigned eventCount) {
+ this->hs = hs;
+ this->events = OrderedList<Event>(events, eventCount);
+}
+
+/*!
+ * Uses HallService pointer to get Hall from hallNumber
+ * \return E_HallDoesntExist \b if hallNumber doesn't correspond to any Hall, saved in HallService
+ * \return E_EventWillOverlap \b if Event's date overlaps with another event in the same Hall
+ * \return Success \b otherwise
+ */
+StatusCode EventService::createEvent(int hallNumber, const String& name, const Date& date) {
+ unsigned hInd = hs->get_halls().findIndex(Hall(hallNumber));
+ if (hInd == hs->get_halls().get_count())
+ return E_HallDoesntExist;
+
+ Event newEv(hs->get_halls()[hInd], name, date);
+
+ unsigned eInd = events.findIndex(newEv);
+ if (eInd < events.get_count())
+ return E_EventWillOverlap;
+
+ events.insert(newEv);
+ return Success;
+}
+
+/*!
+ * \return E_EventDoesNotExist \b if No Event with the given name and date exists
+ * \return Success \b otherwise
+ */
+StatusCode EventService::cancelEvent(const char* name, const Date& date) {
+ unsigned ind = indexOfEvent(name, date);
+ if (ind == events.get_count())
+ return E_EventDoesNotExist;
+
+ events.removeAt(ind);
+ return Success;
+}
+
+/*!
+ * \return E_EventDoesNotExist \b if No Event with the given name and date exists
+ * \return E_TicketAlreadyBought \b if A ticket for the given row and seat has already been bought
+ * \return E_TicketAlreadyReserved \b if A reservation has already been placed on the given row and seat
+ * \return Success \b otherwise
+ */
+StatusCode EventService::reserveTicket(const char* name, const Date& date, const char* password, const char* note, const Ticket& ticket) {
+ unsigned eInd = indexOfEvent(name, date);
+ if (eInd == events.get_count())
+ return E_EventDoesNotExist;
+
+ if (events[eInd].get_hall().get_rows() < ticket.get_row() || events[eInd].get_hall().get_seatsPerRow() < ticket.get_seat())
+ return E_InvalidSeat;
+
+ unsigned tInd = events[eInd].get_tickets().findIndex(ticket);
+ if (tInd < events[eInd].get_tickets().get_count())
+ return E_TicketAlreadyBought;
+
+ Reservation res(ticket, password, note);
+
+ unsigned rInd = events[eInd].get_reservations().findIndex(res);
+ if (rInd < events[eInd].get_reservations().get_count())
+ return E_TicketAlreadyReserved;
+
+ events[eInd].get_reservations().insert(res);
+ return Success;
+}
+
+/*!
+ * Canceling a reservation doesn't require password and doesn't return the Reservation's note
+ *
+ * \return E_EventDoesNotExist \b if No Event with the given name and date exists
+ * \return W_TicketHadNotBeenReserved \b Ticket hadn't been reserved in the first place
+ * \return Success \b otherwise
+ */
+StatusCode EventService::cancelTicketReservation(const char* name, const Date& date, const Ticket& ticket) {
+ unsigned eInd = indexOfEvent(name, date);
+ if (eInd == events.get_count())
+ return E_EventDoesNotExist;
+
+ if (events[eInd].get_hall().get_rows() < ticket.get_row() || events[eInd].get_hall().get_seatsPerRow() < ticket.get_seat())
+ return E_InvalidSeat;
+
+ unsigned rInd = events[eInd].get_reservations().findIndex(ticket);
+ if (rInd == events[eInd].get_reservations().get_count())
+ return W_TicketHadNotBeenReserved;
+
+ events[eInd].get_reservations().removeAt(rInd);
+ return Success;
+}
+
+/*!
+ * \return E_EventDoesNotExist \b if No Event with the given name and date exists
+ * \return W_TicketHadNotBeenReserved \b Ticket hadn't been reserved in the first place
+ * \return Success \b otherwise
+ */
+StatusCode EventService::ticketIsReserved(const char* name, const Date& date, const Ticket& ticket) {
+ unsigned eInd = indexOfEvent(name, date);
+ if (eInd == events.get_count())
+ return E_EventDoesNotExist;
+
+ if (events[eInd].get_reservations().contain(ticket))
+ return Success;
+ else
+ return W_TicketHadNotBeenReserved;
+}
+
+/*!
+ * Calls buyTicket with Reservation, but sets password and noteOutput to nullptr.
+ * \copydetails buyTicket(const char* name, const Date& date, const Ticket& ticket, const char* password, String* reservationNoteOutput)
+ */
+StatusCode EventService::buyTicket(const char* name, const Date& date, const Ticket& ticket) {
+ return buyTicket(name, date, ticket, nullptr, nullptr);
+}
+
+/*!
+ * \return E_EventDoesNotExist \b if No Event with the given name and date exists
+ * \return E_TicketAlreadyBought \b if A ticket for the given row and seat has already been bought
+ * \return E_TicketAlreadyReserved \b if The seat and row are reserved, but given password is nullptr
+ * \return E_WrongReservationPassword \b if The seat and row are reserved, but given password is incorrect
+ * \return Success \b otherwise
+ */
+StatusCode EventService::buyTicket(const char* name, const Date& date, const Ticket& ticket, const char* password, String* reservationNoteOutput) {
+ unsigned eInd = indexOfEvent(name, date);
+ if (eInd == events.get_count())
+ return E_EventDoesNotExist;
+
+ if (events[eInd].get_hall().get_rows() < ticket.get_row() || events[eInd].get_hall().get_seatsPerRow() < ticket.get_seat())
+ return E_InvalidSeat;
+
+ unsigned tInd = events[eInd].get_tickets().findIndex(ticket);
+ if (tInd < events[eInd].get_tickets().get_count())
+ return E_TicketAlreadyBought;
+
+ unsigned rInd = events[eInd].get_reservations().findIndex(ticket);
+ if (rInd < events[eInd].get_reservations().get_count()) {
+ if (password == nullptr)
+ return E_TicketAlreadyReserved;
+ if (!correctReservationPassword(events[eInd].get_reservations()[rInd], password))
+ return E_WrongReservationPassword;
+
+ if (reservationNoteOutput != nullptr)
+ *reservationNoteOutput = events[eInd].get_reservations()[rInd].get_note();
+ events[eInd].get_reservations().removeAt(rInd);
+ }
+
+ events[eInd].get_tickets().insert(ticket);
+ return Success;
+}
+
+/*!
+ * Each seat in the Hall of the Event is represented by a single character, where 'R' means the seat is reserved, 'B' means the seat is bought and ' ' if it's neither.
+ *
+ * \return Empty String \b if No Event with the given name and date exists
+ * \return Proper String \b otherwise
+ */
+String EventService::createSeatingString(const char* name, const Date& date, unsigned* seatsPerRow) {
+ unsigned eInd = indexOfEvent(name, date);
+ if (eInd == events.get_count()) {
+ return "";
+ }
+
+ unsigned rowCount = events[eInd].get_hall().get_rows(), seatsCount = events[eInd].get_hall().get_seatsPerRow();
+ *seatsPerRow = seatsCount;
+
+ String out(rowCount * seatsCount);
+
+ for (unsigned acc = 0, row = 1; row <= rowCount; row++) {
+ for (unsigned seat = 1; seat <= seatsCount; seat++, acc++) {
+ if (events[eInd].get_tickets().contain(Ticket(row, seat)))
+ out[acc] = 'B';
+ else if (events[eInd].get_reservations().contain(Ticket(row, seat)))
+ out[acc] = 'R';
+ else
+ out[acc] = ' ';
+ }
+ }
+
+ return out;
+}
+
+unsigned indexToInsertWhenTicketSort(const List<Event>& elem, unsigned topN, unsigned ticketCount) {
+ for (unsigned i = 0; i < elem.get_count() && i < topN; i++) {
+ if (elem[i].get_tickets().get_count() <= ticketCount)
+ return i;
+ }
+ return (topN < elem.get_count()) ? topN : elem.get_count();
+}
+
+/*!
+ * Events are sorted from index 0 to last index decreasingly by number of watchers.
+ * Watchers count for an Event is the amount of bought tickets.
+ *
+ * If there are less events than topN, all events are returned.
+ */
+List<Event> EventService::queryMostWatched(unsigned topN) {
+ List<Event> result;
+ for (unsigned i = 0; i < events.get_count(); i++) {
+ unsigned ind = indexToInsertWhenTicketSort(result, topN, events[i].get_tickets().get_count());
+ if (ind < topN)
+ result.insertAt(events[i], ind);
+ if (result.get_count() > topN)
+ result.removeAt(topN);
+ }
+ return result;
+}
+
+List<Event> EventService::queryInsufficientlyVisited() {
+ List<Event> result;
+ for (unsigned i = 0; i < events.get_count(); i++) {
+ if (events[i].get_tickets().get_count() < events[i].get_hall().get_rows() * events[i].get_hall().get_seatsPerRow() / 10)
+ result.add(events[i]);
+ }
+ return result;
+}
+
+template <typename T>
+bool cond_event_all(const Event& e1, T scrap) {
+ return true;
+}
+
+bool cond_event_name(const Event& e, const char* name) {
+ return e.get_name().compare(name) == 0;
+}
+
+bool cond_event_date(const Event& e, const Date& date) {
+ return e.get_date().compare(date) == 0;
+}
+
+/*! \param name C-style string, if it is equal to "ALL", reservations from all Events on the given date will be reported
+ * \param date If day, month and year are equal to 0, reservations from all dates will be reported
+ *
+ * Report is saved in a file in the current directory, named "report-NAME-DATE.txt",
+ * where NAME is the given name, and DATE is the given date or "ALL" if the date is 0/0/0
+ *
+ * All Events are inserted into the file with the << operator and a setting of 0b00101.
+ *
+ * \return E_FileCouldNotBeOpened \b if Report file couldn't be created
+ * \return Success \b otherwise
+ */
+StatusCode EventService::reportReservations(const char* name, const Date& date) {
+ List<Event> result;
+ bool (*cond_name)(const Event&, const char*) = cond_event_name;
+ bool (*cond_date)(const Event&, const Date&) = cond_event_date;
+
+ if (strcmp(name, "ALL") == 0) cond_name = cond_event_all;
+ if (date.compare(Date(0, 0, 0)) == 0) cond_date = cond_event_all;
+
+ for (unsigned i = 0; i < events.get_count(); i++) {
+ if (cond_name(events[i], name) && cond_date(events[i], date))
+ result.add(events[i]);
+ }
+
+ String outFileName("report-");
+ (outFileName += name) += "-";
+ if (date.compare(Date(0, 0, 0)) == 0)
+ outFileName += "ALL";
+ else
+ outFileName += date.createString().get_cstr();
+ outFileName += ".txt";
+
+ std::ofstream outFile(outFileName.get_cstr());
+ if (!outFile.is_open())
+ return E_FileCouldNotBeOpened;
+
+ configureEventInsertionOp(0b00101);
+ outFile << result;
+ outFile.close();
+
+ return Success;
+}
+
+bool cond_event_hallNumber(const Event& event, int hallNumber) {
+ return event.get_hall().get_number() == hallNumber;
+}
+
+bool cond_event_dates(const Event& event, const Date& start, const Date& end) {
+ return event.get_date().compare(start) >= 0 && event.get_date().compare(end) <= 0;
+}
+
+/*! \param hallNumber Number of the Event's Hall
+ * \param start Starting Date from which to take Events
+ * \param end Ending Date until which to take Evnets (including)
+ *
+ * Report is saved in a file named "boughtTickets.txt" in the current directory.
+ *
+ * All Events are inserted into the file with the << operator and a setting of 0b01001.
+ *
+ * \return E_FileCouldNotBeOpened \b if Report file couldn't be created
+ * \return Success \b otherwise
+ */
+StatusCode EventService::reportBoughtTickets(int hallNumber, const Date& start, const Date& end, bool all) {
+ List<Event> result;
+ bool (*cond_hall)(const Event&, int) = cond_event_hallNumber;
+ if (all) cond_hall = cond_event_all;
+
+ for (unsigned i = 0; i < events.get_count(); i++) {
+ if (cond_hall(events[i], hallNumber) && cond_event_dates(events[i], start, end))
+ result.add(events[i]);
+ }
+
+ std::ofstream outFile("boughtTickets.txt");
+ if (!outFile.is_open())
+ return E_FileCouldNotBeOpened;
+
+ configureEventInsertionOp(0b01001);
+ outFile << result;
+ outFile.close();
+
+ return Success;
+
+}
+
+/*!
+ * Looks for file named "eventsDatabse.fmits", which is just a binary file, and then reads it with the "read" function in events List.
+ *
+ * \return E_FileCouldNotBeOpened \b if The files couldn't be opened/Doesn't exist
+ * \return Success \b otherwise
+ */
+StatusCode EventService::load() {
+ std::ifstream inFile("eventsDatabase.fmits");
+ if (!inFile.is_open())
+ return E_FileCouldNotBeOpened;
+
+ events.read(inFile);
+ inFile.close();
+ return Success;
+}
+
+/*!
+ * Looks for file named "eventsDatabse.fmits", which is just a binary file, and then writes to it with the "write" function in events List.
+ *
+ * \return E_FileCouldNotBeOpened \b if The files couldn't be opened
+ * \return Success \b otherwise
+ */
+StatusCode EventService::save() {
+ std::ofstream outFile("eventsDatabase.fmits");
+ if (!outFile.is_open())
+ return E_FileCouldNotBeOpened;
+
+ events.write(outFile);
+ outFile.close();
+ return Success;
+}
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Services/EventService.h b/Year 1/Object-oriented Programming/Project 1/src/Services/EventService.h
new file mode 100644
index 0000000..f6c94ca
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Services/EventService.h
@@ -0,0 +1,65 @@
+#ifndef HEADER_SERVICES_EVENTSERVICE
+#define HEADER_SERVICES_EVENTSERVICE
+
+/*! \file EventService.h
+ * \brief Stores the declaration of class EventService
+ */
+
+#include "../Generic/List/OrderedList.hpp"
+#include "../Generic/Date/Date.h"
+#include "../Models/Event.h"
+#include "HallService.h"
+#include "StatusCode.h"
+
+/*! \brief Each EventService stores all events and a pointer to HallService
+ */
+class EventService {
+ OrderedList<Event> events;
+
+ const HallService* hs;
+
+ unsigned indexOfEvent(const char* name, const Date& date);
+
+public:
+ //! Sets HallService pointer and initializes events List
+ EventService(const HallService* hs);
+ //! Sets HallService pointer and copies values from events into events List
+ EventService(const HallService* hs, const Event* events, unsigned eventCount);
+
+ //! Creates an Event, with the given hallNumber, name and date
+ StatusCode createEvent(int hallNumber, const String& name, const Date& date);
+ //! Cancels an Event with the given name and date
+ StatusCode cancelEvent(const char* name, const Date& date);
+
+ //! Creates a Reservation for an Event by name and date
+ StatusCode reserveTicket(const char* name, const Date& date, const char* password, const char* note, const Ticket& ticket);
+ //! Cancels a Reservation for a ticket
+ StatusCode cancelTicketReservation(const char* name, const Date& date, const Ticket& ticket);
+ //! Whether a ticket is a reserved or not
+ StatusCode ticketIsReserved(const char* name, const Date& date, const Ticket& ticket);
+
+ //! Buys ticket, assuming it is reserved and stores the reservation note
+ StatusCode buyTicket(const char* name, const Date& date, const Ticket& ticket, const char* password, String* reservationNoteOutput);
+ //! Buys ticket, assuming it isn't reserved
+ StatusCode buyTicket(const char* name, const Date& date, const Ticket& ticket);
+
+ //! Creates a special String for status of all seats in given Event (by name and date) and returns seatsPerRow in given pointer
+ String createSeatingString(const char* name, const Date& date, unsigned* seatsPerRow);
+
+ //! \return A List of topN most watched Events
+ List<Event> queryMostWatched(unsigned topN);
+ //! \return A List of events which have attracted sales of less than 10% of the Hall's seat
+ List<Event> queryInsufficientlyVisited();
+
+ //! Creates a report that lists all Events (with given name and date) and their reserved tickets
+ StatusCode reportReservations(const char* name, const Date& date);
+ //! Creates a report that Lists all Events (with given name and date) and number of bought tickets
+ StatusCode reportBoughtTickets(int hallNumber, const Date& start, const Date& end, bool all = false);
+
+ //! Loads Events from a database file
+ StatusCode load();
+ //! Saves Events to a database file
+ StatusCode save();
+};
+
+#endif
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Services/HallService.cpp b/Year 1/Object-oriented Programming/Project 1/src/Services/HallService.cpp
new file mode 100644
index 0000000..20c7a0f
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Services/HallService.cpp
@@ -0,0 +1,42 @@
+#include "HallService.h"
+#include <fstream>
+
+HallService::HallService(const Hall* halls, unsigned hallCount) {
+ this->halls = OrderedList<Hall>(halls, hallCount);
+}
+
+const OrderedList<Hall>& HallService::get_halls() const {
+ return halls;
+}
+
+/*!
+ * Looks for file named "hallsDatabse.fmits", which is just a binary file, and then reads it with the "read" function in events List.
+ *
+ * \return E_FileCouldNotBeOpened \b if The files couldn't be opened/Doesn't exist
+ * \return Success \b otherwise
+ */
+StatusCode HallService::load() {
+ std::ifstream inFile("hallsDatabase.fmits");
+ if (!inFile.is_open())
+ return E_FileCouldNotBeOpened;
+
+ halls.read(inFile);
+ inFile.close();
+ return Success;
+}
+
+/*!
+ * Looks for file named "hallsDatabse.fmits", which is just a binary file, and then writes to it with the "write" function in events List.
+ *
+ * \return E_FileCouldNotBeOpened \b if The files couldn't be opened
+ * \return Success \b otherwise
+ */
+StatusCode HallService::save() {
+ std::ofstream outFile("hallsDatabase.fmits");
+ if (!outFile.is_open())
+ return E_FileCouldNotBeOpened;
+
+ halls.write(outFile);
+ outFile.close();
+ return Success;
+}
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Services/HallService.h b/Year 1/Object-oriented Programming/Project 1/src/Services/HallService.h
new file mode 100644
index 0000000..09bda89
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Services/HallService.h
@@ -0,0 +1,30 @@
+#ifndef HEADER_SERVICES_HALLSERVICE
+#define HEADER_SERVICES_HALLSERVICE
+
+/*! \file HallService.h
+ * \brief Stores the declaration of class HallService
+ */
+
+#include "../Generic/List/OrderedList.hpp"
+#include "../Models/Hall.h"
+#include "StatusCode.h"
+
+/*! \brief Each HallService stores all halls
+ */
+class HallService {
+ OrderedList<Hall> halls;
+
+public:
+ //! Copies halls from parameters
+ HallService(const Hall* halls, unsigned hallCount);
+
+ //! Returns a constant reference to halls
+ const OrderedList<Hall>& get_halls() const;
+
+ //! Loads Halls to a database file
+ StatusCode load();
+ //! Saves Halls to a database file
+ StatusCode save();
+};
+
+#endif
diff --git a/Year 1/Object-oriented Programming/Project 1/src/Services/StatusCode.h b/Year 1/Object-oriented Programming/Project 1/src/Services/StatusCode.h
new file mode 100644
index 0000000..9d3b94f
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/Services/StatusCode.h
@@ -0,0 +1,35 @@
+#ifndef HEADER_SERVICES_STATUSCODE
+#define HEADER_SERVICES_STATUSCODE
+
+/*! \file StatusCode.h
+ * \brief Stores declaration of enum StatusCode
+ */
+
+/*! \brief Used for communication between Services and what uses them
+ *
+ * Most functions in Services return a StatusCode.
+ *
+ * Those starting with W should be considered Warning, and those starting with E should be considered Errors.
+ */
+enum StatusCode {
+ Success,
+
+
+ W_TicketHadNotBeenReserved,
+
+
+ E_FileCouldNotBeOpened,
+
+ E_HallDoesntExist,
+
+ E_EventWillOverlap,
+ E_EventDoesNotExist,
+
+ E_InvalidSeat,
+ E_TicketAlreadyBought,
+ E_TicketAlreadyReserved,
+ E_ReservationDoesNotExist,
+ E_WrongReservationPassword,
+};
+
+#endif
diff --git a/Year 1/Object-oriented Programming/Project 1/src/UserInterface/FMITicketSystemConsoleUI.cpp b/Year 1/Object-oriented Programming/Project 1/src/UserInterface/FMITicketSystemConsoleUI.cpp
new file mode 100644
index 0000000..6e4321d
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/UserInterface/FMITicketSystemConsoleUI.cpp
@@ -0,0 +1,295 @@
+#include "FMITicketSystemConsoleUI.h"
+#include "../Generic/List/OrderedList.hpp"
+#include "../Generic/String/String.h"
+#include "../Generic/Date/Date.h"
+#include "../Generic/ConsoleInterface/Menu.h"
+#include "../Generic/ConsoleInterface/Toolbox.hpp"
+#include "../Services/StatusCode.h"
+#include "../Models/Reservation.h"
+#include <cstring>
+
+EventService* es;
+HallService* hs;
+
+Menu mainMenu("FMI Ticket System", true, false),
+ ticketManagementMenu("Ticket management", false, true),
+ eventManagementMenu("Event management", false, true),
+ reportsMenu("Report management", false, true);
+
+void handleStatusCode(StatusCode sc, Menu menu) {
+ switch (sc) {
+ case Success:
+ menu.registerSuccess("Success!"); break;
+ case W_TicketHadNotBeenReserved:
+ menu.registerWarning("Ticket hadn't been reserved. Nothing changed."); break;
+ case E_EventDoesNotExist:
+ menu.registerError("Event doesn't exist!"); break;
+ case E_EventWillOverlap:
+ menu.registerError("There is already an event at same time!"); break;
+ case E_TicketAlreadyBought:
+ menu.registerError("Ticket was already bought!"); break;
+ case E_TicketAlreadyReserved:
+ menu.registerError("Ticket was already reserved!"); break;
+ case E_ReservationDoesNotExist:
+ menu.registerError("Reservation doesn't exist!"); break;
+ case E_WrongReservationPassword:
+ menu.registerError("Wrong reservation password!"); break;
+ case E_FileCouldNotBeOpened:
+ menu.registerError("An error occurred while trying to open a file!"); break;
+ case E_InvalidSeat:
+ menu.registerError("The seat doesn't exist!"); break;
+ default:
+ menu.registerError("An unhandled status code was returned!"); break;
+ }
+}
+
+/* Ticket Management */
+
+void command_freeSeats() {
+ char name[MAX_LINE_WIDTH];
+ inputLineSubBox("Enter event name: ", name, MAX_LINE_WIDTH);
+ Date date;
+ inputSubBox("Enter event date: ", &date);
+
+ unsigned seatsPerRow = 0;
+ String seating = es->createSeatingString(name, date, &seatsPerRow);
+ if (seating.get_length() == 0) {
+ handleStatusCode(E_EventDoesNotExist, ticketManagementMenu);
+ return;
+ }
+
+ table(1, seatsPerRow, seating.get_cstr());
+ pressEnterToContinue();
+}
+
+void command_reserveTicket() {
+ char name[MAX_LINE_WIDTH];
+ inputLineSubBox("Enter event name: ", name, MAX_LINE_WIDTH);
+ Date date;
+ inputSubBox("Enter event date [day month year]: ", &date);
+ Ticket tic;
+ inputSubBox("Enter row and seat [row seat]: ", &tic);
+ char password[PASSWORD_LEN];
+ inputLineSubBox("Enter password [Max 8 characters]: ", password, PASSWORD_LEN);
+ char note[NOTE_LEN];
+ inputLineSubBox("Enter note [Max 32 characters]: ", note, NOTE_LEN, false);
+
+ StatusCode s = es->reserveTicket(name, date, password, note, tic);
+ handleStatusCode(s, ticketManagementMenu);
+}
+
+void command_cancelReservation() {
+ char name[MAX_LINE_WIDTH];
+ inputLineSubBox("Enter event name: ", name, MAX_LINE_WIDTH);
+ Date date;
+ inputSubBox("Enter event date [day month year]: ", &date);
+ Ticket tic;
+ inputSubBox("Enter row and seat [row seat]: ", &tic);
+
+ StatusCode s = es->cancelTicketReservation(name, date, tic);
+ handleStatusCode(s, ticketManagementMenu);
+}
+
+void command_buyTicket() {
+ char name[MAX_LINE_WIDTH];
+ inputLineSubBox("Enter event name: ", name, MAX_LINE_WIDTH);
+ Date date;
+ inputSubBox("Enter event date [day month year]: ", &date);
+ Ticket tic;
+ inputSubBox("Enter row and seat [row seat]: ", &tic);
+
+ StatusCode s = es->ticketIsReserved(name, date, tic);
+ if (s == Success) {
+ warningSubBox("Ticket is reserved!");
+
+ char pass[PASSWORD_LEN];
+ inputLineSubBox("Enter reservation password: ", pass, PASSWORD_LEN);
+
+ String note;
+ s = es->buyTicket(name, date, tic, pass, &note);
+ if (note.get_length() > 0) {
+ successSubBox("The reservation had a note attached. It reads:");
+ successSubBox(note.get_cstr());
+ pressEnterToContinue(false);
+ }
+ }
+ else if (s == W_TicketHadNotBeenReserved) {
+ s = es->buyTicket(name, date, tic);
+ }
+
+ handleStatusCode(s, ticketManagementMenu);
+}
+
+void submenu_ticketManagement() {
+ ticketManagementMenu.navigate();
+}
+
+/* Event Management */
+
+void command_createEvent() {
+ int hallNumber;
+ inputSubBox("Enter hall number: ", &hallNumber);
+ char name[MAX_LINE_WIDTH];
+ inputLineSubBox("Enter event name: ", name, MAX_LINE_WIDTH);
+ Date date;
+ inputSubBox("Enter event date [day month year]: ", &date);
+
+ StatusCode s = es->createEvent(hallNumber, name, date);
+ handleStatusCode(s, eventManagementMenu);
+}
+
+void command_cancelEvent() {
+ char name[MAX_LINE_WIDTH];
+ inputLineSubBox("Enter event name: ", name, MAX_LINE_WIDTH);
+ Date date;
+ inputSubBox("Enter event date [day month year]: ", &date);
+
+ StatusCode s = es->cancelEvent(name, date);
+ handleStatusCode(s, eventManagementMenu);
+}
+
+void customPrintEvent(const Event& ev) {
+ print(ev.get_name());
+ print(" || Hall ");
+ print(ev.get_hall().get_number());
+ print(" @ ");
+ printLine(ev.get_date());
+}
+
+void command_mostWatched() {
+ unsigned topN;
+ inputSubBox("How many to take?: ", &topN);
+
+ List<Event> top = es->queryMostWatched(topN);
+
+ printLine("");
+ print("The top ");
+ print(topN);
+ printLine(" most watched events are:");
+
+ resetOrderedList(1);
+ for (unsigned i = 0; i < top.get_count(); i++) {
+ _printOrderedListBeginning();
+ customPrintEvent(top[i]);
+ }
+
+ pressEnterToContinue();
+}
+
+void command_belowWatchers() {
+ printLine("Events with less than 10% bought tickets in hall:");
+
+ List<Event> least = es->queryInsufficientlyVisited();
+ for (unsigned i = 0; i < least.get_count(); i++) {
+ customPrintEvent(least[i]);
+ }
+
+ bool toDelete;
+ inputBox("Do you want to cancel them? [0/1]: ", &toDelete);
+ if (toDelete) {
+ StatusCode s = Success;
+ for (unsigned i = 0; i < least.get_count(); i++)
+ s = es->cancelEvent(least[i].get_name().get_cstr(), least[i].get_date());
+ handleStatusCode(s, eventManagementMenu);
+ }
+}
+
+void submenu_eventManagement() {
+ eventManagementMenu.navigate();
+}
+
+/* Report Management */
+
+void command_reservationsList() {
+ char name[MAX_LINE_WIDTH];
+ inputLineSubBox("Enter event name: ", name, MAX_LINE_WIDTH);
+ char dateStr[MAX_LINE_WIDTH];
+ inputLineSubBox("Enter event date [day month year]: ", dateStr, MAX_LINE_WIDTH, false);
+
+ Date date(dateStr);
+
+ StatusCode s = es->reportReservations(name, date);
+ handleStatusCode(s, reportsMenu);
+}
+
+void command_boughtTickets() {
+ char hallNumber[MAX_LINE_WIDTH];
+ inputLineSubBox("Enter hall number: ", hallNumber, MAX_LINE_WIDTH);
+ Date start, end;
+ inputSubBox("Enter start date [day month year]: ", &start);
+ inputSubBox("Enter end date [day month year]: ", &end);
+
+ StatusCode s;
+ if (strcmp(hallNumber, "ALL") == 0)
+ s = es->reportBoughtTickets(0, start, end, true);
+ else
+ s = es->reportBoughtTickets(atoi(hallNumber), start, end);
+
+ handleStatusCode(s, reportsMenu);
+}
+
+void submenu_reportManagement() {
+ reportsMenu.navigate();
+}
+
+/* Main */
+
+void load() {
+ StatusCode s = es->load();
+ if (s == E_FileCouldNotBeOpened) {
+ errorBox("Could not load events from file!");
+ pressEnterToContinue(false);
+ }
+ s = hs->load();
+ if (s == E_FileCouldNotBeOpened) {
+ errorBox("Could not load halls from file!");
+ pressEnterToContinue(false);
+ }
+}
+
+void save() {
+ StatusCode s = es->save();
+ if (s == E_FileCouldNotBeOpened) {
+ errorBox("Could not save events to file!");
+ pressEnterToContinue();
+ }
+ s = hs->save();
+ if (s == E_FileCouldNotBeOpened) {
+ errorBox("Could not save halls to file!");
+ pressEnterToContinue(false);
+ }
+}
+
+void init() {
+ mainMenu.addCommand(Command("Ticket Management", submenu_ticketManagement));
+ mainMenu.addCommand(Command("Event Management", submenu_eventManagement));
+ mainMenu.addCommand(Command("Report Management", submenu_reportManagement));
+
+ ticketManagementMenu.addCommand(Command("Print Seats", command_freeSeats));
+ ticketManagementMenu.addCommand(Command("Reserve Ticket", command_reserveTicket));
+ ticketManagementMenu.addCommand(Command("Cancel Ticket Reservation", command_cancelReservation));
+ ticketManagementMenu.addCommand(Command("Buy Ticket", command_buyTicket));
+
+ eventManagementMenu.addCommand(Command("Create Event", command_createEvent));
+ eventManagementMenu.addCommand(Command("Cancel Event", command_cancelEvent));
+ eventManagementMenu.addCommand(Command("Query - Most Watched", command_mostWatched));
+ eventManagementMenu.addCommand(Command("Query - Below 10% watchers", command_belowWatchers));
+
+ reportsMenu.addCommand(Command("Reservations List", command_reservationsList));
+ reportsMenu.addCommand(Command("Bought Tickets", command_boughtTickets));
+}
+
+/*!
+ * Stores EventService and HallService pointers in internal global variables,
+ * calls EventService and HallService load() functions,
+ * initializes all menus, navigates the main menu and
+ * finally calls EventService and HallService save() functions
+ */
+void runUI(EventService* eventService, HallService* hallService) {
+ es = eventService;
+ hs = hallService;
+ load();
+ init();
+ mainMenu.navigate();
+ save();
+}
diff --git a/Year 1/Object-oriented Programming/Project 1/src/UserInterface/FMITicketSystemConsoleUI.h b/Year 1/Object-oriented Programming/Project 1/src/UserInterface/FMITicketSystemConsoleUI.h
new file mode 100644
index 0000000..e8c4ac7
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/UserInterface/FMITicketSystemConsoleUI.h
@@ -0,0 +1,14 @@
+#ifndef HEADER_FMITICKETSYSTEMCONSOLEUI
+#define HEADER_FMITICKETSYSTEMCONSOLEUI
+
+/*! \file FMITicketSystemConsoleUI.h
+ * \brief Stores declaration of runUI function
+ */
+
+#include "../Services/EventService.h"
+#include "../Services/HallService.h"
+
+//! Runs the console interface for the ticket system
+void runUI(EventService* eventService, HallService* hallService);
+
+#endif
diff --git a/Year 1/Object-oriented Programming/Project 1/src/main.cpp b/Year 1/Object-oriented Programming/Project 1/src/main.cpp
new file mode 100644
index 0000000..bdf3a2b
--- /dev/null
+++ b/Year 1/Object-oriented Programming/Project 1/src/main.cpp
@@ -0,0 +1,23 @@
+/*! \file main.cpp
+ * \brief Entry point for application
+ *
+ * Contains the main() function.
+ */
+
+#include "Services/EventService.h"
+#include "Services/HallService.h"
+#include "Models/Hall.h"
+#include "UserInterface/FMITicketSystemConsoleUI.h"
+
+/*!
+ * Creates instances of HallService and EventService and
+ * executes runUI() function.
+ */
+int main() {
+ Hall myVenueHalls[] = { Hall(1, 20, 30), Hall(2, 15, 15), Hall(3, 10, 20) };
+
+ HallService hs(myVenueHalls, 3);
+ EventService es(&hs);
+
+ runUI(&es, &hs);
+}