/**
 * Class Purchase.
 * 
 * <h4>ITI 1120 Fall 2011, Assignment 5, Question 3</h4>
 * <p>
 * This class handles purchase transactions
 * <p>
 * Each purchase is associated with a client and a colletion of items.  Within
 * each object, a bill number, the dates of the purchase, and the total
 * amount paid (including shipping fees) is stored.
 * <p>
 * The class also stores the next bill number that should be issued to a
 * new object.  This value is incremented in the constructor, and copied
 * to each object at that time.
 * <p>
 * Operations that are provided are as follows:
 * <ul>
 * <li> ask for the bill number</li>
 * <li> ask for the name of the client associated with the transaction</li>
 * <li> ask for the day of purchase</li>
 * <li> ask whether the transaction includes a specific item </li>
 * <li> compute the total cost of the purchase</li>
 * <li> print the purchase information</li>
 * </ul>
 * 
 */

class Purchase
{   // static variables
    private static int transportHandling = 2; // handling fee
    private static int transportParItem = 1; // transport cost par item
    /**
     * The next bill number to be assigned as a Purchase object is constructed.
     */
    private static int nextBill = 1000;
    
    /**
     * The actual bill number for a purchase object.
     */
    private int billNumber;
    
    /**
     * The collection of items that were rented as part of this Purchase
     * transaction.
     */
    private Item[] items;
    
    /**
     * The client associated with this purchase.
     */
    private Client client;
    
    /**
     * Day number on which the items were rented.
     */
    private int datePurchased;
    
    /**
     * The total amount paid for the purchase, including shipping.
     */
    private int totalPaid;
    
    /**
     * Constructs a new Purchase object, using a client reference, the day number
     * on which the items were purchased, and a reference to an array of items
     * rented.
     * <p>
     * As part of creating a new purchase, we have to determine the bill number,
     * and determine the cost of the purchase.
     * 
     * @param theClient
     * @param today
     * @param itemsPurchased
     */
    public Purchase( Client theClient, int today, Item[] itemsPurchased )
    {
        // Copy parameters to instance variables
        this.items = itemsPurchased;
        this.client = theClient;
        this.datePurchased = today;
        
        // Use static value from class to assign a bill number
        this.billNumber = Purchase.nextBill;
        
        // Be sure to tell class to increase the next bill number.
        Purchase.nextBill = Purchase.nextBill + 1;
        
        // calculate total cost and store it
        totalPaid = this.calculateCost( );
    }
    
    /**
     * Returns the bill number for this Purchase transaction.
     * 
     * @return The instance variable with the bill number.
     */
    public int getBillNumber( )
    {
        return billNumber;
    }
    
    /**
     * Returns the day number on which the items were rented.
     * 
     * @return The day number of the purchase transaction.
     */
    public int getDatePurchased( )
    {
        return datePurchased;
    }
     
     /**
     * Returns the cost of this Purchase transaction.
     * 
     * @return The instance variable totalPaid.
     */
    public int getTotalCost( )
    {
        return totalPaid;
    }
    
    /**
     * Returns the total cost of the purchase, including shipping fees.
     * 
     * @return The total cost of the purchase transaction.
     */
    private int calculateCost( )
    {
        int index; // Array index
        int sumCost; // cost of all items
        int transportCost; 
        int numItemsDelivered; 
        int totalCost; // Running total of item costs plus shipping.
        int credit; 
        int result;
        
        // Go through array of items and ask each item what it costs
        // decrement copies if the item is available 
        
        totalCost = 0;
        sumCost = 0;
        numItemsDelivered = 0;
   
        for (index = 0; index < items.length; index = index + 1)
        {
          if (items[index].decrementCopies())
          {
            sumCost = sumCost + items[index].getPrice();
            numItemsDelivered ++;
          }
        }
     
       if (numItemsDelivered > 0)
        {
         transportCost = sumCost + transportHandling + transportParItem * numItemsDelivered;
        }
       else
        {
         transportCost = 0; // No item will be delivered
        }
    
      credit = client.getCredit();
      if (credit> 0)
      {
         if (credit > transportCost)
         {
          client.reduceAmountCredited(transportCost);
          result = 0; // Entirely covered by credit
         }
        else
         {
          result = transportCost - credit;
          client.reduceAmountCredited(credit); // Credit is all used!
         }
      }
      else
      {
        result = transportCost;
      }

      return result;
    }
    
    /**
     * Returns the name of the client associated with this transaction.
     * 
     * @return The client's name.
     */
    public String getClientName( )
    {
        return this.client.getName( );
    }
    
      
    /**
     * Returns true if this Purchase transaction includes the specified item and
     * false otherwise.
     * 
     * @param anItem
     *            Item for which to search
     * @return True if item is found, and false otherwise.
     */
    public boolean includesItem( Item anItem )
    {
        int index; // Array index
        boolean result; // Result of search
        
        // So far, we haven't found the tiem.
        
        result = false;
        index = 0;
        
        // Stop search when we run out of items, or when we find the
        // item for which we are searching.
        
        while ( index < items.length && !result )
        {
            // We are matching by the item title.
            
            // It might be better to match by both title and type; videos and DVDs
            // certainly can have the same name, and something like "Tomb Raider"
            // could be any of a game, a video, or a DVD. On the other hand,
            // matching by object references using == is trickier for users.
            // It will work for A5Q3 because we are using the same Item object,
            // as was passed in by the object constructor, but in a more realistic
            // system, this would be difficult.
            
            result = ( ( items[index].getTitle( ) ).compareTo( anItem.getTitle( ) ) == 0 );
            index = index + 1;
        }
        
        return result;
    }
    
    /**
     * Returns a String with information about the purchase.
     * <p>
     * This method prints the following information to the screen:
     * <ul>
     * <li>The bill number</li>
     * <li>The day number of the purchase</li>
     * <li>The name of the client</li>
     * <li>The client's email</li>
     * <li>The title and type of each item purchased</li>
     * <li>The total cost of the purchase</li>
     * </ul>
     */
    
    public String toString( )
    {
        int index;
        String result; 
        final String newLine = System.getProperty("line.separator");
         
        result = "Bill number: " + this.billNumber;
        result = result + ", date: " + this.getDatePurchased() + newLine;
        result = result + "Client: " + client.getName( );
        result = result + ", email: " + client.getEmail( ) + newLine;
        result = result + "Items ordered:" + newLine;
        for ( index = 0; index < items.length; index = index + 1 )
        {
            result = result + "   * " + items[index].getTitle( );
            result = result + " (" + Item.typeToString( items[index].getType( ) ) 
                     + ")" + newLine;
        }
        
        result = result + "Total: $" + this.totalPaid + newLine;
        return result;
    }
}