package příklady;

import rup.česky.tvary.AHýbací;
import rup.česky.tvary.Barva;
import rup.česky.tvary.Elipsa;
import rup.česky.tvary.Kreslítko;
import rup.česky.tvary.Obdélník;
import rup.česky.tvary.Oblast;
import rup.česky.tvary.Pozice;
import rup.česky.tvary.Rozměr;


/*******************************************************************************
 * Třída Strom_9c obsahuje podobu třídy po definici rodičovské třídy AHýbací
 *
 *  Od Strom_9b je změněno:
 *  - Změněna rodičovská třída na AHýbací
 *
 * @author     Rudolf Pecinovský
 * @version    2.01, duben 2004
 */
public class Strom_9c extends AHýbací 
{
//== KONSTANTNÍ ATRIBUTY TŘÍDY =================================================

    /** Udává, kolikrát je strom vyšší než samotný kmen. */
    public static final int IMPLICITNÍ_POMĚR_VÝŠKY =  3;

    /** Udává, kolikrát je koruna širší než kmen. */
    public static final int IMPLICITNÍ_POMĚR_ŠÍŘKY = 10;



//== PROMĚNNÉ ATRIBUTY TŘÍDY ===================================================
//== KONSTANTNÍ ATRIBUTY INSTANCÍ ==============================================

    /* Odkaz na instanci představující korunu stromu. */
    private final Elipsa   koruna;

    /* Odkaz na instanci představující korunu stromu. */
    private final Obdélník kmen;



//== PROMĚNNÉ ATRIBUTY INSTANCÍ ================================================
    
    /** Kolikrát je celý strom širší než samotný kmen. */
    private int podílŠířkyKmene;
    
    /** Kolikrát je celý strom vyšší než samotný kmen. */
    private int podílVýškyKmene;

    
    
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ TŘÍDY ========================================
//== OSTATNÍ METODY TŘÍDY ======================================================

    /***************************************************************************
     * Vytvoří instanci zadané velikosti a upraví rozměr plátna tak,
     * aby byla na plátně právě zarámovaná.
     *
     * @param šířka   Šířka stromu, který chceme vytvořit a zarámovat.
     * @param výška   Výška stromu, který chceme vytvořit a zarámovat.
     */
    public static void zarámuj( int šířka, int výška )
    {
        AP.nekresli();        
            AP.setKrokRozměr( 1, šířka, výška );
            new Strom_9c( 0, 0, šířka, výška ).nakresli();
        AP.vraťKresli();
    }


    /***************************************************************************
     * Metoda upraví rozměr plátna a "vysadí" na něj alej dvou řad stromů
     * se třemi stromy v každé řadě. Stromy budou vysazeny šikmo ve směru
     * hlavní diagonály s kmenem zabírajícím 1/3 výšky a 1/10 šířky stromu.
     */
    public static void alej()
    {
        AP.nekresli();        
            AP.setKrokRozměr( 50, 8, 7 );
            new Strom_9c( 100,   0 ).nakresli();
            new Strom_9c( 300,   0 ).nakresli();
            new Strom_9c(  50, 100 ).nakresli();
            new Strom_9c( 250, 100 ).nakresli();
            new Strom_9c(   0, 200 ).nakresli();
            new Strom_9c( 200, 200 ).nakresli();
        AP.vraťKresli();
    }


    /***************************************************************************
     * Vytvoří v zadané oblasti zarámovaný obrázek stromu, přičemž šířka
     * rámu je zadána jako druhý parametr.
     * 
     * @param oblast     Oblast, do níž se má strom v rámu vykreslit.
     * @param šířkaRámu  Šířka rámu v obrazových bodech.
     */
    public static void obrázek( Oblast oblast, int šířkaRámu )
    {
        AP.nekresli();        
            AP.přidej( new Obdélník(oblast, Barva.ČERNÁ) );
            oblast.x += šířkaRámu;
            oblast.y += šířkaRámu;
            oblast.šířka -= 2*šířkaRámu;
            oblast.výška -= 2*šířkaRámu;
    
            AP.přidej( new Obdélník(oblast, Barva.AZUROVÁ) );
            new Strom_9c( oblast ).nakresli();
        AP.vraťKresli();
    }



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

