//package igel;

import java.awt.*;
import java.awt.event.*;


/**
*@author (c) 2002,2004,2006,2008 Horst Rettberg
*@version 1.2 vom 12.3.2008
*Eine Klasse zum Zeichnen der turtle-Grafik. Die turtle bewegt sich über die Zeichenfläche und zeichnet dabei ggf. ihren Weg.
*Grafik im mathematischen Koordinatensystem mit einfachen relativen (Turtle Grafik) und absoluten Zeichenbefehlen.
*Ursprung in der Klasse "Turtle", (C) Alfred Hermes & Barbara Leipolz-Schumacher (http://www.zitadelle.juel.nw.schule.de/if/java).
*Koordinatengrafik entnommen aus Grafik2002 von Ulrich Hirsch (Oldenburg-Kolleg) und Norbert Winzeler (Herbartgymnasium).
*in Anlehnung an eine Pascal-Unit des Herbartgymnasiums Oldenburg (Grafik94). Abgeändert von Norbert Winzeler im März 2001, Januar 2002, Oktober 2002.
*Die Turtle kann sichtbar und unsichtbar gemacht werden. Wenn die Turtle sichtbar ist, kann eine Verzögerungszeit für die Turtle-Aktionen eingestellt werden.
*Eine Verzoegerung kann auch bei unsichtbarer Turtle abgerufen werden.
*/
public class Igel {
  protected double posX;
  protected double posY;
  protected double winkel;
  protected Color farbe = Color.black;
  protected Color tfarbe = Color.red;
  protected Color hfarbe;
  protected Component c;
  protected double urX;
  protected double urY;
  protected boolean stiftUnten = true;
  protected boolean turtlesichtbar = false;
  protected boolean xorMode = false;
  protected boolean verzoegerung = false;
  protected Graphics g;
  protected int schlafzeit = 500;

  public Igel(Component comp) {
    this(comp, 0, 0, 0);
  }

  /**
  *Initialisiert die Turtle und übergibt die Bildschirmkoordinaten an das Turtle-Koordinatensystem.
  *@param comp ist die Komponente auf dem die turtle malen soll, ein Canvas, Panel, Frame oder Applet.
  *@param x die Anfangsposition der turtle waagerecht (Bildschirm: 0 ist linker Rand).
  *@param y die Anfangsposition der turtle senkrecht (Bildschirm: 0 ist oberer Rand).
  *@param richtung der Anfangswinkel der turtle. 0 zeigt nach rechts.
  *Es wird auf einem mathematischen Koordinatensystem gezeichnet, dh positive y-Werte zeigen nach oben und positive Winkel drehen nach links.
  *x und y definieren den Koordinatenursprung.
  */
  public Igel(Component comp, double x, double y, double richtung) {
    posX = 0;
    posY = 0;
    winkel = richtung;
    urX = x;
    urY = y;
    c = comp;
    g = c.getGraphics();
    hfarbe = c.getBackground();
  }

  ////////// 2008 hinzugefügt ////////////////////

  /**
  *Setzt den XOR-Modus.
  *Zeichnungen werden mit der Hintergrundfarbe xor-verknüpft => Zeichnen und löschen im Wechsel möglich
  *@see Igel#setPaintMode
  *@see Igel#getXORMode
  */
  public void setXORMode() {
    xorMode = true;
    g.setXORMode(hfarbe);
  }

  /**
  *Setzt den Paint-Modus.
  *Zeichnungen werden nicht mit der Hintergrundfarbe xor-verknüpft => nur Zeichnen
  *@see Igel#setXORMode
  *@see Igel#getXORMode
  */
  public void setPaintMode() {
    xorMode = false;
    g.setPaintMode();
  }

  /**
  *Liest den XOR-Modus.
  *True :Zeichnungen werden mit der Hintergrundfarbe xor-verknüpft => Zeichnen und löschen im Wechsel möglich
  *false :Zeichnungen werden nicht mit der Hintergrundfarbe xor-verknüpft => nur Zeichnen
  *@see Igel#setPaintMode
  *@see Igel#getXORMode
  */
  public boolean getXORMode() {
    return xorMode;
  }

  //////////aus Grafik 2002////////////////////

  /**
  *Setzt eine Punkt an der angegebenen Stelle.
  *Die aktuelle Turtle-Position wird nicht verändert.
  *Keine sichtbare Turtle, keine Verzögerung, kein Einfluss von stiftAuf/stiftAb.
  *@param x ist die X-Koordinate.
  *@param y ist die Y-Koordinate.
  *@see Igel#strecke
  */
  public void punkt(double x, double y) {
    strecke(x, y, x, y);
  }

