package yi.ds.hash;

import java.util.*;
/**
 * ObjectsPredicted represents the objects predicted (or recognized) in a
 * testing case (eg. image).  Each predicted object has a corresponding score
 * with it.
 */

public class DoubleScoreHashMap extends HashMap implements Comparator{
  public DoubleScoreHashMap() {
    super();
  }

  public DoubleScoreHashMap(HashMap m) {
    for (Iterator i=m.keySet().iterator(); i.hasNext(); ) {
      Object key = i.next();
      put(key, m.get(key));
    }
  }

  /**
   * Add an object with new score.  Remember this will replace the score if
   * there is one for the object already
   * @param obj
   * @param score
   */
  public void putScore(Object obj, double score) {
    put(obj, new Double(score));
  }

  /**
   * Get the score of the specified object.  Return Double.NaN if that object
   * is not in the list.
   * @param obj
   * @return
   */
  public double getScore(Object obj) {
    if (!containsKey(obj)) {
      return Double.NaN;
    }
    return ((Double)get(obj)).doubleValue();
  }

  /**
   * Add the score to the saved one
   * @param obj
   * @param score
   * @return
   */
  public double addScore(Object obj, double score) {
    // if there is no score available yet
    if (!containsKey(obj)) {
      putScore(obj, score);
      return score;
    }
    double old = getScore(obj);
    putScore(obj, score + old);
    return getScore(obj);
  }

  /**
   * Add new scores into the score map.  The higher scores will be kept
   * @param new_scores
   */
  public void addScores(HashMap new_scores) {
    for (Iterator i=new_scores.keySet().iterator(); i.hasNext(); ) {
      Object obj = i.next();
      double score = ((Double)new_scores.get(obj)).doubleValue();
      addScore(obj, score);
    }
  }


  /**
   * Add score for the given object only when the new score is qualified or
   * there is no score yet.
   * @param obj
   * @param score
   * @param when_higher only change the old score when the new score is higher;
   * do opposite otherwise
   */
  public boolean putScoreOnCondition(Object obj, double score, boolean when_higher) {
    // if there is no score available yet
    if (!containsKey(obj)) {
      putScore(obj, score);
      return true;
    }

    double old = getScore(obj);
    if (when_higher && score > old) { // replace with higher score
      putScore(obj, score);
      return true;
    }

    if (!when_higher && score < old) { // replace with lower score
      putScore(obj, score);
      return true;
    }
    return false;
  }

  /**
   * Add score for the given object only when the new score is higher than the
   * old score or there is no score yet.
   * @param obj
   * @param score
   */
  public boolean putScoreWhenHigher(Object obj, double score) {
    return putScoreOnCondition(obj, score, true);
  }

  /**
   * Add new scores into the score map.  The higher scores will be kept
   * @param new_scores
   */
  public void putScoreWhenHigher(HashMap new_scores) {
    for (Iterator i=new_scores.keySet().iterator(); i.hasNext(); ) {
      Object obj = i.next();
      double score = ((Double)new_scores.get(obj)).doubleValue();
      putScoreOnCondition(obj, score, true);
    }
  }

  public ArrayList getObjectsByOrder() {
    ArrayList objects = new ArrayList(keySet());
    Collections.sort(objects, this);
    return objects;
  }

  public int compare(Object o1, Object o2) {
    double score1 = getScore(o1);
    double score2 = getScore(o2);
    if (score1 > score2) return 1;
    else if (score1 < score2) return -1;
    return 0;
  }

  public boolean equals(Object obj) {
    return super.equals(obj);
  }

  public String toString() {
    StringBuffer str = new StringBuffer();
    ArrayList list = getObjectsByOrder();
    for (int i=0; i<list.size(); i++) {
      Object obj = list.get(i);
      double score = getScore(obj);
      if (i != 0) str.append(',');
      str.append(obj.toString() + "[" + score + "]");
    }
    return str.toString();
  }

  public String toStringBykeyOrder() {
    StringBuffer str = new StringBuffer();
    ArrayList list = new ArrayList(keySet());
    Collections.sort(list);
    for (int i=0; i<list.size(); i++) {
      Object obj = list.get(i);
      if (i != 0) str.append('\t');
      str.append(obj.toString());
    }
    str.append("\n");
    for (int i=0; i<list.size(); i++) {
      Object obj = list.get(i);
      double score = getScore(obj);
      if (i != 0) str.append('\t');
      str.append(score);
    }
    return str.toString();
  }

  public String objsToString() {
    StringBuffer str = new StringBuffer();
    ArrayList list = getObjectsByOrder();
    for (int i=0; i<list.size(); i++) {
      Object obj = list.get(i);
      if (i != 0) str.append(", ");
      str.append(obj.toString());
    }
    return str.toString();
  }
}