/**
 * ProgrammApplet dient zum vereinfachten Kennenlernen der Java-Programmiersprache.
 * Es bietet einige Methoden, mit denen u.a. Textfelder erstellt und darauf zugegriffen werden kann.
 * @author D. ?
 * @author <a href="http://www.strazny.de>T. Strazny</a>
 * @version 2.0, 03/25/2001
 */

/*
 * modified by T. Strazny on March 15th 2001
 * --> Doc-Comments hinzugefügt
 * --> Kompatibilität zu Java 2.0 hergestellt
 *   -- TextArea.appendText() wurde zu TextArea.append().
 *   -- Java 1.0 Ereignisbehandlung (handleEvent()) durch ActionListener ersetzt.
 *      (Wobei ProgrammApplet selbst ActionListener ist, um nur eine
 *      CLASS-Datei zu haben.)
 *   -- Canvas.size() wurde zu Canvas.getSize()
 *   -- ANMERKUNG ZU DER THREAD-STEUERUNG:
 *        Die Methoden Thread.suspend(), Thread.resume(), Thread.stop() sind
 *        "deprecated"! Da ich leider nicht die Möglichkeit hatte, diese Methoden
 *        zu ersetzen und gleichzeitig die selben Ergebnisse zu erhalten,
 *        habe ich diese Methoden gelassen, wie sie waren.
 */

import java.applet.*;
import java.awt.*;
import java.util.*;
import java.awt.event.*;

public abstract class ProgrammApplet extends Applet implements Runnable, ActionListener {
  Panel oben, links;
  Button ausfuehren, stoppen, pauseWeiter;
  Canvas canvas;
  Checkbox box;
  Thread thread;
  CheckboxGroup cbg;
  Hashtable eingabeFelder;
  
//============================================
  /**
   * Hier müssen Initialisierungen in der abgeleiteten Klasse eingefügt werden.
   * @see #ausfuehren(Graphics)
   */
  public abstract void initialisieren();
  
  /**
   * In der abgeleiteten Klasse müssen Sie hier den Programmcode einfügen.
   * @param g Die übergebene Zeichenfläche des Applets.
   * @see     #initialisieren() 
   */
  public abstract void ausfuehren(Graphics g);  
//============================================
  
  
  /**
   * Fügt dem Applet eine neue TextArea hinzu.
   * @param name Zeichenkette, mit der die neue TextArea identifiziert wird.
   * @see        #appendArea(String, String)
   * @see        #getArea(String)
   * @see        #putArea(String, String)
   * @see        #getInts(String)
   * @see        #getStrings(String)
   */
  public final void addArea(String name) { addArea(name, ""); }

  /**
   * Fügt dem Applet eine neue TextArea hinzu.
   * @param name Zeichenkette, mit der die TextArea identifiziert wird.
   * @param wert Der anfängliche Text in der TextArea.
   * @see        #appendArea(String, String)
   * @see        #getArea(String)
   * @see        #putArea(String, String)
   * @see        #getInts(String)
   * @see        #getStrings(String)
   */
  public final void addArea(String name, String wert) {
    addArea(name, wert, 20, 5);
  }
  
  /**
   * Fügt dem Applet eine neue TextArea hinzu.
   * @param name    Zeichenkette, mit der die neue TextArea identifiziert wird.
   * @param zeilen  Höhe
   * @param spalten Breite
   * @see           #appendArea(String, String)
   * @see           #getArea(String)
   * @see           #putArea(String, String)
   * @see           #getInts(String)
   * @see           #getStrings(String)
   */  
  public final void addArea(String name, int zeilen, int spalten) {
    addArea(name, "", zeilen, spalten);
  }
  
  /**
   * Fügt dem Applet eine neue TextArea hinzu.
   * @param name    Zeichenkette, mit der die neue TextArea identifiziert wird.
   * @param wert    Der anfängliche Text in der TextArea.
   * @param zeilen  Höhe
   * @param spalten Breite
   * @see           #appendArea(String, String)
   * @see           #getArea(String)
   * @see           #putArea(String, String)
   * @see           #getInts(String)
   * @see           #getStrings(String)
   */  
  public final void addArea(String name, String wert, int zeilen, int spalten) {
    Panel p = new Panel();
    p.setLayout(new BorderLayout());
    p.add("North", new Label(name));
    TextArea feld = new TextArea(wert, zeilen, spalten);
    eingabeFelder.put(name, feld);
    p.add("Center", feld);
    links.add(p);
  }

  /**
   * Fügt dem Applet eine neue Checkbox hinzu.
   * @param name Zeichenkette, mit der die neue Checkbox identifiziert wird.
   * @see        #getCheck(String)
   */
  public final void addCheck(String name) {
    addCheck(name, false, false);
  }

  /**
   * Fügt dem Applet eine neue Checkbox hinzu.
   * @param name    Zeichenkette, mit der die neue Checkbox identifiziert wird.
   * @param checked Gibt an, ob die Checkbox bei Erstellung markiert sein soll oder nicht.
   * @see           #getCheck(String)
   */
  public final void addCheck(String name, boolean checked) {
    addCheck(name, false, checked);
  }

