import javax.swing.JOptionPane;


/*******************************************************************************
 * TPomocná třída sloužící jako schránka na pomocné statické metody
 * s různými užitečnými funkcemi.
 *
 * @author    Rudolf Pecinovský
 * @version   0.00.000,  12. únor 2004, 14:52
 */
public class P
{
//== SOUKROMÉ KONSTANTY ========================================================
//== VEŘEJNÉ KONSTANTY =========================================================
//== ŘETĚZCOVÉ LITERÁLY ========================================================
//== ATRIBUTY TŘÍDY ============================================================
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ TŘÍDY ========================================
//== OSTATNÍ METODY TŘÍDY ======================================================

    /***************************************************************************
     * Počká zadaný počet milisekund.
     * Na přerušení nijak zvlášť nereaguje - prostě skončí dřív.
     *
     * @param milisekund   Počet milisekund, po něž se má čekat.
     */
    public static void čekej( int milisekund )
    {
        try {
            Thread.sleep( milisekund);
        }catch( InterruptedException e) {
            throw new RuntimeException( "Čekání bylo přerušeno", e );
        }
    }


    /***************************************************************************
     * Spočte délku úsečky se zadanými krajními body.
     *
     * @param x1  Vodorovná souřadnice počátku úsečky
     * @param y1  Svislá souřadnice počátku úsečky
     * @param x2  Vodorovná souřadnice konce úsečky
     * @param y2  Svislá souřadnice konce úsečky
     *
     * @return   Délka úsečky
     */
    public static double délka( double x1, double y1,
                                double x2, double y2 )
    {
        double dx = x2 - x1;
        double dy = y2 - y1;
        return P.přepona( dx, dy );
    }


    /***************************************************************************
     * Vrátí řetězec s názvem metody, která tuto metodu zavolala.
     *
     * @param hloubka Ptá-li se metoda na svůj název nebo na název některé
     *                jí volajících metod. <br>
     *                0 - vrátí název metody, která zavolal tuto metodu<br>
     *                1 - vrátí název metody, jež zavolal metodu,
     *                    která zavolal tuto metodu<br>
     *                atd.
     * @param rodiče  0 - vrátí pouze název metody<br>
     *                1 - vrátí název metody s názvem třídy<br>
     *                2 - vrátí název metody s názvem třídy a balíčku.
     * @return Požadovaný název
     */
    public static String kdoVolá( int hloubka, int rodiče )
    {
    	Throwable t = new Throwable();
        StackTraceElement[] ste = t.getStackTrace();
        if( ste.length < (hloubka+2) )
            return "== NIKDO ==";
        StackTraceElement metoda = ste[hloubka+1];
        String název = metoda.getMethodName();
        if( rodiče > 0 )
        {
            String třída = metoda.getClassName();
            if( rodiče < 2 )
                třída = pouzeNázev( třída );
            název = třída + "." + název;
        }
        return název;
    }


    /***************************************************************************
     * Vrátí řetězec s názvem metody, která tuto metodu zavolala.
     *
     * @param rodiče  0 - vrátí pouze název metody<br>
     *                1 - vrátí název metody s názvem třídy<br>
     *                2 - vrátí název metody s názvem třídy a balíčku.
     * @return Požadovaný název
     */
    public static String kdoVolá( int rodiče )
    {
        return kdoVolá( 1, rodiče );
    }


    /***************************************************************************
     * Vrátí řetězec s pouhým názvem metody, která tuto metodu zavolala.
     *
     * @return
     */
    public static String kdoVolá()
    {
        return kdoVolá( 1, 0 );
    }


    /***************************************************************************
     * Vrátí čistý název třídy bez názvů balíčků.
     *
     * @param c    Objekt Class třídy, jejíž název zjišťujeme
     *
     * @return     Čistý název třídy
     */
    public static String názevTřídy( Class c )
    {
    	return P.pouzeNázev( c.getName() );
    }


    /***************************************************************************
     * Vrátí čistý název vlastní třídy zadané instance bez názvů balíčků.
     *
     * @param o    Odkaz na instanci, jejíž název třídy nás zajímá
     *
     * @return     Čistý název třídy
     */
    public static String názevTřídy( Object o )
    {
    	return P.pouzeNázev( o.getClass().getName() );
    }


    /***************************************************************************
     * Vyvolá výjimku oznamující, že metoda, z níž byla tato metoda volána,
     * není podporována.
     */
    public static void neumim()
    {
    	UnsupportedOperationException uoe = new UnsupportedOperationException();
        StackTraceElement[] ste = uoe.getStackTrace();
        if( ste.length < 2 )
            throw new IllegalStateException( "Přímé volání metody \"neumim\"" );
        StackTraceElement metoda = ste[1];
        String název = metoda.getMethodName();
        String msg = "Metoda " + název + " není implementována!";
        StackTraceElement[] st2 = new StackTraceElement[ste.length - 2];
        System.arraycopy(ste, 2, st2, 0,  st2.length );
        uoe = new UnsupportedOperationException( msg );
        uoe.setStackTrace( st2 );
        throw uoe;
    }


