/******************************************************************************
 ** $Id: Wuerfelbild.java 684 2015-01-27 21:56:05Z wmh $
 ** Diese Datei ist Bestandteil der Java-Quelltexte des Würfelspiels JaFuffy.
 ** Lauffähig ab Java 6.
 ******************************************************************************
 ** Copyright (C) Wolfgang Hauck <wolfgang.hauck@3kelvin.de>
 ******************************************************************************
 ** This program is free software: you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License as published by
 ** the Free Software Foundation, either version 3 of the License, or
 ** (at your option) any later version.
 **
 ** This program is distributed in the hope that it will be useful,
 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ** GNU General Public License for more details.
 **
 ** You should have received a copy of the GNU General Public License
 ** along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************
 ** Die aktuellste Version von JaFuffy findet sich im Internet unter
 ** <http://jafuffy.3kelvin.de>.
 **
 ** Kommentare, Fehler oder Erweiterungswünsche bitte per E-Mail senden an
 ** <jafuffy@3kelvin.de>.
 ******************************************************************************/
package jafuffy.bedienung;

import java.awt.BorderLayout;
import java.util.Arrays;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JPanel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import jafuffy.logik.CEAblauf;
import jafuffy.logik.CEJaFuffy;
import jafuffy.logik.Spieler;
import jafuffy.logik.Turnier;
import jafuffy.logik.Wuerfel;

/** Alle Würfel sind innerhalb des Würfelfelds in einer Reihe angeordnet. */
@SuppressWarnings("serial")
class Wuerfelreihe extends JPanel implements ChangeListener {

    /** Halber Mindestabstand zwischen zwei Würfeln. */
    private static final int MINDESTWUERFELABSTAND = 2;
    /** Würfel, die im laufenden Turnier verwendet werden. */
    private Wuerfel[] wuerfel;
    /** Alle Würfeldarstellungen. */
    private final Wuerfelbild[] wuerfelbilder = new Wuerfelbild[Turnier.WUERFEL];

    /** Konstruiert die Würfelreihe. */
    Wuerfelreihe() {
        super(new BorderLayout());
        for (int i = 0; i < Turnier.WUERFEL; i++) {
            wuerfelbilder[i] = new Wuerfelbild(i);
        }
        add(baue(), BorderLayout.CENTER);
    }

    @Override
    public void stateChanged(ChangeEvent ce) {
        if (CEJaFuffy.adressiert(ce, CEAblauf.class)) {
            CEJaFuffy<CEAblauf> cej = CEJaFuffy.ereignisbehaelter(ce);
            Turnier turnier = (Turnier) cej.quelle(Turnier.class);
            switch (cej.ereignis()) {
            case START:
                verwende(turnier.wuerfel());
            case SPIEL:
            case GESETZT:
                akzeptiere(turnier.aktiver().neu());
            case GEWUERFELT:
            case RUECKGAENGIG:
                aktiviere(turnier.aktiver());
                break;
            case VORGESCHLAGEN:
                uebernehme();
                break;
            case PAUSE:
                pausiere();
                break;
            default:
                break;
            }
        }
    }

    /**
     * Aktiviert die Würfelauswahl, so dass Würfel ausgewählt werden können.
     *
     * @param aktiver
     *            Der aktive Spieler, der an Reihe ist.
     */
    private void aktiviere(Spieler aktiver) {
        boolean fertig = aktiver.rest() == 0;
        for (Wuerfelbild wuerfelbild : wuerfelbilder) {
            wuerfelbild.setEnabled(!fertig);
        }
    }

    /**
     * Vorbereitung auf nächsten Spieler, sofern Turnier noch nicht beendet.
     *
     * @param neu
     *            Gibt an, ob Spieler soeben begonnen hat neu zu würfeln.
     */
    private void akzeptiere(boolean neu) {
        for (Wuerfelbild bild : wuerfelbilder) {
            bild.setEnabled(true);
            bild.setSelected(neu);
        }
    }

    /**
     * Baut die Würfelauswahl zusammen.
     *
     * @return Würfelreihe.
     */
    private JPanel baue() {
        JPanel wuerfelauswahl = new JPanel();
        wuerfelauswahl.setLayout(new BoxLayout(wuerfelauswahl, BoxLayout.X_AXIS));
        for (Wuerfelbild bild : wuerfelbilder) {
            wuerfelauswahl.add(Box.createHorizontalGlue());
            wuerfelauswahl.add(Box.createHorizontalStrut(MINDESTWUERFELABSTAND));
            wuerfelauswahl.add(bild);
            wuerfelauswahl.add(Box.createHorizontalStrut(MINDESTWUERFELABSTAND));
        }
        wuerfelauswahl.add(Box.createHorizontalGlue());
        return wuerfelauswahl;
    }

    /** Pausiere, um jegliche Aktionen verhindern. */
    private void pausiere() {
        for (Wuerfelbild bild : wuerfelbilder) {
            bild.setEnabled(false);
            bild.setSelected(false);
        }
    }

    /** Vorschlag zur Würfelauswahl übernehmen. */
    private void uebernehme() {
        for (Wuerfelbild bild : wuerfelbilder) {
            if (bild.isSelected() != bild.modell().vorgeschlagen()) {
                bild.doClick();
            }
        }
    }

    /**
     * Setzt Modelle, wie sie von den Würfelbildern verwendet werden.
     *
     * @param wuerfel
     *            Die zu verwendenden Würfelmodelle.
     */
    private void verwende(Wuerfel[] wuerfel) {
        this.wuerfel = wuerfel;
        for (int w = 0; w < Turnier.WUERFEL; w++) {
            wuerfelbilder[w].setModel(wuerfel[w]);
        }
    }

    /**
     * Klickt alle Würfel mit dem vorgegebenen Auswahlzustand an, um die Klick-Aktion auszuführen.
     *
     * @param ausgewaehlt
     *            Gibt an, ob der die anzuklickenden Würfel ausgewählt sein sollen.
     */
    void klicke(boolean ausgewaehlt) {
        for (Wuerfelbild bild : wuerfelbilder) {
            if (bild.isSelected() == ausgewaehlt) {
                bild.doClick();
            }
        }
    }

    /** @return Gibt ob irgendein Würfel ausgewählt ist. */
    boolean selektiert() {
        boolean selektiert = false;
        for (Wuerfelbild bild : wuerfelbilder) {
            selektiert = selektiert || bild.isSelected();
        }
        return selektiert;
    }

    /** Sortiere Würfel für die Anzeige in der Reihe. */
    void sortiere() {
        Arrays.sort(wuerfel);
        verwende(wuerfel);
    }

    /** @return Gibt an, ob die Würfelreihe der Größe nach sortiert ist. */
    boolean sortiert() {
        boolean sortiert = true;
        for (int w = 0; w < Turnier.WUERFEL - 1; w++) {
            sortiert = sortiert && wuerfel[w].augen() <= wuerfel[w + 1].augen();
        }
        return sortiert;
    }

}