  /**
   * Fügt dem Applet einen neuen Radiobutton hinzu.
   * @param name Zeichenkette, mit der der neue Radiobutton identifiziert wird.
   * @see        #getCheck(String)
   */  
  public final void addOpt(String name) {
    addCheck(name, true, false);
  }
        
  /**
   * Fügt dem Applet einen neuen (markierten) Radiobutton hinzu.
   * @param name Zeichenkette, mit der der neue Radiobutton identifiziert wird.
   * @see        #getCheck(String)
   */    
  public final void addOptChoice(String name) {
    addCheck(name, true, true);
  }
        
  /**
   * Fügt dem Applet eine neue Checkbox hinzu.
   * @param name    Zeichenkette, mit der die neue Checkbox identifiziert wird.
   * @param opt     Gibt an, ob die Checkbox ein Radiobutton ist.
   * @param checked Gibt an, ob die Checkbox standartmäßig markiert ist.
   * @see           #getCheck(String)
   */    
  public final void addCheck(String name,boolean opt, boolean checked) {
    if(eingabeFelder.get(name) != null)
      return; // Feld schon belegt;

    oben.add(new Label("", Label.RIGHT));
    if (opt)
      box = new Checkbox(name,cbg,checked);
    else
      box = new Checkbox(name,null,checked);

    eingabeFelder.put(name, box);
    oben.add(box);
  }
  
  /**
   * Fügt dem Applet ein neues TextField hinzu.
   * @param name Zeichenkette, mit der das neue TextField identifiziert wird.
   * @see        #getDouble(String)
   * @see        #getInt(String)
   * @see        #getString(String)
   */
  public final void addFeld(String name) { addFeld(name, ""); }

  /**
   * Fügt dem Applet ein neues TextField hinzu.
   * @param name Zeichenkette, mit der das neue TextField identifiziert wird.
   * @param wert Der anfängliche Text in dem TextField.
   * @see        #getDouble(String)
   * @see        #getInt(String)
   * @see        #getString(String)
   */
  public final void addFeld(String name, String wert) {
    if(eingabeFelder.get(name) != null) 
      return;  // Feld schon belegt;

    oben.add(new Label(name+" ", Label.RIGHT));
    TextField feld = new TextField(wert);
    eingabeFelder.put(name, feld);
    oben.add(feld);
  }

  /**
   * Fügt einer TextArea Text hinzu.
   * @param name Zeichenkette, über die die TextArea angesprochen wird.
   * @param wert Text, der in der TextArea hinten angehängt wird.
   * @see        #getArea(String)
   * @see        #putArea(String, String)
   * @see        #getInts(String)
   * @see        #getStrings(String)
   */
  public final void appendArea(String name, String wert) {      
    TextArea a =(TextArea)(eingabeFelder.get(name));
    a.append(wert);
  }

  /**
   * Ermittelt den Textinhalt einer TextArea.
   * @param name Zeichenkette, über die die TextArea angesprochen wird.
   * @return     Der Inhalt der TextArea.
   * @see        #appendArea(String, String)
   * @see        #putArea(String, String)
   * @see        #getInts(String)
   * @see        #getStrings(String)
   */
  public final String getArea(String feldName) {
    return ((TextArea)(eingabeFelder.get(feldName))).getText();
  }

  /**
   * Ersetzt Textinhalt einer TextArea.
   * @param name Zeichenkette, über die die TextArea angesprochen wird.
   * @param wert Zeichenkette, die den Text der TextArea ersetzen soll.
   * @see        #appendArea(String, String)
   * @see        #getArea(String)
   * @see        #getInts(String)
   * @see        #getStrings(String)
   */
  public final void putArea(String name, String wert) { 
    TextArea a =(TextArea)(eingabeFelder.get(name));
    a.setText(wert);
  }  
  
  /**
   * Ermittelt den Status einer Checkbox.
   * @param name Zeichenkette, über die die Checkbox angesprochen wird.
   * @return     Der Status der Checkbox (markiert, nicht markiert).
   */
  public final boolean getCheck(String feldName) {
    return ((Checkbox)(eingabeFelder.get(feldName))).getState();
  }

  /** 
   * Ermittelt den Zahlenwert des Textes in einem TextField.
   * @param  feldName Der String, mit dem das TextField identifiziert wird.
   * @return          Der Zahlenwert der Eingabe.
   */
  public final double getDouble(String feldName) {
    try {
      return Double.valueOf(getString(feldName)).doubleValue();
    } catch(NumberFormatException e) {
      throw new RuntimeException("Fehleingabe (" + feldName + ")");
    }
  }
  
