package data.filters;

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

import java.util.*;

/**
  * StockFilter for StoringStocks.
  *
  * <p>The filter condition can be defined by overriding method
  * {@link #contains(data.StockItem, data.DataBasket)}.</p>
  *
  * @author Steffen Zschaler
  * @version 2.0 19/08/1999
  * @since v2.0
  */
public abstract class StoringStockFilter extends AbstractStockFilter implements StoringStock {

  /**
    * Create a new StoringStockFilter.
    *
    * @param ssSource the source Stock.
    */
  public StoringStockFilter (StoringStock ssSource) {
    super (ssSource);
  }

  /**
    * Get all StockItems for a 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 Iterator m_iIterator = m_stSource.get (sKey, db, fForEdit);
      protected Object m_oCurrent;
      protected Object m_oNext;

      public boolean hasNext() {
        return findNext (false);
      }

      public Object next() {
        if (!findNext (true)) {
          throw new NoSuchElementException();
        }

        return m_oCurrent;
      }

      public void remove() {
        if (m_oCurrent == null) {
          throw new IllegalStateException();
        }

        try {
          StoringStockFilter.this.remove ((StockItem) m_oCurrent, db);
        }
        catch (VetoException ve) {
          throw new UnsupportedOperationException();
        }
      }

      private boolean findNext (boolean fGet) {
        if (m_oNext != null) {
          if (fGet) {
            m_oCurrent = m_oNext;
            m_oNext = null;
          }

          return true;
        }

        while (m_iIterator.hasNext()) {
          StockItem si = (StockItem) m_iIterator.next();

          if (contains (si, db)) {
            if (fGet) {
              m_oCurrent = si;
              m_oNext = null;
            }
            else {
              m_oNext = si;
            }

            return true;
          }
        }

        return false;
      }
    }

    return new I();
  }

  /**
    * Count all StockItems for a given key that are contained in the filtered Stock.
    *
    * @override Never
    */
  public int countItems (String sKey, DataBasket db) {
    int nCount = 0;

    for (Iterator i = get (sKey, db, false); i.hasNext();) {
      nCount++;
      i.next();
    }

    return nCount;
  }

  /**
    * Filter condition: Check whether a given item is contained in the filtered Stock.
    *
    * @override Always
    *
    * @param si the StockItem to be checked.
    * @param db the DataBasket to be used to check visibility.
    *
    * @return true if the given item is to be contained in the filtered Stock.
    */
  public abstract boolean contains (StockItem si, DataBasket db);

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

    if (fResult) {
      for (Iterator i = st.iterator (db, false); i.hasNext();) {
        if (!contains ((StockItem) i.next(), db)) {
          return false;
        }
      }
    }

    return fResult;
  }
}