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



/********************************************************************************
 * Knihovní třída {@code ExceptionCatching} obsahuje metody
 * sloužící k demonstraci činností spojených se zachytáváním výjimek.
 */
public class ExceptionCatching
{
//== CONSTANT CLASS ATTRIBUTES =================================================

    /** Formát zprávy o spuštění testu. */
    private static final String TEST = "\n================== %s\n";

    /** Formát zprávy spuštění sady testů. */
    private static final String SET  = "\n################## %s\n";



//== VARIABLE CLASS ATTRIBUTES =================================================



//##############################################################################
//== STATIC INITIALIZER (CLASS CONSTRUCTOR) ====================================
//== CLASS GETTERS AND SETTERS =================================================
//== OTHER NON-PRIVATE CLASS METHODS ===========================================

    /***************************************************************************
     * Metoda demonstruje zachycení výjimky a zprávu o něm.
     *
     * @param level Kolikrát se ještě budeme rekurzivně zanořovat
     */
    public static void recursion1(int level)
    {
        System.out.println("+++++ Příchod na hladinu "  + level);
        int breaker = 1 / level;
        System.out.println("      Dělení v hladině " + level + " se povedlo");
        try {
            recursion1(level - 1);
        }catch(RuntimeException rex) {
            //Bude chodit i pro typ ArithmeticException
            System.out.println("xxxxx V hladině " + level + " přišla " + rex);
            rex.printStackTrace(System.out);
        }
        System.out.println("----- Konec akce v hladině " + level);
    }


    /***************************************************************************
     * Metoda demonstruje současné odchytávání různých typů výjimek s tím,.
     * že se na různé výjimky reaguje různě
     *
     * @param level Kolikrát se ještě budeme rekurzivně zanořovat
     */
    public static void recursion2(int level)
    {
        System.out.println("+++++ Příchod na hladinu "  + level);
        try {
            multitest(level);
            System.out.println("     Test v hladině " + level + " prošel");
            recursion2(level - 1);
        }
        catch(ArithmeticException e) {
            System.out.println("xxxxx Něco se nespočítalo\n      " + e);
        }
        catch(NullPointerException e) {
            System.out.println("xxxxx Prázdný ukazatel\n      " + e);
        }
        catch(IndexOutOfBoundsException e) {
            System.out.println("xxxxx Index mimo meze\n      " + e);
        }
        catch(RuntimeException e) {
            System.out.println("xxxxx Někde se stala chyba\n      " + e);
        }
        catch(Throwable e) {
            System.out.println("xxxxx Něco se stalo\n      " + e);
        }
        System.out.println("----- Konec akce v hladině " + level);
    }


    /***************************************************************************
     * Metoda demonstruje současné odchytávání různých typů výjimek s tím,.
     * že se na různé výjimky reaguje různě
     *
     * @param level Kolikrát se ještě budeme rekurzivně zanořovat
     */
    public static void recursion3(int level)
    {
        System.out.println("+++++ Příchod na hladinu "  + level);
        try {
            multitest(level);
            System.out.println("     Test v hladině " + level + " prošel");
            recursion3(level - 1);
        }
        catch(ArithmeticException | NullPointerException e) {
            System.out.println("xxxxx Nastala výjimka typu\n      " + e);
        }
        catch(IndexOutOfBoundsException e) {
            System.out.println("xxxxx Index mimo meze\n      " + e);
        }
        catch(RuntimeException e) {
            System.out.println("xxxxx Někde se stala chyba\n      " + e);
        }
        catch(Throwable e) {
            System.out.println("xxxxx Něco se stalo\n      " + e);
        }
        System.out.println("----- Konec akce v hladině " + level);
    }


