import java.util.*;

  
/** 
 * Contains booklist and book pricelist information.
 * 
 */ 
public class BookReference {

  /* Since we cannot use arrays, we are storing book titles in strings.
   * The books are separated from one another by BOOK_SEPARATOR.
   */
  /** Booklist for the first academic year. */
  private String year1BookList;

  /** Booklist for the second academic year. */
  private String year2BookList;

  /** Booklist for the third academic year. */
  private String year3BookList;

  /** Booklist for the fourth academic year. */
  private String year4BookList;

  /** The pricelist is a string consisting of 
   * book units separated by BOOK_SEPARATOR.  Each book unit 
   * consists of the book title, then the wholesale price, 
   * and finally the retail price.  These pieces of information 
   * are separated by DELIMITOR.
   *  Price list for the books in the book lists. */
  private String priceList = null;
  
  /** Constants created to avoid the use of magic numbers
   * and allow flexibility.
   *
   *  Constant used to separate books and units of
   *  book information in the book and price lists.
   */
  private static final String BOOK_SEPARATOR = "#";
  
  /** 
   *  Constant used to separate price information fields within
   *  a unit of information about a book.
   */
  private static final String DELIMITOR = ":";  
  
  
  /** 
   *  Create a BookReference using four strings containing the 
   *  books for years one through four repectively, and a fifth
   *  string which contains the price list for all books in the
   *  list.  Books in a booklist must be separated by "#",
   *  Prices in the price list are organized by book unit,
   *  Each book unit, separated by a "#", contains the book name,
   *  followed by the wholesale price, followed by the retail
   *  price.  These fields are separated by ":".
   *  @param bl1 Booklist for first year.
   *  @param bl2 Booklist for second year.
   *  @param bl3 Booklist for third year.
   *  @param bl4 Booklist for fourth year.
   *  @param pl the price list containing prices for all of the books
   *  on the book lists.
   */
  public BookReference(String bl1, String bl2, 
                       String bl3, String bl4,  String pl) {
    this.year1BookList = bl1;
    this.year2BookList = bl2;
    this.year3BookList = bl3;
    this.year4BookList = bl4;
    this.priceList = pl;
  }

  /** 
   *  Create a BookReference using four strings containing the 
   *  books and their prices, for years one through four repectively.
   *  Each book is in a book unit containing the book name
   *  followed by the wholesale price, followed by the retail
   *  price.  These fields are separated by ":".
   *  Book units are separated by 
   *  Prices in the book list are organized by book unit,
   *  Each book unit, separated by a "#", contains the book name,
   *  followed by the wholesale price, followed by the retail
   *  price.  These fields are separated by ":".
   * @param b1 Book unit list for first year.
   * @param b2 Book unit list for second year.
   * @param b3 Book unit list for third year.
   * @param b4 Book unit list for fourth year.
   */
  public BookReference(String b1, String b2, 
                       String b3, String b4) {
    this.year1BookList = unstringBookList(b1);
    this.year2BookList = unstringBookList(b2);
    this.year3BookList = unstringBookList(b3);
    this.year4BookList = unstringBookList(b4);
  }
  
  /**
   *  This is a helper function to unstring list of book units
   *  and add to the price list, and create a booklist.
   *  Takes a string containing a list of book units separated by 
   *  a "#".  Each book unit, contains the book name,
   *  followed by the wholesale price, followed by the retail
   *  price.  These fields are separated by ":".
   *  The price list is updated for each book unit added.
   *  Duplicates may exist on the price list as each book unit
   *  is added to the end of the price list.
   * @param list A book price (unit) list.	
   * @return The boook list.
   */
  private String unstringBookList(String list) { 
    String books = null;
    StringTokenizer bookUnits = new StringTokenizer(list, BOOK_SEPARATOR); 
    while (bookUnits.hasMoreTokens() ) { // add to book list and price list 
      // book units may exist twice on the list
      String bookPrices = (String) bookUnits.nextToken();
      if (this.priceList == null) {
        this.priceList = bookPrices;
      } else {
        this.priceList += BOOK_SEPARATOR + bookPrices;
      }
      if (books == null) {
        books = bookPrices.substring(0, bookPrices.indexOf(DELIMITOR));
      } else {
        books += BOOK_SEPARATOR + 
          bookPrices.substring(0, bookPrices.indexOf(DELIMITOR));
      }
    }
    return books;
  }
  