    /***************************************************************************
     * Implicitní konstruktor vytvoří v levém horním rohu plátna
     * instanci širokou 100 bodů, vysokou 150 bodů
     * s kmenem zabírajícím 1/3 výška a 1/10 šířky stromu.
     */
    public Strom_9c()
    {
        this( 0, 0 );
    }


    /***************************************************************************
     * Vytvoří na zadaných souřadnicích
     * instanci širokou 100 bodů, vysokou 150 bodů
     * s kmenem zabírajícím 1/3 výška a 1/10 šířky stromu.
     *
     * @param x       x-ová souřadnice počátku, x>=0, x=0 má levý okraj plátna
     * @param y       y-ová souřadnice počátku, y>=0, y=0 má horní okraj plátna
     */
    public Strom_9c(int x, int y)
    {
        this( x, y, 100, 150 );
    }


    /***************************************************************************
     * Vytvoří na zadaných souřadnicích instanci se zadanou šířkou a výškou.
     * Poměr velikosti kmene ku zbytku stromu zůstane implicitní, tj.
     * kmen bude zabírat 1/3 výška a 1/10 šířky stromu.
     *
     * @param x       x-ová souřadnice počátku, x>=0, x=0 má levý okraj plátna
     * @param y       y-ová souřadnice počátku, y>=0, y=0 má horní okraj plátna
     * @param šířka   Šířka vytvářené instance,  šířka > 0
     * @param výška   Výška vytvářené instance,  výška > 0
     */
    public Strom_9c(int x, int y, int šířka, int výška)
    {
        this( x, y, šířka, výška,
            IMPLICITNÍ_POMĚR_ŠÍŘKY, IMPLICITNÍ_POMĚR_VÝŠKY );
    }


    /**************************************************************************
     * Vytvoří novou instanci se zadanou polohou a rozměry.
     *
     * @param pozice  Pozice vytvářené instance
     * @param rozměr  Rozměr vytvářené instance
     */
    public Strom_9c(Pozice pozice, Rozměr rozměr)
    {
        this( pozice.x, pozice.y, rozměr.šířka, rozměr.výška );
    }


    /**************************************************************************
     * Vytvoří novou instanci vyplňující zadanou oblast.
     *
     * @param oblast   Oblast definující pozici a rozměr vytvářené instance
     */
    public Strom_9c(Oblast oblast)
    {
        this( oblast.x, oblast.y, oblast.šířka, oblast.výška );
    }


    /***************************************************************************
     * Vytvoří na zadaných souřadnicích instanci se zadanou šířkou, výškou.
     * a poměrem velikosti kmene ku zbytku stromu.
     * Vytvořené instanci přiřadí její "rodné číslo".
     *
     * @param x       x-ová souřadnice počátku, x>=0, x=0 má levý okraj plátna
     * @param y       y-ová souřadnice počátku, y>=0, y=0 má horní okraj plátna
     * @param šířka   Šířka vytvářené instance,  šířka > 0
     * @param výška   Výška vytvářené instance,  výška > 0
     * @param podílŠířkyKmene  Kolikrát je kmen užší než celý strom
     * @param podílVýškyKmene  Kolikrát je kmen menší než celý strom
     */
    public Strom_9c(int x, int y, int šířka, int výška, int podílŠířkyKmene, int podílVýškyKmene)
    {
        super( x, y, šířka, výška );
        this.podílVýškyKmene = podílVýškyKmene;
        this.podílŠířkyKmene = podílŠířkyKmene;
        AP.nekresli();        
            koruna = new Elipsa  ( x, y, 1, 1, Barva.ZELENÁ  );
            kmen   = new Obdélník( x, y, 1, 1, Barva.HNĚDÁ );
            můjSetRozměr( šířka, výška );
        AP.vraťKresli();
    }



//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ INSTANCÍ =====================================

