package org.jcon.util.minor;

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

/**
 * Provides a normal Vector with index and key access.
 * Useful when a Vector's elements must be located by an
 * index and a key, such as in an indexed list where each
 * item is associated with a key. Add more methods as needed.
 * <p>
 * We have chosen to use method names identical to Vector
 * rather than more beanlike ones, such as getCount() instead
 * of size(). This makes this class easier to use since it
 * more closely mimics Vector. 
 * <p>
 * Modified 10/1/98 by Mike Panetta, added useful methods
 *
 * @author Jack Harich
 */
public class KeyedVector implements Cloneable {

//---------- Private Fields ------------------------------
private Vector   rows = new Vector();

// Key = Object key, Object = Integer, rows index
private Hashtable keys = new Hashtable();

//---------- Properties ----------------------------------
public int size() {
    return rows.size();
}
public boolean isEmpty() {
    return rows.isEmpty();
}
//---------- Public Methods ------------------------------
/**
* Adds the element and key. Note the key is the second
* argument, unlike first in Hashtable. The key cannot
* be null since it must be unique.
*/
public void addElement(Object element, Object key) {
    rows.addElement(element);
    // Maintain parallel Hashtable keys
    Integer rowIndex = new Integer(rows.size() - 1);
    keys.put(key, rowIndex);
}
public Object getElementAt(int index) {
    return rows.elementAt(index);
}
/**
* Returns the Object for the key or null if not found.
*/
public Object getElementForKey(Object key) {
    Integer rowIndex = (Integer)keys.get(key);
    if (rowIndex == null) {
        return null; // Not found
        //throw new IllegalStateException("Key '" +
        //     key + "' not found.");
    } else {
        return rows.elementAt(rowIndex.intValue());
    }
}
public int getIndexForKey(Object key) {
    Integer rowIndex = (Integer)keys.get(key);
    if (rowIndex == null) {
        throw new IllegalArgumentException("Key '" +
             key + "' not found.");
    } else {
        return rowIndex.intValue();
    }
}
/**
* Returns an enumeration of the objects in the order in
* which they were added.
*/
public Enumeration elements() {
    return rows.elements();
}
/**
 * This method removes an element given the key, returning
 * the element removed or null if not found.
 */
public Object removeElement(Object key) {
    Integer rowIndex = (Integer)keys.get(key);
    if (rowIndex == null) {
        return null;
        //throw new IllegalStateException("Key '" +
        //    key + "' not found, cannot remove.");
    } else {
         rows.removeElementAt(rowIndex.intValue());
         return keys.remove(key);
    }
}
public void removeAll() {
    rows.removeAllElements();
    keys.clear();
}
/**
 * This method shallow clones the KeyedVector Object.
 */
public Object clone() {
    KeyedVector clone = new KeyedVector();
    clone.rows = (Vector)this.rows.clone();
    clone.keys = (Hashtable)this.keys.clone();
    return clone;
}
/**
 * This method returns a clone of the internal Vector.
 * This could be used to convert the KeyedVector to a Vector.
 * A clone is returned so that the internal keys to internel
 * vector index don't get
 * clobbered if the vector returned is modified.
 */
public Vector toVector() {
    return (Vector)rows.clone();
}
//---------- Private Methods -----------------------------
//--- Std
private static void print(String text) {
    System.out.println("KeyedVector" + text);
}

} // End class