  /**
  *Zeichnet einen Kreis mit Radius r um die angegebene Stelle als Mittelpunkt.
  *Die aktuelle Turtle-Position wird nicht verändert.
  *Keine sichtbare Turtle, keine Verzögerung, kein Einfluss von stiftAuf/stiftAb.
  *@param x ist die X-Koordinate des Mittelpunkts.
  *@param y ist die Y-Koordinate des Mittelpunkts.
  *@param r ist der Radius.
  *@see Igel#fuelleKreis
  */
  public void kreis(double x, double y, double r) {
    // Kreis an der Position (x/y) mit Radius r
    int r0 = (int) (r + 0.5);
    g.setColor(farbe);

    if (stiftUnten) {
      g.drawOval(relX(x) - r0, relY(y) - r0, 2 * r0, 2 * r0);
    }
  }

  /**
  *Zeichnet einen Kreis mit Radius r um die aktuelle Position der Turtle als Mittelpunkt.
  *Die aktuelle Turtle-Position wird nicht verändert.
  *Keine sichtbare Turtle, keine Verzögerung, kein Einfluss von stiftAuf/stiftAb.
  *@param r ist der Radius.
  *@see Igel#fuelleKreis
  */
  public void kreis(double r) {
    // Kreis an der aktuellen Position mit Radius r
    kreis(posX, posY, r);
  }

  /**
  *Zeichnet eine Strecke.
  *Die aktuelle Turtle-Position wird nicht verändert.
  *Keine sichtbare Turtle, keine Verzögerung, kein Einfluss von stiftAuf/stiftAb.
  *@param x1 ist die X-Koordinate des Anfangspunktes.
  *@param y1 ist die Y-Koordinate des Anfangspunktes.
  *@param x2 ist die X-Koordinate des Endpunktes.
  *@param y2 ist die Y-Koordinate des Endpunktes.
  *@see Igel#punkt
  *@see Igel#springeZu
  *@see Igel#zeichneBis
  *@see Igel#geheZu
  *@see Igel#vor
  */
  public void strecke(double x1, double y1, double x2, double y2) {
    g.setColor(farbe);
    g.drawLine(relX(x1), relY(y1), relX(x2), relY(y2));
  }

  /**
  *Zeichnet eine Strecke von der aktuellen Position bis zur angegebenen Position.
  *Die aktuelle Turtle-Position wird nicht verändert.
  *Keine sichtbare Turtle, keine Verzögerung, kein Einfluss von stiftAuf/stiftAb.
  *@param neuX ist die X-Koordinate des Endpunktes.
  *@param neuY ist die Y-Koordinate des Endpunktes.
  *@see Igel#springeZu
  *@see Igel#strecke
  */
  public void zeichneBis(double neuX, double neuY) {
    strecke(posX, posY, neuX, neuY);
    posX = neuX;
    posY = neuY;
  }

  /**
  *Setzt die neue Turtleposition ohne zu zeichnen.
  *Keine sichtbare Turtle, keine Verzögerung, kein Einfluss von stiftAuf/stiftAb.
  *@param neuX ist die X-Koordinate der neuen Position.
  *@param neuY ist die Y-Koordinate der neuen Position.
  *@see Igel#zeichneBis
  *@see Igel#strecke
  */
  public void springeZu(double neuX, double neuY) {
    posX = neuX;
    posY = neuY;
  }

  /**
  *Schreibt Text an die angegebene Position (linker oberer Rand des Textes).
  *Die aktuelle Turtle-Position wird nicht verändert.
  *Keine sichtbare Turtle, keine Verzögerung, kein Einfluss von stiftAuf/stiftAb.
  *@param x ist die X-Koordinate des Textanfangs.
  *@param y ist die Y-Koordinate des Textanfangs.
  *@param text ist der zu schreibende Text.
  */
  public void schreibeText(double x, double y, String text) {
    g.setColor(farbe);
    g.drawString(text, relX(x), relY(y));
  }

  /**
  *Schreibt Text an die aktuelle Position (linker oberer Rand des Textes).
  *Die aktuelle Turtle-Position wird nicht verändert.
  *Keine sichtbare Turtle, keine Verzögerung, kein Einfluss von stiftAuf/stiftAb.
  *@param text ist der zu schreibende Text.
  */
  public void schreibeText(String text) {
    g.setColor(farbe);
    g.drawString(text, relX(posX), relY(posY));
  }

  //////////Ende aus Grafik 2002////////////////////

  /**
  *Bringt die turtle in die Ausgangsposition. Der Winkel bleibt unverändert.
  *Sichtbare Turtle möglich, Verzögerung möglich.
  *@see Igel#loesche
  */
  public void zumAnfang() {
    zeichneIgel();
    posX = 0;
    posY = 0;
    zeichneIgel();
    pause();
  }