  /**
   * Determine if book is on any of the booklists.
   * This determines whether the book is required or
   * not by the bookstore.
   * @param book The book to be found in the booklist.
   * @return Whether the book is found in a booklist.
   */ 
  public boolean bookRequired(String book) {
    return (this.bookFound(book, this.year1BookList) 
              || this.bookFound(book, this.year2BookList) 
              || this.bookFound(book, this.year3BookList) 
              || this.bookFound(book, this.year4BookList)); 
  }
  /**
   * Return whether a book is in a list.
   * @param b The book sought.
   * @param list The list of books in which to search for the book.
   * @return Whether the book is in the list.
   */
  public static boolean bookFound(String b, String list) {
    StringTokenizer bookUnits = new StringTokenizer(list, BOOK_SEPARATOR); 
    boolean found = false;
    while (bookUnits.hasMoreTokens() && !found) {
      found = (b.equals(bookUnits.nextToken()));
    }
    return found;
  }

  /** 
   *  Get the list of books required.  If not 1 through 4, an empty
   *  list ("") is returned.
   *  @param year The year of study for which the books are required.
   *  @return The string containing books required for that year of study. 
   * 
   */
  public String getBookList(int year) {
    switch(year) {
      case 1: { // books for year 1 of study
        return year1BookList;
      }          
      case 2: { // books for year 2 of study
        return year2BookList;
      }
      case 3: { // books for year 3 of study
        return year3BookList;
      }
      case 4: { // books for year 4 of study
        return year4BookList;
      }
      default: {
        return "";
      }
    }
  }
  
  /** 
   *  Return the wholesale price for the book specified.
   *  Assumes that every book in the book list is also 
   *  present in the price list.  
   * @param b The book for which price is requested.
   * @return The wholesale price for book b.
   */
  public double getWholesalePrice( String b ) {
    String bookPrices;
    double wholesale = 0.0; 
    if (this.priceList != null) {
      StringTokenizer bookUnits =  new StringTokenizer(this.priceList, 
						       BOOK_SEPARATOR); 
      while (bookUnits.hasMoreTokens() && wholesale == 0.0) {
        bookPrices = bookUnits.nextToken();
        if (bookPrices.substring(0, bookPrices.indexOf(DELIMITOR)).equals(b)) {
          bookPrices = bookPrices.substring(bookPrices.indexOf(DELIMITOR) + 1);
          wholesale = Double.parseDouble(bookPrices.substring(0, 
				         bookPrices.indexOf(DELIMITOR)));
        }
      }
    }
    return wholesale;
  }
  
  /**
   * Get the book price list.
   * @return The book price list.
   */
  public String getPriceList() {
    return priceList;
  }
  
  /** 
   * Return the retail price for the book specified
   * @param b The book for which price is requested.
   * @return The retail price for book b.
   */
  public double getRetailPrice ( String b) {
    double retail = 0.0;
    String bookPrices;
    if (this.priceList != null) {
      StringTokenizer bookUnits = 
        new StringTokenizer(this.priceList, BOOK_SEPARATOR); 
      while (bookUnits.hasMoreTokens() && retail == 0.0) {
        bookPrices = (String) bookUnits.nextToken();
        if (bookPrices.substring(0, bookPrices.indexOf(DELIMITOR)).equals(b)) {
          bookPrices = bookPrices.substring(bookPrices.indexOf(DELIMITOR) + 1);
          retail = Double.parseDouble(bookPrices.substring
                                        (bookPrices.indexOf(DELIMITOR) + 1));
        }
      }
    }
    return retail;
  }
  
  /**
   * Returns a string equal to all books in the second list minus those
   * that occur in the first list.
   * @param list1 The first book list.
   * @param list2 The second book list.
   * @return A list containing only those books in the second list that do 
   * not also occur in the first list.
   */
  public static String removeBooks(String list1, String list2) {
    String keep = "";
    StringTokenizer books = new StringTokenizer(list2, BOOK_SEPARATOR);
    while (books.hasMoreTokens()) {
      String book = (String) books.nextToken();
      if (!bookFound(book, list1)) { // if we do not find this book in our list
        if (keep.equals("")) {
          keep = book;
        } else {
          keep += BOOK_SEPARATOR + book;
        }
      }
    }
    return keep;
  }
    

}

