package lsystem;

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.net.URL;
/**
 * Lindenmayer-System <br>
 * Belegarbeit AlgoDat WS99/SS2000, Aufgabe 8
 * <p>
 * Applet.
 * Funktioniert auch als standalone.
 *
 * @author Christian Semrau<br>
 * Christian.Semrau@student.uni-magdeburg.de<br>
 */
public class LSystemApplet
extends Applet
//extends Panel
/*
Um das Programm in einer IDE als Standalone zu starten, kann es notwendig
sein (bei VisualAge ist es noetig), die Superklasse von Applet nach Panel
zu aendern. Aber auch als Applet-Erbe kann das Programm als Applikation
augerufen werden.
*/
{
	/** der Rechenknecht */
	LSystemThread theThread;
	/** das Control-Panel */
	LSystemControls controls;
	/** die Zeichenflaeche */
	LSystemCanvas canvas;

	/** Applet (false) oder Applikation (true), wird im Konstruktor festgelegt */
	final boolean standalone;

	final static String version = "Lindenmayer-System Applet v1.2, 18.03.2000";
/** Standard-Konstruktor. Wird vom Appletviewer und vom Browser aufgerufen. */
public LSystemApplet() {
	super();
	standalone = false;
}
/**
 * Konstruktor, der festlegt, ob das Programm Applet oder Applikation ist.
 * Wird von main() aufgerufen.
 * @param alone true: Standalone-Applikation
 */
public LSystemApplet(boolean alone) {
	super();
	standalone = alone;
}
/**
 * 
 */
public void destroy() {
//	controls.removeListeners();
	remove(controls);
	remove(canvas);
}
/**
 * Returns information about this applet.
 * @return a string of information about this applet
 */
public String getAppletInfo() {
	return "\n"+
		version+"\n" +
		"Belegarbeit AlgoDat WS99/SS2000, Aufgabe 8\n" +
		"Christian Semrau, http://chsemrau.de";
}
/**
 * Liest die HTML-Parameter und liefert ein LSystem mit diesen Parametern.
 * Wenn keine Regel angegeben ist, wird null geliefert.
 * @return belegLsystem.LSystem
 */
public LSystem getDefault() {
	// Default: keine Regeln festgelegt
	String name = "HTML-Parameter";
	char axiom = 'F';
	String[] regeln = LSystem.defRegeln();
	float winkel = 0, startwinkel = 0;
	int tiefe = 1;
	String s;

	// das Axiom muss genau ein Buchstabe sein
	s = getParameter2("Axiom");
	if (s!=null && s.length()==1 && Utils.isLatinLetter(s.charAt(0)))
		axiom = s.charAt(0);

	// die 26 moeglichen Regeln einlesen
	boolean regelDa = false;
	for (int i=0; i<26; i++){
		s = getParameter2("Regel"+Utils.letter(i));
		if (s!=null){
			// auf Fehler wird im Konstruktor des LSystems geprueft
			regeln[i] = s;
			regelDa = true;
		}
	}
	// wenn keine Regel angegeben ist, wird kein LSystem geliefert
	if (!regelDa)
		return null;

	// Drehwinkel einlesen
	s = getParameter2("Winkel");
	if (s!=null){
		try{
			winkel = new Float(s).floatValue();
		}catch(NumberFormatException e){
		}
	}
	// Startwinkel einlesen
	s = getParameter2("StartWinkel");
	if (s!=null){
		try{
			startwinkel = new Float(s).floatValue();
		}catch(NumberFormatException e){
		}
	}
	// Rekursionstiefe einlesen
	s = getParameter2("Tiefe");
	if (s!=null){
		try{
			tiefe = new Integer(s).intValue();
		}catch(NumberFormatException e){
		}
	}

	// LSystem anlegen aus den ermittelten Paramtern
	LSystem l = new LSystem(name, axiom, regeln, winkel, tiefe, startwinkel);
	return l;
}
/**
 * Liefert die DocumentBase, wenn das Programm als Applet ausgefuehrt wird,
 * oder null, wenn es als Standalone-Applikation ausgefuehrt wird.
 */
public URL getDocumentBase2() {
	return (!standalone && (Object)this instanceof Applet)
		? (((Applet)(Object)this).getDocumentBase()) : null;
/*
Wenn standalone false ist und this von Applet abgeleitet ist,
dann wird getDocumentBase() aufgerufen, nachdem this in ein Applet gecastet
wurde. Ein direkter Cast (Applet)this ist dabei nicht moeglich, wenn this
nicht von Applet abgeleitet ist (sondern z.B. von Panel).
*/
}
/**
 * Liefert den Applet-Parameter, wenn das Programm als Applet ausgefuehrt wird,
 * oder null, wenn es als Standalone-Applikation ausgefuehrt wird.
 */
public String getParameter2(String p) {
	return (!standalone && (Object)this instanceof Applet)
		? (((Applet)(Object)this).getParameter(p)) : null;
/* siehe getDocumentBase2 */
}
/**
 * Returns parameters defined by this applet.
 * @return an array of descriptions of the receiver's parameters
 */
public java.lang.String[][] getParameterInfo() {
	String[][] info = {
		{"Axiom", "char", "der Startausdruck (A bis Z)"},
		{"RegelA", "String", "RegelA bis RegelZ geben die Produktionsregeln"+
			" fuer A bis Z an"},
		{"Winkel", "float", "Drehwinkel (in Grad)"},
		{"Tiefe", "int", "Rekursionstiefe"},
		{"StartWinkel", "float", "anfaenglicher Winkel (in Grad)"}
	};
	return info;
}
/**
 * Liefert die gewuenschte Groesse des Applets, fuer den Aufruf als standalone.
 * @return java.awt.Dimension
 */
public Dimension getPreferredSize() {
	return new Dimension(760, 400);
}
/**
 * Initialisiert das Applet.
 */
public void init() {
	// Info auf die Java-Konsole schreiben
	System.out.println(getAppletInfo());

	// Kontrollen anlegen
	controls = new LSystemControls(this);

	// Zeichenflaeche anlegen
	canvas = new LSystemCanvas();

	// Komponenten einfuegen
	setLayout(new BorderLayout());
//	add("North",controls);
	add("West",controls);
	add("Center",canvas);
}
/**
 * 
 * @param args java.lang.String[]
 */
public static void main(String args[]) {
	final Frame frame = new Frame("LSystemApplet");
	final LSystemApplet app = new LSystemApplet(true);
	frame.addWindowListener(new WindowAdapter(){
		public void windowClosing(WindowEvent e){
			app.stop();
			frame.setVisible(false);
			app.destroy();
			System.exit(0);
		}
	});
	frame.add(app);
	app.init();

	frame.pack();
	// setzt das Applet auf seine gewuenschte Groesse,
	// verwendet dabei getPreferredSize()

	frame.setVisible(true);
	app.start();
}
/**
 * Startet das Applet.
 * Laedt die HTML-Parameter und startet den Thread.
 */
public void start() {
	LSystem L = getDefault();
	if (L!=null){
		// "HTML-Parameter" in die LSystem-Liste eintragen
		controls.replaceLSystem("default", L);
		controls.select("default", L.getName());
	}else{
		controls.selectFirst();
	}

	// Startbild anzeigen
	canvas.setStartImage(
		version+", Christian Semrau",
		controls.couldReadFile ? "" : 
		"Konnte die Ini-Datei nicht lesen (s. Java-Konsole)"
	);
}
/**
 * Startet einen neuen Thread, der LS zur Berechnung verwendet.
 */
public void startThread(LSystem LS) {
	if (theThread != null){
		// alten Thread beenden
		theThread.stop();
	}
	// neuen Thread starten
	theThread = new LSystemThread(LS, canvas);
}
/**
 * Stoppt das Applet.
 * Terminates the thread and leaves it for garbage collection.
 */
public void stop() {
	if (theThread != null){
		theThread.stop();
		theThread = null;
	}
}
/**
 * Stoppt den aktuellen LSystemThread und stellt das alte Bild wieder her.
 */
public void stopThread() {
	if (theThread != null){
		if (!theThread.died){
			// wenn der Thread noch nicht fertig war, dann stoppen
			// und Bild wiederherstellen
			theThread.stop();
			canvas.setImage(canvas.oldImg);
		}
		theThread = null;
	}
}
}