
package de.ivu.elect.util;

import org.apache.commons.lang3.StringUtils;

/**
 * Aufgabe: In Verträgen und Schecks muß man immer auch den Betrag in Worten schreiben. Für eine Versicherung sollen Sie ein Programm schreiben, das eine von stdin zeilenweise Zahlen einliest und
 * diese Zahlen gemein- sam mit den Worten, die diese Zahl repräsentieren, ausgeben. Für die Zahl 21 soll also zum Beispiel der Text "einundzwanzig" ausgegeben werden. Ihr Programm soll alle ganzen
 * Zahlen von 0 bis 2147483647 verarbeiten können. Berücksichtigen dabei auch die korrekte Schreibweise. Laut Duden 1973, S. 59 ff, schreibt man Zahlen unter einer Million zusammen. Getrennt schreibt
 * man dagegen Zahlen über einer Million. Beispiele: eintausendneunhundertfünfundfünfzig, dreiundzwanzigtausend zwei Millionen dreitausendvierhundert Lösung: Das Programm teilt die eingegebene Zahl in
 * Blöcke zu drei Ziffern, indem die Zahlen solange durch 1000 dividiert wird, bis bei dieser Division 0 herauskommt. Jeder dieser Blöcke wird durch Aufruf einer Funktion in das entsprechende Wort
 * gewandelt. Danach wird je nach Wertigkeit des Blockes das Wort "tausend", "Million", usw. angehängt.
 *
 */
public class NumberToText {

  public static int bestimmeAnzahlStellen(int nummer) {
    int l;
    int absoluteNummer = Math.abs(nummer);
    for (l = 0; absoluteNummer > 0; ++l) {
      absoluteNummer /= 10;
    }
    return l;
  }

  /**
   * Betrag in Worten einer ganzen, positiven Zahl in Worten für 1 bis 999.
   *
   * @param x
   *          umzuwandelnde Zahl zwisch 1 und 999
   * @return Zahl in Worten
   */
  public static String intToText(int value) {
    int x = value;

    if (x < 0) {
      throw new IllegalArgumentException("Die umzuwandelnde Zahl darf nicht negativ sein! [umzuwandelnde Zahl=" + x + "]");
    }
    if (x == 0) {
      return "null";
    }

    int digits = 0;
    String result = "";

    while (x > 0) {
      String zahl = intToText1000(x % 1000, digits);
      String quantifier = intToTextDigits(digits, x % 1000 > 1);
      if (StringUtils.isNotBlank(zahl)) {
        result = zahl + quantifier + result;
      }
      x /= 1000;
      digits += 3;
    }

    return StringUtils.trim(result);
  }

  /**
   * Gibt das Wort für die Zehnerstellen zurück.
   *
   * @param x
   *          die umzuwandelnde Zahl
   * @return Text für die Zahl
   */
  static String intToText10(int x) {
    int y = x / 10; /* nur Zehnerstelle */
    switch (y) {
      case 1 :
        return "zehn";
      case 2 :
        return "zwanzig";
      case 3 :
        return "dreißig";
      case 4 :
        return "vierzig";
      case 5 :
        return "fünfzig";
      case 6 :
        return "sechzig";
      case 7 :
        return "siebzig";
      case 8 :
        return "achtzig";
      case 9 :
        return "neunzig";
      default :
        return "FEHLER";
    }
  }

  /**
   * Gibt den Betrag in Worten für 1 bis 99 zurück.
   *
   * @param x
   *          die umzuwandelnde Zahl
   * @param digits
   *          Anzahl der Stellen hinter der Zahl
   * @return Text für die Zahl
   */
  static String intToText100(int x, int digits) {
    int y = x % 100; /* nur Einer- und Zehnerstelle */
    /* -- Sonderbehandlung der Zahl 1 -- */
    if (y == 1) {
      switch (digits) {
        case 0 :
          return "eins";
        case 1 :
        case 2 :
        case 3 :
          return "ein";
        case 6 :
        case 9 :
        case 12 :
        case 15 :
          /* -- Einzahl oder Mehrzahl ? -- */
          if (x == 1) {
            return "eine";
          } else {
            return "ein";
          }
        default :
          return "FEHLER";
      }
    }
    /* -- Zahlen 2 bis 19 -- */
    if (y >= 2 && y <= 19) {
      switch (y) {
        case 2 :
          return "zwei";
        case 3 :
          return "drei";
        case 4 :
          return "vier";
        case 5 :
          return "fünf";
        case 6 :
          return "sechs";
        case 7 :
          return "sieben";
        case 8 :
          return "acht";
        case 9 :
          return "neun";
        case 10 :
          return "zehn";
        case 11 :
          return "elf";
        case 12 :
          return "zwölf";
        case 13 :
          return "dreizehn";
        case 14 :
          return "vierzehn";
        case 15 :
          return "fünfzehn";
        case 16 :
          return "sechzehn";
        case 17 :
          return "siebzehn";
        case 18 :
          return "achtzehn";
        case 19 :
          return "neunzehn";
        default :
          return "FEHLER";
      }
    }
    /* -- Zahlen 20 bis 99 -- */
    if (y >= 20 && y <= 99) {
      if (y % 10 == 0) {
        return intToText10(y);
      } else {
        return intToText100(y % 10, 1) + "und" + intToText10(y);
      }
    }
    return "";
  }

  /**
   * Bezeichnung der Werte über einer Miilion
   *
   * @param digits
   *          Anzahl der Null-Stellen
   * @param mehrzahl
   *          Merhzahl
   * @return Zahlen-Suffix
   */
  static String intToTextDigits(int digits, boolean mehrzahl) {
    if (digits < 0) {
      throw new IllegalArgumentException("Die Anzahl an Nullstell (Null-Stellen=" + digits + ") ist zu klein!");
    }

    if (digits > 17) {
      throw new IllegalArgumentException("Die Anzahl an Nullstell (Null-Stellen=" + digits + ") ist zu groß!");
    }
    switch (digits) {
      case 0 :
      case 1 :
      case 2 :
        return "";
      case 3 :
      case 4 :
      case 5 :
        return "tausend";
      case 6 :
      case 7 :
      case 8 :
        return mehrzahl ? " Millionen " : " Million ";
      case 9 :
      case 10 :
      case 11 :
        return mehrzahl ? " Milliarden " : " Milliarde ";
      case 12 :
      case 13 :
      case 14 :
        return mehrzahl ? " Billionen " : " Billion ";
      case 15 :
      case 16 :
      case 17 :
        return mehrzahl ? " Billiarden " : " Billiarde ";
      default :
        return "";
    }
  }

  /**
   * Gibt den Betrag in Worten für 1 bis 999 zurück.
   *
   * @param x
   *          die umzuwandelnde Zahl
   * @param digits
   *          Anzahl der Stellen hinter der Zahl
   * @return Text für die Zahl
   */
  static String intToText1000(int x, int digits) {
    if (x / 100 == 0) {
      return intToText100(x, digits);
    } else {
      return intToText100(x / 100, 2) + "hundert" + intToText100(x, digits);
    }
  }
}
