import java.util.Scanner;

/**
 * A program to demonstrate a simple hash table.
 *
 * @author Mark Young (A00000000)
 */
public class OpenLinear {

    public static int arraySize = 23;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        printIntroduction();
        pause();

        String[] mine = getWordList();
        printWordList(mine);
        pause();

        // create and fill the hash table
        String[] openHashTable = new String[arraySize];
        for (String me : mine) {
            add(me, openHashTable);
        }
        System.out.println();
        pause();

        // print the hash table
        printHashTable(openHashTable);
        pause();
        
        /* DELETE THIS LINE
        // test contains method
        for (String test : new String[]{"me", "Mark", "yo", "swollen head"}) {
            System.out.println("contains(" + test + ") is "
                    + contains(test, openHashTable));
        }
        pause();

        delete("me", openHashTable);
        printHashTable(openHashTable);
        pause();

        for (String test : new String[]{"me", "Mark", "yo", "swollen head"}) {
            System.out.println("contains(" + test + ") is "
                    + contains(test, openHashTable));
        }
        pause();

        /* To avoid error when line above deleted!
        */
    }

    /**
     * Print out a hash table, one line per entry, with empty cells included.
     *
     * @param openHashTable the table to print.
     */
    private static void printHashTable(String[] openHashTable) {
        System.out.printf("%4s %-15s%n", "i", "hashTable[i]");
        System.out.printf("%4s %-15s%n", "-", "------------");
        for (int i = 0; i < arraySize; ++i) {
            System.out.printf("%4d %s%n",
                    i, quoteValue(openHashTable[i]));
        }
    }

    /**
     * Return the word in single quotes, or the empty string if there is no
     * word.
     *
     * @param word the word to quote
     * @return the word in single quotes, or "" if word == null
     */
    private static String quoteValue(String word) {
        if (word == null) {
            return "";
        } else {
            return "'" + word + "'";
        }
    }

    /**
     * Add the given word to the given hash table. Uses linear probe collision
     * handling. This is VERY BAD. Try looking up quadratic probe and rehashing.
     * Those are better alternatives.
     *
     * @param me the word to add.
     * @param openHashTable the table to add the word to.
     */
    private static void add(String me, String[] openHashTable) {
        System.out.println("Adding '" + me + "'");
        int location = Math.abs(me.hashCode() % arraySize);
        while (openHashTable[location] != null) {
            System.out.println("...location " + location + " is in use...");
            if (openHashTable[location].equals(me)) {
                System.out.println("Duplicate entry not added");
                return;
            }

            // linear probe -- BAD open addressing rule!
            location += 3;
            location %= arraySize;
        }
        openHashTable[location] = me;
        System.out.println("...'" + me + "' added at location " + location);
    }

    /**
     * Print a list of words together with their hash codes.
     *
     * @param mine the list to print.
     */
    private static void printWordList(String[] mine) {
        System.out.printf("%15s %15s%n", "String", "Hash Code");
        System.out.printf("%15s %15s%n", "------", "---------");
        for (String me : mine) {
            System.out.printf("%15s %,15d%n", me, me.hashCode());
        }
    }

    /**
     * Create a list of words.
     *
     * @return a list of perfectly cromulent words and phrases.
     */
    private static String[] getWordList() {
        // make the list of words to add to the hash table
        String[] mine = new String[]{
            "me", "myself", "I", "mine", "Mark", "Young", "ego", "swollen head"
        };
        return mine;
    }

    /**
     * Introduce this program.
     */
    private static void printIntroduction() {
        System.out.println("This program creates a hash table. "
                + "It uses a VERY BAD open-addressing rule.");
    }

    /**
     * The one and only Scanner on System.in.
     */
    private static final Scanner KBD = new Scanner(System.in);

    /**
     * Wait for the user to press the enter key. Includes a prompt and before-
     * after blank lines.
     */
    private static void pause() {
        System.out.println();
        System.out.print("Press enter...");
        KBD.nextLine();
        System.out.println();
    }

}
