/**
  *
  * Programmieraufgabe P-20 (Zahlenleser.java)
  *
  * @author Leonhard Fellermayr
  * @version 1.0
  *
  */

/** Benoetigte Packages zum Einlesen von der Konsole und fuer Handling von IO Exceptions */

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

/** Implementierung der Klasse Zahlenleser. */

public class Zahlenleser
{

    /******************************************************************************************
      * @param INTEGER Sprechende Konstante, signalisiert liesWert(), dass int gelesen wird
      * @param DOUBLE Sprechende Konstante, signalisiert liesWert(), dass double gelesen wird
      * @param NO_INPUT_VALUE liesXXX() gibt diesen Wert zurueck, falls nichts eingegeben wird
      * @param zahlGelesen Gibt an, ob eine Zahl erfolgreich von der Konsole gelesen wurde
      * @param console Instanz des BufferedReader fuer console input
      *
      **/

    private final int INTEGER        =  1;
    private final int DOUBLE         =  2;
    private final int NO_INPUT_VALUE = -1;

    private boolean        zahlGelesen;
    private BufferedReader console;

    /******************************************************************************************
      * liesInt (String) : Liest mittels liesWert () einen int-Wert von der Konsole und
      * gibt diesen als int zurueck.
      *
      * @param msg Die auf der Konsole auszugebende Eingabeaufforderung
      * @return Der eingelesene Wert (int)
      * @throws IO-Exception
      *
      **/

    public int liesInt (String msg) throws IOException
    {
	return Integer.parseInt (liesWert (msg, INTEGER));
    }

    /******************************************************************************************
      * liesDouble (String) : Liest mittels liesWert () einen double-Wert von der Konsole und
      * gibt diesen als double zurueck.
      *
      * @param msg Die auf der Konsole auszugebende Eingabeaufforderung
      * @return Der eingelesene Wert (double)
      * @throws IO-Exception
      *
      **/

    public double liesDouble (String msg) throws IOException
    {
	return Double.parseDouble (liesWert (msg, DOUBLE));
    }

    /******************************************************************************************
      * zahlGelesen () : Gibt den Wert der booleschen Instanzvariable zahlGelesen zurueck.
      * Diese gibt an, ob erfolgreich eine Zahl (int|double) gelesen werden konnte oder nicht.
      *
      * @return Wert der Instanzvariable zahlGelesen
      *
      **/

    public boolean zahlGelesen ()
    {
	return (zahlGelesen);
    }


    /******************************************************************************************
      * Zahlenleser () : Konstruktor der Klasse.
      *
      * Instantiiert einen BufferedReader zum Einlesen von der Konsole.
      *
      **/

    public Zahlenleser ()
    {
	console = new BufferedReader (new InputStreamReader (System.in));
    }

    /******************************************************************************************
      * liesWert (String, int) : Liest Eingabe von der Konsole und versucht, diese je nach type
      * mittels parseInt() bzw. parseDouble() zu parsen. Im Fehlerfall (Exception) wird der
      * Einlesevorgang unter erneuter Ausgabe der Eingabeaufforderung msg wiederholt.
      *
      * Mittels <Return> oder Strg-D kann eine Eingabe verweigert werden. liesWert () gibt
      * dann NO_INPUT_VALUE zurueck.
      *
      * Bei erfolgreichem Parsing erhaelt zahlGelesen den Wert true.
      *
      * Durch diese "Universal"-Methode laesst sich eine Duplizierung der try..catch-
      * Bloecke fuer liesDouble() und liesInt() vermeiden.
      *
      * @param msg Die auf der Konsole auszugebende Eingabeaufforderung
      * @param type Gibt an, ob ein int- oder ein double-Wert erwartet wird
      * @return Der eingelesene Wert (String)
      * @throws IO-Exception
      *
      **/

    private String liesWert (String msg, int type) throws IOException
    {

	/** @param eingabe Vom Benutzer eingegebene Zeichenkette */

	String eingabe;

	/** Zunaechst wurde noch keine Zahl erfolgreich gelesen und geparsed -> zahlGelesen := false */

	zahlGelesen = false;

	/** Eingabeaufforderung ausgeben */

	System.out.print (msg);

	/** Die while()-Schleife wird bei "Leereingabe" und bei korrekter Eingabe jeweils via
	  * return()-Statement verlassen. Andernfalls erfolgt Wiederholung. */

	while (true)
	{
	    try
	    {
		/** Zeichenkette einlesen */
		eingabe = console.readLine ();

		/** Strg-D oder <Return> gedrueckt -> NO_INPUT_VALUE zurueckgeben */

		if ( eingabe == null || eingabe.equals ("") )
			return ("" + NO_INPUT_VALUE);

		/** Andernfalls erfolgt abhaengig von type ein (int|double)-Parsing-Versuch */

		else
		{
			switch (type)
			{
				case INTEGER : Integer.parseInt (eingabe);   break;
				case DOUBLE  : Double.parseDouble (eingabe); break;
			}

			/** Falls hier angelangt, wurde keine exception geworfen -> zahlGelesen := true */
			zahlGelesen = true;

			/** Rueckgabe des Werts an Aufrufer */
			return (eingabe);
		}

	    } // try

	    /** Im Fehlerfall soll eine Beschreibung der geworfenen exception ausgegeben werden.
	      * Ausserdem soll die Eingabeaufforderung msg erneut erscheinen. */

	    catch (NumberFormatException myException)
	    {
		System.out.println ("EXCEPTION: " + myException);
		System.out.print (msg);
	    } // catch

	} // while

    } // liesWert ()

} // Klasse Zahlenleser
