Website Summary Files Commits Branches @commit @diff @stats
path: root / Week07 / Exercise01
diff options
context:
space:
mode:
Commit945f7e67d6ca8047c961457786fac5e2d9a13d82 (patch)
Author
 Syndamia <kamen@syndamia.com>
2026-04-03 18:17:51 +0300
Committer
 Syndamia <kamen@syndamia.com>
2026-04-03 18:17:51 +0300
Files5c6b23aaee4eb653f9c461d7303edcd31d697f10 /Week07/Exercise01
oop-2025-solutions-945f7e67d6ca8047c961457786fac5e2d9a13d82.tar
oop-2025-solutions-945f7e67d6ca8047c961457786fac5e2d9a13d82.tar.gz
oop-2025-solutions-945f7e67d6ca8047c961457786fac5e2d9a13d82.zip
Parent8f162cde46a34d04e3a8a655067ee5174258e249 (diff)
feat(Week07): Add solutions
diff --git a/Week07/Exercise01/BankClerk.cpp b/Week07/Exercise01/BankClerk.cpp
new file mode 100644
index 0000000..697894b
--- /dev/null
+++ b/Week07/Exercise01/BankClerk.cpp
@@ -0,0 +1,21 @@
+#include "BankClerk.h"
+
+BankClerk::BankClerk(unsigned clerkNumber) {
+ this->clerkNumber = clerkNumber;
+ this->staticPassword = "password";
+}
+
+BankClerk::BankClerk() : clerkNumber(0), staticPassword()
+{ }
+
+unsigned BankClerk::GetClerkNumber() const {
+ return clerkNumber;
+}
+
+void BankClerk::SetPassword(const String& newPassword) {
+ staticPassword = newPassword;
+}
+
+bool BankClerk::Login(unsigned clerkNumber, unsigned dynamicPassword, const String& staticPassword) {
+ return (clerkNumber * dynamicPassword) % 8581 == 0 && this->staticPassword.EqualTo(staticPassword);
+}
diff --git a/Week07/Exercise01/BankClerk.h b/Week07/Exercise01/BankClerk.h
new file mode 100644
index 0000000..5692ef8
--- /dev/null
+++ b/Week07/Exercise01/BankClerk.h
@@ -0,0 +1,23 @@
+#ifndef _BANKCLERK
+#define _BANKCLERK
+
+#include "String.h"
+
+class BankClerk {
+ unsigned clerkNumber;
+ String staticPassword;
+
+public:
+ BankClerk(unsigned clerkNumber);
+ // Ако направим поне един конструктор, то конструктора по подразбиране
+ // спира да се създава автоматично
+ BankClerk();
+
+ unsigned GetClerkNumber() const;
+
+ void SetPassword(const String& newPassword);
+
+ bool Login(unsigned clerkNumber, unsigned dynamicPassword, const String& staticPassword);
+};
+
+#endif /* _BANKCLERK */
diff --git a/Week07/Exercise01/Book.cpp b/Week07/Exercise01/Book.cpp
new file mode 100644
index 0000000..d48e090
--- /dev/null
+++ b/Week07/Exercise01/Book.cpp
@@ -0,0 +1,96 @@
+#include "Book.h"
+#include <iostream>
+#include <fstream>
+
+void Book::SetTitle(const String& newTitle) {
+ title = newTitle;
+}
+
+const String& Book::GetTitle() const {
+ return title;
+}
+
+void Book::SetAuthor(const String& newAuthor) {
+ author = newAuthor;
+}
+
+const String& Book::GetAuthor() const {
+ return author;
+}
+
+void Book::SetYear(short newYear) {
+ year = newYear;
+}
+
+short Book::GetYear() const {
+ return year;
+}
+
+void Book::SetText(const String& newText) {
+ text = newText;
+}
+
+const String& Book::GetText() const {
+ return text;
+}
+
+void Book::SetPrice(double newPrice) {
+ price = newPrice;
+}
+
+double Book::GetPrice() const {
+ return price;
+}
+
+void Book::SetAvailableForPurchase(bool isAvailableForPurchase) {
+ availableForPurchase = isAvailableForPurchase;
+}
+
+bool Book::GetAvailableForPurchase() const {
+ return availableForPurchase;
+}
+
+void Book::PrintBookInfo() const {
+ std::cout << GetTitle().GetStr() << ", "
+ << GetAuthor().GetStr() << ' '
+ << GetYear() << std::endl;
+}
+
+bool Book::Export(const String& fileName) {
+ std::ofstream exportFile(fileName.GetStr(), std::ios::binary);
+
+ if (!exportFile.is_open()) {
+ std::cout << "Couldn't export book to file!" << std::endl;
+ }
+ else {
+ exportFile.write(title.GetStr(), title.GetLength() + 1);
+ exportFile.write(author.GetStr(), author.GetLength() + 1);
+ exportFile.write((const char*)&year, sizeof(year));
+ exportFile.write(text.GetStr(), text.GetLength() + 1);
+ }
+
+ return exportFile.is_open();
+}
+
+void readNullTerminated(String& readInto, std::ifstream& file) {
+ readInto.Clear();
+ for (char buffer = file.get(); buffer != '\0' && !file.eof(); buffer = file.get()) {
+ readInto.AppendChar(buffer);
+ }
+}
+
+bool Book::Import(const String& fileName) {
+ std::ifstream importFile(fileName.GetStr(), std::ios::binary);
+
+ if (!importFile.is_open()) {
+ std::cout << "Couldn't import book to file!" << std::endl;
+ }
+ else {
+ readNullTerminated(title, importFile);
+ readNullTerminated(author, importFile);
+ importFile.read((char*)&year, sizeof(year));
+ readNullTerminated(text, importFile);
+ }
+
+ return importFile.is_open();
+}
diff --git a/Week07/Exercise01/Book.h b/Week07/Exercise01/Book.h
new file mode 100644
index 0000000..eaddaea
--- /dev/null
+++ b/Week07/Exercise01/Book.h
@@ -0,0 +1,39 @@
+#ifndef _BOOK
+#define _BOOK
+
+#include "String.h"
+
+class Book {
+ String title;
+ String author;
+ short year;
+ String text;
+ double price;
+ bool availableForPurchase;
+
+public:
+ void SetTitle(const String& newTitle);
+ const String& GetTitle() const;
+
+ void SetAuthor(const String& newAuthor);
+ const String& GetAuthor() const;
+
+ void SetYear(short newYear);
+ short GetYear() const;
+
+ void SetText(const String& newText);
+ const String& GetText() const;
+
+ void SetPrice(double newPrice);
+ double GetPrice() const;
+
+ void SetAvailableForPurchase(bool isAvailableForPurchase);
+ bool GetAvailableForPurchase() const;
+
+ void PrintBookInfo() const;
+
+ bool Export(const String& fileName);
+ bool Import(const String& fileName);
+};
+
+#endif /* _BOOK */
diff --git a/Week07/Exercise01/Librarian.cpp b/Week07/Exercise01/Librarian.cpp
new file mode 100644
index 0000000..0e6179d
--- /dev/null
+++ b/Week07/Exercise01/Librarian.cpp
@@ -0,0 +1,21 @@
+#include "Librarian.h"
+
+Librarian::Librarian(unsigned librarianNumber) {
+ this->librarianNumber = librarianNumber;
+ this->password = "password";
+}
+
+Librarian::Librarian() : librarianNumber(0), password()
+{ }
+
+unsigned Librarian::GetLibrarianNumber() const {
+ return librarianNumber;
+}
+
+void Librarian::SetPassword(const String& newPassword) {
+ this->password = newPassword;
+}
+
+bool Librarian::Login(unsigned librarianNumber, const String& password) {
+ return this->librarianNumber == librarianNumber && this->password.EqualTo(password);
+}
diff --git a/Week07/Exercise01/Librarian.h b/Week07/Exercise01/Librarian.h
new file mode 100644
index 0000000..839a258
--- /dev/null
+++ b/Week07/Exercise01/Librarian.h
@@ -0,0 +1,23 @@
+#ifndef _LIBRARIAN
+#define _LIBRARIAN
+
+#include "String.h"
+
+class Librarian {
+ unsigned librarianNumber;
+ String password;
+
+public:
+ Librarian(unsigned librarianNumber);
+ // Ако направим поне един конструктор, то конструктора по подразбиране
+ // спира да се създава автоматично
+ Librarian();
+
+ unsigned GetLibrarianNumber() const;
+
+ void SetPassword(const String& newPassword);
+
+ bool Login(unsigned librarianNumber, const String& password);
+};
+
+#endif /* _LIBRARIAN */
diff --git a/Week07/Exercise01/LibraryBanking.cpp b/Week07/Exercise01/LibraryBanking.cpp
new file mode 100644
index 0000000..66e0959
--- /dev/null
+++ b/Week07/Exercise01/LibraryBanking.cpp
@@ -0,0 +1,159 @@
+#include "LibraryBanking.h"
+#include "Transaction.h"
+#include <fstream>
+#include <iostream>
+
+void LibraryBanking::free() {
+ delete[] clerks;
+ delete[] transactions;
+}
+
+void LibraryBanking::copyFrom(const LibraryBanking& other) {
+ clerksAlloc = other.clerksAlloc;
+ clerksCount = other.clerksCount;
+ clerks = new BankClerk[clerksAlloc];
+ for (unsigned i = 0; i < clerksCount; ++i)
+ clerks[i] = other.clerks[i];
+
+ transactionsAlloc = other.transactionsAlloc;
+ transactionsCount = other.transactionsCount;
+ transactions = new Transaction[transactionsAlloc];
+ for (unsigned i = 0; i < transactionsCount; ++i)
+ transactions[i] = other.transactions[i];
+}
+
+void LibraryBanking::resizeClerks() {
+ clerksAlloc = clerksAlloc == 0 ? 8 : clerksAlloc * 2;
+ BankClerk* newClerks = new BankClerk[clerksAlloc];
+
+ for (unsigned i = 0; i < clerksCount; ++i)
+ newClerks[i] = clerks[i];
+
+ delete[] clerks;
+ clerks = newClerks;
+}
+
+void LibraryBanking::resizeTransactions() {
+ transactionsAlloc = transactionsAlloc == 0 ? 8 : transactionsAlloc * 2;
+ Transaction* newTransactions = new Transaction[transactionsAlloc];
+
+ for (unsigned i = 0; i < transactionsCount; ++i)
+ newTransactions[i] = transactions[i];
+
+ delete[] transactions;
+ transactions = newTransactions;
+}
+
+LibraryBanking::LibraryBanking() : clerks(nullptr), clerksCount(0), clerksAlloc(0), transactions(nullptr), transactionsCount(0), transactionsAlloc(0)
+{ }
+
+LibraryBanking::~LibraryBanking() {
+ free();
+}
+
+LibraryBanking::LibraryBanking(const LibraryBanking& other) {
+ copyFrom(other);
+}
+
+LibraryBanking& LibraryBanking::operator=(const LibraryBanking& other) {
+ if (this != &other) {
+ free();
+ copyFrom(other);
+ }
+ return *this;
+}
+
+LibraryBanking::LibraryBanking(LibraryBanking&& other) {
+ clerks = other.clerks;
+ clerksCount = other.clerksCount;
+ clerksAlloc = other.clerksAlloc;
+
+ transactions = other.transactions;
+ transactionsCount = other.transactionsCount;
+ transactionsAlloc = other.transactionsAlloc;
+
+ other.clerks = nullptr;
+ other.clerksCount = other.clerksAlloc = 0;
+
+ other.transactions = nullptr;
+ other.transactionsCount = other.transactionsAlloc = 0;
+}
+
+LibraryBanking& LibraryBanking::operator=(LibraryBanking&& other) {
+ if (this != &other) {
+ free();
+
+ clerks = other.clerks;
+ clerksCount = other.clerksCount;
+ clerksAlloc = other.clerksAlloc;
+
+ transactions = other.transactions;
+ transactionsCount = other.transactionsCount;
+ transactionsAlloc = other.transactionsAlloc;
+
+ other.clerks = nullptr;
+ other.clerksCount = other.clerksAlloc = 0;
+
+ other.transactions = nullptr;
+ other.transactionsCount = other.transactionsAlloc = 0;
+ }
+ return *this;
+}
+
+void LibraryBanking::RegisterClerk(const BankClerk& clerk) {
+ if (clerksCount >= clerksAlloc)
+ resizeClerks();
+ clerks[clerksCount++] = clerk;
+}
+
+BankClerk* LibraryBanking::LoginClerk(unsigned clerkNumber, unsigned dynamicPassword, const String& staticPassword) {
+ for (unsigned i = 0; i < clerksCount; ++i) {
+ if (clerks[i].Login(clerkNumber, dynamicPassword, staticPassword))
+ // "clerks + i" е същото като "&clerks[i]"
+ return clerks + i;
+ }
+ return nullptr;
+}
+
+void LibraryBanking::ListPendingTransactions() {
+ for (unsigned i = 0; i < transactionsCount; ++i) {
+ if (transactions[i].GetStatus() == STATUS_PENDING) {
+ std::cout << '[' << i << "] ";
+ transactions[i].PrintTransactionInfo();
+ }
+ }
+}
+
+Transaction* LibraryBanking::GetTransaction(unsigned index) {
+ if (index >= transactionsCount)
+ return nullptr;
+ // "transactions + index" е същото като "&transactions[index]"
+ return transactions + index;
+}
+
+const Transaction* LibraryBanking::RegisterTransaction(const Transaction& transaction) {
+ if (transactionsCount >= transactionsAlloc)
+ resizeTransactions();
+ transactions[transactionsCount] = transaction;
+
+ if (transaction.GetSum() == 0.0)
+ transactions[transactionsCount].SetStatus(0, STATUS_ACCEPTED);
+
+ return transactions + transactionsCount++;
+}
+
+void LibraryBanking::ExportNonPendingTransactions(const String& fileName) {
+ std::ofstream exportFile(fileName.GetStr(), std::ios::trunc);
+
+ if (!exportFile.is_open()) {
+ std::cout << "Couldn't open file!" << std::endl;
+ }
+ else {
+ for (unsigned i = 0; i < transactionsCount; ++i) {
+ if (transactions[i].GetStatus() != STATUS_PENDING) {
+ exportFile << i << ",";
+ transactions[i].Export(exportFile);
+ }
+ }
+ }
+}
diff --git a/Week07/Exercise01/LibraryBanking.h b/Week07/Exercise01/LibraryBanking.h
new file mode 100644
index 0000000..08e9d9d
--- /dev/null
+++ b/Week07/Exercise01/LibraryBanking.h
@@ -0,0 +1,40 @@
+#ifndef _LIBRARY_BANKING
+#define _LIBRARY_BANKING
+
+#include "BankClerk.h"
+#include "Transaction.h"
+
+class LibraryBanking {
+ BankClerk* clerks;
+ unsigned clerksCount;
+ unsigned clerksAlloc;
+
+ Transaction* transactions;
+ unsigned transactionsCount;
+ unsigned transactionsAlloc;
+
+ void free();
+ void copyFrom(const LibraryBanking& other);
+
+ void resizeClerks();
+ void resizeTransactions();
+
+public:
+ LibraryBanking();
+ ~LibraryBanking();
+ LibraryBanking(const LibraryBanking& other);
+ LibraryBanking& operator=(const LibraryBanking& other);
+ LibraryBanking(LibraryBanking&& other);
+ LibraryBanking& operator=(LibraryBanking&& other);
+
+ void RegisterClerk(const BankClerk& clerk);
+ BankClerk* LoginClerk(unsigned clerkNumber, unsigned dynamicPassword, const String& staticPassword);
+
+ void ListPendingTransactions();
+ Transaction* GetTransaction(unsigned index);
+ const Transaction* RegisterTransaction(const Transaction& transaction);
+
+ void ExportNonPendingTransactions(const String& fileName);
+};
+
+#endif /* _LIBRARY_BANKING */
diff --git a/Week07/Exercise01/OnlineLibrary.cpp b/Week07/Exercise01/OnlineLibrary.cpp
new file mode 100644
index 0000000..495ee95
--- /dev/null
+++ b/Week07/Exercise01/OnlineLibrary.cpp
@@ -0,0 +1,264 @@
+#include "OnlineLibrary.h"
+#include <iostream>
+
+void OnlineLibrary::free() {
+ delete[] books;
+ delete[] users;
+ delete[] librarians;
+ delete[] connections;
+}
+
+void OnlineLibrary::copyFrom(const OnlineLibrary& other) {
+ booksCount = other.booksCount;
+ booksAlloc = other.booksAlloc;
+ books = new Book[booksAlloc];
+ for (unsigned i = 0; i < booksCount; ++i)
+ books[i] = other.books[i];
+
+ usersCount = other.usersCount;
+ usersAlloc = other.usersAlloc;
+ users = new User[usersAlloc];
+ for (unsigned i = 0; i < usersCount; ++i)
+ users[i] = other.users[i];
+
+ librariansCount = other.librariansCount;
+ librariansAlloc = other.librariansAlloc;
+ librarians = new Librarian[librariansAlloc];
+ for (unsigned i = 0; i < librariansCount; ++i)
+ librarians[i] = other.librarians[i];
+
+ connectionsCount = other.connectionsCount;
+ connectionsAlloc = other.connectionsAlloc;
+ connections = new TransactionConnection[connectionsAlloc];
+ for (unsigned i = 0; i < connectionsCount; ++i)
+ connections[i] = other.connections[i];
+}
+
+void OnlineLibrary::resizeBooks() {
+ booksAlloc = booksAlloc == 0 ? 8 : booksAlloc * 2;
+ Book* booksLarger = new Book[booksAlloc];
+
+ for (unsigned i = 0; i < booksCount; ++i)
+ booksLarger[i] = books[i];
+
+ delete[] books;
+ books = booksLarger;
+}
+
+void OnlineLibrary::resizeUsers() {
+ usersAlloc = usersAlloc == 0 ? 8 : usersAlloc * 2;
+ User* usersLarger = new User[usersAlloc];
+
+ for (unsigned i = 0; i < usersCount; ++i)
+ usersLarger[i] = users[i];
+
+ delete[] users;
+ users = usersLarger;
+}
+
+void OnlineLibrary::resizeLibrarians() {
+ librariansAlloc = librariansAlloc == 0 ? 8 : librariansAlloc * 2;
+ Librarian* librariansLarger = new Librarian[librariansAlloc];
+
+ for (unsigned i = 0; i < librariansCount; ++i)
+ librariansLarger[i] = librarians[i];
+
+ delete[] librarians;
+ librarians = librariansLarger;
+}
+
+void OnlineLibrary::resizeConnections() {
+ connectionsAlloc = connectionsAlloc == 0 ? 8 : connectionsAlloc * 2;
+ TransactionConnection* connectionsLarger = new TransactionConnection[connectionsAlloc];
+
+ for (unsigned i = 0; i < connectionsCount; ++i)
+ connectionsLarger[i] = connections[i];
+
+ delete[] connections;
+ connections = connectionsLarger;
+}
+
+OnlineLibrary::OnlineLibrary() {
+ books = nullptr;
+ booksCount = booksAlloc = 0;
+ users = nullptr;
+ usersCount = usersAlloc = 0;
+ librarians = nullptr;
+ librariansCount = librariansAlloc = 0;
+ connections = nullptr;
+ connectionsCount = connectionsAlloc = 0;
+}
+
+OnlineLibrary::~OnlineLibrary() {
+ free();
+}
+
+OnlineLibrary::OnlineLibrary(const OnlineLibrary& other) {
+ copyFrom(other);
+}
+
+OnlineLibrary& OnlineLibrary::operator=(const OnlineLibrary& other) {
+ if (this != &other) {
+ free();
+ copyFrom(other);
+ }
+ return *this;
+}
+
+OnlineLibrary::OnlineLibrary(OnlineLibrary&& other) {
+ books = other.books;
+ booksCount = other.booksCount;
+ booksAlloc = other.booksAlloc;
+
+ users = other.users;
+ usersCount = other.usersCount;
+ usersAlloc = other.usersAlloc;
+
+ librarians = other.librarians;
+ librariansCount = other.librariansCount;
+ librariansAlloc = other.librariansAlloc;
+
+ connections = other.connections;
+ connectionsCount = other.connectionsCount;
+ connectionsAlloc = other.connectionsAlloc;
+
+ other.books = nullptr;
+ other.booksCount = other.booksAlloc = 0;
+
+ other.users = nullptr;
+ other.usersCount = other.usersAlloc = 0;
+
+ other.librarians = nullptr;
+ other.librariansCount = other.librariansAlloc = 0;
+
+ other.connections = nullptr;
+ other.connectionsCount = other.connectionsAlloc = 0;
+}
+
+OnlineLibrary& OnlineLibrary::operator=(OnlineLibrary&& other) {
+ if (this != &other) {
+ free();
+
+ books = other.books;
+ booksCount = other.booksCount;
+ booksAlloc = other.booksAlloc;
+
+ users = other.users;
+ usersCount = other.usersCount;
+ usersAlloc = other.usersAlloc;
+
+ librarians = other.librarians;
+ librariansCount = other.librariansCount;
+ librariansAlloc = other.librariansAlloc;
+
+ connections = other.connections;
+ connectionsCount = other.connectionsCount;
+ connectionsAlloc = other.connectionsAlloc;
+
+ other.books = nullptr;
+ other.booksCount = other.booksAlloc = 0;
+
+ other.users = nullptr;
+ other.usersCount = other.usersAlloc = 0;
+
+ other.librarians = nullptr;
+ other.librariansCount = other.librariansAlloc = 0;
+
+ other.connections = nullptr;
+ other.connectionsCount = other.connectionsAlloc = 0;
+ }
+ return *this;
+}
+
+void OnlineLibrary::RegisterUser(const User& user) {
+ if (usersCount >= usersAlloc)
+ resizeUsers();
+ users[usersCount++] = user;
+}
+
+User* OnlineLibrary::LoginUser(const String& email, const String& password) {
+ for (unsigned i = 0; i < usersCount; ++i) {
+ if (users[i].Login(email, password))
+ // "users + i" е същото като "&users[i]"
+ return users + i;
+ }
+ return nullptr;
+}
+
+void OnlineLibrary::RegisterLibrarian(const Librarian& librarian) {
+ if (librariansCount >= librariansAlloc)
+ resizeLibrarians();
+ librarians[librariansCount++] = librarian;
+}
+
+Librarian* OnlineLibrary::LoginLibrarian(unsigned librarianNumber, const String& password) {
+ for (unsigned i = 0; i < librariansCount; ++i) {
+ if (librarians[i].Login(librarianNumber, password))
+ // "librarians + i" е същото като "&librarians[i]"
+ return librarians + i;
+ }
+ return nullptr;
+}
+
+void OnlineLibrary::ListBooks() const {
+ for (unsigned i = 0; i < booksCount; ++i) {
+ if (books[i].GetAvailableForPurchase()) {
+ std::cout << '[' << i << "] ";
+ books[i].PrintBookInfo();
+ }
+ }
+}
+
+Book* OnlineLibrary::GetBook(unsigned index) {
+ if (index >= booksCount)
+ return nullptr;
+ // "books + index" е същото като "&books[index]"
+ return books + index;
+}
+
+void OnlineLibrary::AddBook(const Book& book) {
+ if (booksCount >= booksAlloc)
+ resizeBooks();
+ books[booksCount++] = book;
+}
+
+void OnlineLibrary::PurchaseBook(const Book& book, const User& user, LibraryBanking& banking) {
+ if (connectionsCount >= connectionsAlloc)
+ resizeConnections();
+
+ TransactionConnection tc;
+ tc.user = &user;
+ tc.book = &book;
+ tc.transaction = banking.RegisterTransaction(Transaction(book.GetPrice(), user.GetBankCard()));
+
+ connections[connectionsCount++] = tc;
+}
+
+void OnlineLibrary::ListTransactions(const User& user) const {
+ for (unsigned i = 0; i < connectionsCount; ++i) {
+ if (connections[i].user == &user) {
+ std::cout << connections[i].book->GetTitle().GetStr() << ", "
+ << connections[i].book->GetAuthor().GetStr() << " Price:"
+ << connections[i].book->GetPrice() << " Card:"
+ << connections[i].transaction->GetBankCard() << " Status:"
+ << connections[i].transaction->GetStatusStr().GetStr() << std::endl;
+ }
+ }
+}
+
+void OnlineLibrary::ExportTransactions(const User& user, const String& fileName) const {
+ std::ofstream exportFile(fileName.GetStr(), std::ios::trunc);
+
+ if (!exportFile.is_open()) {
+ std::cout << "Couldn't open export file!" << std::endl;
+ }
+ else {
+ for (unsigned i = 0; i < connectionsCount; ++i) {
+ if (connections[i].user == &user) {
+ exportFile << i << ','
+ << connections[i].book->GetTitle().GetStr() << ',';
+ connections[i].transaction->Export(exportFile);
+ }
+ }
+ }
+}
diff --git a/Week07/Exercise01/OnlineLibrary.h b/Week07/Exercise01/OnlineLibrary.h
new file mode 100644
index 0000000..4121af0
--- /dev/null
+++ b/Week07/Exercise01/OnlineLibrary.h
@@ -0,0 +1,65 @@
+#ifndef _ONLINE_LIBRARY
+#define _ONLINE_LIBRARY
+
+#include "Book.h"
+#include "LibraryBanking.h"
+#include "Transaction.h"
+#include "User.h"
+#include "Librarian.h"
+
+class OnlineLibrary {
+ Book* books;
+ unsigned booksCount;
+ unsigned booksAlloc;
+
+ User* users;
+ unsigned usersCount;
+ unsigned usersAlloc;
+
+ Librarian* librarians;
+ unsigned librariansCount;
+ unsigned librariansAlloc;
+
+ // В методи на OnlineLibrary, тази структура се казва "TransactionConnection"
+ // Извън методи на OnlineLibrary, тази структура се казва "OnlineLibrary::TransactionConnection"
+ struct TransactionConnection {
+ const User* user;
+ const Book* book;
+ const Transaction* transaction;
+ };
+ TransactionConnection* connections;
+ unsigned connectionsCount;
+ unsigned connectionsAlloc;
+
+ void free();
+ void copyFrom(const OnlineLibrary& other);
+
+ void resizeBooks();
+ void resizeUsers();
+ void resizeLibrarians();
+ void resizeConnections();
+
+public:
+ OnlineLibrary();
+ ~OnlineLibrary();
+ OnlineLibrary(const OnlineLibrary& other);
+ OnlineLibrary& operator=(const OnlineLibrary& other);
+ OnlineLibrary(OnlineLibrary&& other);
+ OnlineLibrary& operator=(OnlineLibrary&& other);
+
+ void RegisterUser(const User& user);
+ User* LoginUser(const String& email, const String& password);
+
+ void RegisterLibrarian(const Librarian& librarian);
+ Librarian* LoginLibrarian(unsigned librarianNumber, const String& password);
+
+ void ListBooks() const;
+ Book* GetBook(unsigned index);
+ void AddBook(const Book& book);
+ void PurchaseBook(const Book& book, const User& user, LibraryBanking& banking);
+
+ void ListTransactions(const User& user) const;
+ void ExportTransactions(const User& user, const String& fileName) const;
+};
+
+#endif /* _ONLINE_LIBRARY */
diff --git a/Week07/Exercise01/String.cpp b/Week07/Exercise01/String.cpp
new file mode 100644
index 0000000..8272658
--- /dev/null
+++ b/Week07/Exercise01/String.cpp
@@ -0,0 +1,98 @@
+#include "String.h"
+#include <cstring>
+
+void String::free() {
+ delete[] str;
+}
+
+void String::copyFrom(const String& other) {
+ length = other.length;
+
+ // Не забравяме за терминиращата нула
+ str = new char[length + 1];
+ strncpy(str, other.str, length + 1);
+}
+
+void String::resize() {
+ allocated = allocated == 0 ? 8 : allocated * 2;
+ char* strLarger = new char[allocated];
+
+ memcpy(strLarger, str, length);
+ strLarger[length] = '\0';
+
+ delete[] str;
+ str = strLarger;
+}
+
+String::String() {
+ str = nullptr;
+ allocated = length = 0;
+}
+
+String::~String() {
+ free();
+}
+
+String::String(const String& other) {
+ copyFrom(other);
+}
+
+String& String::operator=(const String& other) {
+ if (this != &other) {
+ free();
+ copyFrom(other);
+ }
+ return *this;
+}
+
+String::String(String&& other) {
+ str = other.str;
+ length = other.length;
+
+ other.str = nullptr;
+ other.length = 0;
+}
+
+String& String::operator=(String&& other) {
+ if (this != &other) {
+ free();
+
+ str = other.str;
+ length = other.length;
+
+ other.str = nullptr;
+ other.length = 0;
+ }
+ return *this;
+}
+
+String::String(const char* str) {
+ length = strlen(str);
+ this->str = new char[length + 1];
+ strncpy(this->str, str, length + 1);
+}
+
+void String::Clear() {
+ free();
+ str = nullptr;
+ length = allocated = 0;
+}
+
+void String::AppendChar(char c) {
+ if (length + 1 >= allocated)
+ resize();
+ str[length++] = c;
+ str[length] = '\0';
+}
+
+bool String::EqualTo(const String& other) const {
+ return strcmp(str, other.str) == 0;
+}
+
+const char* String::GetStr() const {
+ return str;
+}
+
+unsigned String::GetLength() const {
+ return length;
+}
diff --git a/Week07/Exercise01/String.h b/Week07/Exercise01/String.h
new file mode 100644
index 0000000..c9cc263
--- /dev/null
+++ b/Week07/Exercise01/String.h
@@ -0,0 +1,33 @@
+#ifndef _STRING
+#define _STRING
+
+class String {
+ char* str;
+ unsigned length;
+ unsigned allocated;
+
+ void free();
+ void copyFrom(const String& other);
+
+ void resize();
+
+public:
+ String();
+ ~String();
+ String(const String& other);
+ String& operator=(const String& other);
+ String(String&& other);
+ String& operator=(String&& other);
+
+ String(const char* str);
+ void Clear();
+
+ void AppendChar(char c);
+
+ bool EqualTo(const String& other) const;
+
+ const char* GetStr() const;
+ unsigned GetLength() const;
+};
+
+#endif /* _STRING */
diff --git a/Week07/Exercise01/Transaction.cpp b/Week07/Exercise01/Transaction.cpp
new file mode 100644
index 0000000..8978c05
--- /dev/null
+++ b/Week07/Exercise01/Transaction.cpp
@@ -0,0 +1,56 @@
+#include "Transaction.h"
+#include <iostream>
+
+Transaction::Transaction(double sum, unsigned bankCard) {
+ this->clerkNumber = 0;
+ this->sum = sum;
+ this->bankCard = bankCard;
+ this->status = STATUS_PENDING;
+}
+
+Transaction::Transaction() : clerkNumber(0), sum(0), bankCard(0), status(0)
+{ }
+
+unsigned Transaction::GetClerkNumber() const {
+ return clerkNumber;
+}
+
+double Transaction::GetSum() const {
+ return sum;
+}
+
+unsigned Transaction::GetBankCard() const {
+ return bankCard;
+}
+
+unsigned Transaction::GetStatus() const {
+ return status;
+}
+
+String Transaction::GetStatusStr() const {
+ switch (status) {
+ case STATUS_PENDING: return "Pending";
+ case STATUS_ACCEPTED: return "Accepted";
+ case STATUS_REJECTED: return "Rejected";
+ }
+ return "";
+}
+
+void Transaction::SetStatus(unsigned clerk, unsigned status) {
+ this->clerkNumber = clerk;
+ this->status = status;
+}
+
+void Transaction::PrintTransactionInfo() const {
+ std::cout << clerkNumber << ' '
+ << bankCard << ' '
+ << sum << ' '
+ << GetStatusStr().GetStr() << std::endl;
+}
+
+void Transaction::Export(std::ofstream& exportFile) const {
+ exportFile << sum << ','
+ << bankCard << ','
+ << clerkNumber << ','
+ << status << std::endl;
+}
diff --git a/Week07/Exercise01/Transaction.h b/Week07/Exercise01/Transaction.h
new file mode 100644
index 0000000..d4941ce
--- /dev/null
+++ b/Week07/Exercise01/Transaction.h
@@ -0,0 +1,46 @@
+#ifndef _TRANSACTION
+#define _TRANSACTION
+
+#include "String.h"
+#include <fstream>
+
+const unsigned STATUS_PENDING = 0;
+const unsigned STATUS_ACCEPTED = 1;
+const unsigned STATUS_REJECTED = 2;
+
+// Няма да обвързваме транзакции с потребители директно
+// (т.е. няма член-данна която свързва User обект).
+// Тази връзка осъществяваме с UserTransaction класа.
+// Логически, можем да приемем че не искаме банковия служител
+// да знае за акаунтите на купувачите.
+class Transaction {
+ unsigned clerkNumber;
+ double sum;
+ unsigned bankCard;
+ // Уговаряме се, че стойността на status ще бъде равна на една
+ // от глобалните променливи STATUS_PENDING, STATUS_ACCEPTED и STATUS_REJECTED.
+ // Тук е добро място за употреба на енумерации (enum).
+ unsigned status;
+
+public:
+ Transaction(double sum, unsigned bankCard);
+ // Ако направим поне един конструктор, то конструктора по подразбиране
+ // спира да се създава автоматично
+ Transaction();
+
+ // Не искаме транзакции да могат да се променят своеволно.
+ // Т.е. след като се създаде транзакция, единствено можем да променяме статус
+ unsigned GetClerkNumber() const;
+ double GetSum() const;
+ unsigned GetBankCard() const;
+
+ unsigned GetStatus() const;
+ String GetStatusStr() const;
+ void SetStatus(unsigned clerk, unsigned status);
+
+ void PrintTransactionInfo() const;
+
+ void Export(std::ofstream& exportFile) const;
+};
+
+#endif /* _TRANSACTION */
diff --git a/Week07/Exercise01/User.cpp b/Week07/Exercise01/User.cpp
new file mode 100644
index 0000000..be5f76f
--- /dev/null
+++ b/Week07/Exercise01/User.cpp
@@ -0,0 +1,128 @@
+#include "User.h"
+#include <iostream>
+
+void User::copyFrom(const User& other) {
+ email = other.email;
+ password = other.password;
+ bankCard = other.bankCard;
+
+ libraryCount = other.libraryCount;
+ libraryAlloc = other.libraryAlloc;
+ library = new const Book*[libraryAlloc];
+ for (unsigned i = 0; i < libraryCount; ++i)
+ library[i] = other.library[i];
+}
+
+void User::free() {
+ delete[] library;
+}
+
+void User::resizeLibrary() {
+ libraryAlloc = libraryAlloc == 0 ? 8 : libraryAlloc * 2;
+ const Book** libraryLarger = new const Book*[libraryAlloc];
+
+ for (unsigned i = 0; i < libraryCount; ++i)
+ libraryLarger[i] = library[i];
+
+ delete[] library;
+ library = libraryLarger;
+}
+
+User::User() : email(), password(), bankCard(0), library(nullptr), libraryCount(0), libraryAlloc(0)
+{ }
+
+User::~User() {
+ free();
+}
+
+User::User(const User& other) {
+ copyFrom(other);
+}
+
+User& User::operator=(const User& other) {
+ if (this != &other) {
+ free();
+ copyFrom(other);
+ }
+ return *this;
+}
+
+User::User(User&& other) {
+ email = other.email;
+ password = other.password;
+ bankCard = other.bankCard;
+
+ library = other.library;
+ libraryCount = other.libraryCount;
+ libraryAlloc = other.libraryAlloc;
+
+ other.email.Clear();
+ other.password.Clear();
+ other.bankCard = 0;
+
+ other.library = nullptr;
+ other.libraryCount = other.libraryAlloc = 0;
+}
+
+User& User::operator=(User&& other) {
+ if (this != &other) {
+ free();
+
+ email = other.email;
+ password = other.password;
+ bankCard = other.bankCard;
+
+ library = other.library;
+ libraryCount = other.libraryCount;
+ libraryAlloc = other.libraryAlloc;
+
+ other.email.Clear();
+ other.password.Clear();
+ other.bankCard = 0;
+
+ other.library = nullptr;
+ other.libraryCount = other.libraryAlloc = 0;
+ }
+ return *this;
+}
+
+void User::SetEmail(const String& newEmail) {
+ email = newEmail;
+}
+
+const String& User::GetEmail() const {
+ return email;
+}
+
+void User::SetPassword(const String& newPassword) {
+ password = newPassword;
+}
+
+bool User::Login(const String& email, const String& password) {
+ return this->email.EqualTo(email) && this->password.EqualTo(password);
+}
+
+void User::AddBookToLibrary(const Book* book) {
+ if (libraryCount >= libraryAlloc)
+ resizeLibrary();
+ library[libraryCount++] = book;
+}
+
+void User::ListLibrary() {
+ for (unsigned i = 0; i < libraryCount; ++i) {
+ std::cout << '[' << i << "] ";
+ library[i]->PrintBookInfo();
+ }
+}
+
+const Book* User::GetBook(unsigned index) const {
+ return library[index];
+}
+
+void User::SetBankCard(unsigned newBankCard) {
+ bankCard = newBankCard;
+}
+
+unsigned User::GetBankCard() const {
+ return bankCard;
+}
diff --git a/Week07/Exercise01/User.h b/Week07/Exercise01/User.h
new file mode 100644
index 0000000..7e04560
--- /dev/null
+++ b/Week07/Exercise01/User.h
@@ -0,0 +1,45 @@
+#ifndef _USER
+#define _USER
+
+#include "String.h"
+#include "Book.h"
+
+class User {
+ String email;
+ String password;
+ unsigned bankCard;
+
+ // Масив от указатели към книги
+ const Book** library;
+ unsigned libraryCount;
+ unsigned libraryAlloc;
+
+ void copyFrom(const User& other);
+ void free();
+
+ void resizeLibrary();
+
+public:
+ User();
+ ~User();
+ User(const User& other);
+ User& operator=(const User& other);
+ User(User&& other);
+ User& operator=(User&& other);
+
+ void SetEmail(const String& newEmail);
+ const String& GetEmail() const;
+
+ void SetPassword(const String& newPassword);
+
+ bool Login(const String& email, const String& password);
+
+ void AddBookToLibrary(const Book* book);
+ void ListLibrary();
+ const Book* GetBook(unsigned index) const;
+
+ void SetBankCard(unsigned newBankCard);
+ unsigned GetBankCard() const;
+};
+
+#endif /* _USER */
diff --git a/Week07/Exercise01/main.cpp b/Week07/Exercise01/main.cpp
new file mode 100644
index 0000000..ca97b15
--- /dev/null
+++ b/Week07/Exercise01/main.cpp
@@ -0,0 +1,382 @@
+#include "OnlineLibrary.h"
+#include "LibraryBanking.h"
+#include "Transaction.h"
+#include <iostream>
+
+// Игнорираме всички букви до края на реда вкл.
+void ignoreLine() {
+ while (std::cin.get() != '\n');
+}
+
+// Тази функция ни позволява да приемем от входа низ с неограничена дължина
+String getlineEndless() {
+ String bufferString;
+ for (char buffer = std::cin.get(); buffer != '\n'; buffer = std::cin.get()) {
+ bufferString.AppendChar(buffer);
+ }
+ return bufferString;
+}
+
+void RegisterConsole(OnlineLibrary& lib, LibraryBanking& libBank) {
+ char c;
+ std::cin >> c;
+ switch (c) {
+ case 'u': {
+ User newUser;
+
+ std::cout << "Username: ";
+ ignoreLine();
+ newUser.SetEmail(getlineEndless());
+
+ std::cout << "Password: ";
+ newUser.SetPassword(getlineEndless());
+
+ std::cout << "Bank card: ";
+ unsigned bankCard;
+ std::cin >> bankCard;
+ newUser.SetBankCard(bankCard);
+
+ lib.RegisterUser(newUser);
+ }
+ break;
+ case 'l': {
+ std::cout << "Librarian Number: ";
+ unsigned number;
+ std::cin >> number;
+
+ Librarian newLib(number);
+
+ std::cout << "Password: ";
+ ignoreLine();
+ newLib.SetPassword(getlineEndless());
+
+ lib.RegisterLibrarian(newLib);
+ }
+ break;
+ case 'c': {
+ std::cout << "Clerk Number: ";
+ unsigned number;
+ std::cin >> number;
+
+ BankClerk newClerk(number);
+
+ std::cout << "Static password: ";
+ ignoreLine();
+ newClerk.SetPassword(getlineEndless());
+
+ libBank.RegisterClerk(newClerk);
+ }
+ break;
+ }
+}
+
+void UserConsole(OnlineLibrary& lib, LibraryBanking& libBank) {
+ std::cout << "Username: ";
+ ignoreLine();
+ String bufferUsername = getlineEndless();
+
+ std::cout << "Password: ";
+ String bufferPassword = getlineEndless();
+
+ User* loggedIn = lib.LoginUser(bufferUsername, bufferPassword);
+ if (loggedIn == nullptr) {
+ std::cout << "Invalid username or password!" << std::endl;
+ return;
+ }
+
+ while (true) {
+ char c;
+ std::cin >> c;
+ switch (c) {
+ case 'e':
+ return;
+ case 'l':
+ loggedIn->ListLibrary();
+ break;
+ case 'r': {
+ std::cout << "User library index: ";
+ unsigned i;
+ std::cin >> i;
+ const Book* book = loggedIn->GetBook(i);
+
+ if (book == nullptr) {
+ std::cout << "Invalid index!" << std::endl;
+ }
+ else {
+ std::cout << book->GetText().GetStr() << std::endl;
+ }
+ }
+ break;
+ case 's':
+ lib.ListBooks();
+ break;
+ case 'p': {
+ std::cout << "Book index: ";
+ unsigned i;
+ std::cin >> i;
+ const Book* book = lib.GetBook(i);
+
+ if (book == nullptr) {
+ std::cout << "Invalid index!" << std::endl;
+ }
+ else if (loggedIn->GetBankCard() == 0 && book->GetPrice() != 0.0) {
+ std::cout << "Cannot purchase book with invalid card!" << std::endl;
+ }
+ else {
+ lib.PurchaseBook(*book, *loggedIn, libBank);
+ loggedIn->AddBookToLibrary(book);
+ }
+ }
+ break;
+ case 't':
+ lib.ListTransactions(*loggedIn);
+ break;
+ case 'x': {
+ std::cout << "Output file: ";
+ ignoreLine();
+ String fileName = getlineEndless();
+
+ lib.ExportTransactions(*loggedIn, fileName);
+ }
+ break;
+
+ case 'P': {
+ std::cout << "New password: ";
+ ignoreLine();
+ String newPassword = getlineEndless();
+
+ loggedIn->SetPassword(newPassword);
+ }
+ break;
+ case 'C': {
+ std::cout << "New bank card: ";
+ unsigned newBankCard;
+ std::cin >> newBankCard;
+
+ loggedIn->SetBankCard(newBankCard);
+ }
+ break;
+ }
+ }
+}
+
+void LibrarianConsole(OnlineLibrary& lib) {
+ std::cout << "Librarian number: ";
+ unsigned bufferLibrarianNo;
+ std::cin >> bufferLibrarianNo;
+
+ std::cout << "Password: ";
+ ignoreLine();
+ String bufferPassword = getlineEndless();
+
+ Librarian* loggedIn = lib.LoginLibrarian(bufferLibrarianNo, bufferPassword);
+ if (loggedIn == nullptr) {
+ std::cout << "Invalid librarian number or password!" << std::endl;
+ return;
+ }
+
+ while (true) {
+ char c;
+ std::cin >> c;
+ switch (c) {
+ case 'e':
+ return;
+ // Не се изисква по условие, но е удобно
+ case 's':
+ lib.ListBooks();
+ break;
+ case 'a': {
+ Book newBook;
+ newBook.SetAvailableForPurchase(true);
+
+ std::cout << "Title: ";
+ ignoreLine();
+ newBook.SetTitle(getlineEndless());
+
+ std::cout << "Author: ";
+ newBook.SetAuthor(getlineEndless());
+
+ std::cout << "Year: ";
+ short year;
+ std::cin >> year;
+ newBook.SetYear(year);
+
+ std::cout << "Price: ";
+ double price;
+ std::cin >> price;
+ newBook.SetPrice(price);
+
+ ignoreLine();
+ String text;
+ char prevprev = std::cin.get(), prev = std::cin.get(), curr = std::cin.get();
+ while (prevprev != '\n' || prev != '.' || curr != '\n') {
+ text.AppendChar(prevprev);
+ std::cout << '[' << (int)prevprev << ',' << (int)prev << ',' << (int)curr << ']' << std::endl;
+
+ prevprev = prev;
+ prev = curr;
+ curr = std::cin.get();
+ }
+ text.AppendChar(prevprev);
+ newBook.SetText(text);
+
+ lib.AddBook(newBook);
+ }
+ break;
+ case 'i': {
+ Book newBook;
+ newBook.SetAvailableForPurchase(true);
+
+ std::cout << "File name: ";
+ ignoreLine();
+ if (newBook.Import(getlineEndless())) {
+ double price;
+ std::cout << "Price: ";
+ std::cin >> price;
+ newBook.SetPrice(price);
+
+ lib.AddBook(newBook);
+ }
+ }
+ break;
+ case 'x': {
+ std::cout << "Book index: ";
+ unsigned i;
+ std::cin >> i;
+ Book* book = lib.GetBook(i);
+
+ if (book == nullptr) {
+ std::cout << "Invalid index!" << std::endl;
+ }
+ else {
+ std::cout << "File name: ";
+ ignoreLine();
+ book->Export(getlineEndless());
+ }
+ }
+ break;
+ case 'E': {
+ std::cout << "Book index: ";
+ unsigned i;
+ std::cin >> i;
+ Book* book = lib.GetBook(i);
+
+ if (book == nullptr) {
+ std::cout << "Invalid index!" << std::endl;
+ }
+ else {
+ ignoreLine();
+ std::cout << "Title: ";
+ book->SetTitle(getlineEndless());
+
+ std::cout << "Author: ";
+ book->SetAuthor(getlineEndless());
+
+ std::cout << "Price: ";
+ double price;
+ std::cin >> price;
+ book->SetPrice(price);
+ }
+ }
+ break;
+ case 'A': {
+ std::cout << "Book index: ";
+ unsigned i;
+ std::cin >> i;
+ Book* book = lib.GetBook(i);
+
+ if (book == nullptr) {
+ std::cout << "Invalid index!" << std::endl;
+ }
+ else {
+ book->SetAvailableForPurchase(! book->GetAvailableForPurchase());
+ if (book->GetAvailableForPurchase()) {
+ std::cout << "Book is now available!" << std::endl;
+ }
+ else {
+ std::cout << "Book is now not available!" << std::endl;
+ }
+ }
+ }
+ break;
+ }
+ }
+}
+
+void ClerkConsole(LibraryBanking& libBank) {
+ std::cout << "Clerk number: ";
+ unsigned bufferClerkNo;
+ std::cin >> bufferClerkNo;
+
+ std::cout << "Dynamic password: ";
+ unsigned dynamicPassword;
+ std::cin >> dynamicPassword;
+
+ ignoreLine();
+ std::cout << "Static password: ";
+ String bufferPassword = getlineEndless();
+
+ BankClerk* loggedIn = libBank.LoginClerk(bufferClerkNo, dynamicPassword, bufferPassword);
+ if (loggedIn == nullptr) {
+ std::cout << "Invalid clerk number or password!" << std::endl;
+ return;
+ }
+
+ while (true) {
+ char c;
+ std::cin >> c;
+ switch (c) {
+ case 'e':
+ return;
+ case 'l':
+ libBank.ListPendingTransactions();
+ break;
+ case 'A':
+ case 'R': {
+ std::cout << "Transaction index: ";
+ unsigned i;
+ std::cin >> i;
+ Transaction* transaction = libBank.GetTransaction(i);
+
+ if (transaction == nullptr) {
+ std::cout << "Invalid index!" << std::endl;
+ }
+ else if (transaction->GetStatus() != STATUS_PENDING) {
+ std::cout << "Transaction not pending!" << std::endl;
+ }
+ else {
+ transaction->SetStatus(loggedIn->GetClerkNumber(), c == 'A' ? STATUS_ACCEPTED : STATUS_REJECTED);
+ }
+ }
+ break;
+ case 'x': {
+ std::cout << "File name: ";
+ ignoreLine();
+ libBank.ExportNonPendingTransactions(getlineEndless());
+ }
+ break;
+ }
+ }
+}
+
+// Поискано ни е да имплементираме система,
+// това да направим конзолен интерфейс се подразбира
+int main() {
+ OnlineLibrary lib;
+ LibraryBanking libBank;
+
+ while (true) {
+ char c;
+ std::cin >> c;
+ switch (c) {
+ case 'r': RegisterConsole(lib, libBank); break;
+ case 'u': UserConsole(lib, libBank); break;
+ case 'l': LibrarianConsole(lib); break;
+ case 'c': ClerkConsole(libBank); break;
+ case 'e': return 0;
+ default: std::cout << "Invalid!" << std::endl;
+ }
+ }
+
+ return 0;
+}