package data;

import java.util.*;

import data.events.*;

/**
  * A Stock.
  *
  * <p>Stocks are lists that refer to a {@link Catalog} and denote for each {@link CatalogItem} how many
  * objects of this type are actually available. There are two basically different types of Stocks:
  *
  * <ol>
  *   <li><b>{@link CountingStock}</b><br>
  *       Stocks that store only the number of objects available for each CatalogItem.<br>
  *       This type of Stock will be used whenever the information given by the CatalogItem sufficiently
  *       describes the object.<br>
  *       In general this type of Stock should be sufficient.</li>
  *   <li><b>{@link StoringStock}</b><br>
  *       Stocks that store a list of actual StockItems for each CatalogItem.<br>
  *       This type of Stock is usually used to store additional information with the StockItems. E.g. to store
  *       the 'Stock' of lent books in a library you would create {@link StockItem StockItems} that can store
  *       the name of the borrower and the date of borrowing.<br>
  *       This type of Stock is also needed when implementing nested Stocks.</li>
  * </ol>
  *
  * <p>To suit both types of Stock, {@link StockItem StockItems} are introduced. A StockItem refers to a
  * CatalogItem but can store additional information as well.</p>
  *
  * <p>Stocks work always on StockItems. They add, remove and search StockItems. They are able to return an
  * Iterator of StockItems for a given key, but can as well just count all StockItems for the same key.</p>
  *
  * @author Steffen Zschaler
  * @version 2.0 18/08/1999
  * @since v0.5
  */
public interface Stock extends StockItem, DataBasketEntrySource, DataBasketEntryDestination {

  /**
    * Add an item to the Stock.
    *
    * <p>The item will only be visible to users of the same DataBasket. Only after a {@link DataBasket#commit}
    * was performed on the DataBasket, the item will become visible to other users.</p>
    *
    * <p>For a {@link ListenableStock} a <code>addedStockItems</code> event will be fired.</p>
    *
    * @param si the item to be added.
    * @param db the DataBasket relative to which the item will be added.
    *
    * @override Always
    *
    * @exception CatalogConflictException if the items key is not contained in the corresponding {@link Catalog}.
    * @exception DataBasketConflictException if the item has already been added/removed using another DataBasket.
    */
  public void add (StockItem si, DataBasket db);

  /**
    * Add the contents of a Stock to this Stock. The method conceptually calls {@link #add} for each item in
    * the source Stock so the same constraints apply and the same exceptions may be thrown.
    *
    * @override Always
    *
    * @param st the Stock whose contents is to be added to this Stock.
    * @param db the DataBasket relative to which to perform the actions. <code>addStock</code> will add all
    * items from the source Stock that are visible using this DataBasket.
    * @param fRemove if true, the items will be removed from the source Stock prior to adding them to this
    * Stock. Otherwise, they will be cloned prior to adding them to the Stock.
    */
  public void addStock (Stock st, DataBasket db, boolean fRemove);

  /**
    * Iterate all items with a given key.
    *
    * <p>This method, together with {@link #iterator} is the only way of accessing the individual
    * {@link StockItem StockItems} contained in a Stock. The iterator will deliver all items that have the
    * specified key and are visible using the given DataBasket. Depending on the <code>fForEdit</code>
    * parameter, the items will be retrieved in different ways. See {@link DataBasket} for an explanation of
    * the different possibilities.</p>
    *
    * <p>For a {@link ListenableStock} <code>canEditStockItems</code> and <code>editingStockItems</code> events
    * will be fired if <code>fForEdit</code> == true. {@link VetoException VetoExceptions} will be converted
    * into <code>UnSupportedOperationException</code>s.</p>
    *
    * @override Always
    *
    * @param sKey the key for which to retrieve the StockItems.
    * @param db the DataBasket relative to which to retrieve the StockItems.
    * @param fForEdit if true, the StockItems will be retrieved for editing.
    */
  public Iterator get (String sKey, DataBasket db, boolean fForEdit);

  /**
    * Count the StockItems with a given key that are visible using a given DataBasket.
    *
    * @override Always
    *
    * @param sKey the key for which to count the StockItems.
    * @param db the DataBasket that is used to determine visibility.
    */
  public int countItems (String sKey, DataBasket db);

  /**
    * Check whether the Stock contains an item with the given key.
    *
    * <p>Equivalent to:<code>({@link #countItems} (sKey, db) > 0)</code>.</p>
    *
    * @override Always
    *
    * @param sKey the key for which to check containment.
    * @param db the DataBasket used to check visibility.
    */
  public boolean contains (String sKey, DataBasket db);

  /**
    * Check whether the Stock contains the given StockItem.
    *
    * <p>Return true if the Stock contains a StockItem that is equal to the given one.</p>
    *
    * @param si the StockItem for which to check containment.
    * @param db the DataBasket used to check visibility.
    *
    * @override Always.
    */
  public boolean contains (StockItem si, DataBasket db);

  /**
    * Check whether the given Stock is completely contained in this Stock.
    *
    * <p>Conceptually calls {@link #contains(data.StockItem, data.DataBasket)} for each item in the given Stock.
    * </p>
    *
    * @override Always
    *
    * @param st the Stock for which to check containment.
    * @param db the DataBasket used to determine visibility.
    */
  public boolean containsStock (Stock st, DataBasket db);

