import java.util.*;
import java.io.*;

/** Manage a set of Strings with associated weights.
 *  Methods to increment / decrement / set / get weight for a String,
 *  find String with greatest weight...
 *
 *  Inherited Hashtable methods we can use as-is:

 *  constructors (); or (int size); or (int size, float factor);

 *  void clear ();
 *  boolean contains (Value);
 *  boolean containsKey (Key);
 *  int size () -- number of Keys
 *  Enumeration keys ()
 * <IMG SRC="/cgi-bin/counter">
 *
 * @author Morris Hirsch
 */

public class HashWeight extends Hashtable {

/** If the key is already present,
 * increment the associated weight,
 * otherwise create a new entry.
 * Returns new or modified value.
 *
 * @arg key new or existing key.
 * @arg value new or incremental value. */

    public float incr (String key, float value) {

       if ((null == key)
	 || (0 == key.trim ().length ()))
	     return 0;

       Float old = (Float) super.get (key);

/* At first key appearance */

       if (null == old) {
	   old = new Float (value);
           super.put (key, old);
           return value;
       }

/* At later key appearance, */

       else {
	   Float next = new Float
	       (old.floatValue() + value);
           super.put (key, next);
           return next.floatValue();
       }
    }


/** If the key is already present,
 * decrement the associated weight,
 * return modified value,
 * otherwise return zero.
 *
 * @arg key existing key.
 * @arg value decremental value. */

    public float decr (String key, float value) {

       if ((null == key)
	 || (0 == key.trim ().length ()))
	     return 0;

       Float old = (Float) super.get (key);

/* At first key appearance return zero -- do not insert key */

       if (null == old)
           return 0;

/* At later key appearance,
 * decr weight and remove if it falls too low,
 * this should be settable... */

       else {
	   Float next = new Float
	       (old.floatValue() - value);

           if (value <= 0.01) {
	       remove (key);
	       return 0;
	   }

           super.put (key, next);
           return next.floatValue();
       }
    }

/** Returns current value.
 * @arg key existing key. */

    public float get (String key) {

       if ((null == key)
	 || (0 == key.trim ().length ()))
	     return 0;

       Float old = (Float) super.get (key);
       if (null != old)
	   return old.floatValue ();

       return 0;
    }

/** Remove a key,
 * do nothing if key is not present.
 * @arg key to remove. */

    public void remove (String key) {

       if ((null == key)
	 || (0 == key.trim ().length ()))
	     return;

        super.remove (key);
    }

    public String maxKey () {
	String kNames [] = getKeyStrings ();

	String maxName = kNames [0];
	float maxValue = get (maxName);

	int ii;
	for (ii = 0; ii < kNames.length; ii++) {
	    float temp = get (kNames [ii]);
	    if (maxValue < temp) {
		maxValue = temp;
		maxName = kNames [ii];
	    }
	}
	return maxName;
    }

/** Returns Key names as String [],
 *  an alternative to inherited Enumeration keys () method,
 *  possible because our Keys are Strings. */

    public String []getKeyStrings () {
	int ii = 0;
	String []mNames = new String [size ()];
	Enumeration mKeys = keys ();
	while (mKeys.hasMoreElements())
	      mNames[ii++] = (String)mKeys.nextElement();
	return mNames;
    }

/** Returns Key names as String [],
 *  sorted by their associated weights,
 *  greatest first */

    public String []getSortedKeyStrings () {
	int ii, jj;

/* get all the names */

	String []kNames = getKeyStrings ();

/* get all the associated weights */

	float []values = new float [size ()];
	for (ii = 0; ii < kNames.length; ii++)
	    values [ii] = get (kNames [ii]);

/* simple bubble sort by associated weights */

	for (ii = 0; ii < kNames.length; ii++) {
	    int maxJJ = ii;
	    float maxValue = get (kNames [maxJJ]);

	    for (jj = ii; jj < kNames.length; jj++) {
		float aValue = get (kNames [jj]);
		if (maxValue < aValue) {
		    maxValue = aValue;
		    maxJJ = jj;
		}
	    }

/* Swap [maxJJ] and [ii] */

	    String tempS = kNames [ii];
	    float tempf = values [ii];
	    values [ii] = values [maxJJ];
	    kNames [ii] = kNames [maxJJ];
	    values [ii] = tempf;
	    kNames [ii] = tempS;
	}

	return kNames;
    }
}
/* <IMG SRC="/cgi-bin/counter">*/
