/******************************************************************************
 ** $Id: Spielplatz.java 1171 2017-04-13 23:04:57Z 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.bedienung;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

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

/** Erstellung des Spielplatzes, der den Zettel und das Würfelfeld enthält. */
@SuppressWarnings("serial")
public class Spielplatz extends JPanel implements PropertyChangeListener, ChangeListener {

    /** Hinweistext, wie man ein Turnier beginnt. */
    private static final String KLICKEN = "<html>" + "<p>" + "Turnier beginnen:" + "<ul>" + "<li>Hier klicken</li>"
            + "<li>Menü: Turnier&rarr;Beginnen...</li>" + "</ul>" + "</p>" + "</html>";
    /** Intro-Grafik. */
    static final String INTRO = "Intro";
    /** Intro-Text . */
    static final String TEXT = "Text";
    /** Spielfeld. */
    static final String FELD = "Feld";

    /** Rand der Komponenten. */
    private static final int KOMPONENTENRAND = 2;
    /** Icon für Gewinnerbekanntgabe. */
    private static final ImageIcon KRANZ = Grafik.icon("Kranz.png");
    /** Titel-Font. */
    private static final Font TITEL = new Font("SansSerif", Font.BOLD | Font.ITALIC, 32);
    /** Untertitel-Font. */
    private static final Font UNTERTITEL = new Font("SansSerif", Font.BOLD, 24);

    /** Zettel auf dem die Punkte notiert werden. */
    private final Zettel zettel;
    /** Das Würfelfeld mit Würfelbecher, allen fünf Würfeln und ein Statusfeld. */
    private final Wuerfelfeld wuerfelfeld;

