Website Summary Files Commits Branches @commit @diff @stats
path: root / src / Generic
diff options
context:
space:
mode:
Commitb844597fd23bc57aa97e231fc90eecfd6322cecc (patch)
Author
 Syndamia <kamen.d.mladenov@protonmail.com>
2022-05-07 08:28:27 +0300
Committer
 Syndamia <kamen.d.mladenov@protonmail.com>
2022-05-07 08:28:27 +0300
Files86a4112ecfa1e3a54dbcf44a7ddf37575ba4aa39 /src/Generic
FMI-OOP-P1_TicketSystem-b844597fd23bc57aa97e231fc90eecfd6322cecc.tar
FMI-OOP-P1_TicketSystem-b844597fd23bc57aa97e231fc90eecfd6322cecc.tar.gz
FMI-OOP-P1_TicketSystem-b844597fd23bc57aa97e231fc90eecfd6322cecc.zip
Parent0910afb91c8f9672be1d6184f47fb75947ea14f1 (diff)
Reorganized whole architecture
diff --git a/src/Generic/ConsoleInterface/Command.cpp b/src/Generic/ConsoleInterface/Command.cpp
new file mode 100644
index 0000000..d3d058c
--- /dev/null
+++ b/src/Generic/ConsoleInterface/Command.cpp
@@ -0,0 +1,18 @@
+#include "Command.h"
+#include <cstring>
+
+Command::Command() : Command("", nullptr) {}
+
+Command::Command(const char* nameInMenu, void (*exec)()) {
+ strcpy(this->nameInMenu, nameInMenu);
+ this->exec = exec;
+}
+
+void Command::run() const {
+ if (exec != nullptr)
+ exec();
+}
+
+const char* Command::get_nameInMenu() const {
+ return nameInMenu;
+}
diff --git a/src/Generic/ConsoleInterface/Command.h b/src/Generic/ConsoleInterface/Command.h
new file mode 100644
index 0000000..d00b277
--- /dev/null
+++ b/src/Generic/ConsoleInterface/Command.h
@@ -0,0 +1,16 @@
+#ifndef HEADER_CONSOLEINTERFACE_COMMAND
+#define HEADER_CONSOLEINTERFACE_COMMAND
+
+class Command {
+ char nameInMenu[256];
+ void (*exec)();
+
+public:
+ Command();
+ Command(const char* nameInMenu, void (*exec)());
+ void run() const;
+
+ const char* get_nameInMenu() const;
+};
+
+#endif
diff --git a/src/Generic/ConsoleInterface/Menu.cpp b/src/Generic/ConsoleInterface/Menu.cpp
new file mode 100644
index 0000000..0b27d48
--- /dev/null
+++ b/src/Generic/ConsoleInterface/Menu.cpp
@@ -0,0 +1,90 @@
+#include "Menu.h"
+#include "Toolbox.hpp"
+#include <cstring>
+
+Menu::Menu() : Menu("Menu", false, false) {}
+
+Menu::Menu(const char* title, bool backExistsApp, bool isSubMenu) : menuOptions() {
+ this->backExistsApp = backExistsApp;
+ this->isSubMenu = isSubMenu;
+ strcpy(this->title, title);
+}
+
+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);
+ strcpy(this->title, title);
+}
+
+void Menu::addCommand(const Command& command) {
+ menuOptions.add(command);
+}
+
+enum MessageType {
+ NoPrint,
+ Success,
+ Warning,
+ Error,
+};
+String msg;
+MessageType msgType;
+
+void Menu::registerError(const char* message) const {
+ msg = message;
+ msgType = Error;
+}
+
+void Menu::registerWarning(const char* message) const {
+ msg = message;
+ msgType = Warning;
+}
+
+void Menu::registerSuccess(const char* message) const {
+ msg = message;
+ msgType = Success;
+}
+
+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.get_cstr()); msgType = NoPrint; break;
+ case Warning: warningBox(msg.get_cstr()); msgType = NoPrint; break;
+ case Success: successBox(msg.get_cstr()); 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/src/Generic/ConsoleInterface/Menu.h b/src/Generic/ConsoleInterface/Menu.h
new file mode 100644
index 0000000..2501871
--- /dev/null
+++ b/src/Generic/ConsoleInterface/Menu.h
@@ -0,0 +1,27 @@
+#ifndef HEADER_CONSOLEINTERFACE_MENU
+#define HEADER_CONSOLEINTERFACE_MENU
+
+#include "Command.h"
+#include "../List/List.hpp"
+
+class Menu {
+ char title[256];
+ List<Command> menuOptions;
+
+ bool backExistsApp;
+ bool isSubMenu;
+
+public:
+ Menu();
+ Menu(const char* title, bool backExistsApp, bool isSubMenu);
+ Menu(const char* title, bool backExistsApp, bool isSubMenu, const Command* commands, unsigned commandCount);
+
+ void addCommand(const Command& command);
+
+ void registerError(const char* message) const;
+ void registerWarning(const char* message) const;
+ void registerSuccess(const char* message) const;
+ void navigate() const;
+};
+
+#endif
diff --git a/src/Generic/ConsoleInterface/Toolbox.cpp b/src/Generic/ConsoleInterface/Toolbox.cpp
new file mode 100644
index 0000000..1f2e42c
--- /dev/null
+++ b/src/Generic/ConsoleInterface/Toolbox.cpp
@@ -0,0 +1,99 @@
+#include "Toolbox.hpp"
+
+void clear() {
+ // Clears console on Linux
+ // Source: https://stackoverflow.com/a/52895729/12036073
+ std::cout << u8"\033[2J\033[1;1H";
+}
+
+int orderedListIndex = 1;
+
+void resetOrderedList(int starter) {
+ orderedListIndex = starter;
+}
+
+void titleBox(const char* title) {
+ std::cout << std::endl << "=== " << title << " ===" << std::endl;
+}
+
+void subTitleBox(const char* title) {
+ std::cout << std::endl << "--- " << title << " ---" << std::endl;
+}
+
+void successBox(const char* message) {
+ std::cout << "<S> " << message << std::endl;
+}
+
+void warningBox(const char* message) {
+ std::cout << "<W> " << message << std::endl;
+}
+
+void errorBox(const char* message) {
+ std::cout << "<E> " << message << std::endl;
+}
+
+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;
+}
+
+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;
+}
+
+void _printOrderedListBeginning() {
+ std::cout << "[" << orderedListIndex++ << "] ";
+}
+
+void _printInputBoxLabel(const char* label) {
+ std::cout << "(+) " << label;
+}
+
+void _printInputSubBoxLabel(const char* label) {
+ std::cout << " ";
+ _printInputBoxLabel(label);
+}
+
+void __inputLineBoxGetInput(char* output, unsigned maxWidth) {
+ std::cin.ignore();
+ std::cin.getline(output, maxWidth);
+}
+
+void inputLineBox(const char* label, char* output, unsigned maxWidth) {
+ _printInputBoxLabel(label);
+ __inputLineBoxGetInput(output, maxWidth);
+}
+
+void inputLineSubBox(const char* label, char* output, unsigned maxWidth) {
+ _printInputSubBoxLabel(label);
+ __inputLineBoxGetInput(output, maxWidth);
+}
diff --git a/src/Generic/ConsoleInterface/Toolbox.hpp b/src/Generic/ConsoleInterface/Toolbox.hpp
new file mode 100644
index 0000000..ed5d6ac
--- /dev/null
+++ b/src/Generic/ConsoleInterface/Toolbox.hpp
@@ -0,0 +1,76 @@
+#ifndef HEADER_CONSOLEINTERFACE_TOOLBOX
+#define HEADER_CONSOLEINTERFACE_TOOLBOX
+
+#include "../String/String.h"
+#include <iostream>
+
+#define MAX_LINE_WIDTH 1024
+
+void clear();
+void titleBox(const char* title);
+void subTitleBox(const char* title);
+
+void successBox(const char* message);
+void warningBox(const char* message);
+void errorBox(const char* message);
+
+void table(unsigned startNumber, unsigned columns, const char* items);
+
+void inputLineBox(const char* label, char* output, unsigned maxWidth);
+void inputLineSubBox(const char* label, char* output, unsigned maxWidth);
+void resetOrderedList(int starter = 1);
+
+void _printInputBoxLabel(const char* label);
+void _printInputSubBoxLabel(const char* label);
+void _printOrderedListBeginning();
+
+template <class T>
+void read(T* storage) {
+ std::cin >> storage;
+}
+
+template <class T>
+void read(T& storage) {
+ std::cin >> storage;
+}
+
+template <class T>
+void print(const T* item) {
+ std::cout << item;
+}
+
+template <class T>
+void printLine(const T* item) {
+ std::cout << item << std::endl;
+}
+
+template <class T>
+void print(const T& item) {
+ std::cout << item;
+}
+
+template <class T>
+void printLine(const T& item) {
+ std::cout << item << std::endl;
+}
+
+
+template <typename T>
+void printOrderedListElem(const T& elem) {
+ _printOrderedListBeginning();
+ printLine(elem);
+}
+
+template <typename T>
+void inputBox(const char* label, T* output) {
+ _printInputBoxLabel(label);
+ std::cin >> *output;
+}
+
+template <typename T>
+void inputSubBox(const char* label, T* output) {
+ _printInputSubBoxLabel(label);
+ std::cin >> *output;
+}
+
+#endif
diff --git a/src/Generic/Date/Date.cpp b/src/Generic/Date/Date.cpp
new file mode 100644
index 0000000..4732b0c
--- /dev/null
+++ b/src/Generic/Date/Date.cpp
@@ -0,0 +1,74 @@
+#include "Date.h"
+
+/* 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) {}
+
+Date::Date(unsigned short day, unsigned short month, unsigned short year) {
+ this->day = day;
+ this->month = month;
+ this->year = year;
+}
+
+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;
+}
+
+unsigned short Date::get_day() const {
+ return day;
+}
+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;
+}
+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;
+}
+bool Date::set_year(unsigned short newYear) {
+ year = newYear;
+ return true;
+}
+
+/* Outside of class */
+
+std::istream& operator>>(std::istream& istr, Date& dt) {
+ unsigned short d, M, y;
+ istr >> d >> M >> y;
+ dt = Date(d, M, y);
+ return istr;
+}
+
+std::ostream& operator<<(std::ostream& ostr, const Date& dt) {
+ ostr << dt.get_day() << "." << dt.get_month() << "." << dt.get_year();
+ return ostr;
+}
diff --git a/src/Generic/Date/Date.h b/src/Generic/Date/Date.h
new file mode 100644
index 0000000..5d1ff62
--- /dev/null
+++ b/src/Generic/Date/Date.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_DATETIME
+#define HEADER_DATETIME
+
+#include <istream>
+#include <ostream>
+
+class Date {
+ unsigned short day;
+ unsigned short month;
+ unsigned short year;
+
+ bool isLeapYear();
+ unsigned short daysInMonth();
+
+public:
+ Date();
+ Date(unsigned short day, unsigned short month, unsigned short year);
+ int compare(const Date& other) const;
+
+ unsigned short get_day() const;
+ bool set_day(unsigned short newDay);
+
+ unsigned short get_month() const;
+ bool set_month(unsigned short newMonth);
+
+ unsigned short get_year() const;
+ bool set_year(unsigned short newYear);
+};
+
+std::istream& operator>>(std::istream& istr, Date& dt);
+std::ostream& operator<<(std::ostream& ostr, const Date& dt);
+
+#endif
diff --git a/src/Generic/List/List.hpp b/src/Generic/List/List.hpp
new file mode 100644
index 0000000..7088f2e
--- /dev/null
+++ b/src/Generic/List/List.hpp
@@ -0,0 +1,213 @@
+#ifndef HEADER_LIST
+#define HEADER_LIST
+
+#include <istream>
+#include <ostream>
+
+template <class T>
+class List {
+protected:
+ T* elements;
+ unsigned length;
+ unsigned count;
+
+ void resize();
+ void free();
+ void copyFrom(const List& other);
+
+public:
+ List(const T* elements, unsigned elementsCount);
+ void add(const T& element);
+ void insertAt(const T& element, unsigned index);
+ bool removeAt(unsigned index);
+ unsigned findIndex(const T& element) const;
+ bool contain(const T& element) const;
+ T& operator[](unsigned index);
+ const T& operator[](unsigned index) const;
+
+ std::istream& read(std::istream& istr);
+ std::ostream& write(std::ostream& ostr) const;
+
+ unsigned get_length() const;
+ unsigned get_count() const;
+
+ List();
+ List& operator=(const List& other);
+ List(const List& other);
+ ~List();
+
+ List(List&& other);
+ List& operator=(List&& other);
+};
+
+/* Private */
+
+template <class 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 <class T>
+void List<T>::free() {
+ delete[] elements;
+}
+
+template <class 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 <class 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];
+}
+
+template <class T>
+void List<T>::add(const T& element) {
+ if (length == count) resize();
+
+ elements[count++] = element;
+}
+
+template <class T>
+void List<T>::insertAt(const T& element, unsigned index) {
+ if (index >= count) add(element);
+ if (length == count) resize();
+
+ for (unsigned i = count; i > index; i--)
+ elements[i] = elements[i - 1];
+
+ elements[index] = element;
+ count++;
+}
+
+template <class 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;
+}
+
+template <class T>
+unsigned List<T>::findIndex(const T& element) const {
+ unsigned ind = 0;
+ while (ind < count && elements[ind].compare(element) != 0)
+ ind++;
+ return ind;
+}
+
+template <class T>
+bool List<T>::contain(const T& element) const {
+ return findIndex(element) < count;
+}
+
+template <class T>
+T& List<T>::operator[](unsigned index) {
+ return elements[index];
+}
+
+template <class T>
+const T& List<T>::operator[](unsigned index) const {
+ return elements[index];
+}
+
+template <class 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); // disgusting
+
+ return istr;
+}
+
+template <class 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); // disgusting
+
+ return ostr;
+}
+
+template <class T>
+unsigned List<T>::get_length() const {
+ return length;
+}
+
+template <class T>
+unsigned List<T>::get_count() const {
+ return count;
+}
+
+// Rule of 4
+
+template <class T>
+List<T>::List() : List(nullptr, 0) {}
+
+template <class T>
+List<T>& List<T>::operator=(const List& other) {
+ if (this != &other) {
+ free();
+ copyFrom(other);
+ }
+ return *this;
+}
+
+template <class T>
+List<T>::List(const List& other) {
+ copyFrom(other);
+}
+
+template <class T>
+List<T>::~List() {
+ free();
+}
+
+// Move semantics
+
+template <class T>
+List<T>::List(List&& other) {
+ length = other.length;
+ count = other.count;
+ elements = other.elements;
+ other.elements = nullptr;
+}
+
+template <class 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;
+}
+
+#endif
diff --git a/src/Generic/List/OrderedList.hpp b/src/Generic/List/OrderedList.hpp
new file mode 100644
index 0000000..4396d33
--- /dev/null
+++ b/src/Generic/List/OrderedList.hpp
@@ -0,0 +1,36 @@
+#ifndef HEADER_ORDEREDLIST
+#define HEADER_ORDEREDLIST
+
+#include "List.hpp"
+
+template <class T>
+class OrderedList : public List<T> {
+public:
+ OrderedList();
+ OrderedList(const T* elements, unsigned elementsCount);
+
+ void add(const T& element) = delete;
+ void insertAt(const T& element, unsigned index) = delete;
+
+ void insert(const T& element);
+ // unsigned findIndex(const T& element) const; TODO: binary search
+};
+
+template <class T>
+OrderedList<T>::OrderedList() : OrderedList(nullptr, 0) {}
+
+template <class T>
+OrderedList<T>::OrderedList(const T* elements, unsigned elementsCount) : List<T>::List(elements, elementsCount) {}
+
+template <class T>
+void OrderedList<T>::insert(const T& element) {
+ if (List<T>::length == List<T>::count) List<T>::resize();
+
+ unsigned insertionInd = 0;
+ while (List<T>::elements[insertionInd].compare(element) < 0 && insertionInd < List<T>::count)
+ insertionInd++;
+
+ List<T>::insertAt(element, insertionInd);
+}
+
+#endif
diff --git a/src/Generic/String/String.cpp b/src/Generic/String/String.cpp
new file mode 100644
index 0000000..055f48e
--- /dev/null
+++ b/src/Generic/String/String.cpp
@@ -0,0 +1,68 @@
+#include "String.h"
+#include <cstring>
+
+/* Private */
+
+void String::free() {
+ delete[] str;
+}
+
+void String::copyFrom(const String& other) {
+ str = new char[other.length];
+ strcpy(str, other.str);
+ length = other.length;
+}
+
+/* Public */
+
+String::String(const char* str) {
+ length = strlen(str) + 1; // capture terminating zero
+ this->str = new char[length];
+ strcpy(this->str, str);
+}
+
+const char* String::get_cstr() const {
+ return str;
+}
+
+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;
+}
+
+int String::compare(const String& other) const {
+ return strcmp(str, other.str);
+}
+
+char String::operator[](unsigned index) {
+ return str[index];
+}
diff --git a/src/Generic/String/String.h b/src/Generic/String/String.h
new file mode 100644
index 0000000..85bb284
--- /dev/null
+++ b/src/Generic/String/String.h
@@ -0,0 +1,27 @@
+#ifndef HEADER_STRING
+#define HEADER_STRING
+
+class String {
+ char* str;
+ unsigned length;
+
+ void free();
+ void copyFrom(const String& other);
+
+public:
+ String(const char* str);
+ const char* get_cstr() const;
+
+ String();
+ String(const String& other);
+ String& operator=(const String& other);
+ ~String();
+
+ String(String&& other);
+ String& operator=(String&& other);
+
+ int compare(const String& other) const;
+ char operator[](unsigned index);
+};
+
+#endif