  /**
    * Remove one StockItem with the specified key from the Stock.
    *
    * <p>If there are any StockItems with the specified key, one will be removed. There is no guarantee as to
    * which StockItem will be removed. The removed item, if any, will be returned.</p>
    *
    * <p>For a {@link ListenableStock} <code>canRemoveStockItems</code> and <code>removedStockItems</code>
    * events will be fired.</p>
    *
    * @override Always
    *
    * @param sKey the key for which to remove an item.
    * @param db the DataBasket relative to which to remove the item.
    *
    * @return the removed item
    *
    * @exception VetoException if a listener vetoed the removal.
    * @exception DataBasketConflictException if the item cannot be removed due to conflicts from DataBasket
    * usage.
    */
  public StockItem remove (String sKey, DataBasket db)
    throws VetoException;

  /**
    * Remove the given StockItem from the Stock.
    *
    * <p>If the given StockItem is contained in the Stock, it will be removed. The removed item, if any, will
    * be returned.</p>
    *
    * <p>For a {@link ListenableStock} <code>canRemoveStockItems</code> and <code>removedStockItems</code>
    * events will be fired.</p>
    *
    * @override Always
    *
    * @param si the StockItem to be removed.
    * @param db the DataBasket relative to which to remove the item.
    *
    * @return the removed item
    *
    * @exception VetoException if a listener vetoed the removal.
    * @exception DataBasketConflictException if the item cannot be removed due to conflicts from DataBasket
    * usage.
    */
  public StockItem remove (StockItem si, DataBasket db)
    throws VetoException;

  /**
    * Iterate all items in the Stock.
    *
    * <p>This method, together with {@link #get} is the only way of accessing the individual
    * {@link StockItem StockItems} contained in a Stock. The iterator will deliver all items that are visible
    * using the given DataBasket. Depending on the <code>fForEdit</code> parameter, the items will be retrieved
    * in different ways. See {@link DataBasket} for an explanation of the different possibilities.</p>
    *
    * <p>For a {@link ListenableStock} <code>canEditStockItems</code> and <code>editingStockItems</code> events
    * will be fired if <code>fForEdit</code> == true. {@link VetoException VetoExceptions} will be converted
    * into <code>UnSupportedOperationException</code>s.</p>
    *
    * @override Always
    *
    * @param db the DataBasket relative to which to retrieve the StockItems.
    * @param fForEdit if true, the StockItems will be retrieved for editing.
    */
  public Iterator iterator (DataBasket db, boolean fForEdit);

  /**
    * Return the set of keys for which {@link StockItem StockItems} are visible using the given DataBasket.
    *
    * <p>The returned set is static and gives the state of the Stock at the time of the call. It will not
    * automatically update when the contents of the Stock changes.</p>
    *
    * @param db the DataBasket used for determining visibility.
    *
    * @override Always
    */
  public Set keySet (DataBasket db);

  /**
    * Sum up the Stock.
    *
    * <p>The method will determine the value of each {@link CatalogItem} in the associated Catalog and
    * {@link Value#multiplyAccumulating(int) multiply} this by
    * {@link #countItems the number of StockItems for the respective key}. These products will be
    * {@link Value#addAccumulating added up} and the resulting total will be returned.</p>
    *
    * @override Always
    *
    * @param db the DataBasket that is used to determine visibility.
    * @param civ the CatalogItemValue used for determining the value of a CatalogItem.
    * @param vInit the initial value. The sum of the Stock will be added to this value.
    *
    * @return the resulting total. Usually the returned object is the same as the one passed as
    * <code>vInit</code>, only with a changed value.
    */
  public Value sumStock (DataBasket db, CatalogItemValue civ, Value vInit);

  /**
    * Increase the {@link #sumStock Stock's value} by a given value.
    *
    * <p>The method will try to break the given value as exactly as possible into StockItems that will be
    * added to the Stock. The actual algorithm used for breaking up the value will be determined by the last
    * parameter. The return value of the method will specify the remaining value that could not be represented
    * by StockItems by the given algorithm.</p>
    *
    * @param db the DataBasket relative to which to perform the operation.
    * @param vTarget the value by which to increase the Stock's total value.
    * @param sfvc the strategy used to fill the Stock.
    *
    * @return the value that remained and could not be represented by StockItems.
    *
    * @override Always
    */
  public Value fillStockWithValue (DataBasket db, Value vTarget, StockFromValueCreator sfvc);

  /**
    * Get the size of this Stock. I.e. calculate the number of StockItems that can be seen when using the
    * given DataBasket.
    *
    * @param db the DataBasket used to determine visibility.
    *
    * @override Always
    */
  public int size (DataBasket db);

  /**
    * Get the Catalog associated to this Stock. 
    * 
    * <p>For a substock of another stock this is essentially equivalent to 
    * <pre>
    * Catalog cReturn = (Catalog) {@link StockItem#getAssociatedItem getAssociatedItem} (db);
    *
    * if (cReturn != null) {
    *   return cReturn;
    * }
    * else {
    *   throw new {@link DataBasketConflictException}();
    * }
    * </pre>
    *
    * @param db a DataBasket determinig visibility of the stock's catalog.
    *
    * @override Always
    */
  public Catalog getCatalog (DataBasket db);
}