  /**
  *Bewegt die turtle in der aktuellen Rchtung vorwärts.
  *Sichtbare Turtle möglich, Verzögerung möglich.
  *@param l die strecke, um die die turtle läuft. Negative Werte lassen sie rückwärts laufen.
  *@see Igel#geheZu
  *@see Igel#zeichneBis
  *@see Igel#springeZu
  *@see Igel#strecke
  */
  public void vor(double l) {
    zeichneIgel();
    g.setColor(farbe);

    double neux = posX + (Math.cos(bogen(winkel)) * l);
    double neuy = posY + (Math.sin(bogen(winkel)) * l);

    if (stiftUnten) {
      strecke(posX, posY, neux, neuy);
    }

    posX = neux;
    posY = neuy;
    zeichneIgel();
    pause();
  }

  /**
  *Dreht die turtle. Sie dreht sich rechts herum.
  *Sichtbare Turtle möglich, Verzögerung möglich.
  *@param grad der Drehwinkel. Negative Werte lassen die turtle rechts herum drehen.
  *@see Igel#inRichtung
  */
  public void drehe(double grad) {
    zeichneIgel();
    winkel += grad;
    zeichneIgel();
    pause();
  }

  /**
  *Malt einen ausgefüllten Kreis.
  *Keine sichtbare Turtle, keine Verzögerung, kein Einfluss von stiftAuf/stiftAb.
  *@param radius der Radius des Kreises.
  *@see Igel#kreis
  */
  public void fuelleKreis(double radius) {
    int r = (int) (radius + 0.5);
    g.setColor(farbe);
    g.fillOval((int) (relX(posX) - radius), (int) (relY(posY) - radius), 2 * r,
               2 * r);
  }

  /**
  *Löscht die gesamte Zeichnung.
  *Keine sichtbare Turtle, keine Verzögerung
  */
  public void loesche() {
    zumAnfang();
    winkel = 0;

    int x = c.getBounds().width;
    int y = c.getBounds().height;
    g.clearRect(0, 0, x, y);
  }

  /**
  *Dreht die turtle in die angegebene Richtung.
  *Sichtbare Turtle möglich, Verzögerung möglich.
  *@param grad der neue Winkel. Null Grad zeigt nach rechts.
  *@see Igel#liesRichtung
  *@see Igel#drehe
  */
  public void inRichtung(double grad) {
    zeichneIgel();
    winkel = grad;
    zeichneIgel();
    pause();
  }

  /**
  * bewegt die turtle zur angegebenen Position.
  *Sichtbare Turtle möglich, Verzögerung möglich.
  *@param neux die neue x-Koordinate.
  *@param neuy die neue y-Koordinate
  *@see Igel#liesX
  *@see Igel#liesY
  *@see Igel#springeZu
  *@see Igel#zeichneBis
  *@see Igel#strecke
  */
  public void geheZu(double neux, double neuy) {
    zeichneIgel();
    g.setColor(farbe);

    if (stiftUnten) {
      strecke(posX, posY, neux, neuy);
    }

    posX = neux;
    posY = neuy;
    zeichneIgel();
    pause();
  }

  /**
  * stellt eine neue Zeichenfarbe ein.
  *@param c die neue Zeichenfarbe.
  *@see Igel#liesFarbe
  *@see Igel#stiftAb
  */
  public void stiftFarbe(Color c) {
    farbe = c;
  }

  /**
  * stellt eine neue Zeichenfarbe im RGB-Format ein.
  *@param r der Rotanteil der neue Zeichenfarbe.
  *@param g der Grünanteil der neue Zeichenfarbe.
  *@param b der Blauanteil der neue Zeichenfarbe.
  *@see Igel#liesFarbe
  */
  public void stiftFarbe(int r, int g, int b) {
    stiftFarbe(new Color(r, g, b));
  }

  /**
  * hebt den Zeichenstift an. es wird nicht mehr gezeichnet, sondern nur bewegt.
  *@see Igel#stiftAb
  */
  public boolean stiftHoch() {
    stiftUnten = false;

    return false;
  }

  /**
  * senkt den Zeichenstift ab. es wird bei der Bewegung gezeichnet.
  *@see Igel#stiftHoch
  */
  public boolean stiftAb() {
    stiftUnten = true;

    return true;
  }

  /**
  * Liefert die aktuelle Richtung.
  *@return die aktuelle Richtung in Grad als double.
  *@see Igel#liesX
  *@see Igel#liesY
  */
  public double liesRichtung() {
    return winkel;
  }

  /**
  * Liefert die aktuelle x-Koordinate.
  *@return die aktuelle x-Koordinate als double.
  *@see Igel#liesRichtung
  *@see Igel#liesY
  */
  public double liesX() {
    return posX;
  }

