import theater.*;


/**
 * Repraesentation von objektorientierten Hamstern im Java-Hamster-Modell
 *
 * @author Dietrich Boles (Universitaet Oldenburg)
 * @version 2.0 (07.06.2008)
 *
 */
public class Hamster extends Actor {
    /**
     * Blickrichtung Nord
     */
    public final static int NORD = 0;

    /**
     * Blickrichtung Ost
     */
    public final static int OST = 1;

    /**
     * Blickrichtung Sued
     */
    public final static int SUED = 2;

    /**
     * Blickrichtung West
     */
    public final static int WEST = 3;
    private int blickrichtung;
    private int koernerImMaul;

    /**
     * Konstruktor zum Erzeugen eines neuen Hamsters mit der angegebenen
     * Blickrichtung und Anzahl an Koernern im Maul
     *
     * @param blickrichtung
     *            Blickrichtung des Hamsters
     * @param anzahlKoerner
     *            Anzahl an Koernern im Maul
     */
    public Hamster(int blickrichtung, int anzahlKoerner) {
        this.setImage("hamster.png");
        this.setBlickrichtung(blickrichtung);
        this.koernerImMaul = anzahlKoerner;
    }

    /**
     * Konstruktor zum Erzeugen eines neuen Hamsters mit Blickrichtung OST und
     * keinem Korn im Maul
     */
    public Hamster() {
        this(Hamster.OST, 0);
    }

    // Copy-Konstruktor
    private Hamster(Hamster h) {
        this(h.blickrichtung, h.koernerImMaul);
    }

    /**
     * Tue was
     */
    public void run() {
        if (kornDa()) {
            nimm();
        }

        if (vornFrei()) {
            vor();
        } else {
            linksUm();
        }
    }

    /**
     * liefert genau dann true, wenn sich in Blickrichtung vor dem aufgerufenen
     * Hamster keine Mauer befindet (wenn sich der Hamster in Blickrichtung am
     * Rand des Territoriums befindet, wird false geliefert)
     *
     * @return true, wenn sich in Blickrichtung vor dem aufgerufenen Hamster
     *         keine Mauer befindet; sonst false
     */
    public boolean vornFrei() {
        int col = this.getColumn();
        int row = this.getRow();

        switch (this.blickrichtung) {
        case SUED:
            row++;

            break;

        case OST:
            col++;

            break;

        case NORD:
            row--;

            break;

        case WEST:
            col--;

            break;
        }

        if ((col >= this.getStage().getNumberOfColumns()) ||
                (row >= this.getStage().getNumberOfRows()) || (col < 0) ||
                (row < 0)) {
            return false;
        }

        return this.getStage().getComponentsAt(col, row, Mauer.class).size() == 0;
    }

    /**
     * liefert genau dann true, wenn auf der Kachel, auf der sich der
     * aufgerufene Hamster gerade befindet, mindestens ein Korn liegt
     *
     * @return true, wenn auf der Kachel, auf der sich der aufgerufene Hamster
     *         gerade befindet, mindestens ein Korn liegt; sonst false
     */
    public boolean kornDa() {
        return this.getStage()
                   .getComponentsAt(this.getColumn(), this.getRow(), Korn.class)
                   .size() > 0;
    }

    /**
     * liefert genau dann true, wenn der aufgerufene Hamster keine Koerner im
     * Maul hat
     *
     * @return true, wenn der aufgerufene Hamster keine Koerner im Maul hat;
     *         sonst false
     */
    public boolean maulLeer() {
        return this.koernerImMaul == 0;
    }

    /**
     * Der aufgerufene Hamster springt auf die in Blickrichtung vor ihm liegende
     * Kachel.
     *
     * @throws MauerDaException
     *             wird geworfen, wenn die Kachel in Blickrichtung vor dem
     *             Hamster durch eine Mauer blockiert ist oder der Hamster in
     *             Blickrichtung am Rand des Territoriums steht
     */
    public void vor() throws MauerDaException {
        if (!this.vornFrei()) {
            throw new MauerDaException(this, this.getRow(), this.getColumn());
        }

        switch (this.blickrichtung) {
        case SUED:
            this.setLocation(this.getColumn(), this.getRow() + 1);

            break;

        case OST:
            this.setLocation(this.getColumn() + 1, this.getRow());

            break;

        case NORD:
            this.setLocation(this.getColumn(), this.getRow() - 1);

            break;

        case WEST:
            this.setLocation(this.getColumn() - 1, this.getRow());

            break;
        }
    }

