import java.io.*;
import java.util.*;

/****************************************************************
 *This Static Class provides for simple console input.
 *The class is designed primarily for simple keyboard input of the form
 *one input value per line. If the user enters an improper input,
 *i.e., an input of the wrong type or a blank line, then the user
 *is prompted to reenter the input and is given a brief explanation
 *of what is required.
 *In addition, the class will maintain a buffer so multiple inputs can be
 *input on a single line.
 ***************************************************************/
public class ConsoleInput
{
  private static String inputBuffer;  // Stores an input line, which "feeds" the
                                      // other methods
  private static int bufferPos;       // Points to the next characher to read from
                                      // inputBuffer
  // Indicates the status of inputBuffer
  private static boolean bufferEmpty = true;

  // A test program
  public static void main(String[] args)
  {
    String inputWord;
    int intVal;
    double doubleVal;

    //*******
    System.out.println("Enter a string:");
    String inputString = readLine();
    System.out.println("You entered: " + inputString);
    System.out.println("Now enter another line:");
    inputWord = readLineWord();
    System.out.println("The first word of the line is: " + inputWord);
    System.out.println("Enter an integer:");
    intVal = readLineInt();
    System.out.println("You entered: " + intVal);
    System.out.println("Enter a decimal number:");
    doubleVal = readLineDouble();
    System.out.println("You entered: " + doubleVal);
    System.out.println("Enter a line, but only the first character will be read:");
    char chVal = readLineChar();
    System.out.println("The first character of the line is: " + chVal);
    System.out.println("Enter a boolean value:" );
    boolean boolVal = readLineBoolean();
    System.out.println("You entered: " + boolVal);

    System.out.println("Enter characters until 'z' is entered:");
    char charVal = readStreamChar();
    while( charVal != 'z') {
      System.out.println("You entered: " + charVal + " " + (int) charVal);
      charVal = readStreamChar();
    }
    //********
    //********
    System.out.println("Enter words until 'end' is entered:");
    inputWord = readStreamWord();
    while ( !inputWord.equalsIgnoreCase("end") ) {
      System.out.println("You entered: " + inputWord);
      inputWord = readStreamWord();
    }
    //*********

    //******************
    System.out.println("Enter numbers in a stream until -1 is entered:");
    intVal = readStreamInt();
    while ( intVal != -1 ) {
      System.out.println("You entered: " + intVal);
      intVal = readStreamInt();
    }
    //********

     //********
     System.out.println("Enter numbers in a stream until -1 is entered:");
     long longVal = readStreamLong();
     while ( longVal != -1 ) {
       System.out.println("You entered: " + longVal);
       longVal = readStreamLong();
    }
    //************

    //*************
    System.out.println("Enter decimal in a stream until -1 is entered:");
    doubleVal = readStreamDouble();
    while ( doubleVal != -1.0 ) {
      System.out.println("You entered: " + doubleVal);
      doubleVal = readStreamDouble();
    }
    //**************/

    System.out.println("Enter decimal in a stream until -1 is entered:");
    float floatVal = readStreamFloat();
    while ( floatVal != -1.0 ) {
      System.out.println("You entered: " + floatVal);
      floatVal = readStreamFloat();
    }


  }

    /***********************************************************
     *Precondition: None
     *Action:
     *Reads a line of text and returns that line as a String value.
     *The end of a line must be indicated either by a new line
     *character '\n' or by a carriage return '\r' followed by a
     *new line character '\n'.
     *Neither the '\n', nor the '\r' if present, are part of the
     *string returned. This method will read the rest of a line if the
     *line is already partially read and will empty inputBuffer
     *If inputBuffer is already empty, a new line will be read
     *Postcondition: The input line is returned as a String
     **********************************************************/
    public static String readLine()
    {
      String inputLine;
      if (bufferEmpty) {
        inputLine = setInputBuffer();
      }
      else {
        inputLine = inputBuffer.substring(bufferPos);
      }
      bufferEmpty = true;
      return inputLine;
    }

