package data.filters;

import data.*;
import data.events.*;

import java.util.*;

/**
  * StockFilter for CountingStocks.
  *
  * <p>The filter condition will be defined by overriding method {@link #countItems}.</p>
  *
  * @author Steffen Zschaler
  * @version 2.0 19/08/1999
  * @since v2.0
  */
public abstract class CountingStockFilter extends AbstractStockFilter implements CountingStock {

  /**
    * Create a new CountingStockFilter.
    *
    * @param csSource the source Stock.
    */
  public CountingStockFilter (CountingStock csSource) {
    super (csSource);
  }

  /**
    * Return all items with the given key that are contained in the filtered Stock.
    *
    * @override Never
    */
  public Iterator get (final String sKey, final DataBasket db, final boolean fForEdit) {
    class I implements Iterator {
      protected int m_nMaxCount = countItems (sKey, db);
      protected Iterator m_iIterator = m_stSource.get (sKey, db, fForEdit);

      public boolean hasNext() {
        return ((m_iIterator.hasNext()) &&
                (m_nMaxCount > 0));
      }

      public Object next() {
        if (m_nMaxCount <= 0) {
          throw new NoSuchElementException();
        }

        m_nMaxCount--;

        return m_iIterator.next();
      }

      public void remove() {
        m_iIterator.remove();
      }
    }

    return new I();
  }

  /**
    * Count the items of the given key in the filtered Stock.
    *
    * <p>This method must be overridden, as it represents the filter condition. All other methods that use or
    * return filtered values will call this method.</p>
    *
    * @override Always This method must be overridden, as it represents the filter condition. All other methods
    * that use or return filtered values will call this method.
    */
  public abstract int countItems (String sKey, DataBasket db);

  /**
    * Check whether the filtered Stock contains the given StockItem.
    *
    * @override Never
    */
  public boolean contains (StockItem si, DataBasket db) {
    return contains (si.getName(), db);
  }

  /**
    * Check whether the filtered Stock contains the given Stock.
    *
    * @override Never
    */
  public boolean containsStock (Stock st, DataBasket db) {
    boolean fResult = m_stSource.containsStock (st, db);

    if (fResult) {
      for (Iterator i = st.keySet (db).iterator(); i.hasNext();) {
        String sKey = (String) i.next();

        if (countItems (sKey, db) < st.countItems (sKey, db)) {
          return false;
        }
      }
    }

    return fResult;
  }

  /**
    * Add the specified number of items to the source Stock.
    *
    * @override Never
    */
  public void add (String sKey, int nCount, DataBasket db) {
    ((CountingStock) m_stSource).add (sKey, nCount, db);
  }

  /**
    * Remove at most the specified number of items from the source Stock. If the filtered Stock contains fewer
    * items than specified only as many items as are contained in the filtered Stock will be removed from the
    * source Stock.
    *
    * @override Never
    */
  public void remove (String sKey, int nCount, DataBasket db)
    throws VetoException {
    int nFilteredCount = countItems (sKey, db);
    if (nFilteredCount > nCount) {
      nFilteredCount = nCount;
    }

    if (nFilteredCount > 0) {
      ((CountingStock) m_stSource).remove (sKey, nFilteredCount, db);
    }
  }
}