////////////////////////////////////////////////////////////////////////////
// File: circularbooks.java

// Problem:
// Develop a program that assists a bookstore manager. The
// manager's program should keep a record for each book. The record must
// include information about the author, the book's title, its price, and its
// publication year. The information about the author includes author's name,
// year of birth, and a list of books written by this author.


//      +--------------------------+
//      |  +---------------------+ |          +-----------+
//      |  |                     | |          |           |
//      v  v                     | |          v           |
//  +----------+                 | |  +----------------+  |
//  | ALoBooks |                 | |  | Author         |  |
//  +----------+                 | |  +----------------+  |
//      / \                      | |  | String name    |  |
//      ---                      | |  | int dob        |  |
//       |                       | +--| ALoBooks books |  |
//    +--+------------+          |    +----------------+  |
//    |               |          |                        |
// +-------+  +----------------+ |                        |
// | MTLoB |  | ConsLoBooks    | |                        |
// +-------+  +----------------+ |                        |
//         +--| Book fst       | |                        |
//         |  | ALoBooks blist |-+                        |
//         |  +----------------+                          |
//         v                                              |
//   +---------------+                                    |
//   | Book          |                                    |
//   +---------------+                                    |
//   | String title  |                                    |
//   | Author author |------------------------------------+
//   | int year      |
//   | int price     |
//   +---------------+ 



// Problems:
// 
// (a) Count how many books did an author write
// 
// (b) Develop the method that produces the list of all books by a given author
// from a list of books
// 
// 



class Book {
  String title;
  Author author;
  int year;
  int price;

  Book(String title, Author author, int year, int price){
    this.title = title;
    this.author = author;
    this.year = year;
    this.price = price;
    this.author.addBook(this);
  }

  // determine whether this book is the same as the given one
  boolean sameBook(Book b){
    return    (this.title.equals(b.title))
           && (this.year == b.year)
           && ( ((this.price - b.price) < 0.000001) && ((this.price - b.price) > -0.000001))
           && this.author.sameAuthor(b.author);
  }
}

class Author {
  String name;
  int dob;
  ALoBooks books;

  Author(String name, int dob){
    this.name = name;
    this.dob = dob;
    this.books = new MTLoBooks();
  }

// Template for the class Author
// ...this.name...
// ...this.dob...
// ...this.books...


  void addBook(Book b){
    this.books = new ConsLoBooks(b, this.books);
  }

  // determine whether this is the same as the given author
  // Note: compare only the name and date of birth
  boolean sameAuthor(Author author){

// Template for the method sameAuthor
// ...author.name...
// ...author.dob...
// ...author.books...

    return    (this.name.equals(author.name))
           && (this.dob == author.dob);
  }
}


abstract class ALoBooks { 

  // count the number of books in this list
  abstract int count();

  // produce a list of all books by a given author in this list
  abstract ALoBooks booksBy(Author author);

}

class MTLoBooks extends ALoBooks {
  MTLoBooks(){}

  int count(){
    return 0;
  }

  ALoBooks booksBy(Author author){
    return this;
  }
}

class ConsLoBooks extends ALoBooks {
  Book fst;
  ALoBooks rst;

  ConsLoBooks(Book fst, ALoBooks rst){
    this.fst = fst;
    this.rst = rst;
  }

  int count(){
    return 1 + this.rst.count();
  }

  ALoBooks booksBy(Author author){
    if (this.fst.author.sameAuthor(author))
      return new ConsLoBooks(this.fst, this.rst.booksBy(author));
    else 
      return this.rst.booksBy(author);
  }
}

// Template for the class ConsLoBooks
// ...this.fst...
// ...this.rst...
// ...this.rst.count()...




// Author jackL = new Author("Jack London", 1876);

// Author julesV = new Author("Jules Verne", 1828);


// Book b1 = new Book("Call of the Wild", jackL, 1995, 10);

// Book b2 = new Book("The Sea-Wolf", jackL, 1999, 12);

// Book b3 = new Book("White Fang", jackL, 2001, 10);


// Book b4 = new Book("Five Weeks in a Balloon", julesV, 1998, 10);

// Book b5 = new Book("From Earth to the Moon", julesV, 1999, 10);

// Book b6 = new Book(" Mysterious Island", julesV, 2000, 10);


// ALoBooks books0 = new MTLoBooks();

// ALoBooks books1 = new ConsLoBooks(b6, books0);

// ALoBooks books2 = new ConsLoBooks(b5, books1);

// ALoBooks books3 = new ConsLoBooks(b4, books2);

// ALoBooks books4 = new ConsLoBooks(b3, books3);

// ALoBooks books5 = new ConsLoBooks(b2, books4);

// ALoBooks books = new ConsLoBooks(b1, books5);


// "Test of the method booksBy(Author author)"

// books.booksBy(jackL)

// "Should be"

// new ConsLoBooks(b1, new ConsLoBooks(b2, new ConsLoBooks(b3, books0)))


// ALoBooks booksByJackL = new ConsLoBooks(b1, new ConsLoBooks(b2, new ConsLoBooks(b3, books0)));

// "Expected:"

// booksByJackL


// (books.booksBy(jackL)).equals(booksByJackL)



...(books.booksBy(jackL)).count() == 3.true.

."Compare books"..books.booksBy(jackL).booksByJackL.

."Test book count"..booksByJackL.count() == 3.true.

