package org.jcon.util.minor;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

/**
 * This class extends Hashtable and provides the additional
 * feature of ordered keys. Currently null values not
 * supported, may change.
 *
 * @author Jack Harich
 */
public class BetterHashtable extends Hashtable {

//---------- Private Fields ------------------------------
// Maintained in order added
private Vector orderedKeys = new Vector();

//---------- Superclass Overrides ------------------------
// Override all mutators to maintain orderedKeys
/**
 * This behaves identically to the Hashtable verion. We
 * override it to maintain additional state.
 */
public synchronized void clear() {
    super.clear();
    orderedKeys.removeAllElements();
}
/**
 * This behaves identically to the Hashtable verion. We
 * override it to provide additional state.
 */
public synchronized Object clone() {
    BetterHashtable newHash = (BetterHashtable)super.clone();
    newHash.orderedKeys = orderedKeys;
    return newHash;
}
/**
 * This behaves identically to the Hashtable verion. We
 * override it to maintain additional state.
 */
public synchronized Object put(Object key, Object value) {
    orderedKeys.addElement(key);
    return super.put(key, value);
}
/**
 * This behaves identically to the Hashtable verion. We
 * override it to maintain additional state.
 */
public synchronized Object remove(Object key) {
    orderedKeys.removeElement(key);
    return super.remove(key);
}
//---------- Public Methods ------------------------------
/**
 * Returns an Enumeration of the keys in the order
 * they were added.
 */
public synchronized Enumeration getOrderedKeys() {
    return orderedKeys.elements();
}
/**
* Returns a Vector of the Objects in the order added.
*/
public synchronized Vector getOrderedObjects() {
    Vector objects = new Vector();
    Enumeration keys = getOrderedKeys();
    while (keys.hasMoreElements()) {
        objects.addElement(get(keys.nextElement()));
    }
    return objects;
}
/**
* Inserts the keyed value before the relativeKey. If
* the relativeKey is null then it is inserted at the end.
* Throws an IllegalStateException if the relativeKey is
* not found.
*
* @return  the previous Object with that key or null if none.
*/
public synchronized Object insert(Object key, Object value,
                Object relativeKey) {
                
    if (relativeKey == null) {
        return put(key, value);                
        
    } else {
        int index = orderedKeys.indexOf(key);
        if (index < 0) throw new IllegalStateException(
            "Key '" + key + "' not found.");
               
        orderedKeys.insertElementAt(key, index);
        return super.put(key, value);
    }        
}
//---------- Private Methods -----------------------------
//--- Std
private static void print(String text) {
    System.out.println("BetterHashtable" + text);
}

} // End class
