(********************************************************************)
(*                                                                  *)
(*  wrinum.s7i    Functions to write numbers                        *)
(*  Copyright (C) 1991, 1992, 1993, 1994, 2005  Thomas Mertes       *)
(*                                                                  *)
(*  This file is part of the Seed7 Runtime Library.                 *)
(*                                                                  *)
(*  The Seed7 Runtime Library is free software; you can             *)
(*  redistribute it and/or modify it under the terms of the GNU     *)
(*  Lesser General Public License as published by the Free Software *)
(*  Foundation; either version 2.1 of the License, or (at your      *)
(*  option) any later version.                                      *)
(*                                                                  *)
(*  The Seed7 Runtime Library is distributed in the hope that it    *)
(*  will be useful, but WITHOUT ANY WARRANTY; without even the      *)
(*  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(*  PURPOSE.  See the GNU Lesser General Public License for more    *)
(*  details.                                                        *)
(*                                                                  *)
(*  You should have received a copy of the GNU Lesser General       *)
(*  Public License along with this program; if not, write to the    *)
(*  Free Software Foundation, Inc., 51 Franklin Street,             *)
(*  Fifth Floor, Boston, MA  02110-1301, USA.                       *)
(*                                                                  *)
(********************************************************************)


(**
 *  Convert an [[integer]] to a roman numeral.
 *  @return a string containing the roman numeral.
 *)
const func string: str (ROMAN, in integer: number) is func
  result
    var string: romanNumber is "";
  local

    const func string: str_0_to_9 (in integer: number,
        in string: one, in string: five, in string: ten) is func
      result
        var string: romanNumber is "";
      begin
        if number <= 3 then
          romanNumber := one mult number;
        else
          if number = 4 then
            romanNumber := one & five;
          else
            if number <= 8 then
              romanNumber := five & one mult (number - 5);
            else
              romanNumber := one & ten;
            end if;
          end if;
        end if;
      end func;

  begin
    romanNumber :=
        str_0_to_9(number div 1000,         "M", "?", "?") &
        str_0_to_9((number div 100) rem 10, "C", "D", "M") &
        str_0_to_9((number div 10) rem 10,  "X", "L", "C") &
        str_0_to_9(number rem 10,           "I", "V", "X");
  end func;


(**
 *  Convert an [[integer]] to its written english equivalent.
 *  @return a string containing the number in english.
 *)
const func string: str (ENGLISH, in integer: number) is func
  result
    var string: englishNumber is "";
  local
    const array string: STR_0_TO_19 is [](
        "zero",      "one",       "two",       "three",     "four",
        "five",      "six",       "seven",     "eight",     "nine",
        "ten",       "eleven",    "twelve",    "thirteen",  "fourteen",
        "fifteen",   "sixteen",   "seventeen", "eighteen",  "nineteen");

    const array string: STR_20_TO_90 is [](
        "twenty",    "thirty",    "forty",     "fifty",
        "sixty",     "seventy",   "eighty",    "ninety");

    const func string: str_99 (in integer: number) is func
      result
        var string: stri is "";
      begin
        if number < 20 then
          stri := STR_0_TO_19[succ(number)];
        else
          stri := STR_20_TO_90[pred(number div 10)];
          if number rem 10 <> 0 then
            stri &:= STR_0_TO_19[succ(number rem 10)];
          end if;
        end if;
      end func;

    const func string: str_1E3 (in integer: number) is func
      result
        var string: stri is "";
      begin
        if number >= 100 then
          if number >= 200 then
            stri := STR_0_TO_19[succ(number div 100)];
          end if;
          stri &:= "hundred";
        end if;
        if number rem 100 <> 0 or number = 0 then
          if number >= 100 then
            stri &:= "and";
          end if;
          stri &:= str_99(number rem 100);
        end if;
      end func;

    const func string: str_1E6 (in integer: number) is func
      result
        var string: stri is "";
      begin
        if number >= 1000 then
          if number >= 2000 then
            stri := str_1E3(number div 1000);
          end if;
          stri &:= "thousand";
        end if;
        if number rem 1000 <> 0 or number = 0 then
          if number >= 1000 then
            stri &:= "and";
          end if;
          stri &:= str_1E3(number rem 1000);
        end if;
      end func;

    const func string: str_1E9 (in integer: number) is func
      result
        var string: stri is "";
      begin
        if number >= 1000000 then
          if number < 2000000 then
            stri := "onemillion";
          else
            stri := str_1E3(number div 1000000) & "millions";
          end if;
        end if;
        if number rem 1000000 <> 0 or number = 0 then
          stri &:= str_1E6(number rem 1000000);
        end if;
      end func;

  begin
    englishNumber := str_1E9(number);
  end func;


(**
 *  Convert an [[integer]] to its written german equivalent.
 *  @return a string containing the number in german.
 *)
const func string: str (GERMAN, in integer: number) is func
  result
    var string: germanNumber is "";
  local
    const array string: STR_0_TO_19 is [](
        "null",      "eins",      "zwei",      "drei",      "vier",
        "fuenf",     "sechs",     "sieben",    "acht",      "neun",
        "zehn",      "elf",       "zwoelf",    "dreizehn",  "vierzehn",
        "fuenfzehn", "sechzehn",  "siebzehn",  "achtzehn",  "neunzehn");

    const array string: STR_0_TO_9 is [](
        "",          "ein",       "zwei",      "drei",      "vier",
        "fuenf",     "sechs",     "sieben",    "acht",      "neun");

    const array string: STR_20_TO_90 is [](
        "zwanzig",   "dreissig",  "vierzig",   "fuenfzig",
        "sechzig",   "siebzig",   "achzig",    "neunzig");

    const func string: str_99 (in integer: number) is func
      result
        var string: stri is "";
      begin
        if number < 20 then
          stri := STR_0_TO_19[succ(number)];
        else
          if number rem 10 <> 0 then
            stri := STR_0_TO_9[succ(number rem 10)];
            stri &:= "und";
          end if;
          stri &:= STR_20_TO_90[pred(number div 10)];
        end if;
      end func;

    const func string: str_1E3 (in integer: number) is func
      result
        var string: stri is "";
      begin
        if number >= 100 then
          if number >= 200 then
            stri := STR_0_TO_9[succ(number div 100)];
          end if;
          stri &:= "hundert";
        end if;
        if number rem 100 <> 0 or number = 0 then
          if number >= 100 then
            stri &:= "und";
          end if;
          stri &:= str_99(number rem 100);
        end if;
      end func;

    const func string: str_1E6 (in integer: number) is func
      result
        var string: stri is "";
      begin
        if number >= 1000 then
          if number >= 2000 then
            stri := str_1E3(number div 1000);
          end if;
          stri &:= "tausend";
        end if;
        if number rem 1000 <> 0 or number = 0 then
          if number >= 1000 then
            stri &:= "und";
          end if;
          stri &:= str_1E3(number rem 1000);
        end if;
      end func;

    const func string: str_1E9 (in integer: number) is func
      result
        var string: stri is "";
      begin
        if number >= 1000000 then
          if number < 2000000 then
            stri := "einemillion";
          else
            stri := str_1E3(number div 1000000) & "millionen";
          end if;
        end if;
        if number rem 1000000 <> 0 or number = 0 then
          stri &:= str_1E6(number rem 1000000);
        end if;
      end func;

  begin
    germanNumber := str_1E9(number);
  end func;