/**
 *
 * Programmieraufgabe P-7 (Wechsler2.java)
 *
 * @author Leonhard Fellermayr
 * @version 1.1
 */

/** Implementierung der Klasse Wechsler2 */

public class Wechsler2 {

   /** ***** INSTANZ- und KLASSENVARIABLEN ***** */

   /**
     *  @param B_EURO Konstante - Das Flag weist die anzahl_XXX-Methoden an, mit EUROS zu rechnen.
     *  @param B_CENT Konstante - Das Flag weist die anzahl_XXX-Methoden an, mit CENTS zu rechnen.
     *
     *  @param EUROS Eingabegrš§e Euros
     *  @param CENTS Eingabegrš§e Cents
     *
     *  @param WERT_1 "magische Groesse" fuer den Faktor 1
     *  @param WERT_2 "magische Groesse" fuer den Faktor 2
     *  @param WERT_5 "magische Groesse" fuer den Faktor 5
     *
     *  @param ZEHN "magische Groesse" fuer den Faktor 10
     *  @param HUNDERT "magische Groesse" fuer den Faktor 100
     *
     *  @param AUSGABE_ANZ_STELLEN Anzahl der ausgegebenen Stellen fuer die Geldbetraege (wg. rechtsbuendiger Ausrichtung)
     *
     */

   private final static boolean B_EURO = true;
   private final static boolean B_CENT = false;

   private final static int WERT_1  = 1;
   private final static int WERT_2  = 2;
   private final static int WERT_5  = 5;

   private final static int ZEHN    = 10;
   private final static int HUNDERT = 100;

   /** benoetigt fuer rechtsbuendige Ausrichtung der Waehrungs-Werte in mySimpleNumberFormat.
     * Gibt die Anzahl der maximal zu erwartenden Ziffernstellen an. Da der groesste Schein
     * bei 500 liegt, reichen 3 Stellen. */

   private final static int AUSGABE_ANZ_STELLEN = 3;

   /** EUROS und CENTS kšnnten hier auch "final" deklariert werden, dann brŠuchten wir allerdings
       eine beschreibbare Kopie davon, um in cents_mod_100 ŸberschŸssige Cents umrechnen zu dŸrfen. */

   private static int     EUROS = 2124;
   private static int     CENTS = 3418;

   /** ***** METHODEN ***** */

   /**
     *  berechne_anzahl : Berechne die Anzahl der auszugebenden Scheine/MŸnzen von
     *  dem Ÿbergebenen Wert wert. Das Bool-Flag entscheidet dabei, ob EUROS oder CENTS
     *  behandelt werden.
     *
     *  @param euroOrCent Legt fest, ob mit Euro oder Cent gerechnet wird (relevant fuer die Wahl der Variablen)
     *  @param wert Gegenwert des aktuellen Geldscheins / MŸnze
     *  @return Anzahl der auszugebenden Scheine / MŸnzen
     *
     */

   public static int berechne_anzahl (boolean euroOrCent, int wert) {

		int anzahl;

		if (euroOrCent == B_CENT) {
			anzahl = CENTS / wert;
			CENTS -= anzahl * wert;
		}
		else {
			anzahl = EUROS / wert;
			EUROS -= anzahl * wert;
		}

		return (anzahl);

   } // berechne_anzahl ()

   /**
     *  ausgabe : Rufe berechne_anzahl auf und gib die errechnete
     * Anzahl Scheine/MŸnzen fuer den Wert wert formatiert aus.
     *
     *  @param euroOrCent Legt fest, ob mit Euro oder Cent gerechnet wird (relevant fuer die Konsolen-Ausgabe)
     *  @param wert Gegenwert des aktuellen Geldscheins / MŸnze
     *  @return void
     *
     */

   public static void ausgabe (boolean euroOrCent, int wert) {

	int anzahl = berechne_anzahl (euroOrCent, wert);

	/** Eine Ausgabe auf der Konsole soll nur erfolgen, falls Ÿberhaupt Geld von dieser "Sorte"
	  * ausbezahlt wird. */

	if (anzahl > 0) {

		System.out.print (anzahl + " mal " + mySimpleNumberFormat (wert));

		/** Geht es um Cent oder Euro? */

		if (euroOrCent == B_CENT) {
			System.out.print (" Cent");
			if (wert > 1) System.out.print ("s"); /* Plural */
			System.out.print ("\n");
		}
		else
			System.out.println (" Euro");

	} // endif

   } // ausgabe ()