    private static String setInputBuffer()
    {
        char nextChar;
        String result = "";
        boolean done = false;

        while (!done)
        {
            nextChar = readChar();
            if (nextChar == '\n')
               done = true;
            else if (nextChar == '\r')
            {
                //Do nothing.
                //Next loop iteration will detect '\n'
            }
            else
               result = result + nextChar;
        }
        inputBuffer = result.substring(0);
        bufferEmpty = false;
        bufferPos = 0;
        return result;
    }


    /************************************************************
     *Precondition: Text has been entered on the input line
     *Actions:
     *Reads the first string of nonwhite characters on a line and
     *returns that string. The rest of the line is discarded. If
     *the line contains only white space, then the user is asked
     *to reenter the line.
     *Postcondition:
     *A String is returned consisting of the first word of the line
     ************************************************************/
    public static String readLineWord()
    {
        String inputString = null,
               result = null;
        boolean done = false;

        while(!done)
        {
            inputString = readLine();
            StringTokenizer wordSource =
                                new StringTokenizer(inputString);
            if (wordSource.hasMoreTokens())
            {
                result = wordSource.nextToken();
                done = true;
            }
            else
            {
                System.out.println(
                       "Your input is not correct. Your input must");
                System.out.println(
                    "contain at least one nonwhitespace character.");
                System.out.println(
                                 "Please, try again. Enter input:");
           }
       }

       return result;
   }


    /************************************************************
     *Precondition: The user has entered a number of type int on
     *a line by itself, except that there may be white space before
     *and/or after the number.
     *Action: Reads and returns the number as a value of type int.
     *The rest of the line is discarded. If the input is not
     *entered correctly, the user will be
     *asked to reenter the input. In particular, this applies to
     *incorrect number formats and blank lines.
     *Postcondition: The first word on the line is converted to an int and returned
     ************************************************************/
    public static int readLineInt()
    {
        String inputString = null;
        int number = -9999;//To keep the compiler happy.
                              //Designed to look like a garbage value.
        boolean done = false;

        while (! done)
        {
            try
            {
                inputString = readLine();
                inputString = inputString.trim();
                number = (Integer.valueOf(inputString).intValue());
                done = true;
            }
            catch (NumberFormatException e)
            {
                System.out.println(
                                "Your input number is not correct.");
                System.out.println("Your input number must be");
                System.out.println("a whole number written as an");
                System.out.println("ordinary numeral, such as 42");
                System.out.println("Please, try again.");
                System.out.println("Enter a whole number:");
            }
        }

        return number;
    }


    /************************************************************
     *Precondition: The user has entered a number of type long on
     *a line by itself, possibly with  white space
     *before and/or after the number.
     *Action: Reads and returns the number as a value of type
     *long. The rest of the line is discarded. If the input is not
     *entered correctly, the user will be asked
     *to reenter the input.
     *Postcondition: The first word on the line is converted to a long and returned
     ***********************************************************/
    public static long readLineLong()
    {
        String inputString = null;
        long number = -9999;//To keep the compiler happy.
                            //Designed to look like a garbage value.
        boolean done = false;

        while (! done)
        {
            try
            {
                inputString = readLine();
                inputString = inputString.trim();
                number = (Long.valueOf(inputString).longValue());
                done = true;
            }
            catch (NumberFormatException e)
            {
                System.out.println(
                                "Your input number is not correct.");
                System.out.println("Your input number must be");
                System.out.println("a whole number written as an");
                System.out.println("ordinary numeral, such as 42");
                System.out.println("Please, try again.");
                System.out.println("Enter a whole number:");
            }
       }

        return number;
    }


