/******************************************************************************
 ** $Id: Intro.java 739 2015-05-23 16:13:32Z 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.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.util.Random;

import javax.swing.JPanel;
import javax.swing.Timer;

/** Intro-Sequenz (Generierung eines IFS-Bildes oder Schriftzug "JaFuffy"). */
@SuppressWarnings("serial")
class Intro extends JPanel implements ActionListener {

    /** Schriftzug, der als Hintergrund wiederholt ausgegeben wird. */
    private static final String SCHRIFTZUG = "JaFuffy!";
    /** Größe der Schriftart, die für den Schriftzug verwendet wird. */
    private static final int SCHRIFTGROESSE = 18;
    /** Skalierungswert für die Verkleinerung des IFS. */
    private static final int SKALIERUNG = 3;
    /** Basisdateiname für Würfel-Grafiken. */
    private static final String WUERFEL = "Wuerfel";
    /** Anzahl der Würfelseiten. */
    private static final int ANZAHL_WUERFELSEITEN = 6;
    /** Würfelbilder für alle möglichen Augen. */
    private static final BufferedImage[] BILDER = new BufferedImage[ANZAHL_WUERFELSEITEN];
    /** Kantenlänge der quadratischen Würfelbilder. */
    private static final int D;
    /** Anzahl der Würfel für den ersten Iterationsschritt. */
    private static final int ANZAHL_WUERFEL = 5;

    static {
        Image[] images = new Image[ANZAHL_WUERFELSEITEN];
        // Laden der Würfelbilder aus den Ressourcen
        for (int i = 0; i < ANZAHL_WUERFELSEITEN; i++) {
            images[i] = Grafik.bild(WUERFEL + (i + 1) + ".gif");
        }
        // Farbinvertierungsoperator aufsetzen
        RescaleOp invertierung = new RescaleOp(-1f, 255f, null);
        // Bilder erzeugen und invertieren
        for (int i = 0; i < ANZAHL_WUERFELSEITEN; i++) {
            BILDER[i] =
                    new BufferedImage(images[i].getWidth(null), images[i].getHeight(null),
                            BufferedImage.TYPE_INT_RGB);
            BILDER[i].getGraphics().drawImage(images[i], 0, 0, null);
            BILDER[i] = invertierung.filter(BILDER[i], null);
        }
        // Bildgröße merken
        D = BILDER[0].getWidth(null);
    }

    /** Periode der Iterationen. */
    private static final int PERIODE = 3000;
    /** Anzahl der maximalen Iterationen. */
    private static final int ITERATIONEN = 5;

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

    /** Bild für Zeichenfläche. */
    private BufferedImage bild;
    /** Größe der aktuellen Zeichenfläche. */
    private int s;
    /** Abstand zwischen Würfeln variieren. */
    private int faktor;
    /** Muster ("x" oder "+"). */
    private int muster;
    /** Taktgeber für Iterationen. */
    private final Timer timer = new Timer(PERIODE, this);
    /** Zähler (Iterationsstufe). */
    private int zaehler;

    /** Konstruktor. */
    Intro() {
        // Initialisierung bei Veränderung der Fenstergröße
        addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                Intro.this.initialisiereGenerierung();
                Intro.this.starteGenerierung();
            }
        });
        // Timer läuft nur bei sichtbarer Komponente
        addHierarchyListener(new HierarchyListener() {
            @Override
            public void hierarchyChanged(HierarchyEvent e) {
                if (isShowing()) {
                    timer.start();
                } else {
                    timer.stop();
                }
            }
        });
    }

    /**
     * Takt abarbeiten zur Erzeugung des IFS-Bildes (Kopiermechanismus).
     *
     * @param event
     *            Nicht verwendet.
     */
    @Override
    public void actionPerformed(ActionEvent event) {
        if (bild == null) {
            return;
        }
        BufferedImage kopie =
                new BufferedImage(s / SKALIERUNG, s / SKALIERUNG, BufferedImage.TYPE_INT_RGB);
        kopie.getGraphics().drawImage(
                bild.getScaledInstance(s / SKALIERUNG, s / SKALIERUNG, Image.SCALE_SMOOTH), 0,
                0, null);
        Graphics grafik = bild.getGraphics();
        grafik.setColor(getBackground());
        grafik.fillRect(0, 0, s, s);
        for (int i = 0; i < SKALIERUNG; i++) {
            for (int j = 0; j < SKALIERUNG; j++) {
                if (i == SKALIERUNG / 2 && j == SKALIERUNG / 2 || (i + j) % 2 == muster) {
                    grafik.drawImage(kopie, i * s / SKALIERUNG, j * s / SKALIERUNG, null);
                }
            }
        }
        zaehler++;
        if (zaehler >= ITERATIONEN) {
            starteGenerierung();
        }
        repaint();
    }

    /**
     * Update der Zeichenfläche.
     *
     * @param g
     *            Grafikobjekt.
     */
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(getBackground());
        g.fillRect(0, 0, getWidth(), getHeight());
        if (bild != null) {
            g.drawImage(bild, (getWidth() - bild.getWidth()) / 2,
                    (getHeight() - bild.getHeight()) / 2, null);
        }
    }

    /** Initialisiert Seitenlänge, Abstandsfaktor und Bild. */
    private void initialisiereGenerierung() {
        if (getWidth() > getHeight()) {
            s = getHeight();
        } else {
            s = getWidth();
        }
        if (s <= 3 * D / 2) {
            return;
        } else if (s <= 3 * D) {
            faktor = 0;
        } else if (s <= ANZAHL_WUERFELSEITEN * D) {
            faktor = 1;
        } else {
            faktor = 2;
        }
        bild = new BufferedImage(s, s, BufferedImage.TYPE_INT_RGB);
    }

    /** Started IFS-Generierung. */
    private void starteGenerierung() {
        int i;
        int j;
        int[] x = new int[ANZAHL_WUERFEL];
        int[] y = new int[ANZAHL_WUERFEL];
        do {
            for (i = 0; i < ANZAHL_WUERFEL; i++) {
                x[i] = zufall.nextInt(s - D);
                y[i] = zufall.nextInt(s - D);
            }
            abstand: for (i = 0; i < ANZAHL_WUERFEL; i++) {
                for (j = 0; j < i; j++) {
                    if ((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]) <= faktor
                            * D * D) {
                        break abstand;
                    }
                }
            }
        } while (i < ANZAHL_WUERFEL);
        Graphics grafik = bild.getGraphics();
        grafik.setColor(getBackground());
        grafik.fillRect(0, 0, s, s);
        grafik.setColor(getBackground().darker());
        grafik.setFont(new Font("SansSerif", Font.BOLD | Font.ITALIC, SCHRIFTGROESSE));
        Rectangle2D rahmen = grafik.getFontMetrics().getStringBounds(SCHRIFTZUG, grafik);
        int w = bild.getWidth() / (int) (bild.getWidth() / rahmen.getWidth());
        int h = bild.getHeight() / (int) (bild.getHeight() / rahmen.getHeight());
        for (int m = 0; m < bild.getWidth(); m += w) {
            for (int n = h; n < bild.getHeight(); n += h) {
                grafik.drawString(SCHRIFTZUG, m, n);
            }
        }
        for (i = 0; i < ANZAHL_WUERFEL; i++) {
            grafik.drawImage(BILDER[zufall.nextInt(ANZAHL_WUERFELSEITEN)], x[i], y[i], null);
        }
        zaehler = 0;
        muster = zufall.nextInt(2);
        repaint();
    }

}