  /**
  * Liefert die aktuelle y-Koordinate.
  *@return die aktuelle y-Koordinate als double.
  *@see Igel#liesRichtung
  *@see Igel#liesY
  */
  public double liesY() {
    return posY;
  }

  /**
  * Liefert die aktuelle Zeichenfarbe.
  *@return die aktuelle Zeichenfarbe als Colorobjekt.
  *@see Igel#stiftFarbe
  */
  public Color liesFarbe() {
    return (Color) farbe;
  }

  /**
  * Wartet mit dem Programmablauf für eine bestimmte Zeitspanne.
  *@see Igel#setzeSchlafdauer
  *@see Igel#igelSichtbar
  */
  public void pause() {
    if (turtlesichtbar || verzoegerung) {
      schlafe(schlafzeit);
    }
  }

  public void schlafe(int zeit) {
    try {
      Thread.sleep(zeit);
    } catch (Exception e) {
      throw new RuntimeException("Fehler beim Schlafen");
    } finally {
    }
  }

  /**
  * Läßt die turtle sichtbar werden (ein kleines Dreieck).
  * Gleichzeitig wird verzögert gezeichnet.
  *@see Igel#setzeSchlafdauer
  *@see Igel#igelUnsichtbar
  *@see Igel#igelVerzoegerungEin
  *@see Igel#igelVerzoegerungAus
  */
  public void igelSichtbar() {
    //zeichneIgel();
    turtlesichtbar = true;
  }

  /**
  * Läßt die turtle unsichtbar werden.
  * Gleichzeitig wird die Zeichenverzögerung abgeschaltet.
  *@see Igel#igelSichtbar
  *@see Igel#igelVerzoegerungEin
  *@see Igel#igelVerzoegerungAus
  */
  public void igelUnsichtbar() {
    //zeichneIgel();
    turtlesichtbar = false;
  }

  /**
  * Es wird verzögert gezeichnet.
  *@see Igel#setzeSchlafdauer
  *@see Igel#igelSichtbar
  *@see Igel#igelUnsichtbar
  *@see Igel#igelVerzoegerungAus
  */
  public void igelVerzoegerungEin() {
    //zeichneIgel();
    verzoegerung = true;
  }

  /**
  * Läßt die turtle unsichtbar werden.
  * Gleichzeitig wird die Zeichenverzögerung abgeschaltet.
  *@see Igel#igelSichtbar
  *@see Igel#setzeSchlafdauer
  *@see Igel#igelUnsichtbar
  *@see Igel#igelVerzoegerungEin
  */
  public void igelVerzoegerungAus() {
    //zeichneIgel();
    verzoegerung = false;
  }

  /**
  * Stellt die Verzögerungszeit beim Zeichnen ein, wen die turtle sichtbar ist.
  * Kann auch für andere Zwecke verwendet werden
  *@param d die Verzögerungszeit in Milliseunden
  *@see Igel#igelSichtbar
  *@see Igel#pause
  */
  public void setzeSchlafdauer(int d) {
    schlafzeit = d;
  }

  // private Methoden
  private double bogen(double winkel) {
    return (winkel * Math.PI) / 180;
  }

  private void move(double l) {
    double neux = posX + (Math.cos(bogen(winkel)) * l);
    double neuy = posY + (Math.sin(bogen(winkel)) * l);

    if (stiftUnten) {
      strecke(posX, posY, neux, neuy);
    }

    posX = neux;
    posY = neuy;
  }

  private void turn(double grad) {
    winkel += grad;
  }

  private void zeichneIgel() {
    if (turtlesichtbar) {
      Color zfarbe = g.getColor();

      boolean backup = stiftUnten;
      stiftUnten = true;

      double xcopy = posX;
      double ycopy = posY;
      double wcopy = winkel;
      g.setColor(tfarbe);
      g.setXORMode(hfarbe);
      move(8);
      turn(-36.9);
      move(-10);
      turn(-90 + 36.9);
      move(12);
      turn(90 + 36.9);
      move(10);
      turn(-36.9);
      stiftUnten = false;
      move(-8);
      stiftUnten = backup;
      posX = xcopy;
      posY = ycopy;
      winkel = wcopy;
      g.setPaintMode();
      g.setColor(zfarbe);
    }
  }

  //////////aus Grafik 2002////////////////////
  private int relX(double x) { // Umrechnung in Bildschirmkoordinaten
    x = urX + x + 0.5;

    return (int) x;
  }

  private int relY(double y) {
    y = urY - y + 0.5;

    return (int) y;
  }

  //////////Ende aus Grafik 2002////////////////////
} //IGEL.class
