package shapes77.util;
// Příliš žluťoučký kůň úpěl ďábelské ó - PŘÍLIŠ ŽLUŤOUČKÝ KŮŇ ÚPĚL ĎÁBELSKÉ Ó

import java.util.Random;



/*******************************************************************************
 * Knihovní třída {@code Number2CZWords} slouží k převodu celých čísel
 * na textové řetězce vyjadřující hodnotu zadaného čísla slovy v češtině.
 */
public final class Number2CZWords
{
//\CC== CLASS CONSTANTS (CONSTANT CLASS/STATIC ATTRIBUTES/FIELDS) ==============

    /** Generátor náhodných čísel pro generaci náhodných stringů. */
    private static final Random rnd = new Random();

    /** Největší číslo, které umí program převést na text. */
    public static final long MAX = Long.MAX_VALUE;

    /** Názvy čísel do dvaceti. */
    private static final String[] UNITS__STRINGSCZ = {
        "",        "jedna",    "dva",       "tři",      "čtyři",
        "pět",     "šest",     "sedm",      "osm",      "devět",
        "deset",   "jedenáct", "dvanáct",   "třináct",  "čtrnáct",
        "patnáct", "šestnáct", "sedmnáct",  "osmnáct",  "devatenáct"
    };

    /** Názvy desítek. */
    private static final String[] TENS_CZ = {
        "",        "",         "dvacet",    "třicet",   "čtyřicet",
        "padesát", "šedesát",  "sedmdesát", "osmdesát", "devadesát"
    };

    /** Názvy stovek. */
    private static final String[] HUNDREDS_CZ = {
        "",        "sto",      "dvě stě",   "tři sta",  "čtyři sta",
        "pět set", "šest set", "sedm set",  "osm set",  "devět set"
    };

    /** Názvy řádů. */
    private static final String[][] ORDERS_CZ = {
        null,
        { "tisíc",     "tisíce",   "tisíc"    },
        { "milion",    "miliony",  "milionů"  },
        { "miliarda",  "miliardy", "miliard"  },
        { "bilion",    "biliony",  "bilionů"  },
        { "biliarda",  "biliardy", "biliard"  },
        { "trilion",   "triliony", "trilionů" },
    };



//\CV== CLASS VARIABLES (VARIABLE CLASS/STATIC ATTRIBUTES/FIELDS) ==============



//##############################################################################
//\CI== CLASS (STATIC) INITIALIZER (CLASS CONSTRUCTOR) =========================
//\CF== CLASS (STATIC) FACTORY METHODS =========================================
//\CG== CLASS (STATIC) GETTERS AND SETTERS =====================================

    /***************************************************************************
     * Metoda vrátí řetězec představující slovní vyjádření náhodného čísla
     * ze zadaného intervalu.
     *
     * @param seed  Semeno definující následně generovanou posloupnost
     *              rovnoměrně rozdělených náhodných čísel
     */
    public static void setSeed(long seed)
    {
        rnd.setSeed(seed);
    }



//\CM== CLASS (STATIC) REMAINING NON-PRIVATE METHODS ===========================

    /***************************************************************************
     * Metoda vrátí řetězec představující slovní vyjádření zadaného čísla.
     *
     * @param number  Číslo, které chceme vyjádřit slovy.
     *
     * @return Slovní vyjádření zadaného čísla
     * @throws IllegalArgumentException je-li číslo příliš malé nebo veliké.
     */
    public static String inCzech(long number)
    {
        verify(number);
        return convertCZ(number);
    }


    /***************************************************************************
     * Metoda vrátí řetězec představující slovní vyjádření náhodného čísla
     * ze zadaného intervalu.
     *
     * @param from  Spodní inkluzivní mez generovaných čísel (včetně)
     * @param to    Horní exkluzivní mez (nedosažitelný strop)
     * @return Text odpovídající náhodnému číslu ze zadaného intervalu
     */
    public static String nextRndNum(int from, int to)
    {
        verify(from, to);
        int num = from + rnd.nextInt(to - from);
        return convertCZ(num);
    }


    /***************************************************************************
     * Metoda vrátí pole řetězců představující slovní vyjádření sady
     * rovnoměrně rozložených náhodných čísel ze zadaného intervalu.
     *
     * @param from  Spodní inkluzivní mez generovaných čísel (včetně)
     * @param to    Horní exkluzivní mez (nedosažitelný strop)
     * @param count Požqadovaný počet čísel = délka pole
     * @return Text odpovídající náhodnému číslu ze zadaného intervalu
     */
    public static String[] rndNums(int from, int to, int count)
    {
        String[] result = new String[count];
        for (int i = 0;   i < count;   i++) {
            result[i] = nextRndNum(from, to);
        }
        return result;
    }



//\CP== CLASS (STATIC) PRIVATE AND AUXILIARY METHODS ===========================

    /***************************************************************************
     * Metoda vrátí řetězec představující slovní vyjádření zadaného čísla.
     *
     * @param number  Číslo, které chceme vyjádřit slovy.
     *
     * @return Slovní vyjádření zadaného čísla
     */
    private static String convertCZ(long number)
    {
        if (number == 0) {
            return "nula";                          //====================>
        }
        String[] texts    = new String[ORDERS_CZ.length];
        int      triplets = prepareTriplets(texts, number);
        String   result   = prepareResult(triplets, texts);
        return result;
    }


