package data;

import util.*;

import java.util.*;

/**
  * A StockFromValueCreator for {@link CountingStock CountingStocks}.
  *
  * <p>This StockFromValueCreator assumes a potentially infinite source of available items and adds exactly
  * as many items of each type (i.e. corresponding CatalogItem) as needed to fulfil the requirement.</p>
  *
  * @author Steffen Zschaler
  * @version 2.0 18/08/1999
  * @since v2.0
  */
public class DefaultCountingStockFromValueCreator extends Object implements StockFromValueCreator {

  /**
    * The CatalogItemValue used to determine the CatalogItems' values.
    */
  protected CatalogItemValue m_civEvaluator;

  /**
    * Create a new DefaultCountingStockFromValueCreator.
    *
    * @param civ the CatalogItemValue used to determine the CatalogItems' values.
    */
  public DefaultCountingStockFromValueCreator (CatalogItemValue civ) {
    super();

    m_civEvaluator = civ;
  }

  /**
    * This StockFromValueCreator assumes a potentially infinite source of available items and adds exactly
    * as many items of each type (i.e. corresponding CatalogItem) as needed to fulfil the requirement.
    *
    * @override Never
    */
  public Value fillStock (Stock st, Value v, DataBasket db) {
    CountingStock cs = (CountingStock) st;
    Catalog c = st.getCatalog (db);

    List lCI = new LinkedList();                    // Get items from Catalog
    for (Iterator i = c.iterator (db, false); i.hasNext();) {
      lCI.add (i.next());
    }

    if (lCI.size() == 0) {
      return v;
    }

    Collections.sort (lCI,                          // Sort the items, greates first
                      invertedCIValueOrder (m_civEvaluator));

    // building the Stock
    for (Iterator i = lCI.iterator(); i.hasNext();) {
      CatalogItem ciCurrent = (CatalogItem) i.next();
      Value vItemValue = m_civEvaluator.getValue (ciCurrent);
      Value vCurrent = (Value) vItemValue.clone();

      int nCount = 1;
      while (vCurrent.compareTo (v) < 0) {
        vCurrent.addAccumulating (vItemValue);
        nCount++;
      }

      if (vCurrent.compareTo (v) > 0) {
        nCount--;  // correct, if we went too far.
        vCurrent.subtractAccumulating (vItemValue);
      }

      if (nCount > 0) {
        cs.add (ciCurrent.getName(), nCount, db);
        v.subtractAccumulating (vCurrent);
      }
    }

    return v;
  }

  /**
    * Helper method that creates a Comparator that orders CatalogItems, highest value first.
    */
  public static final Comparator invertedCIValueOrder (final CatalogItemValue civ) {
    return new SerializableComparator() {
      public int compare (Object o1, Object o2) {
        return civ.getValue ((CatalogItem) o2).compareTo (civ.getValue ((CatalogItem) o1));
      }
    };
  }
}