    /***************************************************************************
     * Nastaví novou pozici instance.
     *
     * @param x   Nová x-ová pozice instance
     * @param y   Nová y-ová pozice instance
     */
    public void setPozice(int x, int y)
    {
        AP.nekresli();
            super .setPozice( x, y );
            koruna.setPozice( x, y );
            kmen  .setPozice( x  +  (koruna.getŠířka() - kmen.getŠířka()) / 2,
                              y  +  koruna.getVýška()     );
        AP.vraťKresli();
    }


    /***************************************************************************
     * Nastaví nové rozměry instance.
     *
     * @param šířka    Nově nastavovaná šířka; šířka>0
     * @param výška    Nově nastavovaná výška; výška>0
     */
    public void setRozměr(int šířka, int výška)
    {
        můjSetRozměr( šířka, výška );
    }


    /***************************************************************************
     * Vrátí barvu koruny stromu.
     *
     * @return  Instance třídy Barva definující nastavenou barvu koruny.
     */
    public Barva getBarvaKoruny()
    {
        return koruna.getBarva();
    }


    /***************************************************************************
     * Nastaví novou barvu koruny.
     *
     * @param nová  Požadovaná nová barva.
     */
    public void setBarvaKoruny( Barva nová )
    {
        koruna.setBarva( nová );
    }



//== PŘEKRYTÉ METODY IMPLEMENTOVANÝCH ROZHRANÍ =================================

    /***************************************************************************
     * Vykreslí obraz své instance na plátno.
     *
     * @param kreslítko  Objekt, jehož prostřednictvím se má instance nakreslit.
     */
    public void nakresli(Kreslítko kreslítko)
    {
        //Tady se dvojice nekresli() - vraťKresli() nepoužije,
        //protože se beztak právě překresluje
        koruna.nakresli(kreslítko);
        kmen  .nakresli(kreslítko);
    }



//== PŘEKRYTÉ ABSTRAKTNÍ METODY RODIČOVSKÉ TŘÍDY ===============================
//== PŘEKRYTÉ KONKRÉTNÍ METODY RODIČOVSKÉ TŘÍDY ================================

    /***************************************************************************
     * Převede instanci na řetězec obsahující název třídy, pořadí instance,
     * její souřadnice a rozměry.
     *
     * @return Řetězcová reprezentace dané instance.
     */
    public String toString()
    {
        return super.toString() + ", šířka=" + getŠířka() + 
                                  ", výška=" + getVýška();
    }


//== NOVĚ ZAVEDENÉ METODY INSTANCÍ =============================================

    /***************************************************************************
     * Odstraní z plátna všechny ostatní instance a nastaví
     * parametry okna s plátnem tak, aby právě zarámovalo danou instanci.
     */
    public void zarámuj()
    {
        AP.nekresli();        
            AP.odstraňVše();
            AP.setKrokRozměr( 1, getŠířka(), getVýška() );
            setPozice( 0, 0 );
            AP.přidej( this );
        AP.vraťKresli();
    }


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

    /***************************************************************************
     * Nastaví nové rozměry instance.
     *
     * @param šířka    Nově nastavovaná šířka; šířka>0
     * @param výška    Nově nastavovaná výška; výška>0
     */
    private void můjSetRozměr(int šířka, int výška)
    {
        int x = getX();
        int y = getY();
        int výškaKmene  = výška / podílVýškyKmene;
        int výškaKoruny = výška - výškaKmene;
        int šířkaKmene  = šířka / podílŠířkyKmene;
        int posunKmene  = ( šířka - šířkaKmene) / 2;
        AP.nekresli();        
            koruna.setRozměr( šířka, výškaKoruny );
            kmen.setPozice( x+posunKmene, y+výškaKoruny );
            kmen.setRozměr( šířkaKmene, výškaKmene );
        AP.vraťKresli();
    }

    
    
//== VNOŘENÉ A VNITŘNÍ TŘÍDY ===================================================
//== TESTY A METODA MAIN =======================================================
}

