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

import shapes77.geom.IAdaptable;
import shapes77.geom.AMovable;
import shapes77.util.ICopyable;
import shapes77.geom.Position;
import shapes77.util.IColorable;
import shapes77.util.NamedColor;



/*******************************************************************************
 * Instance třídy {@code Line} představují jednoduché čáry
 * zobrazitelné na plátně spravovaném správcem plátna.
 * Čára je určena svými krajními body, přičemž souřadnice počátečního bodu
 * je současně považována za pozici celé instance.
 */
public class Line
     extends AMovable
  implements ICopyable, IAdaptable, IColorable, ICMPaintable
{
//\CC== CLASS CONSTANTS (CONSTANT CLASS/STATIC ATTRIBUTES/FIELDS) ==============

    /** Počáteční barva nakreslené instance v případě,
     *  kdy uživatel žádnou požadovanou barvu nezadá -
     *  pro čáru {@link NamedColor#BLACK}. */
    public static final NamedColor DEFAULT_COLOR = NamedColor.BLACK;



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

    /** Počet vytvořených instancí. */
    private static int count = 0;



//##############################################################################
//\CI== CLASS (STATIC) INITIALIZER (CLASS CONSTRUCTOR) =========================
//\CF== CLASS (STATIC) FACTORY METHODS =========================================
//\CG== CLASS (STATIC) GETTERS AND SETTERS =====================================
//\CM== CLASS (STATIC) REMAINING NON-PRIVATE METHODS ===========================
//\CP== CLASS (STATIC) PRIVATE AND AUXILIARY METHODS ===========================



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

    /** ID instance = pořadí vytvoření dané instance v rámci třídy. */
    private final int ID = ++count;



//\IV== INSTANCE VARIABLES (VARIABLE INSTANCE ATTRIBUTES/FIELDS) ===============

    /** Bodová x-ová souřadnice konce. */
    protected int xEnd;

    /** Bodová y-ová souřadnice konce. */
    protected int yEnd;

    /** Barva instance. */
    private NamedColor color;



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

    /***************************************************************************
     * Připraví novou instanci s implicitním umístěním, rozměry a barvou.
     * Instance bude umístěna v levém horním rohu plátna
     * a bude mít implicitní barvu,
     * Končit bude ve středu plátna.
     */
    public Line()
    {
        this(0, 0, CM.getWidth()  / 2,
                   CM.getHeight() / 2);
    }


    /***************************************************************************
     * Připraví novou instanci se zadanou pozicí a rozměry
     * a implicitní barvou.
     *
     * @param x   Vodorovná (x-ová) souřadnice instance (jejího počátku),
     *            x=0 má levý okraj plátna, souřadnice roste doprava
     * @param y   Svislá (y-ová) souřadnice instance (jejího počátku),
     *            y=0 má horní okraj plátna, souřadnice roste dolů
     * @param xEnd  x-ová souřadnice koncového bodu instance
     * @param yEnd  y-ová souřadnice koncového bodu instance
     */
    public Line(int x, int y, int xEnd, int yEnd)
    {
        this(x, y, xEnd, yEnd, DEFAULT_COLOR);
    }


    /***************************************************************************
     * Připraví instanci se zadanou pozicí a velikostí a implicitní barvou.
     * Pozice instance je definována pozicí jejího počátečního bodu.
     *
     * @param start Pozice počátečního bodu
     * @param end   Pozice koncového bodu
     */
    public Line(Position start, Position end)
    {
        this(start.x(), start.y(), end.x(), end.y(), DEFAULT_COLOR);
    }


    /***************************************************************************
     * Připraví instanci se zadanou pozicí, velikostí a barvou.
     * Pozice instance je definována pozicí jejího počátečního bodu.
     *
     * @param start Pozice počátečního bodu
     * @param end   Pozice koncového bodu
     * @param color Barva instance
     */
    public Line(Position start, Position end, NamedColor color)
    {
        this(start.x(), start.y(), end.x(), end.y(), color);
    }


    /***************************************************************************
     * Připraví novou instanci se zadanou pozicí, rozměry a barvou.
     *
     * @param x     Vodorovná (x-ová) souřadnice instance (jejího počátku),
     *              x=0 má levý okraj plátna, souřadnice roste doprava
     * @param y     Svislá (y-ová) souřadnice instance (jejího počátku),
     *              y=0 má horní okraj plátna, souřadnice roste dolů
     * @param xEnd  x-ová souřadnice koncového bodu instance
     * @param yEnd  y-ová souřadnice koncového bodu instance
     * @param color Barva vytvářené instance
     */
    public Line(int x, int y, int xEnd, int yEnd, NamedColor color)
    {
        super(x, y);
        this.xEnd  = xEnd;
        this.yEnd  = yEnd;
        this.color = color;
    }



//\IA== INSTANCE ABSTRACT METHODS ==============================================
//\IG== INSTANCE GETTERS AND SETTERS ===========================================

    /***************************************************************************
     * Vrátí aktuální barvu instance.
     *
     * @return Aktuální barva instance
     */
    @Override
    public NamedColor getColor()
    {
        return color;
    }


    /***************************************************************************
     * Nastaví novou barvu instance.
     *
     * @param color  Požadovaná nová barva
     */
    @Override
    public void setColor(NamedColor color)
    {
        this.color = color;
        CM.repaint();
    }


    /***************************************************************************
     * Přemístí instanci na zadanou pozici.
     * Pozice instance je přitom definována jako pozice
     * levého horního rohu opsaného obdélníku.
     *
     * @param x  Nově nastavovaná vodorovná (x-ová) souřadnice instance,
     *           x=0 má levý okraj plátna, souřadnice roste doprava
     * @param y  Nově nastavovaná svislá (y-ová) souřadnice instance,
     *           y=0 má horní okraj plátna, souřadnice roste dolů
     */
    @Override
    public void setPosition(int x, int y)
    {
        CM.changeTogether(() -> {
            xEnd   = x  +  (xEnd - getX());
            yEnd   = y  +  (yEnd - getY());
            super.setPosition(x, y);
        });
    }


    /***************************************************************************
     * Vrátí x-ovou souřadnici koncového bodu instance.
     *
     * @return  Aktuální vodorovná (x-ová) souřadnice koncového bodu instance,
     *          x=0 má levý okraj plátna, souřadnice roste doprava
     */
    public int getEndX()
    {
        return xEnd;
    }


    /***************************************************************************
     * Vrátí y-ovou souřadnici koncového bodu instance.
     *
     * @return  Aktuální svislá (y-ová) souřadnice koncového bodu instance,
     *          y=0 má horní okraj plátna, souřadnice roste dolů
     */
     public int getEndY()
     {
         return yEnd;
     }


    /***************************************************************************
     * Vrátí pozici koncového bodu instance.
     *
     * @return  Instance třídy {@code Position} s aktuální pozicí koncového bodu
     */
     public Position getEndPosition()
     {
         return new Position(getEndX(), getEndY());
     }


    /***************************************************************************
     * Nastaví pozici koncového bodu instance.
     *
     * @param endPosition  Pozice koncového bodu.
     */
     public void setEndPosition(Position endPosition)
     {
         setEndPosition(endPosition.x(), endPosition.y());
     }


    /***************************************************************************
     * Nastaví pozici koncového bodu instance.
     *
     * @param xEnd  Vodorovná souřadnice koncového bodu.
     * @param yEnd  Svislá souřadnice koncového bodu.
     */
     public void setEndPosition(int xEnd, int yEnd)
     {
         this.xEnd = xEnd;
         this.yEnd = yEnd;
         CM.repaint();
     }



//\IM== INSTANCE REMAINING NON-PRIVATE METHODS =================================

    /***************************************************************************
     * Přesune instanci tak, aby spojila zadané body.
     *
     * @param xStart  Vodorovná (x-ová) souřadnice instance počátku
     * @param yStart  Svislá (y-ová) souřadnice instance počátku
     * @param xEnd    x-ová souřadnice koncového bodu
     * @param yEnd    y-ová souřadnice koncového bodu
     */
     public void connect(int xStart, int yStart, int xEnd, int yEnd)
    {
        CM.changeTogether(() -> {
            setPosition(xStart, yStart);
            this.xEnd   = xEnd;
            this.yEnd   = yEnd;
        });
    }


    /***************************************************************************
     * Vrátí kopii daného tvaru,
     * tj. stejný tvar, stejně velký, stejně umístěný a se stejnou barvou.
     *
     * @return Požadovaná kopie
     */
    @Override
    public Line copy()
    {
        return new Line(getX(), getY(), xEnd, yEnd, color);
    }


    /***************************************************************************
     * Vrací charakteristiky dané instance do jejího podpisu.
     *
     * @return String s charakteristikami dané instance
     */
    @Override
    public String forToString()
    {
        return super.forToString()
             + ",xEnd=" + xEnd + ", yEnd=" + yEnd
             + ", color=" + color;
    }


    /***************************************************************************
     * Prostřednictvím zadaného kreslítka vykreslí obraz instance na plátno.
     *
     * @param painter Kreslítko schopné nakreslit instanci
     */
    @Override
    public void paint(Painter painter)
    {
        painter.drawLine(getX(), getY(), xEnd, yEnd, getColor());
    }


    /***************************************************************************
     * Změní pozici a rozměr instance v závislosti na zadané změně kroku plátna.
     *
     * @param oldStep  Původní velikost kroku.
     * @param newStep  Nově nastavená velikost kroku.
     */
    @Override
     public void stepChanged(int oldStep, int newStep)
     {
         CM.changeTogether(() -> {
            double ratio = (double)newStep / oldStep;
            int x = (int)(getX() * ratio);
            int y = (int)(getY() * ratio);
            super.setPosition(x, y);
            xEnd  = (int)(xEnd * ratio);
            yEnd  = (int)(yEnd * ratio);
         });
     }



//\IP== INSTANCE PRIVATE AND AUXILIARY METHODS =================================



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