  /** 
   * Ermittelt den (ganzzahligen) Zahlenwert des Textes in einem TextField.
   * @param  feldName Der String, mit dem das TextField identifiziert wird.
   * @return          Der Zahlenwert der Eingabe.
   */
  public final int getInt(String feldName) {
    try {
      return Integer.parseInt(getString(feldName));
    } catch(NumberFormatException e) {
      throw new RuntimeException("Fehleingabe (" + feldName + ")");
    }
  }

  /** 
   * Ermittelt die Zahlenwerte des Textes in einer TextArea, wobei die einzelnen Zahlen durch Zeileinumbrüche von einander getrennt sind.
   * @param  feldName Der String, mit dem die TextArea identifiziert wird.
   * @return          Die Zahlenwerte der Eingabe.
   * @see             #getArea(String)
   * @see             #appendArea(String, String)
   * @see             #putArea(String, String)
   * @see             #getStrings(String)
   */
  public final int[] getInts(String feldName) {
    String[] strings = getStrings(feldName);
    int[] ints = new int[strings.length];
    try {
      for(int i = 0; i < ints.length; i++)
        ints[i] = Integer.parseInt(strings[i]);
    } catch(NumberFormatException nfe) {
      throw new RuntimeException("Fehleingabe (" + feldName + ")");
    }
    return ints;
  }

  /**
   * Liefert den String, der in das angegebenen Feld eingefügt wurde.
   * @param feldName Die Zeichenkette, mit der das TextField angesprochen wird.
   * @return         Der Text im TextField.
   */
  public final String getString(String feldName) {
    return ((TextField)(eingabeFelder.get(feldName))).getText();
  }

  /** 
   * Ermittelt die Zeilen des Textes in einer TextArea.
   * @param  feldName Der String, mit dem die TextArea identifiziert wird.
   * @return          Die Zeilen der TextArea.
   * @see             #getArea(String)
   * @see             #appendArea(String, String)
   * @see             #putArea(String, String)
   * @see             #getInts(String)
   */
  public final String[] getStrings(String feldName) {
    StringTokenizer st = new StringTokenizer(getArea(feldName), "\n");
    String[] strings = new String[st.countTokens()];
    for(int i = 0; st.hasMoreTokens(); i++) {
      strings[i] = st.nextToken();
      strings[i] = strings[i].trim();
    }
    return strings;
  }
  
  /** 
   * Liefert das entsprechende Graphics-Objekt der Zeichenfläche
   * @return Die Zeichenfläche des Applets.
   */
  public Graphics getGraphics() {
    return canvas.getGraphics();
  }

  /**
   * Liefert die Höhe der Zeichenfläche
   * @return Höhe der Zeichenfläche des Applets in Pixeln.
   */
  public final int getHeight() {
    return canvas.getSize().height;
  }

  /** 
   * Liefert die Breite der Zeichenfläche 
   * @return Breite der Zeichenfläche des Applets in Pixeln.
   */
  public final int getWidth() {
    return canvas.getSize().width;
  }
          
  /** Initialisieren des Applets */
  public final void init() {
    Panel unten   = new Panel();
    oben          = new Panel();
    links         = new Panel();
    canvas        = new Canvas();
    stoppen       = new Button("Stoppen");
    ausfuehren    = new Button("Ausführen");
    pauseWeiter   = new Button("Pause");
    eingabeFelder = new Hashtable();
    cbg           = new CheckboxGroup();
  
    ausfuehren.addActionListener(this);
    stoppen.addActionListener(this);
    pauseWeiter.addActionListener(this);
        
    setLayout(new BorderLayout());
    
    unten.setLayout(new GridLayout(1, 3));
    unten.add(stoppen);
    unten.add(ausfuehren);
    unten.add(pauseWeiter);
    add("South", unten);
    
    oben.setLayout(new GridLayout(0, 4));
    add("North", oben);
    
    links.setLayout(new GridLayout(1, 0));
    add("West", links);
    
    add("Center", canvas);
                
    initialisieren();
  }

  /** Starten des Applets */
  public void run() {
    try {      
      ausfuehren(getGraphics());
    } catch(Exception e) {
      Graphics g = getGraphics();
      g.drawString("Fehler!!", 10, 20);
      g.drawString(e.toString(), 10, 35);
    }
  }
  
  /** Behandelt die Klicks auf die Buttons */
  public void actionPerformed(ActionEvent evt) {
    if(evt.getActionCommand() == ausfuehren.getLabel()) {
      if ((thread != null) && (thread.isAlive()))
        thread.stop();
      thread = new Thread(this);
      pauseWeiter.setLabel("Pause");
      canvas.update(canvas.getGraphics());
      thread.start();
    } else if (evt.getActionCommand() == stoppen.getLabel()) {
      thread.stop();
      pauseWeiter.setLabel("Pause");
    } else if (evt.getActionCommand() == pauseWeiter.getLabel()) {
      if ((thread != null) && (thread.isAlive())) {
        if(pauseWeiter.getLabel() == "Pause") {
          pauseWeiter.setLabel("Weiter");
          thread.suspend();
        } else {
          thread.resume();
          pauseWeiter.setLabel("Pause");
        }
      }
    }
  }
}