    /***************************************************************************
     * Ze zadaného čísla odvodí jednotlivé triplety, které převede na text
     * a uloží do zadaného pole.
     *
     * @param texty     Pole pro vytvořené triplety
     * @param number    Převáděné číslo
     * @return Počet převedených tripletů
     */
    private static int prepareTriplets(String[] texty, long number)
    {
        texty[0] = hundredsCZ((int)(number % 1000));
        int triplets = 1;           //Počet vytvořených tripletů
        while ((number /= 1000) > 0) {
            int triplet = (int)(number % 1000);
            if (triplet == 0) {
                triplets++;         //Triplet je nulový, ber další
                continue;           //^^^^^^^^^^>
            }
            String tripletInWords = hundredsCZ(triplet);
            String order;           //Nyní odvoď řád
            if (triplet == 1)      //Jeden(jedna) xxx
            {
                order = ORDERS_CZ[triplets][0];
                if ((triplets == 1)  ||    //Tisíce
                    ((triplets & 1) == 0)) //Sudé => milióny, bilióny, ...
                {
                    tripletInWords = "jeden"; //Ne jedna, ale jeden
                }
            }
            else if (triplet <= 4) {//Dva(dvě), tři, čtyři
                order = ORDERS_CZ[triplets][1];
                if ((triplet == 2)  &&     //Dvojice => tisíce + stovky
                    (triplets > 2)  &&
                    ((triplets & 1) == 1)) //Liché => miliardy, biliardy, ...
                {
                    tripletInWords = "dvě"; //Ne dva, ale dvě
                }
            }
            else {                  //Pět a více
                order = ORDERS_CZ[triplets][2];
            }
            texty[triplets] = tripletInWords + " " + order;
            triplets++;
        }
        return triplets;
    }


    /***************************************************************************
     * Metoda vrátí řetězec představující slovní vyjádření
     * zadaného trojčíslí (tripletu).
     *
     * @param number  Číslo, které chceme vyjádřit slovy.
     *
     * @return Slovní vyjádření zadaného čísla
     */
    private static String hundredsCZ(int number)
    {
        if (number < 20) {
            return UNITS__STRINGSCZ[number];       //====================>
        }
        int units    = number % 10;     //Počet jednotek
        int tens     = number / 10;     //Celkový počet desítek
        int hundreds = tens / 10;       //Počet stovek
            tens     = tens % 10;       //Počet pouhých desítek
        return HUNDREDS_CZ[hundreds] +
              (((hundreds  > 0)  &&  (number%100 > 0))  ?  " "  :  "")  +
              ((tens < 2)  ?  UNITS__STRINGSCZ[ 10*tens + units ]
                           :  (TENS_CZ [ tens ]) +
                              ((units > 0)  ?  " "  :  "")  +
                              UNITS__STRINGSCZ[ units ]);
    }


    /***************************************************************************
     * Sestaví řetězec z připravených tripletů.
     *
     * @param triplets  Počet vygenerovaných tripletů
     * @param texty     Texty jednotlivých tripletů
     * @return Sestavený řetězec
     */
    private static String prepareResult(int triplets, String[] texty)
    {
        StringBuilder sb = new StringBuilder();
        for (int i = triplets-1;   i >= 0;   i--)
        {
            if (texty[i] == null) {
                continue;
            }
            if (sb.length() > 0) {
                sb.append(" ");
            }
            sb.append(texty[i]);
        }
        String result = sb.toString();
        return result;
    }


    /***************************************************************************
     * Prověří, jestli číslo patří mezi převeditelná.
     *
     * @param number Převáděné číslo
     * @throws IllegalArgumentException Není-li číslo převeditelné
     */
    private static void verify(long number)
        throws IllegalArgumentException
    {
        if ((number < 0)  ||  (MAX < number)) {
            throw new IllegalArgumentException(
                    "Lze převádět pouze nezáporná čísla do " + MAX);
        }
    }


    /***************************************************************************
     * Prověří, jestli zadané parametry mohou sloužit jako interval
     * generovaných náhodných čísel.
     *
     * @param from  Spodní inkluzivní mez
     * @param to    Horní exkluzivní mez
     * @throws IllegalArgumentException Nevzhovují-li čísla podmínkám
     */
    private static void verify(int from, int to)
        throws IllegalArgumentException
    {
        if ((from < 0)  ||  (from >= to)  ||  (MAX < to)) {
            throw new IllegalArgumentException(
                    "Pro interval náhodných čísel musí platit: "
                  + "0 <= from < to <= " + MAX
                  + "\nZadáno: from=" + from + ", to=" + to);
        }
    }



//##############################################################################
//\IC== INSTANCE CONSTANTS (CONSTANT INSTANCE ATTRIBUTES/FIELDS) ===============
//\IV== INSTANCE VARIABLES (VARIABLE INSTANCE ATTRIBUTES/FIELDS) ===============



//##############################################################################
//\II== INSTANCE INITIALIZERS (CONSTRUCTORS) ===================================

    /***************************************************************************
     * Tato třída bude knihovní, bude obsahovat pouze statické metody,
     * takže od ní zakážeme vytvářet instance.
     */
    private Number2CZWords()
    {
    }



//\IA== INSTANCE ABSTRACT METHODS ==============================================
//\IG== INSTANCE GETTERS AND SETTERS ===========================================
//\IM== INSTANCE REMAINING NON-PRIVATE METHODS =================================
//\IP== INSTANCE PRIVATE AND AUXILIARY METHODS =================================



//##############################################################################
//\NT== NESTED DATA TYPES ======================================================
}
