package doprava;

import rup.česky.společně.P;
import rup.česky.tvary.Barva;
import rup.česky.tvary.AktivníPlátno;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;


/*******************************************************************************
 * Testovací třída KabinaTest slouží ke komplexnímu otestování
 * přídkladu s kabinovou lanovkou.
 *
 * @author    Rudolf Pecinovský
 * @version   0.00.000,  0.0.2003
 */
public class KabinaTest extends junit.framework.TestCase
{
//== KONSTANTNÍ ATRIBUTY TŘÍDY =================================================
//== PROMĚNNÉ ATRIBUTY TŘÍDY ===================================================
//== KONSTANTNÍ ATRIBUTY INSTANCÍ ==============================================
//== PROMĚNNÉ ATRIBUTY INSTANCÍ ================================================

    private AktivníPlátno AP = AktivníPlátno.getPlátno();
    private int   krok = AP.getKrok();
    private Linka vnější;
    private Linka střední;
    private Linka vnitřní;
    private static String názevTřídy;


//== METODY TŘÍDY PRO PŘÍPRAVU A SPUŠTĚNÍ SADY =================================
//##############################################################################
//== KONSTRUKTORY A TOVÁRNÍ METODY =============================================

    /***************************************************************************
     * Vytvoří test se zadaným názvem.
     *
     * @param název  Název konstruovaného testu
     */
    public KabinaTest(String název)
    {
        super( název );
    }



//== PŘÍPRAVA A ÚKLID PŘÍPRAVKU ================================================

    /***************************************************************************
     * Vytvoří tři soustředné linky.
     */
    protected void setUp()
    {
        AP.odstraňVše();
        krok = 50;
        AP.setKrokRozměr( krok, 7, 7 );
        AP.setMřížka( true );
        vnější  = Linka.vytvořVnější ( 50 );
        střední = Linka.vytvořStřední( 40 );
        vnitřní = Linka.vytvořVnitřní( 30 );
        P.čekej( 1500 );
    }


    /***************************************************************************
     * Zruší linky aby mohly být v příštím testu vytvořeny znovu.
     */
    protected void tearDown()
    {
        vnější.zruš();
        střední.zruš();
        vnitřní.zruš();
    }


//== SOUKROMÉ A POMOCNÉ METODY TŘÍDY ===========================================
//== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ========================================

    /***************************************************************************
     * Pro každou ze tří linek vytvoří kabinu a umísí ji na ni.
     *
     * @param třída  Třída, jejíž budou vytvořené kabiny instancí.
     */
    private TKabina[] vytvořTrojici( Class třída )
    {
        final int TROJIC = 3;
        TKabina.setTřída( třída );
        TKabina[] trojice = new TKabina[ 3*TROJIC ];
        for( int i=0, t=0;   t++ < TROJIC;   )
        {
            trojice[i++] = new TKabina( vnější  );
            trojice[i++] = new TKabina( střední );
            trojice[i++] = new TKabina( vnitřní );
            P.čekej( 1000 );
        };
        return trojice;
    }


    /***************************************************************************
     * Zdvojnásobí rychlost na všech linkách.
     */
    private void zrychliLinky()
    {
        P.zpráva( názevTřídy + "\nBudeme zrychlovat");
        vnější .setRychlost( 2*vnější .getRychlost() );
        střední.setRychlost( 2*střední.getRychlost() );
        vnitřní.setRychlost( 2*vnitřní.getRychlost() );
    }


    /***************************************************************************
     * Demostruje vzorové řešení: vytvoří tři linky, umístí na ně kabinky
     * a po potvrzení od uživatele pohyb kabin zrychlí.
     */
    private void ukončiSkupinu( TKabina[] skupina )
    {
        P.zpráva( názevTřídy + "\nBudeme končit");
        AP.nekresli();
            for( int i=skupina.length;   --i >= 0;   skupina[i].skonči() );
            //Pro případ, že by kabina nebyla právě v provozu (čeká ve stanici)
            //a čekala teprve na své další nasazení.
            P.čekej( vnější.getČekání() + 50 );
            for( int i=skupina.length;   --i >= 0;   skupina[i].skonči() );
        AP.vraťKresli();
    }



//== VNOŘENÉ A VNITŘNÍ TŘÍDY ===================================================