    /***************************************************************************
     * Metoda demonstruje použití bloku {@code finally}.
     *
     * @param level Kolikrát se ještě budeme rekurzivně zanořovat
     */
    public static void recursion4(int level)
    {
        System.out.println("+++++ Příchod na hladinu "  + level);
        String zpráva =    "      Hl." + level + ": ";
        try {
            multitest(level);
            zpráva += "Test v pořádku";
            recursion4(level - 1);
            zpráva += " včetně volání nižší hladiny";
        }
        catch(ArithmeticException | NullPointerException |
              IndexOutOfBoundsException e)
        {
            zpráva += "\nxxxxx Nastala výjimka typu\n      " + e;
            throw new RuntimeException("z hladiny " + level);
        }
        catch(Throwable e) {
            zpráva += " x Něco se stalo - " + e ;
        }
        finally {
            System.out.println(zpráva);
        }
        System.out.println("----- Konec akce v hladině " + level);
    }



//== PRIVATE AND AUXILIARY CLASS METHODS =======================================

    /***************************************************************************
     * Metoda demonstruje použití bloku {@code finally}.
     *
     * @param hloubka Kolikrát se ještě budeme rekurzivně zanořovat
     */
    private static void multitest(int hloubka)
    {
        //Pro hloubku 0
        int    h0 = 1 / hloubka;
        //Pro záporné a hodně velké hloubky
        char   hM = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".charAt(hloubka + 5);
        //Pro hloubky dělitelné 7
        String h7 = (hloubka%7 == 0) ?  null  :  "";
               h7.toString();
    }



//##############################################################################
//== CONSTANT INSTANCE ATTRIBUTES ==============================================
//== VARIABLE INSTANCE ATTRIBUTES ==============================================



//##############################################################################
//== CONSTRUCTORS AND FACTORY METHODS ==========================================

    /** Soukromý konstruktor bránící vytvoření instance. */
    private ExceptionCatching() {}



//== ABSTRACT METHODS ==========================================================
//== INSTANCE GETTERS AND SETTERS ==============================================
//== OTHER NON-PRIVATE INSTANCE METHODS ========================================
//== PRIVATE AND AUXILIARY INSTANCE METHODS ====================================



//##############################################################################
//== NESTED DATA TYPES =========================================================



//##############################################################################
//== TESTING CLASSES AND METHODS ===============================================

    /***************************************************************************
     * Testovací metoda.
     */
    public static void test1()
    {
        recursion1(3);
    }


    /***************************************************************************
     * Testovací metoda.
     */
    public static void test2()
    {
        System.out.printf(TEST, "R2(+3)");     recursion2(3);
        System.out.printf(TEST, "R2(-3)");     recursion2(-3);
        System.out.printf(TEST, "R2(+9)");     recursion2(9);
        System.out.printf(TEST, "KONEC_2");
    }


    /***************************************************************************
     * Testovací metoda.
     */
    public static void test3()
    {
        System.out.printf(TEST, "R3(+3)");     recursion3(3);
        System.out.printf(TEST, "R3(-3)");     recursion3(-3);
        System.out.printf(TEST, "R3(+9)");     recursion3(9);
        System.out.printf(TEST, "KONEC_3");
    }


    /***************************************************************************
     * Testovací metoda.
     */
    public static void test4()
    {
        System.out.printf(TEST, "R4(+3)");     recursion4(3);
        System.out.printf(TEST, "R4(-3)");     recursion4(-3);
        System.out.printf(TEST, "R4(+9)");     recursion4(9);
        System.out.printf(TEST, "KONEC_4");
    }


    /***************************************************************************
     * Testovací metoda.
     */
    public static void test()
    {
        System.out.printf(SET, "T1");     test1();
        System.out.printf(SET, "T2");     test2();
        System.out.printf(SET, "T3");     test3();
        System.out.printf(SET, "T4");     test4();
    }


    /***************************************************************************
     * Hlavní metoda sloužící k rychlému otestování dané třídy.
     *
     * @param args Parametry příkazového řádku - nepoužívané.
     */
    public static void main(String[] args)
    {
        test();
        System.exit(0);
    }

}
