import java.util.Scanner;

/** Clase de utileria para leer valores validos del teclado.
  *
  * Cuando se solicita a la clase java.lang.Scanner obtener un valor numerico
  * del teclado, y el usuario provee un texto o un numero no valido, Scanner
  * lanza una excepcion obligando al programador a atraparla, de lo contrario el
  * programa se caera.
  *
  * La clase Keyboard facilita la lectura de numeros del teclado de tal forma
  * que el manejo de excepciones es responsabilidad de Keyboard. El programador
  * que utilice los servicios de Keyboard puede tener certeza de que cada
  * metodo retorna un valor valido escrito del teclado. Por ejemplo, si se
  * solicita leer un entero de la forma
  *
  * <pre>
  *   short edad = Keyboard.getNextShort("Edad: ", 0, 130);
  * </pre>
  *
  * El metodo Keyboard.getNextShort() imprimira el texto "Edad: " en la
  * pantalla y luego solicitara que ingrese un short. Si el usuario ingresa
  * un texto, o un numero que excede la capacidad de un short, o un short
  * que esta fuera del rango [0, 130], volvera a hacer la pregunta; y asi
  * repetitivamente hasta que el usuario ingrese un short en el rango [0, 130].
  *
  * @author Jeisson Hidalgo-Cespedes <jeissonh@gmail.com>
  * @version 1.0 [20121004]
  */
public abstract class Keyboard
{
   /** Instancia del objeto Scanner que sera utilizado en cada lectura al
     * teclado entre los metodos de la clase.
     */
   private static Scanner teclado = new Scanner(System.in);


   // short

   /** Lee y retorna un entero corto del teclado en el rango [-32,768; 32,767]
     * Repite la lectura hasta que el usuario provea un entero corto valido.
     * No imprime ningun texto en la pantalla en cada lectura.
     * @return el ultimo entero corto valido ingresado por el usuario
     */
   public static short getNextShort()
   {
      return getNextShort("", Short.MIN_VALUE, Short.MAX_VALUE);
   }

   /** Lee y retorna un entero corto del teclado en el rango [-32,768; 32,767]
     * Repite la lectura hasta que el usuario provea un entero corto valido.
     * En cada lectura imprime el texto text en la pantalla para guiar al
     * usuario que debe ingresar un numero.
     *
     * @param text El texto indicador al usuario de que debe ingresar un short
     * @return el ultimo entero corto valido ingresado por el usuario
     */
   public static short getNextShort(String text)
   {
      return getNextShort(text, Short.MIN_VALUE, Short.MAX_VALUE);
   }

   /** Lee del teclado y retorna un entero corto de 16 bits (2 bytes) mayor que
     * min, es decir, en el rango [min, 32,767]
     * Repite la lectura hasta que el usuario provea un entero corto valido.
     * Imprime el texto text en la pantalla en cada lectura.
     *
     * @param text El texto indicador al usuario de que debe ingresar un short
     * @param min El minimo valor permitido ingresar al usuario
     * @return el ultimo entero corto valido ingresado por el usuario
     */
   public static short getNextShort(String text, short min)
   {
      return getNextShort(text, min, Short.MAX_VALUE);
   }

   /** Lee y retorna un entero corto del teclado en el rango [min, max]
     * Repite la lectura hasta que el usuario provea un entero corto valido
     * en el rango dado. En cada lectura imprime el texto text en la pantalla
     * para guiar al usuario que debe ingresar un numero.
     *
     * @param text El texto indicador al usuario de que debe ingresar un short
     * @param min El minimo valor permitido ingresar al usuario
     * @param max El maximo valor permitido ingresar al usuario
     * @return el ultimo entero corto valido ingresado por el usuario
     */
   public static short getNextShort(String text, short min, short max)
   {
      while ( true )
      {
         try
         {
            System.out.print(text);
            short resultado = teclado.nextShort();
            if ( resultado >= min && resultado <= max )
               return resultado;
         }
         catch(java.util.InputMismatchException e)
         {
            teclado.nextLine();
         }
      }
   }


   // int