    /**
     * Der aufgerufene Hamster dreht sich linksum.
     */
    public void linksUm() {
        switch (this.blickrichtung) {
        case SUED:
            this.setBlickrichtung(Hamster.OST);

            break;

        case OST:
            this.setBlickrichtung(Hamster.NORD);

            break;

        case NORD:
            this.setBlickrichtung(Hamster.WEST);

            break;

        case WEST:
            this.setBlickrichtung(Hamster.SUED);

            break;
        }
    }

    /**
     * Der aufgerufene Hamster frisst ein Korn auf der Kachel, auf der er sich
     * gerade befindet.
     *
     * @throws KachelLeerException
     *             wird geworfen, wenn auf der Kachel, auf der sich der Hamster
     *             gerade befindet, kein Korn liegt
     */
    public void nimm() throws KachelLeerException {
        if (!this.kornDa()) {
            throw new KachelLeerException(this, this.getRow(), this.getColumn());
        }

        this.koernerImMaul++;

        Korn korn = (Korn) this.getStage()
                               .getComponentsAt(this.getColumn(),
                this.getRow(), Korn.class).get(0);
        korn.inkAnzahl(-1);
    }

    /**
     * Der aufgerufene Hamster legt ein Korn auf der Kachel ab, auf der er sich
     * gerade befindet.
     *
     * @throws MaulLeerException
     *             wird geworfen, wenn der Hamster keine Koerner im Maul hat
     */
    public void gib() throws MaulLeerException {
        if (this.maulLeer()) {
            throw new MaulLeerException(this);
        }

        this.koernerImMaul--;
        this.getStage().add(new Korn(), this.getColumn(), this.getRow());
    }

    /**
     * liefert die Reihe der Kachel des Territoriums, auf der sich der
     * aufgerufene Hamster gerade befindet
     *
     * @return die Reihe der Kachel des Territoriums, auf der sich der
     *         aufgerufene Hamster gerade befindet
     */
    public int getReihe() {
        return this.getRow();
    }

    /**
     * liefert die Spalte der Kachel des Territoriums, auf der sich der
     * aufgerufene Hamster gerade befindet
     *
     * @return die Spalte der Kachel des Territoriums, auf der sich der
     *         aufgerufene Hamster gerade befindet
     */
    public int getSpalte() {
        return this.getColumn();
    }

    /**
     * liefert die Blickrichtung, in die der aufgerufene Hamster gerade schaut
     * (die gelieferten Werte entsprechen den obigen Konstanten)
     *
     * @return die Blickrichtung, in die der aufgerufene Hamster gerade schaut
     */
    public int getBlickrichtung() {
        return this.blickrichtung;
    }

    /**
     * liefert die Anzahl der Koerner, die der aufgerufene Hamster gerade im
     * Maul hat
     *
     * @return die Anzahl der Koerner, die der aufgerufene Hamster gerade im
     *         Maul hat
     */
    public int getAnzahlKoerner() {
        return this.koernerImMaul;
    }

    /**
     * liefert die Gesamtzahl an existierenden Hamstern im Territorium
     *
     * @return die Gesamtzahl an existierenden Hamstern im Territorium
     */
    public int getAnzahlHamster() {
        return this.getStage().getComponents(Hamster.class).size();
    }

    // Blickrichtung setzen
    private void setBlickrichtung(int richtung) {
        this.blickrichtung = richtung;

        switch (this.blickrichtung) {
        case SUED:
            this.setRotation(90);

            break;

        case OST:
            this.setRotation(0);

            break;

        case NORD:
            this.setRotation(270);

            break;

        case WEST:
            this.setRotation(180);

            break;

        default:
            break;
        }
    }

    // wird aufgerufen, wenn der Hamster in das Territorium platziert wird
    public void addedToStage(Stage stage) {
        // Hamster kann nicht auf Mauer platziert werden
        if (this.getStage()
                    .getComponentsAt(this.getColumn(), this.getRow(),
                    Mauer.class).size() > 0) {
            this.getStage().remove(this);

            return;
        }

        this.setZCoordinate(1);
    }

    // nur wenn auf der Kachel keine Mauer steht
    public void setLocation(int col, int row) {
        if (this.getStage().getComponentsAt(col, row, Mauer.class).size() == 0) {
            super.setLocation(col, row);
        }
    }
}
