import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JRadioButton;
import javax.swing.ButtonGroup;
import javax.swing.border.TitledBorder;
import javax.swing.border.EtchedBorder;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;


/**
 * eine Klasse für das Fenster, in dem die gesamte Simulation gesteuert wird
 * und auch abläuft 
 * @author Ralph Matthes
 * @version 1.0
 */
public class LabyrinthGUI extends JFrame {

    static final int LABBREITE = 60;
    static final int LABHOEHE = 60;
    private static final int PIXELZAHL = 7;
    private static final int VERZOEGERUNG = 1;

    private int labhoehe, labbreite;
    private int pixelzahl;
    private int verzoegerung;
    private Labyrinth labyrinth, kopie;

    /**
     * erzeugt ein zufälliges Labyrinth, kopiert dieses, stellt beide in
     * Teilfenstern dar und installiert Schaltflächen mit "Listenern"
     */
    public LabyrinthGUI() {
	
	setTitle("Breitensuche versus Tiefensuche");
	labbreite = LABBREITE;
	labhoehe = LABHOEHE;
	pixelzahl = PIXELZAHL;
	verzoegerung = VERZOEGERUNG;
	labyrinth = new Labyrinth(labbreite, labhoehe);
	labyrinth.initialisiere();
	kopie = labyrinth.kopie();

	final LabyrinthDarstellung labyrinthFenster1 =
	    new LabyrinthDarstellung(labyrinth, pixelzahl, verzoegerung);
	final LabyrinthDarstellung labyrinthFenster2 =
	    new LabyrinthDarstellung(kopie, pixelzahl, verzoegerung); 

	/* Startwerte für die Animation */

	class Mausbeobachter extends MouseAdapter {
	    /**
	     * als Reaktion auf ein Drücken der linken Maustaste werden
	     * beide Labyrinthe mit demselben Startpunkt animiert, wenn
	     * er in dem angewählten Labyrinth frei war
	     */
	    public void mousePressed(MouseEvent ereignis) {

		int i = (int)(ereignis.getX()/pixelzahl);
		int j = (int)(ereignis.getY()/pixelzahl);

		if (0<=i && i<labbreite && 0<=j && j<labhoehe &&
		    ((ereignis.getSource() == labyrinthFenster1 &&
		      labyrinth.getEintrag(i,j) == Labyrinth.FREI) ||
		     (ereignis.getSource() == labyrinthFenster2 &&
		      kopie.getEintrag(i,j) == Labyrinth.FREI))) {

		    labyrinthFenster1.start(i, j, new FIFO());
		    labyrinthFenster2.start(i, j, new LIFO());
		}
	    }
	}

	Mausbeobachter beobachter = new Mausbeobachter();
	labyrinthFenster1.addMouseListener(beobachter);
	labyrinthFenster2.addMouseListener(beobachter);
	JPanel beide = new JPanel();

	// Folgende Zeile ist überflüssig, denn FlowLayout ist das
	// Standard-Layout für Objekte von JPanel
	beide.setLayout(new FlowLayout()); 

	beide.add(labyrinthFenster1);
	beide.add(labyrinthFenster2);

	getContentPane().add(beide, BorderLayout.CENTER);

	/* Geschwindigkeit der Animation */

	final JRadioButton rasendKnopf = new JRadioButton("rasend");
	final JRadioButton schnellKnopf = new JRadioButton("schnell");
	schnellKnopf.setSelected(true);
	final JRadioButton moderatKnopf = new JRadioButton("moderat");
	final JRadioButton langsamKnopf = new JRadioButton("langsam");

	// die Knöpfe müssen einander deaktivieren
	ButtonGroup tempoGruppe = new ButtonGroup();
	tempoGruppe.add(rasendKnopf);
	tempoGruppe.add(schnellKnopf);
	tempoGruppe.add(moderatKnopf);
	tempoGruppe.add(langsamKnopf);
	
	class TempoBeobachter implements ActionListener {
	    /**
	     * Abhängig vom gedrückten Knopf wird die Verzögerungszeit
	     * eingestellt.
	     */
	    public void actionPerformed(ActionEvent ereignis) {
		if (rasendKnopf.isSelected()) verzoegerung = 0;
		else if (schnellKnopf.isSelected()) verzoegerung = 1;
		else if (moderatKnopf.isSelected()) verzoegerung = 3;
		else if (langsamKnopf.isSelected()) verzoegerung = 8;
		labyrinthFenster1.verzoegerung = verzoegerung;
		labyrinthFenster2.verzoegerung = verzoegerung;
	    }
	}

	ActionListener tempoBeobachter = new TempoBeobachter();
	rasendKnopf.addActionListener(tempoBeobachter);
	schnellKnopf.addActionListener(tempoBeobachter);
	moderatKnopf.addActionListener(tempoBeobachter);
	langsamKnopf.addActionListener(tempoBeobachter);

	JPanel tempoKnoepfe = new JPanel();
	tempoKnoepfe.add(rasendKnopf);
	tempoKnoepfe.add(schnellKnopf);
	tempoKnoepfe.add(moderatKnopf);
	tempoKnoepfe.add(langsamKnopf);
	tempoKnoepfe.setBorder
	    (new TitledBorder (new EtchedBorder(), "Tempo"));
	getContentPane().add(tempoKnoepfe, BorderLayout.NORTH);

	/* Größe der Animationsfenster */
	final JButton groesserKnopf = new JButton("groesser");
	final JButton kleinerKnopf = new JButton("kleiner");

	class GroessenBeobachter implements ActionListener {
	    /**
	     * vergrößere bzw. verkleinere die Zahl der Pixel eines
	     * Kästchens um 1 (und lasse keine negativen Werte zu)
	     */
	    public void actionPerformed(ActionEvent ereignis) {
		if (ereignis.getSource() == groesserKnopf) {
		    pixelzahl++;
		} else if (pixelzahl > 0){
		    pixelzahl--;
		}
		labyrinthFenster1.pixelzahl = pixelzahl;
		labyrinthFenster2.pixelzahl = pixelzahl;
		
		labyrinthFenster1.setPreferredSize
		    (new Dimension(labbreite*pixelzahl, labhoehe*pixelzahl));
		labyrinthFenster2.setPreferredSize
		    (new Dimension(labbreite*pixelzahl, labhoehe*pixelzahl));
		
		// Größe aller Komponenten neu berechnen
		// Das ist pack() für das Objekt der äußeren Klasse! 
		pack();

		repaint();
	    }
	}

	ActionListener groessenBeobachter = new GroessenBeobachter();
	groesserKnopf.addActionListener(groessenBeobachter);
	kleinerKnopf.addActionListener(groessenBeobachter);


	/* Animations-Threads abbrechen */

	JButton abbrechenKnopf = new JButton("abbrechen");

	class AbbrechenBeobachter implements ActionListener {
	    /**
	     * Abbruch aller Threads in den beiden Teilfenstern
	     */
	    public void actionPerformed(ActionEvent ereignis) {
		
		labyrinthFenster1.abbrechen();
		labyrinthFenster2.abbrechen();
		}
	}

	ActionListener abbrechenBeobachter = new AbbrechenBeobachter();
	abbrechenKnopf.addActionListener(abbrechenBeobachter);

	/* neues Labyrinth herstellen */

	JButton neuKnopf = new JButton("neu");

	class NeuBeobachter implements ActionListener {
	    /**
	     * erzeugt die Labyrinthe neu
	     */
	    public void actionPerformed(ActionEvent ereignis) {
		
		labyrinth = new Labyrinth(labbreite, labhoehe);
		labyrinth.initialisiere();
		kopie = labyrinth.kopie();
		labyrinthFenster1.labyrinth = labyrinth;
		labyrinthFenster2.labyrinth = kopie;
		repaint();
		}
	}

	ActionListener neuBeobachter = new NeuBeobachter();
	neuKnopf.addActionListener(neuBeobachter);

	JPanel untererBereich = new JPanel();
	untererBereich.add(groesserKnopf);
	untererBereich.add(kleinerKnopf);
	untererBereich.add(abbrechenKnopf);
	untererBereich.add(neuKnopf);
	getContentPane().add(untererBereich, BorderLayout.SOUTH);

	// Fensterabmessungen ausrechnen
	pack();
    }
}
