package hirondelle.stocks.portfolio;

import java.util.Observable;
import java.util.*;
import hirondelle.stocks.util.Args;
import hirondelle.stocks.quotes.Stock;

/**
 * The central abstraction of this package, representing the current selection of 
 * stocks of interest to the end user 
 * (a {@link hirondelle.stocks.portfolio.Portfolio}).
 * 
 * <P><tt>CurrentPortfolio</tt> may be used as an example implementation for any
 * application which edits one item at a time.
 * 
 * <p>The {@link #isUntitled} and {@link #getNeedsSave} properties are particularly
 * significant. They influence the file menu actions. For example, a
 * <tt>CurrentPortfolio</tt> for which {@link #isUntitled} is true cannot be deleted.
 * 
 * <p><tt>CurrentPortfolio</tt> is an {@link java.util.Observable}. To minimize spurious
 * updates, related {@link java.util.Observer} objects need to call
 * {@link java.util.Observable#notifyObservers()} explicitly. This is important in this
 * application, since quotes are fetched from the web each time the current portfolio is
 * updated, and this is a relatively expensive operation.
 */
public final class CurrentPortfolio extends Observable {

  /**
   * Constructor.
   *  
   * @param aPortfolio is the set of stocks of current interest to the user; no 
   * defensive copy is made of <tt>aPortfolio</tt>.
   * @param aNeedsSave is true only if this <tt>CurrentPortfolio</tt> 
   * has been edited by the end user, and these edits have not yet been saved.
   */
  public CurrentPortfolio(Portfolio aPortfolio, NeedsSave aNeedsSave) {
    Args.checkForNull(aPortfolio);
    fPortfolio = aPortfolio;
    fNeedsSave = aNeedsSave.getValue();
    // upon construction of the main window, an update is desired in order to
    // synch the gui with the current portfolio. This update is called explicitly.
    // Thus, setChanged needs to be set here, since it's default value is false.
    setChanged();
  }

  /**
  * Enumeration for the two states of <tt>aNeedsSave</tt> passed to the constructor.
  * Use of an enumeration forces the caller to create a constructor call which has
  * high clarity.
  */
  public enum NeedsSave {
    TRUE(true),
    FALSE(false);
    boolean getValue() {
      return fToggle;
    }
    private final boolean fToggle;
    private NeedsSave(boolean aToggle) {
      fToggle = aToggle;
    }
  }

  /**
   * Revert to an untitled <tt>Portfolio</tt> which does not need a save.
   */
  public void clear() {
    setPortfolio(Portfolio.getUntitledPortfolio());
    setNeedsSave(false);
  }

  /**
   * Return <tt>true</tt> only if the current <tt>Portfolio</tt> has never been
   * saved under a user-specified name, neither in this session, nor in any other. Such a
   * <tt>Portfolio</tt> appears as untitled in the display.
   */
  public boolean isUntitled() {
    return fPortfolio.isUntitled();
  }

  /**
   * Return the {@link Portfolio} of current interest to the user.
   */
  public Portfolio getPortfolio() {
    return fPortfolio;
  }

  /**
   * Change the {@link Portfolio} of current interest to the user.
   */
  public void setPortfolio(Portfolio aPortfolio) {
    Args.checkForNull(aPortfolio);
    fPortfolio = aPortfolio;
    setChanged();
  }

  /**
   * Return the name of this <tt>CurrentPortfolio</tt>.
   */
  public String getName() {
    return fPortfolio.getName();
  }

  /**
   * Change the name of this <tt>CurrentPortfolio</tt>.
   * @param aName has the same conditions as 
   * {@link hirondelle.stocks.portfolio.Portfolio#setName(String)}.
   */
  public void setName(String aName) {
    fPortfolio.setName(aName);
    setChanged();
  }

  /**
   * Return the {@link hirondelle.stocks.quotes.Stock} objects in this
   * <tt>CurrentPortfolio</tt>.
   */
  public Set<Stock> getStocks() {
    return fPortfolio.getStocks();
  }

  /**
   * Change the stocks in this <tt>CurrentPortfolio</tt>.
   * @param aStocks has the same conditions as
   * {@link hirondelle.stocks.portfolio.Portfolio#setStocks(Set)}
   */
  public void setStocks(Set<Stock> aStocks) {
    fPortfolio.setStocks(aStocks);
    setChanged();
  }

  /**
   * Return <tt>true</tt> only if this <tt>CurrentPortfolio</tt> has unsaved
   * edits.
   */
  public boolean getNeedsSave() {
    return fNeedsSave;
  }

  /**
   * Indicate that this <tt>CurrentPortfolio</tt> either does or does not have any
   * unsaved edits.
   */
  public void setNeedsSave(boolean aNeedsSave) {
    fNeedsSave = aNeedsSave;
    setChanged();
  }

  // PRIVATE 
  private Portfolio fPortfolio;
  private boolean fNeedsSave;
}