   /** Lee y retorna un entero del teclado en el rango
     * [-2,147,483,648; 2,147,483,647]
     * Repite la lectura hasta que el usuario provea un entero valido.
     * No imprime ningun texto en la pantalla en cada lectura.
     * @return el ultimo entero valido ingresado por el usuario
     */
   public static int getNextInt()
   {
      return getNextInt("", Integer.MIN_VALUE, Integer.MAX_VALUE);
   }

   /** Lee y retorna un entero del teclado en el rango
     * [-2,147,483,648; 2,147,483,647]
     * Repite la lectura hasta que el usuario provea un entero valido.
     * En cada lectura imprime el texto text en la pantalla para guiar al
     * usuario que debe ingresar un numero.
     *
     * @param text El texto indicador al usuario de que debe ingresar un int
     * @return el ultimo entero valido ingresado por el usuario
     */
   public static int getNextInt(String text)
   {
      return getNextInt(text, Integer.MIN_VALUE, Integer.MAX_VALUE);
   }

   /** Lee del teclado y retorna un entero de 32 bits (4 bytes) mayor que
     * min, es decir, en el rango [min, 2,147,483,647]
     * Repite la lectura hasta que el usuario provea un entero valido.
     * Imprime el texto text en la pantalla en cada lectura.
     *
     * @param text El texto indicador al usuario de que debe ingresar un int
     * @param min El minimo valor permitido ingresar al usuario
     * @return el ultimo entero valido ingresado por el usuario
     */
   public static int getNextInt(String text, int min)
   {
      return getNextInt(text, min, Integer.MAX_VALUE);
   }

   /** Lee y retorna un entero del teclado en el rango [min, max]
     * Repite la lectura hasta que el usuario provea un entero valido
     * en el rango dado. En cada lectura imprime el texto text en la pantalla
     * para guiar al usuario que debe ingresar un numero.
     *
     * @param text El texto indicador al usuario de que debe ingresar un int
     * @param min El minimo valor permitido ingresar al usuario
     * @param max El maximo valor permitido ingresar al usuario
     * @return el ultimo entero valido ingresado por el usuario
     */
   public static int getNextInt(String text, int min, int max)
   {
      while ( true )
      {
         try
         {
            System.out.print(text);
            int resultado = teclado.nextInt();
            if ( resultado >= min && resultado <= max )
               return resultado;
         }
         catch(java.util.InputMismatchException e)
         {
            teclado.nextLine();
         }
      }
   }


   // long

   /** Lee y retorna un entero largo de 64 bit (8 bytes) del teclado en el rango
     * [-9,223,372,036,854,775,808, 9,223,372,036,854,775,807]
     * Repite la lectura hasta que el usuario provea un entero largo valido.
     * No imprime ningun texto en la pantalla en cada lectura.
     * @return el ultimo entero largo valido ingresado por el usuario
     */
   public static long getNextLong()
   {
      return getNextLong("", Long.MIN_VALUE, Long.MAX_VALUE);
   }

   /** Lee y retorna un entero largo de 64 bit (8 bytes) del teclado en el rango
     * [-9,223,372,036,854,775,808, 9,223,372,036,854,775,807]
     * Repite la lectura hasta que el usuario provea un entero largo valido.
     * Imprime el texto text en la pantalla en cada lectura.
     *
     * @param text El texto indicador al usuario de que debe ingresar un long
     * @return el ultimo entero largo valido ingresado por el usuario
     */
   public static long getNextLong(String text)
   {
      return getNextLong(text, Long.MIN_VALUE, Long.MAX_VALUE);
   }

   /** Lee del teclado y retorna un entero largo de 64 bit (8 bytes) mayor que
     * min, es decir, en el rango [min, 9,223,372,036,854,775,807]
     * Repite la lectura hasta que el usuario provea un entero largo valido.
     * Imprime el texto text en la pantalla en cada lectura.
     *
     * @param text El texto indicador al usuario de que debe ingresar un long
     * @param min El minimo valor permitido ingresar al usuario
     * @return el ultimo entero largo valido ingresado por el usuario
     */
   public static long getNextLong(String text, long min)
   {
      return getNextLong(text, min, Long.MAX_VALUE);
   }