    /***************************************************************************
     * Soukromá třída umožňující připravit jednu sadu metod pro celou škálu
     * postupně budovaných tříd.
     */
    private static class TKabina
    {
        static boolean     tovární;
        static final Class linka = Linka.class;
        static Class třída;
        static Constructor konstruktor;
        static Method      továrna;
        static Method      skonči;
         

        Object kabina;


        /***********************************************************************
         * Připraví potřebné atributy, aby následně volané metody mohly pracovat
         * s instancemi třídy zadané jako parametr.
         */
        static void setTřída( Class třída )
        {
            názevTřídy = P.názevTřídy( třída );
            AktivníPlátno.getPlátno().setNázev( "Test třídy: " + názevTřídy );
            TKabina.třída = třída;
            try
            {
                try
                {
                    továrna = třída.getMethod( "getInstance", 
                                               new Class[] {linka} );
                    tovární = true;
                }
                catch( NoSuchMethodException e )
                {
                    konstruktor = třída.getConstructor( new Class[] {linka} );
                    tovární = false;
                }
                    
                skonči = třída.getMethod( "skonči", new Class[0] );
            }
            catch( Exception e )
            {
                throw new RuntimeException(
                    "Nepodařilo se zanalyzovat třídu " + třída, e );
            }
        }


        /***********************************************************************
         * Vytvoří novou instanci kabinové třídy a 
         * odkaz na ni uloží do atributu kabina.
         */
        TKabina( Linka linka )
        {
            if( třída == null )
                throw new IllegalStateException(
                    "Není definována třída kabin" );
            try
            {
                if( tovární )
                    kabina = továrna.invoke( null, new Object[] { linka } );
                else
                    kabina = konstruktor.newInstance( new Object[] { linka } );
            }
            catch( Exception e )
            {
                throw new RuntimeException(
                    "Nepodařilo se vytvořit kabinu na lince " + linka, e );
            }
        }
        

        /***********************************************************************
         * Ukončí činnost své kabiny = zavolá její metodu skonči().
         */
        void skonči()
        {
            try
            {
                skonči.invoke( kabina, new Object[0] );
             }
            catch( Exception e )
            {
                throw new RuntimeException(
                    "Nepodařilo se ukončit kabinu na lince " + linka, e );
            }
       }
    }



//== VLASTNÍ TESTY =============================================================

    /***************************************************************************
     * Test schopnosti vytvoření několika nezávislých linek;
     */
    public void testLinka()
    {
        assertTrue( P.souhlas( "Tři soustředné linky úspěšně vytvořeny?" ) );
    }


    /***************************************************************************
     * Test postupné tvorby linky. Protože se mi nechtělo definovat novou
     * testovací třídu, tak jsem nejprve uklidil, pak provedl test a pak zase
     * nechal vybudovat přípravek, aby se uklízecí metoda nevzbouřila.
     * Naní v tom jiný účel než má lenora.
     */
    public void testTvorbyLinky()
    {
        int[][] zastávky = { {25,125}, {125,25}, {125,225} };
        tearDown();
        Linka linka = new Linka( Barva.FIALOVÁ, 25, 25, 225, 225 );
        P.zpráva( "Nová linka se dvěma zastávkami" );
        IZastávka minulá = linka.getPrvní();
        for( int i=0;   i < zastávky.length;   i++ )
        {
            int[] nová = zastávky[i];
            int x = nová[0];
            int y = nová[1];
            linka.přidejZa( minulá, x, y );
            P.zpráva( "Přibyla zastávka na souřadncích [" + x + ";" + y + "]" );
        }
    }


    /***************************************************************************
     * Demostruje vzorové řešení: vytvoří tři linky, umístí na ně kabinky
     * a po potvrzení od uživatele pohyb kabin zrychlí.
     */
    public void testKabina_9a()
    {
        TKabina[] k3 = vytvořTrojici( Kabina_9a.class );
        zrychliLinky();
        ukončiSkupinu( k3 );
    }


