/******************************************************************************
 ** $Id: Zettel.java 741 2015-05-26 20:51:29Z 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 jafuffy.logik.CEAblauf;
import jafuffy.logik.CEJaFuffy;
import jafuffy.logik.CEWuerfel;
import jafuffy.logik.Punkte;
import jafuffy.logik.Tabzeile;
import jafuffy.logik.Turnier;
import jafuffy.logik.Wuerfel;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ContainerAdapter;
import java.awt.event.ContainerEvent;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * Auf dem Zettel werden die Punktstände notiert. Zugehöriges Modell in Klasse "Punkte",
 * durchgereicht an Darstellung "Tabelle".
 */
@SuppressWarnings("serial")
class Zettel extends JScrollPane implements ChangeListener {

    /** Darstellung des Zeilenkopfs für Punkteinträge. */
    private class Zeilenkopf extends JLabel {

        /** Abstand zwischen Zeilenkopfdeckel und Inhalt. */
        private static final int DECKELABSTAND = 4;
        /** Abstand zwischen Zeilenkopfseite und Inhalt. */
        private static final int SEITENABSTAND = 2;

        /** Konstruktion. */
        Zeilenkopf() {
            setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEtchedBorder(),
                    BorderFactory.createEmptyBorder(SEITENABSTAND, DECKELABSTAND,
                            SEITENABSTAND, DECKELABSTAND)));
            setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
            faerbe();
        }

        @Override
        public void updateUI() {
            super.updateUI();
            faerbe();
        }

        /** Färbt den Zeilenkopf ein. */
        protected void faerbe() {
            setForeground(Color.DARK_GRAY);
        }
    }

    /** Darstellung des Zeilenkopfs für Endsumme. */
    private class ZeilenkopfEnde extends Zeilenkopf {
        @Override
        protected void faerbe() {
            setBackground(Zettel.this.getBackground().darker());
            setForeground(Color.BLACK);
        }
    }

    /** Darstellung des Zeilenkopfs für Zwischensummen. */
    private class ZeilenkopfZwischen extends Zeilenkopf {
        @Override
        protected void faerbe() {
            Color bg1 = Zettel.this.getBackground();
            Color bg2 = bg1.darker();
            Color neu =
                    new Color((bg1.getRed() + bg2.getRed()) / 2,
                            (bg1.getGreen() + bg2.getGreen()) / 2,
                            (bg1.getBlue() + bg2.getBlue()) / 2);
            setBackground(neu);
            setForeground(Color.BLACK);
        }
    }

    /** Grafiken für Würfelchen. */
    static final ImageIcon[] WUERFEL = new ImageIcon[Wuerfel.AUGEN];
    static {
        for (int i = 0; i <= Turnier.WUERFEL; i++) {
            WUERFEL[i] = Grafik.icon("Wuerfelchen" + (i + 1) + ".gif");
        }
    }

    static {
        for (int i = 0; i <= Turnier.WUERFEL; i++) {
            WUERFEL[i] = Grafik.icon("Wuerfelchen" + (i + 1) + ".gif");
        }
    }

    /** Zeilenköpfe. */
    private final JPanel zeilenkoepfe;
    /** Passende Auswahl. */
    private Auswahl auswahl;
    /** Tabellenhöhe, ermittelt aus Zeilenköpfen. */
    private int hoehe;

    /** Konstruktor. */
    Zettel() {
        setCorner(UPPER_LEFT_CORNER, erzeugeEcke());
        zeilenkoepfe = erzeugeZeilenkoepfe();
        setzeIcons();
        setRowHeaderView(zeilenkoepfe);
        synchronisiereZeilenhoehen();
    }

    @Override
    public void stateChanged(ChangeEvent ce) {
        Tabelle tabelle = (Tabelle) getViewport().getView();
        if (CEJaFuffy.adressiert(ce, CEAblauf.class)) {
            switch (CEJaFuffy.<CEAblauf> ereignis(ce)) {
            case START:
                Turnier turnier = (Turnier) ce.getSource();
                auswahl = turnier.auswahl();
                getViewport().setView(new Tabelle(turnier.punkte(), auswahl));
                break;
            case GEWUERFELT:
                auswahl.gewuerfelt();
                break;
            case PAUSE:
                ((Punkte) tabelle.getModel()).auswaehlbar(false);
                break;
            case GESETZT:
            case RUECKGAENGIG:
            case RESULTAT:
                ((Punkte) tabelle.getModel()).auswaehlbar(true);
                break;
            case VORSCHLAGEN:
                auswahl.cancelCellEditing();
                tabelle.stateChanged(ce);
                break;
            default:
                break;
            }
        } else if (CEJaFuffy.adressiert(ce, CEWuerfel.class)) {
            if (tabelle != null) {
                tabelle.stateChanged(ce);
            }
        }
    }

    /** Aktualisiert die gewünschte Größe der Punktetabelle. */
    private void aktualisiereTabellengroesse() {
        Tabelle tabelle = (Tabelle) getViewport().getView();
        int breite = tabelle.breite();
        hoehe = zeilenkoepfe.getPreferredSize().height;
        tabelle.setPreferredScrollableViewportSize(new Dimension(breite, hoehe));
    }

    /**
     * Aktualisiert die Zeilenhöhen der Punktetabelle, so dass sie mit der tatsächlichen
     * Tabellengröße übereinstimmen.
     */
    private void aktualisiereZeilenhoehe() {
        Tabelle tabelle = (Tabelle) getViewport().getView();
        if (tabelle != null) {
            for (int zeile = 0; zeile < tabelle.getRowCount(); zeile++) {
                tabelle.setRowHeight(zeile, zeilenkoepfe.getComponent(zeile).getHeight());
            }
        }
    }

    /**
     * @return Ecke.
     */
    private JLabel erzeugeEcke() {
        JLabel ecke = new JLabel("JaFuffy");
        ecke.setHorizontalAlignment(SwingConstants.CENTER);
        ecke.setToolTipText("Felderläuterungen siehe Hilfethemen");
        ecke.setBackground(Color.GRAY.darker());
        ecke.setForeground(Color.WHITE);
        ecke.setOpaque(true);
        ecke.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 2));
        return ecke;
    }

    /**
     * @return Zeilenköpfe.
     */
    private JPanel erzeugeZeilenkoepfe() {
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        for (Tabzeile z : Tabzeile.values()) {
            Zeilenkopf zeilenkopf;
            switch (z) {
            case GESAMT:
            case OSUMME:
            case USUMME:
                zeilenkopf = new ZeilenkopfZwischen();
                break;
            case ESUMME:
                zeilenkopf = new ZeilenkopfEnde();
                break;
            default:
                zeilenkopf = new Zeilenkopf();
            }
            zeilenkopf.setText(z.bezeichnung());
            zeilenkopf.setToolTipText(z.beschreibung());
            zeilenkopf.setFont(zeilenkopf.getFont().deriveFont(Font.BOLD));
            zeilenkopf.setOpaque(true);
            panel.add(zeilenkopf);
        }
        return panel;
    }

    /**
     * Setzt Icons der oberen Einträge.
     */
    private void setzeIcons() {
        for (Tabzeile z : Tabzeile.OBEN) {
            int ind = z.ordinal();
            Zeilenkopf zeilenkopf = (Zeilenkopf) zeilenkoepfe.getComponent(ind);
            zeilenkopf.setHorizontalTextPosition(SwingConstants.LEADING);
            zeilenkopf.setIcon(WUERFEL[ind]);
        }
    }

    /**
     * Sorgt für die Synchronisation der Zeilenhöhen der Punktetabellenzeilen mit der
     * Tabellengröße.
     */
    private void synchronisiereZeilenhoehen() {
        getViewport().addContainerListener(new ContainerAdapter() {
            @Override
            public void componentAdded(ContainerEvent event) {
                aktualisiereTabellengroesse();
                aktualisiereZeilenhoehe();
            }
        });
        getViewport().addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent event) {
                aktualisiereZeilenhoehe();
            }
        });
    }
}