   /** Lee y retorna un entero largo de 64 bit (8 bytes) del teclado en el rango
     * [min, max]. Repite la lectura hasta que el usuario provea un entero largo
     * en dicho rango. En cada lectura imprime el texto text en la pantalla para
     * guiar al usuario que debe ingresar un numero.
     *
     * @param text El texto indicador al usuario de que debe ingresar un long
     * @param min El minimo valor permitido ingresar al usuario
     * @param max El maximo valor permitido ingresar al usuario
     * @return el ultimo entero largo valido ingresado por el usuario
     */
   public static long getNextLong(String text, long min, long max)
   {
      while ( true )
      {
         try
         {
            System.out.print(text);
            long resultado = teclado.nextLong();
            if ( resultado >= min && resultado <= max )
               return resultado;
         }
         catch(java.util.InputMismatchException e)
         {
            teclado.nextLine();
         }
      }
   }


   // double

   /** Lee y retorna un real del teclado
     * Repite la lectura hasta que el usuario provea un real valido.
     * No imprime ningun texto en la pantalla en cada lectura.
     * @return el ultimo real valido ingresado por el usuario
     */
   public static double getNextDouble()
   {
      return getNextDouble("", Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
   }

   /** Lee y retorna un real del teclado
     * Repite la lectura hasta que el usuario provea un real valido.
     * En cada lectura imprime el texto text en la pantalla para guiar al
     * usuario que debe ingresar un numero.
     *
     * @param text El texto indicador al usuario de que debe ingresar un double
     * @return el ultimo real valido ingresado por el usuario
     */
   public static double getNextDouble(String text)
   {
      return getNextDouble(text, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
   }

   /** Lee del teclado y retorna un real mayor a min
     * Repite la lectura hasta que el usuario provea un real valido.
     * Imprime el texto text en la pantalla en cada lectura.
     *
     * @param text El texto indicador al usuario de que debe ingresar un double
     * @param min El minimo valor permitido ingresar al usuario
     * @return el ultimo real valido ingresado por el usuario
     */
   public static double getNextDouble(String text, double min)
   {
      return getNextDouble(text, min, Double.POSITIVE_INFINITY);
   }

   /** Lee y retorna un real del teclado en el rango [min, max]
     * Repite la lectura hasta que el usuario provea un real valido
     * en el rango dado. En cada lectura imprime el texto text en la pantalla
     * para guiar al usuario que debe ingresar un numero.
     *
     * @param text El texto indicador al usuario de que debe ingresar un double
     * @param min El minimo valor permitido ingresar al usuario
     * @param max El maximo valor permitido ingresar al usuario
     * @return el ultimo real valido ingresado por el usuario
     */
   public static double getNextDouble(String text, double min, double max)
   {
      while ( true )
      {
         try
         {
            System.out.print(text);
            double resultado = teclado.nextDouble();
            if ( resultado >= min && resultado <= max )
               return resultado;
         }
         catch(java.util.InputMismatchException e)
         {
            teclado.nextLine();
         }
      }
   }

   /** Lee y retorna un caracter. Repite la lectura hasta que el usuario provea
     * caracter que se encuentre en la cadena validChars. En cada lectura imprime el
     * texto text en la pantalla para guiar al usuario que debe ingresar el caracter.
     *
     * @param text El texto indicador al usuario de que debe ingresar un caracter
     * @param validChars Una cadena con los caracteres aceptables como respuesta
     * @return el ultimo caracter valido ingresado por el usuario
     */
   public static char getNextChar(String text, String validChars)
   {
      while ( true )
      {
         System.out.print(text);
         char result = teclado.next().charAt(0);
         if ( validChars.indexOf(result) >= 0 )
            return result;
      }
   }

   public static String getNextWord()
   {
	   return teclado.next();
   }

   public static String getNextWord(String text)
   {
       System.out.print(text);
	   return teclado.next();
   }

   public static String getNextLine()
   {
	   return teclado.nextLine();
   }
}