   /**
     *  ausgabe_alle : Fuehre (abhaengig vom Parameter euroOrCent) die Ausgabe fuer alle Euro- oder Cent-Werte 
     *  durch. Der Parameter zehnerpotenz legt dabei fest, ab welcher Potenz von 10 die 1er, 2er und 5er
     *  multipliziert werden. Fuer zehnerpotenz=100 z. B. 500,200,100, dann 50,20,10, letztlich 5,2,1.
     *
     *  @param euroOrCent Legt fest, ob mit Euro oder Cent gerechnet wird
     *  @param zehnerpotenz Die maximale Zehnerpotenz, mit der die 5er, 2er und 1er multipliziert werden.
     *  @return void
     *
     */

   private static void ausgabe_alle (boolean euroOrCent, int zehnerpotenz) {

		for (int i = zehnerpotenz; i >= 1; i /= ZEHN) {
			ausgabe (euroOrCent, WERT_5 * i);
			ausgabe (euroOrCent, WERT_2 * i);
			ausgabe (euroOrCent, WERT_1 * i);
		}

   }

   /**
     *  cents_mod_100 : Schlage Cent-BetrŠge >= 100 per Modulo-Rechnung dem Euro-Betrag zu.
     *
     *  @return void
     *
     */

   private static void cents_mod_100 () {

	if (CENTS >= HUNDERT) {
		EUROS += CENTS / HUNDERT;
		CENTS  = CENTS % HUNDERT;
	}

   } // cents_mod_100 ()

   /**
     *  mySimpleNumberFormat : Erweitere ggf. zu kurze Zahlen mittels Blanks auf AUSGABE_ANZ_STELLEN Stellen,
     *  um auf der Konsole eine einfache rechtsbŸndige Ausrichtung zu erreichen.
     *
     *  @param theNumber Die zu formatierende Zahl (int)
     *  @return Formatierte Zahl.
     *
     */

   private static String mySimpleNumberFormat (int theNumber) {

	/** Umgekehrt proportional zur LŠnge der Zahl einen String mit Blanks erweitern. */

	String myString = "";

	/** Natuerlich haette man hier die Zahl auch in einen String wandeln koennen und dann dessen
	  * Zeichenkettenlaenge bestimmen - hier aber die rein mathematische Loesung via Logarithmus. */

	for (int i = 1; i <= AUSGABE_ANZ_STELLEN - Math.floor (Math.log (theNumber) / Math.log (ZEHN)); i++)
		myString += " ";

	/** Gib den Blank-String konkateniert mit der Zahl zurueck. */

	return (myString + theNumber);

   } // simpleNumberFormat ()

   /**
     *  fehlerbehandlung: Einfache Fehlerbehandlung.
     *  BeschrŠnkt sich momentan auf das ZurŸckweisen negativer EUROS oder CENTS.
     *
     *  @return void
     *
     */

   private static void fehlerbehandlung () {

	/** Test auf positiv definite Eingabewerte. Im Fehlerfall Konsolenmeldung und Exitus :) */

	if ((EUROS < 0) || (CENTS < 0)) {
		System.out.println ("Fehler: Werte kleiner Null werden nicht akzeptiert.");
		System.exit(0);
	}

   } // fehlerbehandlung ()

   /** main()-Methode der Klasse Wechsler2.
     *
     * @param args Dieses Programm wertet keine Kommandozeilenparameter aus.
     *
     */

   public static void main (String[] args) {

	/** Aufruf der Methode zur Fehlerbehandlung */

	fehlerbehandlung ();

	/** Schlage "ŸberschŸssige" Cent-MŸnzen >= 100 dem Euro-Betrag zu */

	cents_mod_100 ();

	/** Auszuzahlenden Betrag auf die Konsole schreiben */

	System.out.println ("AUSGEZAHLT WERDEN: " + EUROS + "," + CENTS + " EUR\n");

	/** Es gibt 500,200,100, 50,20,10, 5,2,1 Euro - max. Zehnerpotenz also 10^2 = 100 */

	ausgabe_alle (B_EURO, HUNDERT);

	/** Es gibt 50,20,10, 5,2,1 Cent - max. Zehnerpotenz also 10^1 = 10 */

	ausgabe_alle (B_CENT, ZEHN);

   } // main ()

} // Klasse Wechsler2
