// -------------------------------------------------------------------
// Hashtable.java
//
// File Revision Date: 11/14/08
// -------------------------------------------------------------------

package lab10;

import java.awt.*;
import lab07.List;

/**
 * This class demonstrates the basic functions of a hash table.
 * It provides a subset of the methods of the standard Java class
 * java.util.Hashtable. This "home grown" version implements the
 * table as an array of singly linked lists, here represented by
 * the same linked-list class {@link List} that was
 * introduced in Lab 07.
 */
public class Hashtable {
    public static final int DEFAULT_ARRAY_LENGTH = 13;
    public static final int CELL_WIDTH = 50;
    public static final int CELL_HEIGHT = 25;
    
    private List [] array;
    private int itemCount;
    private int lastHashValue;
  
    /**
     * Creates an empty Hashtable object.
     */
    public Hashtable () {
        array = new List [DEFAULT_ARRAY_LENGTH];
        for (int n = 0; n < array.length; n++) {
            array[n] = new List();
            array[n].setRenderingStyle(List.LINKED_LIST_STYLE);
            array[n].setCellWidth(80);
            array[n].setVisibleIndex(false);
        }
        itemCount = 0;
        lastHashValue = -1;
    }
  
    /**
     * Inserts the specified (key,value) pair into the table. If a pair
     * containing this key is already in the table, its associated value
     * is replaced by the new value parameter, and the old value is
     * returned. If no pair containing this key is already in the table,
     * the pair is inserted and the method returns null.
     * @return Value replaced by this insertion, or null if 
     * the specified key was not already in the table.
     */
    public Object put (Object key, Object value) {

	// The following step selects the List in the array
        // that will be used to insert the new (key,value) pair.
	// In other words, insert into array[lastHashValue]...
 
        lastHashValue = key.hashCode () % array.length;

        // THE REST IS UP TO YOU...


    }
  
    /**
     * Searches the table for the (key,value) pair whose key matches
     * the input parameter. If a match is found, a reference to the
     * associated value is returned. If no pair with this key is found
     * in the table, the method returns null.
     * @return Value associated with the specified key, or null
     * if no matching key was found.
     */
    public Object get (Object key) {

        lastHashValue = key.hashCode () % array.length;

	// THE REST IS UP TO YOU...

        return null;	// STUB -- REPLACE THIS LINE
    }
  
    /**
     * Searches the table for the (key,value) pair whose key matches
     * the input parameter. If a match is found, the pair is removed
     * and a reference to the associated value is returned. If no pair
     * with this key is found in the table, the method returns null.
     * @return Value removed from the table, or null if not found.
     */
    public Object remove (Object key) {

        lastHashValue = key.hashCode () % array.length;

	// THE REST IS UP TO YOU...

	return null;	// STUB
    }

    /**
     * Removes all (key, value) pairs from the table, restoring it
     * to its initial state.
     */
    public void clear () {
        for (int i = 0; i < array.length; i++) {
            array[i].removeAll();
        }
        itemCount = 0;
        lastHashValue = -1;
    }
  
    /**
     * Indicates whether the table is currently empty. 
     * @return <B>true</B> if the table is currently empty,
     * otherwise <B>false</B>.
     */
    public boolean isEmpty () {
        return (itemCount == 0);
    }

    /**
     * Returns the current number of (key,value) pairs stored in the table.
     * return Number of (key, value) pairs.
     */
    public int size () {
        return itemCount;
    }
  	
    /**
     * Renders the Hashtable in a graphics display window. This version
     * of the method centers the table vertically in the display area.
     * @param g Graphics context of the display window.
     * @param winSize Dimensions (width, height) of the display area.
     */
    public void render (Graphics g, Dimension winSize) {
        render (g, winSize, new Point (50, winSize.height / 2));
    }

    public void render (Graphics g, Dimension winSize, Point startPoint) {
        int arrayCellHeight = CELL_HEIGHT + 10;
        int arrayCellWidth = 16;
        int arrayHeight = arrayCellHeight * array.length;
    
        g.drawOval (startPoint.x - 5, startPoint.y - 5, 10, 10);
        
        int xloc = startPoint.x + CELL_WIDTH;
        int yloc = startPoint.y + arrayHeight / 2 - arrayCellHeight;
    
        for (int n = 0; n < array.length; n++) {
            g.drawRect (xloc, yloc, arrayCellWidth, arrayCellHeight);
            Point pt = new Point (xloc + arrayCellWidth / 2,
                            yloc + arrayCellHeight / 2);
            array[n].render (g, winSize, pt);
            yloc -= arrayCellHeight;
        }

        if (!isEmpty ())
            drawHashArrow (g, Color.black, startPoint);
    }

    private void drawHashArrow (Graphics g, Color color, Point base) {
        int arrayCellHeight = CELL_HEIGHT + 10;
        int arrayHeight = arrayCellHeight * array.length;

        int x1 = base.x;
        int y1 = base.y;
    
        int x2 = x1 + CELL_WIDTH;
        int y2 = y1 + (arrayHeight - arrayCellHeight) / 2
            - lastHashValue * arrayCellHeight;
      
        g.setColor (color);
        g.drawLine (x1, y1, x2, y2);
        g.fillOval (x2-3,y2-3,6,6);
    }
}