    /***************************************************************************
     *  Převede plný název třídy na její název bez balíčků.
     *
     * @param  plný     Plný název třídy včetně názvů balíčků
     * @return          Čistý název třídy
     */
    public static String pouzeNázev( String plný )
    {
        return plný.substring( 1+plný.lastIndexOf('.') );
    }


    /***************************************************************************
     * Počká zadaný počet milisekund.
     * Na přerušení nijak zvlášť nereaguje - prostě skončí dřív.
     *
     * @param milisekund   Počet milisekund, po něž se má čekat.
     */
    public static void počkejNa( Thread vlákno )
    {
        if( vlákno == null )
            return;
        try {
            vlákno.join();
        }catch( InterruptedException e) {
            throw new RuntimeException(
                "Čekání na vlákno bylo přerušeno: " + vlákno, e );
        }
    }


    /***************************************************************************
     * Spočte délku přepony pravoúhlého trojúelníku se zadanými odvěsnami.
     *
     * @param x  Délka první odvěsny
     * @param y  Délka druhé odvěsny
     *
     * @return   Délka přepony
     */
    public static double přepona( double x, double y )
    {
        return Math.sqrt(x*x + y*y);
    }


    /***************************************************************************
     * Zobrazí dialogové okno se zprávou a umožní uživateli odpovědět
     * ANO, NE nebo STORNO. Vrátí informaci o tom, jak uživatel odpověděl.
     * Odpovědě-li STORNO nebo zavře-li dialog, ukončí program.
     *
     * @param dotaz   Zobrazovaný text otázky.
     *
     * @return true odpověděl-li uživatel ANO, false odpověděl-li NE
     */
    public static boolean souhlas( Object dotaz )
    {
        return souhlas( "Dotaz", dotaz);
    }


    /***************************************************************************
     * Zobrazí dialogové okno se zprávou a umožní uživateli odpovědět
     * ANO, NE nebo STORNO. Vrátí informaci o tom, jak uživatel odpověděl.
     * Odpovědě-li STORNO nebo zavře-li dialog, ukončí program.
     *
     * @param dotaz   Zobrazovaný text otázky.
     * @param nadpis   Nadpis v titulkové liště dialogového okna.
     *
     * @return true   Odpověděl-li uživatel ANO, false odpověděl-li NE
     */
    public static boolean souhlas( String nadpis, Object dotaz )
    {
        int odpověď = JOptionPane.showOptionDialog(
            null,   //Rodičovská komponenta není - vystředí se na obrazovce
            dotaz,  //Otázka, na kterou má uživatel odpovědět
            nadpis,  //Titulek okna
            0,      //Optiona type
            JOptionPane.QUESTION_MESSAGE, //Message type
            null,   //Icon
            new Object[] { "ANO", "NE", "STORNO"},
            "ANO"
             );
        if( (odpověď == JOptionPane.CANCEL_OPTION)  ||
            (odpověď == JOptionPane.CLOSED_OPTION) )
        {
            System.exit(0);
        }
        return (odpověď == JOptionPane.YES_OPTION);
    }


    /***************************************************************************
     * Na standardní výstup vypíše vzprávu o vstupu do této metody
     * následovanou na dalším řádku zadaným textem.
     *
     * @param hloubka Hloubka dotazu na volanou metodu
     * @param text  Text, vypsaný za řádkem s oznámením vstupu do metody
     *              Je-li text "" nebo null, řádek se nevygeneruje.
     */
    public static void vstup( int hloubka, String text )
    {
        System.out.println("\n>>>>> Start: " + kdoVolá( hloubka, 3 ));
        if( (text != null)  &&  !text.equals("") )
            System.out.println( "      " + text );
    }


    /***************************************************************************
     * Na standardní výstup vypíše vzprávu o vstupu do této metody
     * následovanou na dalším řádku zadaným textem.
     *
     * @param text  Text, vypsaný za řádkem s oznámením vstupu do metody
     *              Je-li text "" nebo null, řádek se nevygeneruje.
     */
    public static void vstup( String text )
    {
        vstup( 2, text );
    }


    /***************************************************************************
     * Na standardní výstup vypíše vzprávu o vstupu do této metody.
     */
    public static void vstup()
    {
        vstup( 2, null );
    }