    /**
     * Konstruktor.
     *
     * @param becher
     *            Der Würfelbecher aus dem Spielfeld.
     * @param verfolgung
     *            Das Bedienungsfeld, welches die Verfolgung der Bot-Aktionen zulässt.
     * @param setzen
     *            Das Objekt zum Setzen des Wurfs.
     */
    public Spielplatz(Becher becher, Verfolgung verfolgung, Setzen setzen) {
        super(new CardLayout());
        zettel = new Zettel(setzen);
        wuerfelfeld = new Wuerfelfeld(becher, verfolgung);
        UIManager.addPropertyChangeListener(this);
        /*
         * Mit dieser Hilfskonstruktion kann sich der Zettel vom Platz her gegen das Würfelfeld behaupten. Andernfalls
         * wäre die maximale Größe beschränkt.
         */
        JPanel zettelfeld = new JPanel(new BorderLayout());
        zettelfeld.add(zettel, BorderLayout.CENTER);
        MouseAdapter klick = new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                Spielplatz.this.firePropertyChange("Beginnen", null, getRootPane());
            }
        };
        add(spielfeld(zettelfeld), FELD);
        Intro intro = new Intro();
        intro.addMouseListener(klick);
        intro.setToolTipText(KLICKEN);
        add(intro, INTRO);
        JPanel titelfeld = titelfeld();
        titelfeld.addMouseListener(klick);
        titelfeld.setToolTipText(KLICKEN);
        add(titelfeld, TEXT);
        zeige(Eigenschaften.GLOBAL.aktiv("Intro"));
    }

    /**
     * Realisiert Veränderungen des Look&Feel und Wechsel der angezeigten Karten.
     */
    @Override
    public void propertyChange(PropertyChangeEvent event) {
        if (event.getPropertyName().equals("lookAndFeel")) {
            SwingUtilities.updateComponentTreeUI(this);
        } else if (event.getPropertyName().equals("Karte")) {
            zeige(event.getNewValue().equals("Intro"));
        }
    }

    /**
     * ChangeEvent eingetreten.
     *
     * @param ce
     */
    @Override
    public void stateChanged(ChangeEvent ce) {
        wuerfelfeld.stateChanged(ce);
        zettel.stateChanged(ce);
        if (CEJaFuffy.adressiert(ce, CEAblauf.class)) {
            CEJaFuffy<CEAblauf> cej = CEJaFuffy.ereignisbehaelter(ce);
            switch (cej.ereignis()) {
            case START:
                // Spielfeld zeigen
                ((CardLayout) getLayout()).show(this, Spielplatz.FELD);
                break;
            case RESULTAT:
                zeigeTurnierausgang((Turnier) ce.getSource());
                break;
            default:
            }
        }
    }

    /**
     * Erzeugt ein Spielfeld für ein Turnier, in dem links der Zettel und rechts daneben das Würfelfeld liegen.
     *
     * @param zettelfeld
     *            Zettel
     * @return Spielfeld
     */
    private JPanel spielfeld(JPanel zettelfeld) {
        JPanel spielfeld = new JPanel();
        spielfeld.setLayout(new BoxLayout(spielfeld, BoxLayout.X_AXIS));
        zettelfeld.setBorder(
                BorderFactory.createEmptyBorder(KOMPONENTENRAND, KOMPONENTENRAND, KOMPONENTENRAND, KOMPONENTENRAND));
        spielfeld.add(zettelfeld);
        wuerfelfeld.setBorder(
                BorderFactory.createEmptyBorder(KOMPONENTENRAND, KOMPONENTENRAND, KOMPONENTENRAND, KOMPONENTENRAND));
        spielfeld.add(wuerfelfeld);
        return spielfeld;
    }

    /**
     * Erzeugt das Titelfeld, das als Begrüßung gezeigt wird.
     *
     * @return Titelfeld
     */
    private JPanel titelfeld() {
        JPanel titelfeld = new JPanel();
        titelfeld.setLayout(new BoxLayout(titelfeld, BoxLayout.PAGE_AXIS));
        JLabel titel = new JLabel("JaFuffy!", SwingConstants.CENTER);
        titel.setEnabled(false);
        titel.setFont(TITEL);
        titel.setAlignmentX(CENTER_ALIGNMENT);
        titelfeld.add(titel, BorderLayout.CENTER);
        JLabel untertitel = new JLabel("- Das Würfelspiel -", SwingConstants.CENTER);
        untertitel.setEnabled(false);
        untertitel.setFont(UNTERTITEL);
        untertitel.setAlignmentX(CENTER_ALIGNMENT);
        titelfeld.add(Box.createVerticalGlue());
        titelfeld.add(Box.createVerticalGlue());
        titelfeld.add(titel);
        titelfeld.add(Box.createVerticalGlue());
        titelfeld.add(untertitel);
        titelfeld.add(Box.createVerticalGlue());
        titelfeld.add(Box.createVerticalGlue());
        return titelfeld;
    }

    /**
     * Zeigt die Karte, die gerade dran ist.
     *
     * @param intro
     *            Bestimmt ob die Intro gezeigt werden soll, oder nur der einfache Begrüßungstext.
     */
    private void zeige(boolean intro) {
        ((CardLayout) getLayout()).show(this, intro ? INTRO : TEXT);
    }

    /**
     * Mitteilung über Spielende und Platzbelegung der Spieler aus dem Turnier.
     *
     * @param turnier
     *            Das Turnier, für das eine Mitteilung erfolgt.
     */
    private void zeigeTurnierausgang(Turnier turnier) {

        JPanel rangliste = new JPanel();
        ArrayList<Spieler> spieler = turnier.spieler();

        if (spieler.size() == 1) {
            rangliste.setLayout(new GridLayout(1, 2));
            rangliste.add(new JLabel(spieler.get(0).toString(), SwingConstants.CENTER));
            rangliste.add(new JLabel(spieler.get(0).endsumme() + " Punkte", SwingConstants.CENTER));
        } else {
            Object[] plaetze = spieler.toArray();
            Arrays.sort(plaetze);
            int lowscore = ((Spieler) plaetze[spieler.size() - 1]).endsumme();
            rangliste.setLayout(new GridLayout(0, 3));
            for (int i = spieler.size() - 1, score, rang = 1; i >= 0; i--) {
                score = ((Spieler) plaetze[i]).endsumme();
                if (score < lowscore) {
                    rang++;
                    lowscore = score;
                }
                rangliste.add(new JLabel(rang + ". Platz: "));
                rangliste.add(new JLabel(((Spieler) plaetze[i]).toString()));
                rangliste.add(new JLabel(score + " Punkte", SwingConstants.RIGHT));
            }
        }

        JOptionPane.showMessageDialog(this, rangliste,
                turnier.spielnummer() < turnier.maximalanzahl() || turnier.maximalanzahl() == 0
                        ? "JaFuffy (Resultat " + turnier.spielnummer() + ". Spiel)"
                        : "JaFuffy (Resultat letztes Spiel)",
                JOptionPane.INFORMATION_MESSAGE, KRANZ);

    }

}