     /**********************************************************
     *Precondition: The user has entered a number of type double
     *on a line by itself, possibly with white space
     *before and/or after the number.
     *Action: Reads and returns the number as a value of type
     *double. The rest of the line is discarded. If the input is
     *not entered correctly, the user will be
     *asked to reenter the input.
     *Postcondition: The first word on the line is converted to a double and returned
     ***********************************************************/
    public static double readLineDouble()
    {
        String inputString = null;
        double number = -9999;//To keep the compiler happy.
                              //Designed to look like a garbage value.
        boolean done = false;

        while (! done)
        {
            try
            {
                inputString = readLine();
                inputString = inputString.trim();
                number = (Double.valueOf(inputString).doubleValue());
                done = true;
            }
            catch (NumberFormatException e)
            {
                System.out.println(
                                "Your input number is not correct.");
                System.out.println("Your input number must be");
                System.out.println("an ordinary number either with");
                System.out.println("or without a decimal point,");
                System.out.println("such as 42 or 9.99");
                System.out.println("Please, try again.");
                System.out.println("Enter a whole number:");
            }
        }

        return number;
    }


    /************************************************************
     *Precondition: The user has entered a number of type float
     *on a line by itself, possibly with white space
     *before and/or after the number.
     *Action: Reads and returns the number as a value of type
     *float. The rest of the line is discarded. If the input is
     *not entered correctly, then in most cases, the user will
     *be asked to reenter the input.
     *Postcondition: The first word on the line is converted to a float and returned
     ************************************************************/
    public static float readLineFloat()
    {
        String inputString = null;
        float number = -9999;//To keep the compiler happy.
                              //Designed to look like a garbage value.
        boolean done = false;

        while (! done)
        {
            try
            {
                inputString = readLine();
                inputString = inputString.trim();
                number = (Float.valueOf(inputString).floatValue());
                done = true;
            }
            catch (NumberFormatException e)
            {
                System.out.println(
                                "Your input number is not correct.");
                System.out.println("Your input number must be");
                System.out.println("an ordinary number either with");
                System.out.println("or without a decimal point,");
                System.out.println("such as 42 or 9.99");
                System.out.println("Please, try again.");
                System.out.println("Enter a whole number:");
            }
        }

        return number;
    }


    /************************************************************
     *Precondition: Text is entered on the input line.
     *Postcondition:
     *The first Nonwhite character on the line is rea and returned
     *The rest of the line is discarded. If the
     *line contains only white space, then the user is asked to
     *reenter the line.
     ************************************************************/
    public static char readLineChar()
    {
        boolean done = false;
        String inputString = null;
        char nonWhite = ' ';//To keep the compiler happy.

        while (! done)
        {
            inputString = readLine();
            inputString = inputString.trim();
            if (inputString.length() == 0)
            {
                System.out.println(
                                "Your input is not correct.");
                System.out.println("Your input must contain at");
                System.out.println(
                              "least one nonwhitespace character.");
                System.out.println("Please, try again.");
                System.out.println("Enter input:");
            }
            else
            {
                nonWhite = (inputString.charAt(0));
                done = true;
            }
        }

        return nonWhite;
    }


    /***********************************************************
     *Precondition: a boolean literal is entered on a line, possibly
     *surrounded by white space.
     *Postcondition
     *If the input word is "true" or "t", then true is returned.
     *If the input word is "false" or "f", then false is returned.
     *Uppercase and lowercase letters are considered equal. If the
     *user enters anything else (e.g. multiple words or different
     *words), then, the user is asked to reenter the input. The rest
     *of the line is discarded
     ***********************************************************/
    public static boolean readLineBoolean()
    {
        boolean done = false;
        String inputString = null;
        boolean result = false;//To keep the compiler happy.

        while (! done)
        {
            inputString = readLine();
            inputString = inputString.trim();
            if (inputString.equalsIgnoreCase("true")
                   || inputString.equalsIgnoreCase("t"))
            {
                result = true;
                done = true;
            }
            else if (inputString.equalsIgnoreCase("false")
                        || inputString.equalsIgnoreCase("f"))
            {
                result = false;
                done = true;
            }
            else
            {
                System.out.println(
                                "Your input number is not correct.");
                System.out.println("Your input number must be");
                System.out.println("one of the following:");
                System.out.println("the word true,");
                System.out.println("the word false,");
                System.out.println("the letter T,");
                System.out.println("or the letter F.");
                System.out.println("You may use either uppercase");
                System.out.println("or lowercase letters.");
                System.out.println("Please, try again.");
                System.out.println("Enter input:");
            }
         }

        return result;
    }