    /***************************************************************************
     * Na standardní výstup vypíše zadaný text následovný vzprávou
     * o ukončení volající metody.
     *
     * @param hloubka Hloubka dotazu na volanou metodu
     * @param text  Text, vypsaný před řádkem s oznámením výstupu z metody
     *              Je-li text "" nebo null, řádek se nevygeneruje.
     */
    public static void výstup( int hloubka, String text )
    {
        if( (text != null)  &&  !text.equals("") )
            System.out.println( "      " + text );
        System.out.println("<<<<< STOP: " + kdoVolá( hloubka, 3 ) + "\n" );
    }


    /***************************************************************************
     * Na standardní výstup vypíše zadaný text následovný vzprávou
     * o ukončení volající metody.
     *
     * @param text  Text, vypsaný před řádkem s oznámením výstupu z metody
     *              Je-li text "" nebo null, řádek se nevygeneruje.
     */
    public static void výstup( String text )
    {
        výstup( 2, text );
    }


    /***************************************************************************
     * Na standardní výstup vypíše vzprávu o ukončení volající metody.
     */
    public static void výstup()
    {
        výstup( 2, null );
    }


    /***************************************************************************
     * Zobrazí dialogové okno s výzvou k zadání reálné hodoty;
     * při zavření okna nebo stisku tlačítka Cancel ukončí aplikaci.
     *
     * @param výzva        Text, který se uživateli zobrazí.
     * @param doubleImpl   Implicitní hodnota.
     *
     * @return Uživatelem zadaná hodnota, resp. potvrzená implicitní hodnota.
     */
    public static double zadej( Object výzva, double doubleImpl )
    {
        return Double.parseDouble( zadej( výzva, ""+doubleImpl ).trim() );
    }


    /***************************************************************************
     * Zobrazí dialogové okno s výzvou k zadání celočíselné hodoty;
     * při zavření okna nebo stisku tlačítka Cancel ukončí aplikaci.
     *
     * @param výzva     Text, který se uživateli zobrazí.
     * @param intImpl   Implicitní hodnota.
     *
     * @return Uživatelem zadaná hodnota, resp. potvrzená implicitní hodnota.
     */
    public static int zadej( Object výzva, int intImpl )
    {
        return Integer.parseInt( zadej( výzva, ""+intImpl ).trim() );
    }


    /***************************************************************************
     * Zobrazí dialogové okno s výzvou k zadání textové hodoty;
     * při zavření okna nebo stisku tlačítka Cancel ukončí aplikaci.
     *
     * @param výzva        Text, který se uživateli zobrazí.
     * @param stringImpl   Implicitní hodnota.
     *
     * @return Uživatelem zadaná hodnota, resp. potvrzená implicitní hodnota.
     */
    public static String zadej( Object výzva, String stringImpl )
    {
        String odpověd = JOptionPane.showInputDialog(null, výzva, stringImpl );
        if( odpověd == null )
            System.exit(0);
        return odpověd;
    }


    /***************************************************************************
     * Zobrazí dialogové okno se zprávou a počká, až je uživatel odklepne;
     * při zavření okna ukončí aplikaci.
     *
     * @param text   Zobrazovaný text.
     */
    public static void zpráva( Object text )
    {
        int odpověď = JOptionPane.showConfirmDialog(
            null,     //Rodičovská komponenta není - vystředí se na obrazovce
            text,     //Zpráva, kteoru uživateli sdělujeme
            "Zpráva", //Titulek okna
            JOptionPane.DEFAULT_OPTION,      //Optiona type - OK
            JOptionPane.INFORMATION_MESSAGE  //Message type
             );
        if( (odpověď == JOptionPane.CLOSED_OPTION) )
            System.exit(0);
    }



//== ATRIBUTY INSTANCÍ =========================================================

//##############################################################################
//== KONSTRUKTORY A TOVÁRNÍ METODY =============================================

    /***************************************************************************
     * Třída P není určena k tomu, aby měla nějaké instance.
     * Konstruktor je zde pouze kvůli tomu, aby bylo možno definovat jejího
     * pototmka, který množinu metod rozšíří. Vzhledem k nemožnosti vytvářet
     * instance ale ale musejí být všechny metody definovány jako statické.
     */
    protected P()
    {
        throw new RuntimeException(
            "Od této třídy není povoleno vytvářet instance");
    }


//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ INSTANCÍ =====================================
//== PŘEKRYTÉ METODY IMPLEMENTOVANÝCH ROZHRANÍ =================================
//== PŘEKRYTÉ ABSTRAKTNÍ METODY RODIČOVSKÉ TŘÍDY ===============================
//== PŘEKRYTÉ KONKRÉTNÍ METODY RODIČOVSKÉ TŘÍDY ================================
//== NOVĚ ZAVEDENÉ METODY INSTANCÍ =============================================
//== SOUKROMÉ A POMOCNÉ METODY TŘÍDY ===========================================
//== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ========================================
//== VNOŘENÉ A VNITŘNÍ TŘÍDY ===================================================
//== TESTY A METODA MAIN =======================================================
}

