package finiteAutomata;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Scanner;
/**
 * Library of public static utility methods to support the classes
 * in the finiteAutomata package.
 * 
 * @author Barbara Wahl
 * @version Fall 2007 
 */

public class Util {
	
	/** 
	 * Scanner for reading keyboard input
	 */
	protected static Scanner scanner = new Scanner(System.in);
	
	// ** BINARY MATH METHODS **
	/**
	 * Returns the given power of 2. 
	 * @param n integer power of 2 to be calculated
	 * @return 2^n
	 */
	public static int twoPower(int n)
	{
		return Math.round((float) Math.pow(2,n));
	}
	
	/**
	 * Returns log-base-two of the given integer.
	 * @param n integer value whose log is to be calculated
	 * @return log2(n)
	 */
	public static double logTwo(int n)
	{
		return Math.log(n)/Math.log(2);
	}
	
	/**
	 * Returns the nearest integer to log-base-2 of the
	 * given integer.
	 * @param n integer value whose log is to be calculated
	 * @return log2(n) rounded to nearest integer
	 */
	public static int intLogTwo(int n)
	{
		double x = logTwo(n);
		return Math.round((float)x);
	}	
	
	// ** OUTPUT METHODS **	
	/**
	 * Prints "epsilon" if the given String is empty; otherwise, prints the
	 * given String. 
	 * @param inString String to be printed
	 * @pre inString is not null
	 */
	public static void printString(String inString)
	{
		if(inString.length() == 0)
			inString = "epsilon";
		System.out.print(inString);
	}
	
	// ** INPUT METHODS **
	/**
	 * Returns the next String read from keyboard input.
	 */
	public static String readString()
	// note: string inputs to be read by this method should not
	//       contain blank spaces
	{
		return scanner.next();
	}
	/**
	 * Repeatedly prompts user to enter TRUE or FALSE.
	 * @return true if user enters a string starting with 't', 'T',
	 * 'y', or 'Y'; false if user enters a string starting with
	 * 'f', 'F', 'n', or 'N'.
	 */
	public static boolean readBoolean()
	// note: string inputs to be read by this method should not
	//       contain blank spaces
	{
		String s;
		char c;
		while(true)
		{
			s = scanner.next();
			c = s.charAt(0);
			if(c == 't' || c == 'T' || c == 'y' || c == 'Y')
				return true;
			if(c == 'f' || c == 'F' || c == 'n' || c == 'N')
				return false;
			System.out.println("TRY AGAIN! Enter TRUE or FALSE: ");
		}
	}
	/**
	 * Reads the next String from keyboard input and decides if it
	 * is a "yes" answer.
	 * @return true iff user enters a string starting with 'y' or 'Y'
	 */
	public static boolean answerIsYes()
	{
		String inString = readString();
		char c = inString.charAt(0);
		return (c == 'Y' || c == 'y');
	}
	/**
	 * Reads the next String from keyboard input and parses it as a
	 * non-negative integer.
	 * @return the non-negative integer form of the String read from 
	 * keyboard input (if possible), otherwise -1
	 */
	public static int readNum()
	{
		String inString;
		inString = readString();
		return stringToInt(inString);
	}
	/**
	 * Returns the integer value of the given (short) string of digits.
	 * @param s the String of digits to be converted
	 * @return the integer equivalent of s
	 * @pre s is not too long (fewer than 10 chars will be okay)
	 */
	protected static int stringToInt(String s)
	// note:  a LONG string of digits will cause the program to crash!
	{
		int val = -1;
		Pattern p = Pattern.compile("[0-9]+"); // one or more digits
		Matcher m = p.matcher(s);
		if(m.matches())
			val = Integer.parseInt(s);
		return val;
	}
	
	// ** STRING METHODS **
	/**
	 * Returns true if the given string contains at least one whitespace
	 * character.
	 * @param inString the string to be examined
	 * @pre inString is not null
	 * @return true iff at least one character in inString is whitespace
	 */
	public static boolean hasWhiteSpace(String inString)
	{
		char c;
		for(int i=0; i<inString.length(); i++)
		{
			c = inString.charAt(i);
			if(Character.isWhitespace(c))
				return true;
		}
		return false;
	}
	/**
	 * Returns true if the given string contains at least one repeated
	 * character.
	 * @param inString the string to be examined
	 * @pre inString is not null
	 * @return true iff at least one character in inString is repeated
	 */
	public static boolean hasRepeat(String inString)
	{
		char c1,c2;
		for(int i=0; i<inString.length()-1; i++)
		// look at characters right of position i to 
		// see if there's a repeat
		{
			c1 = inString.charAt(i);
			for(int j=i+1; j<inString.length(); j++)
			{
				c2 = inString.charAt(j);
				if(c1==c2)
					return true;
			}
		}
		return false;
	}
	
	// ** TEST METHOD **
	public static void main(String args[])
	{
		// test twoPower
		for(int n=0; n<20; n++)
		{
			int i = twoPower(n);
			System.out.println("2^" + n + " = " + i);
		}
		
		// test logTwo
		for(int n=0; n<20; n++)
		{
			System.out.println("log_2 of " + n + " = " + logTwo(n));
		}
		
		// test intLogTwo
		for(int n=0; n<20; n++)
			System.out.println("intLogTwo(" + n + ") = " + intLogTwo(n));

		// test printString
		System.out.print("When we print \"\" with printString, get: ");
		printString("");
		System.out.print("\nWhen we print \"elephant\" with printString, get: ");
		printString("elephant");		
		
		// test readString
		System.out.print("\nEnter any word : ");
		String x = readString();
		System.out.println("According to readString, you entered: " + x);
		
		// test answerIsYes
		System.out.print("Enter any word starting with \'y\' or \'Y\' : ");
		boolean answer = answerIsYes();
		System.out.println("On reading your string, " +
			"answerIsYes returns: " + answer);
		
		System.out.print("Enter any word NOT starting with \'y\' or \'Y\' : ");
		answer = answerIsYes();
		System.out.println("On reading your word, " +
			"answerIsYes returns: " + answer);
				
		// test readNum
		System.out.print("Enter a short string of digits: ");
		int n = readNum();
		System.out.println("On reading your word, " +
			"readNum returns this int: " + n);
		System.out.print("Enter any word: ");
		n = readNum();
		System.out.println("On reading your word, " +
			"readNum returns this int: " + n);
		
		// test hasWhiteSpace
		System.out.println("Applying hasWhiteSpace to string \"big    gap\" ");
		System.out.println("Result = " + Util.hasWhiteSpace("big    gap"));
		System.out.println("Applying hasWhiteSpace to string \"noGap\" ");
		System.out.println("Result = " + Util.hasWhiteSpace("noGap"));
		
		// test hasRepeat
		System.out.println("Applying hasRepeat to string \"misstake\" ");
		System.out.println("Result = " + Util.hasRepeat("big    gap"));
		System.out.println("Applying hasRepeat to string \"mistake\" ");
		System.out.println("Result = " + Util.hasRepeat("noGap"));		
		
		System.out.println("Adios!");
	}

}