/*
 *
 */

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.net.*;
import java.applet.*;
import java.lang.Object;
import java.lang.Object.*;
import java.lang.Math;

/**
 */
public
class zahnradschablone extends Applet implements MouseListener {
    /**
     * Double Buffering des Zeichenbildes um flackern zu vermeiden
     */
     private Image dbImage;
     private Graphics dbg;

    /**
     * Zustandsvariablen
     */
    public Image blattimg; // Zeichenblatt 
    public Graphics blatt; //Zeichenblatt
    int rgk = 180;  //Radius grosser Kreis
    int rkk = 108;
    int rzp = 84; // Radius des Zeichenpunktes
    int zgk = 96; // Zähne des grossen Kreises
    int zkk = 63; // Zähne des kleinen Kreises
    int zoffset = 0; //Offset beim Start in Zähnen
    double aoffset = 0; //Offsetwinkel
    int steps = 36; // Anzahl der Schritte zum Zeichnen eines Kreises
    int rep = 12; // Anzahl der Wiederholungen
    int repcount = 0; // Rundenzähler
    int stepcount = 0; // Stepzähler
    int curx = 0; //aktuelle Position x
    int cury = 0; //aktuelle Postition y
    int curmpx = 0; //aktueller Mittelpunkt der beweglichen Scheibe
    int curmpy = 0; //aktueller Mittelpunkt der bewegl. Scheibe
    int nextx = 0; //neue Position x
    int nexty = 0; //neue Position y
    int midx = 200; // Mittelpunkt x
    int midy = 200; // Mittelpunkt y
    int show=1; //Zeige Schablone und infos an(1) oder aus(0)
    
    /**
     * Farben
     */
    Color cols[] = {Color.blue,Color.green,new Color(255,0,0)};
    int curcol = 0; //aktuelle Farbe
    int colxpos = 340; //Obere Ecke der Farbpalette x
    int colypos = 40; //Obere Ecke der Farbpalette y

    //Prozeduren für Berechnungen
    public static int ggT(int a, int b){
      // verwendet wird der erweiterte Euklidsche Algorithmus
      if(a==b||b==0) return a;
      else return ggT(b,a%b);
    }
    public static int kgV(int a, int b){
      // verwendet wird der Satz ggT(a,b) * kgV(a,b) = a*b
      return (a*b)/ggT(a,b);
    }
    
    
    /**
     * Initialize the applet. 
     */
    public void init() {
	//Zeichenblatt erstellen
	blattimg = createImage(midx+rgk,midy+rgk);
	blatt = blattimg.getGraphics();
	//Blatt leeren
	blatt.setColor(Color.white);
	blatt.fillRect(0,0,this.getSize().width,this.getSize().height);

	myinit();
	addMouseListener(this);
    }

    public void myinit() {
	// Größen des Applets auslesen
	//int x = (int) (getSize().width);
	//int y = (int) (getSize().height);

	//Startwerte festsetzen
	aoffset=zoffset*2*Math.PI/zgk;
	curx = (int)(midx+(rgk-rkk+rzp)*Math.sin(aoffset));
	cury = (int)(midy-(rgk-rkk+rzp)*Math.cos(aoffset));
	curmpx = (int)(midx+(rgk-rkk)*Math.sin(aoffset));
	curmpy = (int)(midy-(rgk-rkk)*Math.cos(aoffset));
	repcount=0;   //Zeichenrundenzähler
	stepcount=0;  //Schrittzähler pro Runde
	steps=(int)(1150*Math.exp(-0.067*zkk)+20);
	repaint();
    }

    public void setvalues(int irkk,int irzp, int izgk, int izkk, int izoffset) {
	//Methode zum erhalt von Infos aus der Webseite
	if (0<irkk && irkk<100) {
		rkk = (int) (irkk*rgk/100);
	} else {
		rkk = (int) (0.8*rgk);
	}
	if (0<irzp && irzp<100) {
		rzp = (int) (irzp*rkk/100);
	} else {
		rkk = (int) (0.8*rkk);
	}
	if (izgk<99) {
		zgk=izgk;
	} else {
		zgk=96;
	}
	if (0<izkk && izkk <= zgk) {
		zkk=izkk;
	} else {
		zkk=(int) (0.6*izgk);
	}
	if (0<izoffset && izoffset < zgk) {
		zoffset=izoffset;
	} else {
		zoffset=0;
	}
	myinit();
    }

    public int getdelay() {
	return Math.max(1,(int)(300/steps));
    }
    public int getsteps() {
      //Bestimmt die Anzahl der benötigten Schritte für eine vollständige 
      //geschlossene Darstellung der Kurve (abhängig von den Zähnen der beiden
      //Kreise
      int vielf=kgV(zgk,zkk);
      int rnd=vielf/zgk;
      return (steps*rnd);
    }

    public void toggleshow() {
      //Anzeige von Schablone und Infos ein und ausschalten
      if (show==1) { 
	show=0; 
      } else {
	show=1;
      }
      repaint();
    }

