import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;

/**
 * Eine Klasse zur Darstellung eines animierten Labyrinths innerhalb eines
 * JPanel
 * @author Ralph Matthes
 * @version 1.0
 */
public class LabyrinthDarstellung extends JPanel {

    Labyrinth labyrinth;
    int pixelzahl;
    int verzoegerung;
    private Warteschlange dieThreads;

    /**
     * setzt die Instanzvariablen und stellt die Größe ein
     * @param labyrinth das dargestellte Labyrinth
     * @param pixelzahl die Pixelzahl eines Kästchens
     * @param verzoegerung die Verzögerung in Millisekunden bei jedem Schritt
     */
    public LabyrinthDarstellung(Labyrinth labyrinth,
				int pixelzahl,
				int verzoegerung) {

	this.labyrinth = labyrinth;
	this.pixelzahl = pixelzahl;
	this.verzoegerung = verzoegerung;
	setPreferredSize(new Dimension(labyrinth.getBreite()*pixelzahl,
				       labyrinth.getHoehe()*pixelzahl));
	dieThreads = new FIFO();
    }

    /**
     * die Aufgabe des Zeichnens wird nach oben und an Labyrinth weitergegeben
     */
    public void paintComponent(Graphics g) {

	super.paintComponent(g);
	Graphics2D g2 = (Graphics2D)g;
	labyrinth.zeichne(g2,pixelzahl);
    }
	
    /**
     * startet die Animation mit Startpunkt und vorgegebener Warteschlange
     * noch zu bearbeitender Punkte
     * @param i  horizontale Koordinate des Startpunkts
     * @param j  vertikale Koordinate des Startpunkts
     * @param schlange vorgegebene Warteschlange, die typischerweise leer ist
     */
    public void start(int i, int j, final Warteschlange schlange) {

	if (!(labyrinth.getEintrag(i,j) == Labyrinth.FREI)) return;
	labyrinth.setBesucht(i,j);
	repaint();
	schlange.in(new Koordinatenpaar(i,j));

	class LabyrinthAblauf extends Thread {

	    //private int nochInSchlange;
	    private boolean weiter;

	    /** setzt die Instanzvariablen */
	    public LabyrinthAblauf() {
		
		//nochInSchlange = 1;
		weiter = true;
	    }

	    /** der Ablauf der Simulation eines "Suchers" */
	    public void run() {
	
		while (!schlange.empty() && weiter){
		    Koordinatenpaar dasAktuelle =
			(Koordinatenpaar)schlange.out();
		    //nochInSchlange--;
		    int i = dasAktuelle.getX();
		    int j = dasAktuelle.getY();
		    behandleKaestchen(i-1,j);
		    behandleKaestchen(i+1,j);
		    behandleKaestchen(i,j-1);
		    behandleKaestchen(i,j+1);
		    if (isInterrupted()) weiter = false;
		}
		// Testausgabe
		//System.out.println(System.currentTimeMillis());
	    }

	    private void behandleKaestchen(int i, int j) {
		
		// Abfrage, ob verzoegerung > 0, da sleep(0) nicht ging
		if (verzoegerung > 0) {
		    try {
			sleep(verzoegerung);
		    } catch(InterruptedException e) {
			weiter = false;
		    }
		}
		

		if (labyrinth.getEintrag(i,j) == Labyrinth.FREI && weiter) {
		    labyrinth.setBesucht(i,j);
		    repaint();
		    schlange.in(new Koordinatenpaar(i,j));
		    //nochInSchlange++;
		}
	    }
	}

	Thread ablauf = new LabyrinthAblauf();
	dieThreads.in(ablauf);
	ablauf.start();
    }

    /** Unterbrechen aller Threads zu diesem Fenster */
    public void abbrechen() {
	while (!dieThreads.empty())
	    ((Thread)(dieThreads.out())).interrupt();
	labyrinth.besuchtNachBelegt();
	repaint();
    }
}