    /***************************************************************************
     * Demostruje vzorové řešení: vytvoří tři linky, umístí na ně kabinky
     * a po potvrzení od uživatele pohyb kabin zrychlí.
     */
    public void testKabina_9b()
    {
        TKabina[] k3 = vytvořTrojici( Kabina_9b.class );
        zrychliLinky();
        ukončiSkupinu( k3 );
    }


    /***************************************************************************
     * Demostruje vzorové řešení: vytvoří tři linky, umístí na ně kabinky
     * a po potvrzení od uživatele pohyb kabin zrychlí.
     */
    public void testKabina_9c()
    {
        TKabina[] k3 = vytvořTrojici( Kabina_9c.class );
        zrychliLinky();
        ukončiSkupinu( k3 );
    }


    /***************************************************************************
     * Demostruje vzorové řešení: vytvoří tři linky, umístí na ně kabinky
     * a po potvrzení od uživatele pohyb kabin zrychlí.
     */
    public void testZpětnáKabina_9a()
    {
        TKabina[] k3 = vytvořTrojici( ZpětnáKabina_9a.class );
        zrychliLinky();
        ukončiSkupinu( k3 );
    }


    /***************************************************************************
     * Demostruje vzorové řešení: vytvoří tři linky, umístí na ně kabinky
     * a po potvrzení od uživatele pohyb kabin zrychlí.
     */
    public void testZpětnáKabina_9b()
    {
        TKabina[] k3 = vytvořTrojici( ZpětnáKabina_9b.class );
        zrychliLinky();
        ukončiSkupinu( k3 );
    }


    /***************************************************************************
     * Demostruje vzorové řešení: vytvoří tři linky, umístí na ně kabinky
     * a po potvrzení od uživatele pohyb kabin zrychlí.
     */
    public void testZpětnáKabina_9c()
    {
        TKabina[] k3 = vytvořTrojici( ZpětnáKabina_9c.class );
        zrychliLinky();
        ukončiSkupinu( k3 );
    }


    /***************************************************************************
     * Demostruje vzorové řešení: vytvoří tři linky, umístí na ně kabinky
     * a po potvrzení od uživatele pohyb kabin zrychlí.
     */
    public void testZpětnáKabina_9d()
    {
        TKabina[] k3 = vytvořTrojici( ZpětnáKabina_9d.class );
        zrychliLinky();
        ukončiSkupinu( k3 );
    }


    /***************************************************************************
     * Demostruje vzorové řešení: vytvoří tři linky, umístí na ně kabinky
     * a po potvrzení od uživatele pohyb kabin zrychlí.
     */
    public void testObaSměry_8c_8d()
    {
        TKabina[] tam3 = vytvořTrojici( Kabina_9c.class );
        TKabina[] zpět3 = vytvořTrojici( ZpětnáKabina_9d.class );
        zrychliLinky();
        ukončiSkupinu( tam3 );
        ukončiSkupinu( zpět3 );
    }


    /***************************************************************************
     * Demostruje vzorové řešení: vytvoří tři linky, umístí na ně kabinky
     * a po potvrzení od uživatele pohyb kabin zrychlí.
     */
    public void testKabina()
    {
        TKabina[] k3 = vytvořTrojici( Kabina.class );
        zrychliLinky();
        ukončiSkupinu( k3 );
    }


    /***************************************************************************
     * Demostruje vzorové řešení: vytvoří tři linky, umístí na ně kabinky
     * a po potvrzení od uživatele pohyb kabin zrychlí.
     */
    public void testZpětnáKabina()
    {
        TKabina[] k3 = vytvořTrojici( ZpětnáKabina.class );
        zrychliLinky();
        ukončiSkupinu( k3 );
    }


    /***************************************************************************
     * Demostruje vzorové řešení: vytvoří tři linky, umístí na ně kabinky
     * a po potvrzení od uživatele pohyb kabin zrychlí.
     */
    public void testObaSměry()
    {
        TKabina[] tam3 = vytvořTrojici( Kabina.class );
        TKabina[] zpět3 = vytvořTrojici( ZpětnáKabina.class );
        zrychliLinky();
        ukončiSkupinu( tam3 );
        ukončiSkupinu( zpět3 );
    }


    /***************************************************************************
     *
     * /
    public void testXXX()
    {
    }

/**/

}