    /************************************************************
     *Precondition: text is entered on the input line
     *Postcondition:
     *The next input character is read and returned. The
     *next read takes place at the position where this one left off.
     ***********************************************************/

    private static char readChar()
    {
        int charAsInt = -1; //To keep the compiler happy
        try
        {
            charAsInt = System.in.read();
        }
        catch(IOException e)
        {
            System.out.println(e.getMessage());
            System.out.println("Severe I/O error encountered in readChar()");
            //System.exit(0);
        }

        return (char)charAsInt;
    }

    /**************************************************
     * Precondition: Text is entered on the input line and returned
     * Postcondition:
     * The next character, white space or not is read from the inputBuffer
     * If inputBuffer is empty, a new line is read
     * If the next character is the end of inputBuffer, /n is returned
     * The next read takes place where this one leaves off
     **************************************************/
    public static char readStreamChar()
    {
      if (bufferEmpty) {
        setInputBuffer();
      }
      if (inputBuffer.length() == 0  || bufferPos >= inputBuffer.length() ) {
        bufferEmpty = true;
        return ('\n');
      }
      else {
        char ch = inputBuffer.charAt(bufferPos);
        bufferPos++;
        return ch;
      }
    }


    /***********************************************************
     *Precondition: Text has been input on the input line
     *Postcondition:
     *The next nonwhite input character is read and returned
     *The next read takes place immediately after
     *the character read.
     **********************************************************/
    public static char readNonwhiteChar()
    {
      char next;

      next =  readStreamChar();
      while (Character.isWhitespace(next))
          next =  readStreamChar();

      return next;
    }


    /*************************************************************
     *Precondition: An integer string has been entered on the input line.
     *Action: A word is read from the input line. Preceding white space
     *is ignored. If the string is not a valid integer, the user is prompted
     *to enter a valid integer. The next read takes place immediately after the
     *input.
     *Postcondition: The next word on the input line is converted to int and returned
     **************************************************************/
    public static int readStreamInt()
    {
        String inputString = null;
        inputString = readStreamWord();

        boolean done = false;
        int number = 0;   // To avoid compiler errors

        while (! done)
        {
            try
            {
                inputString = inputString.trim();
                number = (Integer.valueOf(inputString).intValue());
                done = true;
            }
            catch (NumberFormatException e)
            {
                System.out.println(
                                "Your input number is not correct.");
                System.out.println("Your input number must be");
                System.out.println("a whole number written as an");
                System.out.println("ordinary numeral, such as 42");
                System.out.println("Please, try again.");
                System.out.println("Enter a whole number:");
                inputString = readWord();
            }
       }
       return number;
    }

    /************************************************************
     *Precondition: The next input consists of a long value, possibly
     *preceded by white space
     *Action: Reads the first string of nonwhite characters and returns
     *the long value it represents.  The next read takes place immediately
     *after the input string. The rest of the line is not discarded and
     *the next input takes place where this one leaves off. If a conversion error occurs,
     *the user will be prompted to re-enter the number
     *Postcondition: The next word on the input line is converted to long and returned
     ************************************************************/
    public static long readStreamLong()
    {
        String inputString = null;
        inputString = readStreamWord();

        boolean done = false;
        long number = 0;   // To avoid compiler errors

        while (! done)
        {
            try
            {
                inputString = inputString.trim();
                number = (Long.valueOf(inputString).longValue());
                done = true;
            }
            catch (NumberFormatException e)
            {
                System.out.println("Your input, '" + inputString + "' is not correct.");
                System.out.print("Your input must be");
                System.out.println("a whole number, for example, 44");
                System.out.println("Please, try again. Enter a whole number:");
                inputString = readWord();
            }
       }
       return number;
    }


