/******************************************************************************
 ** $Id: Wuerfel.java 1188 2017-04-16 01:00:49Z wmh $
 ** Diese Datei ist Bestandteil der Java-Quelltexte des Würfelspiels JaFuffy.
 ** Lauffähig ab Java 7.
 ******************************************************************************
 ** 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.logik;

import java.io.Serializable;
import java.util.Random;

import javax.swing.ButtonModel;
import javax.swing.JToggleButton.ToggleButtonModel;
import javax.swing.event.ChangeListener;

/** Zustand und Darstellungsmodell des Würfels. */
public class Wuerfel implements Comparable<Wuerfel>, Serializable {

    /** Zur Serialisierung. */
    private static final long serialVersionUID = 6889772262239748227L;

    /** Die Anzahl aller möglichen Augen. */
    public static final int MAXIMALAUGENAUGENZAHL = 6;

    /** Zufallsgenerator. */
    private static final Random ZUFALL = new Random();

    /** Änderungen im Zustand. */
    private transient Aenderungen<CEWuerfel> aenderungen;
    /**
     * Dar Modell zur Darstellung in der Benutzeroberfläche. Als Attribut gewählt um die Serialisierung klein zu halten,
     * ansonsten würden auch Listener gespeichert werden.
     */
    private transient ButtonModel darstellungsmodell;

    /** Augenzahl (von eins bis sechs). */
    private int augen;
    /** Würfel zum erneuten Würfeln vorschlagen? */
    private boolean vorgeschlagen;

    /**
     * Konstruktor.
     *
     * @param augen
     *            Ursprüngliche Augenzahl
     */
    Wuerfel(int augen) {
        this.augen = augen;
    }

    /**
     * @return Augenzahl von eins bis sechs
     */
    public int augen() {
        return augen;
    }

    @Override
    public int compareTo(Wuerfel wuerfel) {
        return Integer.compare(augen(), wuerfel.augen());
    }

    /** @return Darstellungsmodell für die Darstellung des Würfels in der Benutzeroberfläche. */
    @SuppressWarnings("serial")
    public ButtonModel darstellungsmodell() {
        if (darstellungsmodell == null) {
            darstellungsmodell = new ToggleButtonModel() {
                /**
                 * Würfelauswahl mit Geräuscheffekten.
                 *
                 * @param selektiert
                 *            Gibt an, ob der Würfel ausgewählt und damit in den Becher gelegt werden soll.
                 */
                @Override
                public void setSelected(boolean selektiert) {
                    boolean feuern = isSelected() ^ selektiert;
                    super.setSelected(selektiert);
                    if (feuern) {
                        aenderungen.fireStateChanged(selektiert ? CEWuerfel.ANWAHL : CEWuerfel.ABWAHL);
                    }
                }
            };
        }
        return darstellungsmodell;
    }

    /**
     * ChangeListener entfernen.
     *
     * @param changeListener
     *            Zuvor registriertes Beobachtungsobjekt.
     */
    public void entferneChangeListener(ChangeListener changeListener) {
        aenderungen.removeChangeListener(changeListener);
    }

    /**
     * ChangeListener hinzufügen.
     *
     * @param changeListener
     *            Objekt, das auf Änderungsereignisse reagiert.
     */
    public void installiereChangeListener(ChangeListener changeListener) {
        if (aenderungen == null) {
            aenderungen = new Aenderungen<>();
        }
        aenderungen.addChangeListener(changeListener);
    }

    /** @return Zum erneuten Würfeln vorgeschlagen? */
    public boolean vorgeschlagen() {
        return vorgeschlagen;
    }

    /**
     * @param haeufigkeiten
     *            Feld mit allen Augenhäufigkeiten.
     * @return Anzahl der Würfel mit dieser Augenzahl.
     */
    public int vorkommen(int[] haeufigkeiten) {
        return haeufigkeiten[augen - 1];
    }

    /**
     * Würfel zum erneuten Werfen vorschlagen.
     *
     * @param vorschlagen
     *            Gibt an, ob der Würfel zum erneuten Werfen vorgeschlagen ist.
     */
    void setzeVorschlag(boolean vorschlagen) {
        vorgeschlagen = vorschlagen;
    }

    /** Würfel werfen. Ein anstehender Vorschlag wird dann zurückgenommen. */
    void wirf() {
        vorgeschlagen = false;
        augen = ZUFALL.nextInt(MAXIMALAUGENAUGENZAHL) + 1;
        aenderungen.fireStateChanged(CEWuerfel.WURF); // muss vor Abwahl erfolgen
        darstellungsmodell.setSelected(false);
    }

}
