import theater.*;


/**
 * Die Klasse stellt eine Repraesentation des (unsichtbaren) Spielers dar.
 *
 * @author Dietrich Boles (Universitaet Oldenburg)
 * @version 1.0 (01.10.2009)
 *
 */
public class Koordinator extends Actor {
    private int naechsteFigur = Figur.KREUZ;
    private int[][] spielfeld = new int[3][3];

    // Default-Konstruktor (muss implementiert werden!)
    public Koordinator() {
        super(); // nicht loeschen!

        // weitere Initialisierungen
        setVisible(false);
        init();
    }

    // Copy-Konstruktor (muss implementiert werden!)
    public Koordinator(Koordinator actor) {
        super(actor); // nicht loeschen!

        // weitere Initialisierungen
        setVisible(false);
        this.naechsteFigur = actor.naechsteFigur;

        for (int r = 0; r < 3; r++) {
            for (int s = 0; s < 3; s++) {
                spielfeld[r][s] = actor.spielfeld[r][s];
            }
        }
    }

    @Description("Spielzug ausführen. Fehler bei ungültigem Spielzug.")
    public void ziehen(Spielzug zug) throws UngueltigerSpielzugException {
        ueberpruefeSpielzug(zug);
        setzen(zug);
    }

    @Description("<html>Auf den Spielzug eines Menschen (Mausklick auf entsprechende Kachel) warten." +
    "<br>Parameter ist die Spielfigur, die am Zug ist (Kreuz = 1, Kreis = 2)." +
    "<br>Fehler bei ungültiger Figur.</html>")
    public Spielzug warten(int figur) throws UngueltigerSpielzugException {
        ueberpruefeAufruf(figur);

        String fig = "Kreuz: ";

        if (figur == Figur.KREIS) {
            fig = "Kreis: ";
        }

        Info info = new Info(fig + "Bitte Feld anklicken!");
        getStage()
            .add(info, getStage().getNumberOfColumns() / 2,
            getStage().getNumberOfRows() / 2);

        Spielzug zug = ((Spielfeld) getStage()).warteAufKlick(figur);
        getStage().remove(info);
        setzen(zug);

        return zug;
    }

    // interne Methoden
    @Invisible
    void init() {
        this.naechsteFigur = Figur.KREUZ; // Kreuz beginnt immer

        for (int r = 0; r < 3; r++) {
            for (int s = 0; s < 3; s++) {
                spielfeld[r][s] = Figur.KEINE;
            }
        }
    }

    @Invisible
    private void setzen(Spielzug zug) {
        spielfeld[zug.reihe][zug.spalte] = zug.figur;

        if (naechsteFigur == Figur.KREUZ) {
            naechsteFigur = Figur.KREIS;
        } else {
            naechsteFigur = Figur.KREUZ;
        }

        switch (zug.figur) {
        case Figur.KREIS:
            getStage().add(new Kreis(), zug.spalte, zug.reihe);

            break;

        case Figur.KREUZ:
            getStage().add(new Kreuz(), zug.spalte, zug.reihe);

            break;
        }
    }

    @Invisible
    private void ueberpruefeSpielzug(Spielzug zug)
        throws UngueltigerSpielzugException {
        if (zug == null) {
            throw new UngueltigerSpielzugException("Spielzug == null");
        }

        ueberpruefeAufruf(zug.figur);

        if ((zug.spalte < 0) || (zug.spalte > 2) || (zug.reihe < 0) ||
                (zug.reihe > 2)) {
            throw new UngueltigerSpielzugException(
                "Reihen und Spaltenangaben müssen zwischen 0 und 2 liegen");
        }

        if (spielfeld[zug.reihe][zug.spalte] != Figur.KEINE) {
            throw new UngueltigerSpielzugException("Das Feld in der Reihe " +
                zug.reihe + " und der Spalte " + zug.spalte +
                " ist bereits belegt.");
        }
    }

    @Invisible
    private void ueberpruefeAufruf(int figur)
        throws UngueltigerSpielzugException {
        if (!((figur == Figur.KREIS) || (figur == Figur.KREUZ))) {
            throw new UngueltigerSpielzugException(
                "zu ziehende Figur muss KREIS oder KREUZ sein");
        }

        if (figur != naechsteFigur) {
            String fig = "KREUZ";

            if (naechsteFigur == Figur.KREIS) {
                fig = "KREIS";
            }

            throw new UngueltigerSpielzugException(fig + " ist am Zug");
        }

        if (alleFelderBelegt()) {
            throw new UngueltigerSpielzugException(
                "Das Spiel ist bereits beendet. Alle Felder sind belegt.");
        }

        if (hat3erReihe(Figur.KREUZ)) {
            throw new UngueltigerSpielzugException(
                "Das Spiel ist bereits beendet. KREUZ hat eine 3er Reihe.");
        }

        if (hat3erReihe(Figur.KREIS)) {
            throw new UngueltigerSpielzugException(
                "Das Spiel ist bereits beendet. KREIS hat eine 3er Reihe.");
        }
    }

    @Invisible
    private boolean alleFelderBelegt() {
        for (int r = 0; r < 3; r++) {
            for (int s = 0; s < 3; s++) {
                if (spielfeld[r][s] == Figur.KEINE) {
                    return false;
                }
            }
        }

        return true;
    }

    @Invisible
    private boolean hat3erReihe(int figur) {
        // Reihen überprüfen
        for (int r = 0; r < 3; r++) {
            int anzahl = 0;

            for (int s = 0; s < 3; s++) {
                if (spielfeld[r][s] == figur) {
                    anzahl++;
                }
            }

            if (anzahl == 3) {
                return true;
            }
        }

        // Spalten überprüfen
        for (int s = 0; s < 3; s++) {
            int anzahl = 0;

            for (int r = 0; r < 3; r++) {
                if (spielfeld[r][s] == figur) {
                    anzahl++;
                }
            }

            if (anzahl == 3) {
                return true;
            }
        }

        // Diagonalen überprüfen
        return ((spielfeld[0][0] == figur) && (spielfeld[1][1] == figur) &&
        (spielfeld[2][2] == figur)) ||
        ((spielfeld[0][2] == figur) && (spielfeld[1][1] == figur) &&
        (spielfeld[2][0] == figur));
    }

    @Invisible
    boolean ueberpruefeMenschZug(Spielzug zug) {
        return spielfeld[zug.reihe][zug.spalte] == Figur.KEINE;
    }
}