    /***********************************************************
     *Precondition: The next input consists of a double value,
     *possibly preceded by white space,
     *Postcondition: Reads the first string of nonwhitespace characters
     *and returns the double value it represents. Discards the
     *first whitespace character after the string read. The next
     *read takes place immediately after the discarded whitespace.
     *In particular, if the string read is at the end of a line,
     *the next reading will take place starting on the next line.
     *If the next word does not represent a double value,
     *the user is prompted until a valid double value is entered.
     *Postcondition: The next word on the input line is converted to double and returned.
     ************************************************************/
    public static double readStreamDouble()
    {
        String inputString = null;
        inputString = readStreamWord();

        //return (Double.valueOf(inputString).doubleValue());

        boolean done = false;
        double number = 0.0;   // To avoid compiler errors

        while (! done)
        {
            try
            {
                inputString = inputString.trim();
                number = (Double.valueOf(inputString).doubleValue());
                done = true;
            }
            catch (NumberFormatException e)
            {
                System.out.println("Your input, '" + inputString + "' is not correct.");
                System.out.print("Your input must be ");
                System.out.println("a decimal number, for example, 44.44");
                System.out.println("Please, try again. Enter a decimal number:");
                inputString = readWord();
            }
       }
       return number;
    }


    /***********************************************************
     *Precondition: The next input consists of a float value,
     *possibly preceded by white space
     *Action: Reads the first string of nonwhite characters and
     *returns the float value it represents. Discards the first
     *whitespace character after the string read. The next read
     *takes place immediately after the discarded whitespace.
     *In particular, if the string read is at the end of a line,
     *the next reading will take place starting on the next line.
     *If input word does not represent a float value,
     *the user is prompted until correct input is entered.
     *Postcondition: The next word on the input line is converted to float and returned.
     ************************************************************/
    public static float readStreamFloat()
    {
        String inputString = null;
        inputString = readStreamWord();
        //return (Float.valueOf(inputString).floatValue());
        boolean done = false;
        float number = 0.0f;   // To avoid compiler errors

        while (! done)
        {
            try
            {
                inputString = inputString.trim();
                number = (Float.valueOf(inputString).floatValue());
                done = true;
            }
            catch (NumberFormatException e)
            {
                System.out.println("Your input, '" + inputString + "' is not correct.");
                System.out.print("Your input must be ");
                System.out.println("a decimal number, for example, 44.44");
                System.out.println("Please, try again. Enter a decimal number:");
                inputString = readWord();
            }
        }
               return number;

    }


    /***********************************************************
     *Precondition: Input is entered on the input line
     *Postcondition:
     *The first string of nonwhite characters is read and returned
     *The next read takes place immediately after the string
     *If the string
     *read is at the end of a line, the next reading will take
     *place starting on the next line. Note, that if it receives
     *blank lines, it will wait until it gets a nonwhitespace
     *character.
     *Postcondition: The next word in the input stream is read
     ************************************************************/
    public static String readStreamWord()
    {
        String result = "";
        char next;

        next =  readStreamChar();
        while (Character.isWhitespace(next))
             next =  readStreamChar();

        while (!(Character.isWhitespace(next)))
        {
            result = result + next;
            next =  readStreamChar();
        }
        return result;
    }


    //The following was intentionally not used in the code for
    //other methods so that somebody reading the code could more
    //quickly see what was being used.
    /************************************************************
     *Reads the first byte in the input stream and returns that
     * byte as an int. The next read takes place where this one
     *left off. This read is the same as System.in.read(),
     except that it catches IOExceptions.
     ************************************************************/

    /*************
    private static int read()
    {
        int result = -1; //To keep the compiler happy
        try
        {
            result = System.in.read();
        }
        catch(IOException e)
        {
            System.out.println(e.getMessage());
            System.out.println("Fatal error. Ending Program.");
            System.exit(0);
        }
        return result;
    }
    **********************/


    /********************************
     *Precondition: Something is enteren o the input line
     *Postcondition: I wrod is read and preceding white space is ignored
     *The rest of the line is not discarded and the next read takes
     *psce where this one left off.
     ********************************/
    private static String readWord()
    {
        String result = "";
        char next;

        next =  readChar();
        while (Character.isWhitespace(next))
             next =  readChar();

        while (!(Character.isWhitespace(next)))
        {
            result = result + next;
            next =  readChar();
        }

        return result;
    }

}