// WordTypeCount.java
// Program counts the number of occurrences of each word in a string
package chapter36;

import java.util.StringTokenizer;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
import java.util.Scanner;

public class WordTypeCount
{
    private Map< String, Integer > map;
    private Scanner scanner;

    public WordTypeCount()
    {
        // Create an empty HashMap with a default capacity 16
        // The keys are of type String and the values are of type Integer
        map = new HashMap< String, Integer >(); // create HashMap
        scanner = new Scanner( System.in ); // create scanner
        createMap(); // create map based on user input
        displayMap(); // display map content
    } // end WordTypeCount constructor

    // create map from user input
    private void createMap()
    {
        System.out.println( "Enter a string:" ); // prompt for user input
        String input = scanner.nextLine();

        // Create a StringTokenizer to break the input string argument into its component individual words
        StringTokenizer tokenizer = new StringTokenizer( input );

        // processing input text
        // Use StringTokenizer method hasMoreTokens to determine whether there are more tokens in the string
        while ( tokenizer.hasMoreTokens() ) // while more input
        {
            // Use StringTokenizer method nextToken to obtain the next token
            String word = tokenizer.nextToken().toLowerCase(); // get word

            // Map method containsKey determines whether the key specified as an argument is in the hash table
            if ( map.containsKey( word ) ) // is word in map
            {
                // Use method get to obtain the key’s associated value in the map
                int count = map.get( word ); // get current count
                // Increment the value and use method put to replace the key’s associated value
                map.put( word, count + 1 );  // increment count
            } // end if
            else
                // Create a new entry in the map, with the word as the key and
                // an Integer object containing 1 as the value
                map.put( word, 1 ); // add new word with a count of 1 to map
        } // end while
    } // end method createMap

    // display map content
    private void displayMap()
    {
        // Use HashMap method keySet to obtain a set of the keys
        Set< String > keys = map.keySet(); // get keys

        // sort keys
        TreeSet< String > sortedKeys = new TreeSet< String >( keys );

        System.out.println( "Map contains:\nKey\t\tValue" );

        // generate output for each key in map
        for ( String key : sortedKeys )
            // Access each key and its value in the map
            System.out.printf( "%-10s%10s\n", key, map.get( key ) );

        // Call Map method size to get the number of key-value pairs in the Map
        // Call Map method isEmpty to determine whether the Map is empty
        System.out.printf(
                "\nsize:%d\nisEmpty:%b\n", map.size(), map.isEmpty() );
    } // end method displayMap

    public static void main( String args[] )
    {
        new WordTypeCount();
    } // end main
} // end class WordTypeCount
