Code:
// Osman Zakir
// 7/12/2015
// Programming: Principles and Practice Using C++ 2nd Edition by Bjarne Stroustrup
// Chapter 9 Exercises 5 - 9
// Program implements a Book class, a Library class, a Patron class, a Genre class,
// and a Transaction, and constructs objects for the class to print out data for the books and patrons in a library
#include "../custom_std_lib_facilities.h"
#include <algorithm>
#include <vector>
using namespace std;
enum class Genre
{
fiction, nonfiction, periodical, biography, children
};
class Book
{
private:
string isbn_number;
string title;
string author;
int copyright_date;
Genre book_genre;
bool book_checked_in;
public:
Book(const string& isbn_number, const string& title, const string& author, const int copyright_date, const Genre book_genre, const bool book_checked_in);
const string& isbn() const { return isbn_number; }
const string& book_title() const { return title; }
const string& author_name() const { return author; }
const int copyright() const { return copyright_date; }
const Genre genre_of_book() const { return book_genre; }
const bool checked_in() const { return book_checked_in; }
void set_check(bool check) { book_checked_in = check; }
};
enum class Month
{
jan = 1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec
};
class Date
{
public:
Date(const int y, const Month m, const int d);
int year() const { return y; }
Month month() const { return m; }
int day() const { return d; }
void add_day(int n);
void add_month(int n);
void set_day(int value);
void set_month(Month value);
void set_year(int value);
private:
int y;
Month m;
int d;
};
class Patron
{
private:
string user_name;
string library_card_number;
int library_fee;
public:
const string& username() const { return user_name; }
const string& card_number() const { return library_card_number; }
int fee() const { return library_fee; }
void set_fee(int value) { library_fee = value; }
Patron(const string& user_name, const string& library_card_number, const int library_fee)
: user_name{user_name}, library_card_number{library_card_number}, library_fee{0} {}
};
class Library
{
private:
struct Transaction
{
string book_isbn;
string patron_card_number;
Date date;
Transaction(const string& book_isbn, const string& patron_card_number, const Date& date)
: book_isbn{book_isbn}, patron_card_number{patron_card_number}, date{date} {}
};
vector<Book> books{};
vector<Patron> patrons{};
vector<Transaction> transactions{};
bool is_book_in_library(const Book& book_title) const;
bool is_patron_in_library(const Patron& patron_name) const;
public:
void add_book(const Book& book);
void add_patron(const Patron& patron);
void check_book_in(Book& book, const Date due_date, Patron& patron);
void check_book_out(Book& book, const Date transaction_date, const Patron& patron);
void extend_due_date(Date due_date);
void relieve_patron_debt(Patron& patron);
bool is_fee_owed(const Patron& patron);
int number_of_books();
int number_of_checked_out_books();
};
void printBookData(const Book& book);
void printPatronData(const Patron& patron);
bool operator==(const Book& book1, const Book& book2);
bool operator!=(const Book& book1, const Book& book2);
ostream& operator<<(ostream& os, const Date& dd);
int main()
{
try
{
cout<<"Creating books, patrons and library...\n";
Book book1{"0-15-204560-0", "Heir Apparent", "Vivian Vande Velde", 2002, Genre::fiction, book1.checked_in()};
Book book2{"0-375-82668-8", "Eragon", "Christopher Paolini", 2003, Genre::fiction, book2.checked_in()};
Book book3{"0-590-55356-9", "Sandry's Book", "Tamora Pierce", 1997, Genre::fiction, book3.checked_in()};
Patron patron1{"Mike", "3-2504-58140-9664", patron1.fee()};
Patron patron2{"Osman", "4-2512-21408-5521", patron2.fee()};
Patron patron3{"Draco", "2-1262-52741-6185", patron3.fee()};
Library library;
library.add_book(book1);
library.add_book(book2);
library.add_book(book3);
book1.set_check(true);
book2.set_check(true);
book3.set_check(true);
library.add_patron(patron1);
library.add_patron(patron2);
library.add_patron(patron3);
Date date1{2015, Month::mar, 25};
Date date2{2015, Month::mar, 26};
Date date3{2015, Month::mar, 24};
if (book1.checked_in() || !library.is_fee_owed(patron2))
{
library.check_book_out(book1, date1, patron2);
}
if (book2.checked_in() || !library.is_fee_owed(patron1))
{
library.check_book_out(book2, date2, patron1);
}
if (book3.checked_in() || !library.is_fee_owed(patron3))
{
library.check_book_out(book3, date3, patron3);
}
else if (!book1.checked_in())
{
error("error: book has already been checked out.");
}
else if (!book2.checked_in())
{
error("error: book has already been checked out.");
}
else if (!book3.checked_in())
{
error("error: book has already been checked out.");
}
cout<<"Checking in books...\n";
Date due_date1{2015, Month::apr, 24};
Date due_date2{2015, Month::apr, 25};
Date due_date3{2015, Month::apr, 26};
library.check_book_in(book1, due_date1, patron2);
library.check_book_in(book2, due_date2, patron1);
library.check_book_in(book3, due_date3, patron3);
cout<<"\n\nprinting info...\n";
cout << "The information for " << book1.book_title() << " is:\n";
printBookData(book1);
cout << "\n";
cout << "The information for " << book2.book_title() << " is:\n";
printBookData(book2);
cout << "\n";
cout << "The information for " << book3.book_title() << " is:\n";
printBookData(book3);
cout << "\nInformation on Library Patrons:\n";
printPatronData(patron1);
cout << "\n";
printPatronData(patron2);
cout << "\n";
printPatronData(patron3);
cout << "\n";
keep_window_open();
}
catch(runtime_error& r)
{
cout << r.what() << "\n";
keep_window_open();
return 1;
}
catch(...)
{
cout << "Whoops! Unknown exception! Please try again later.\n";
keep_window_open();
return 2;
}
}
Book::Book(const string& isbn_number, const string& title, const string& author, const int copyright_date, const Genre book_genre, const bool book_checked_in)
:isbn_number{isbn_number}, title{title}, author{author}, copyright_date{copyright_date}, book_genre{book_genre}, book_checked_in{true}
{
constexpr int MaxDate = 2015;
if (copyright_date <= 0 || copyright_date > MaxDate)
{
error("invalid copyright date");
}
stringstream ss(isbn_number);
char valid = '-';
char invalid = ' ';
for (int i = 0; i < 3; i++)
{
int integer = -1;
char character = invalid;
ss >> integer >> character;
if (integer < 0 || character != valid)
{
error("Invalid ISBN");
}
}
string final;
ss >> final;
if (final.size() != 1)
{
error("Invalid ISBN");
}
else if(!isdigit(final[0]) && !isalpha(final[0]))
{
error("Invalid ISBN");
}
}
Date::Date(const int y, const Month m, const int d)
: y{y}, m{m}, d{d}
{
if (m == Month::feb && d > 28)
{
error("Error: Invalid date; unless this is/was a leap-year, February should only have 28 days. Try again later.");
}
if ((m == Month::jan || m == Month::mar || m == Month::may || m == Month::jul || m == Month::aug || m == Month::oct || m == Month::dec) && d > 31)
{
error("Error: Invalid date; this month only has 31 days. Try again later.");
}
if ((m == Month::apr || m == Month::jun || m == Month::sep || m == Month::nov) && d > 30)
{
error("Error: Invalid date; this month only has 30 days. Try again later.");
}
if (m < Month::jan || m > Month::dec || d <= 0)
{
error("Error: Invalid month and/or day! Try again later.");
}
if (y <= 0 || y > 2200)
{
error("Error: Invalid year! Please try again later.");
}
}
void Date::add_day(int n)
{
d += n;
if (m == Month::feb && d > 28)
{
error("Error: Invalid date; unless this is/was a leap-year, February should only have 28 days. Try again later.");
}
if ((m == Month::jan || m == Month::mar || m == Month::may || m == Month::jul || m == Month::aug || m == Month::oct || m == Month::dec) && d > 31)
{
error("Error: Invalid date; this month only has 31 days. Try again later.");
}
if ((m == Month::apr || m == Month::jun || m == Month::sep || m == Month::nov) && d > 30)
{
error("Error: Invalid date; this month only has 30 days. Try again later.");
}
if (d <= 0)
{
error("Error: Invalid day! Try again later.");
}
}
void Date::add_month(int n)
{
m = static_cast<Month>(static_cast<int>(m) + n);
if (m < Month::jan || m > Month::dec)
{
error("Error: Invalid month and/or day! Try again later.");
}
}
void Date::set_day(int value)
{
d = value;
if (m == Month::feb && d > 28)
{
error("Error: Invalid date; unless this is/was a leap-year, February should only have 28 days. Try again later.");
}
if ((m == Month::jan || m == Month::mar || m == Month::may || m == Month::jul || m == Month::aug || m == Month::oct || m == Month::dec) && d > 31)
{
error("Error: Invalid date; this month only has 31 days. Try again later.");
}
if ((m == Month::apr || m == Month::jun || m == Month::sep || m == Month::nov) && d > 30)
{
error("Error: Invalid date; this month only has 30 days. Try again later.");
}
if (d <= 0)
{
error("Error: Invalid day! Try again later.");
}
}
void Date::set_month(Month value)
{
m = value;
if (m < Month::jan || m > Month::dec)
{
error("Error: Invalid month and/or day! Try again later.");
}
}
void Date::set_year(int value)
{
y = value;
if (y <= 0 || y > 2200)
{
error("Error: Invalid year! Please try again later.");
}
}
void Library::check_book_in(Book& book, const Date due_date, Patron& patron)
{
int fee = 10 * 100;
bool finished_reading_book = true;
if (finished_reading_book)
{
Date return_date{2015, Month::apr, 24};
if (due_date.day() == 24 && due_date.month() == Month::apr)
{
return_date.set_month(Month::apr);
return_date.set_day(24);
}
else if (due_date.day() == 25 && due_date.month() == Month::apr)
{
return_date.set_month(Month::apr);
return_date.set_day(25);
}
else if (due_date.day() == 26 && due_date.month() == Month::apr)
{
return_date.set_month(Month::apr);
return_date.set_day(26);
}
if (return_date.day() > due_date.day() || static_cast<int>(return_date.month()) > static_cast<int>(due_date.month()))
{
patron.set_fee(fee);
error("error: book is overdue, please pay fee of $10.");
}
book.set_check(true);
}
else
{
extend_due_date(due_date);
}
relieve_patron_debt(patron);
}
void Library::check_book_out(Book& book, const Date transaction_date, const Patron& patron)
{
if (is_fee_owed(patron))
{
error("error: fee is owed; relieve fee first before borrowing another book.");
}
else
{
if (is_book_in_library(book) && is_patron_in_library(patron))
{
Date due_date{2015, Month::apr, 24};
if (transaction_date.day() == 24)
{
due_date.set_day(24);
}
else if (transaction_date.day() == 25)
{
due_date.set_day(25);
}
else if (transaction_date.day() == 26)
{
due_date.set_day(26);
}
Transaction transaction{book.isbn(), patron.card_number(), transaction_date};
transactions.push_back(transaction);
if (is_book_in_library(book))
{
book.set_check(false);
}
}
else
{
error("error: this book and patron aren't in the library");
}
}
}
void Library::extend_due_date(Date due_date)
{
int extension_value = 1;
due_date.add_month(extension_value);
if (due_date.month() > Month::dec || due_date.month() < Month::jan)
{
error("error: invalid month value.");
}
}
void Library::relieve_patron_debt(Patron& patron)
{
bool fee_paid;
if (patron.fee() > 0)
{
fee_paid = false;
}
else
{
fee_paid = true;
}
}
int Library::number_of_checked_out_books()
{
int number_of_books;
for (size_t i = 0; i < books.size(); i++)
{
if (!books[i].checked_in())
{
number_of_books = i;
}
}
return number_of_books;
}
ostream& operator<<(ostream& os, const Date& dd)
{
return os << dd.year() << '-' << static_cast<int>(dd.month()) << '-' << dd.day();
}
void printBookData(const Book& book)
{
cout << "ISBN number: " << book.isbn() << "\n"
<< "Title: " << book.book_title() << "\n"
<< "Author: " << book.author_name() << "\n";
switch(book.genre_of_book())
{
case Genre::biography:
cout << "Genre: Biography\n";
break;
case Genre::children:
cout << "Genre: Children\n";
break;
case Genre::fiction:
cout << "Genre: Fiction\n";
break;
case Genre::nonfiction:
cout << "Genre: Nonfiction\n";
break;
case Genre::periodical:
cout << "Genre: Periodical\n";
break;
default:
cout << "No Genre?\n";
break;
}
}
bool operator==(const Book& book1, const Book& book2)
{
return book1.isbn() == book2.isbn();
}
bool operator!=(const Book& book1, const Book& book2)
{
return !(book1.isbn() == book2.isbn());
}
void printPatronData(const Patron& patron)
{
cout << "Patron's name: " << patron.username() << "\n"
<< "Library card no: " << patron.card_number() << "\n"
<< "Fee owed: $" << patron.fee() << "\n";
}
void Library::add_book(const Book& book)
{
for (size_t i = 0; i < books.size(); i++)
{
if (is_book_in_library(book))
{
error("error: Book is already in library.");
}
}
books.push_back(book);
}
void Library::add_patron(const Patron& patron)
{
patrons.push_back(patron);
}
int Library::number_of_books()
{
return books.size();
}
bool Library::is_book_in_library(const Book& book) const
{
for (size_t i = 0; i < books.size(); i++)
{
if (book == books[i])
{
return true;
}
}
return false;
}
bool Library::is_patron_in_library(const Patron& patron) const
{
for (size_t i = 0; i < patrons.size(); i++)
{
if (patron.username() == patrons[i].username())
{
return true;
}
}
return false;
}
bool Library::is_fee_owed(const Patron& patron)
{
if (patron.fee() > 0)
{
return true;
}
return false;
}