    public void drawnextline() {
	//geht beim Zeichnen einen Schritt weiter
	//Zunächst auf Mittelpunkt des kleinen Kreises setzen 
	//(dreht sich im Urzeigersinn)
	double phi=0; //Winkel um den der Mittelpunkt aus der 12 Uhr lage
	              //herausgewandert ist.
	stepcount++;
	phi=(stepcount)*2*Math.PI/steps;
	curmpx=(int)(midx+(rgk-rkk)*Math.sin(phi+aoffset));
	curmpy=(int)(midy-(rgk-rkk)*Math.cos(phi+aoffset));
	//dann die Drehung des kleinen Rades aufaddieren 
	//dreht gegen den Uhrzeigersinn
	double theta=0; //Winkel um den das kleine Rad aus der Radiuslage 
	                //herausgedreht ist
	double alpha=0; //Winkel um den das kleine Rad aus der 12 Uhr lage
	                //herausgedreht ist. alpha=theta-phi
        double z=(repcount*steps+stepcount)*zgk/steps; //am äusseren Rad zurückgelegte
	                //Zahnradstrecke
	theta = z*2*Math.PI/zkk;
	//alpha = theta-phi;
	alpha=(repcount*steps+stepcount)*(zgk-zkk)*2*Math.PI/(steps*zkk);
	nextx=(int)(curmpx-rzp*Math.sin(alpha-aoffset));
	nexty=(int)(curmpy-rzp*Math.cos(alpha-aoffset));
	blatt.setColor(cols[curcol]);
	blatt.drawLine(curx,cury,nextx,nexty);
	if(stepcount==steps) {
	  //eine Runde vollständig
	  stepcount=0;
	  repcount++;
	}
	curx=nextx;
	cury=nexty;
    }

    public void destroy() {
        removeMouseListener(this);
    }

    /**
     * Paint it.
     */
    public void paint(Graphics g) {
	Dimension d = getSize();
	g.setColor(Color.white);
	g.fillRect(0,0,340,340);
	g.drawImage(blattimg,0,0,this);
	if (show==1) {
          g.setColor(Color.black);
	  /*//for debugging
	  g.drawString("curx "+curx+" cury "+cury,0,38);
	  g.drawString("curmpx "+curmpx+" curmpy "+curmpy,0,60);
	  g.drawString("steps "+steps+" stepcount "+stepcount,0,80);//*/
	  g.drawString("rkk:"+(rkk*100/rgk)+" rzp:"+(rzp*100/rkk)+" zgk:"+zgk+" zkk:"+zkk+" zoffset:"+zoffset,0,12);
	  //Schablone zeichnen
	  g.setColor(Color.black);
	  g.drawOval(midx-rgk,midy-rgk,2*rgk,2*rgk);
	  g.setColor(Color.red);
	  g.drawOval(curmpx-rkk,curmpy-rkk,2*rkk,2*rkk);
	  g.drawLine(curmpx,curmpy,curx,cury);
	  //Schalter
	  g.fillRect(colxpos,10,60,20);//wipe-Button
	  g.setColor(Color.black);
	  g.drawString("Wipe",colxpos+20,23);
	  //Farbwahl
	  g.setColor(cols[0]);
	  g.fillRect(colxpos,colypos,20,20);
	  g.setColor(cols[1]);
	  g.fillRect(colxpos+20,colypos,20,20);
	  g.setColor(cols[2]);
	  g.fillRect(colxpos+40,colypos,20,20);
	  g.setColor(cols[curcol]);
	  g.fillRect(colxpos,colypos+20,60,20);
	}
    }

    /** Update - Method, implements double buffering */
    public void update (Graphics g)
    {
    // initialize buffer
    if (dbImage == null)
    {
    dbImage = createImage (this.getSize().width, this.getSize().height);
    dbg = dbImage.getGraphics ();
    
    }
    
    // clear screen in background
    dbg.setColor (getBackground ());
    dbg.fillRect (0, 0, this.getSize().width, this.getSize().height);
    
    // draw elements in background
    dbg.setColor (getForeground());
    paint (dbg);
    
    // draw image on the screen
    g.drawImage (dbImage, 0, 0, this);
    
    }
    
    /**
     * The user has clicked in the applet. Figure out where
     * and react
     */
    public void mouseReleased(MouseEvent e) {
	int x = e.getX();
	int y = e.getY();

	if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) {
	  //linker Mousebutton wurde geklickt
	  if (x > colxpos && y > 10 && y < 30 && x < (colxpos+60)) {
	    //Blatt leeren
	    blatt.setColor(Color.white);
	    blatt.fillRect(0,0,this.getSize().width,this.getSize().height);
	  } else if (x > colxpos && y > colypos && x < colxpos+60 && y < colypos+20) {
	    if (x > colxpos+40) {
	      curcol=2;
	    } else if (x > colxpos+20) {
	      curcol=1;
	    } else {
	      curcol=0;
	    }
	  } else if (x > 0 && y > 0 && y < 360 && x < 360) {
	    // Klick in das Applet
	    for (int i=0;i<steps;i++) {
	      drawnextline();
	    }
	  }
	}
	repaint();
    }

    public void mousePressed(MouseEvent e) {
    }

    public void mouseClicked(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public String getAppletInfo() {
	return "Ein neuer Versuch - Zahnradschablone";
    }
}

