//******************************************************************************
// DiBi.java:	Applet
//
//******************************************************************************
import java.applet.*;
import java.awt.*;

//==============================================================================
// Main Class for applet DiBi
//
//==============================================================================
public class DiBi extends Applet
{
	private int maxx;
	private int maxy;
	private boolean plusminus=true;
	private Dimension mausposition;

	private int Buttonx=5,Buttony=5,Buttonwidth=16,Buttonheight=16;

	private Image m_image;  //verstecktes Bild
	private Graphics m_g;   //verstecktes Graphic Objekt
	private Dimension m_dimImage;   //Groesse des Bildes

	private FontMetrics m_fm; //Schriftmass
	
	// DiBi Class Constructor
	//--------------------------------------------------------------------------
	public DiBi()
	{
		// TODO: Add constructor code here
		
	}

	// APPLET INFO SUPPORT:
	//		The getAppletInfo() method returns a string describing the applet's
	// author, copyright date, or miscellaneous information.
    //--------------------------------------------------------------------------
	public String getAppletInfo()
	{
		return "Name: DiBi\r\n" +
		       "Author: Thomas Froitzheim\r\n" +
		       "\r\n" +
		       "Ding-Bild Visualisierung\r\n" +
		       "\r\n" +
		       "Created with Microsoft Visual J++ Version 1.0\r\n" +
		       "";
	}


	// The init() method is called by the AWT when an applet is first loaded or
	// reloaded.  Override this method to perform whatever initialization your
	// applet needs, such as initializing data structures, loading images or
	// fonts, creating frame windows, setting the layout manager, or adding UI
	// components.
    //--------------------------------------------------------------------------
	public void init()
	{
        // If you use a ResourceWizard-generated "control creator" class to
        // arrange controls in your applet, you may want to call its
        // CreateControls() method from within this method. Remove the following
        // call to resize() before adding the call to CreateControls();
        // CreateControls() does its own resizing.
        //----------------------------------------------------------------------
		//resize(500, 250);

		// TODO: Place additional initialization code here
		Dimension dimFenstergroesse;
		dimFenstergroesse=size();
		maxx=dimFenstergroesse.width;
		maxy=dimFenstergroesse.height;

		//Schriftgroesse ermittelm
		Font f = getFont();
		m_fm = getFontMetrics(f);

		setBackground(Color.green);
		//Anfangsobjekt setzen, etwas ausserhalb doppelter Brennweite
		mausposition = new Dimension ((int)(maxx/12),(int)maxy/4);

		//Puffer initialisieren und erstes Bild zeichnen
		ResizeImage();
		repaint();

	}

	// Place additional applet clean up code here.  destroy() is called when
	// when you applet is terminating and being unloaded.
	//-------------------------------------------------------------------------
	public void destroy()
	{
		// TODO: Place applet cleanup code here
	}

	// DiBi Paint Handler
	//--------------------------------------------------------------------------
	public void paint(Graphics g)
	{
		//wenn Bild vorhanden dann zeichnen
		if(m_image!=null)
		{
			g.drawImage(m_image,0,0,null);
		}
		
	}

	// Update-Funktion zur zweifachen Pufferung
	public void update(Graphics g)
	{
		// erst mal sehen ob die Bildgroesse sich geaendert hat
		ResizeImage();

		//gebpuffertes Bild loeschen
		//Color colFG = getForeground();
		Color colBG = getBackground();
		m_g.setColor(colBG);
		m_g.fillRect(0,0,m_dimImage.width-1,m_dimImage.height-1);
		//m_g.setColor(colFG);

		//Bildaufbau in den Puffer schreiben
		//schwarzer Rahmen
		m_g.setColor(Color.black);
		m_g.drawRect(0,0,m_dimImage.width-1,m_dimImage.height-1);
		
		//Copyrighttext rechtsunten zeichnen
		m_g.setColor(Color.gray);
		String sCopyright = "Ding-Bild Visualisierung ©1998 von froitzheim@optician.com";
		// 10 pkt von rechts
		int Copyrightx = m_dimImage.width-m_fm.stringWidth(sCopyright)-10;
		// 10 pkt von unten
		int Copyrighty = m_dimImage.height-10;
		m_g.drawString(sCopyright,Copyrightx,Copyrighty);	
		
		//den Knopf zeichnen
		Button_zeichnen(m_g);

		//jetzt die eigentliche Konstruktion
		bild_aufbau(mausposition.width-maxx/2,(mausposition.height-maxy/2)*(-1),m_g);

		//jetzt ist alles geschrieben und der Puffer kann ins Fenster
		paint(g);
	}


	//Groesse des Puffers aendern falls erforderlich
	private void ResizeImage()
	{
		//Groesse des Applets ermitteln
		Dimension dim = size();
		int nWidth=dim.width;
		int nHeight=dim.height;

		//mal sehen ob sich die Groesse geaendert hat
		if (m_dimImage != null && 
			m_dimImage.width == nWidth &&
			m_dimImage.height == nHeight)
		{
			return; //wenn nichts geaendert dann muss auch nichts geschehen
		}

		//neues Graphics Objekt muss erstellt werden
		m_dimImage = new Dimension(nWidth,nHeight);
		m_image = createImage(nWidth,nHeight);
		m_g = m_image.getGraphics();
	}


	//		The start() method is called when the page containing the applet
	// first appears on the screen. The AppletWizard's initial implementation
	// of this method starts execution of the applet's thread.
	//--------------------------------------------------------------------------
	public void start()
	{
		// TODO: Place additional applet start code here
	}
	
	//		The stop() method is called when the page containing the applet is
	// no longer on the screen. The AppletWizard's initial implementation of
	// this method stops execution of the applet's thread.
	//--------------------------------------------------------------------------
	public void stop()
	{
	}


	// MOUSE SUPPORT:
	//		The mouseDown() method is called if the mouse button is pressed
	// while the mouse cursor is over the applet's portion of the screen.
	//--------------------------------------------------------------------------
	public boolean mouseDown(Event evt, int x, int y)
	{
		// TODO: Place applet mouseDown code here
		
		if ((x>Buttonx)&&(x<Buttonx+Buttonwidth)&&
			(y>Buttony)&&(y<Buttony+Buttonheight))
		{
			if(plusminus)
			{
				plusminus=false;
			}
			else
			{
				plusminus=true;
			}
		}
		else
		{   //wenn Button gedrueckt wurde nicht neuzeichnen
			mausposition = new Dimension (x,y);
		}

		repaint();
		return true;
	}

	// MOUSE SUPPORT:
	//		The mouseUp() method is called if the mouse button is released
	// while the mouse cursor is over the applet's portion of the screen.
	//--------------------------------------------------------------------------
	public boolean mouseUp(Event evt, int x, int y)
	{
		// TODO: Place applet mouseUp code here
		return true;
	}

	// MOUSE SUPPORT:
	//		The mouseDrag() method is called if the mouse cursor moves over the
	// applet's portion of the screen while the mouse button is being held down.
	//--------------------------------------------------------------------------
	public boolean mouseDrag(Event evt, int x, int y)
	{
		// TODO: Place applet mouseDrag code here
		//mausposition = new Dimension (x,y);
		if ((x>Buttonx)&&(x<Buttonx+Buttonwidth)&&
			(y>Buttony)&&(y<Buttony+Buttonheight))
		{
			// MouseDrag innerhalb vom Button ignorieren	
		}
		else
		{   //wenn Button gedrueckt wurde nicht neuzeichnen
			mausposition = new Dimension (x,y);
		}

		repaint();

		return true;
	}

	// MOUSE SUPPORT:
	//		The mouseMove() method is called if the mouse cursor moves over the
	// applet's portion of the screen and the mouse button isn't being held down.
	//--------------------------------------------------------------------------
	public boolean mouseMove(Event evt, int x, int y)
	{
		// TODO: Place applet mouseMove code here
		return true;
	}


	// TODO: Place additional applet code here
	private void line(double x1,double y1,double x2, double y2,Graphics g)
	{
		// Neue line Funktion damit das alte C Programm einfacher
		// umgeschrieben werden kann
		g.setColor(Color.black);
		g.drawLine((int)x1,(int)y1,(int)x2,(int)y2);
	}

	private void lined(double x1,double y1,double x2, double y2,Graphics g)
	{
		// Neue line Funktion damit das alte C Programm einfacher
		// umgeschrieben werden kann
		// soll mal eine gedottete Linie werden.
		// ist jetzt eine gepunktete Linie
		// aber es hakt beim ersten Aufruf noch ein wenig.
		// Haken scheint geloest!

		double laenge,richtx,richty;
		double zaehlerlaenge,zaehlerx,zaehlery;

		laenge=Math.sqrt(Math.pow(x1-x2,2)+Math.pow(y1-y2,2));
		richtx=(x2-x1)/laenge;
		richty=(y2-y1)/laenge;

		zaehlerlaenge=0;zaehlerx=x1;zaehlery=y1;
		while(zaehlerlaenge<=laenge)
		{
			//nur zeichnen wenn auch sichtbar, sonst wird das
			//Graphics-Objekt zu gross und die Darszellung
			//hakt.
			if((zaehlerx>=0)&&(zaehlerx<=maxx)&&
				(zaehlery>=0)&&(zaehlery<=maxy))
			{
				g.drawLine((int)zaehlerx,(int)zaehlery,(int)zaehlerx,(int)zaehlery);
			}
			zaehlerlaenge+=4;	//jeden 4. Punkt zeichnen
			zaehlerx+=richtx*4;
			zaehlery+=richty*4;
		}

		//vorerst statt gepunktet nur weisse Linie zeichnen.
		//g.setColor(Color.white);
		//g.drawLine((int)x1,(int)y1,(int)x2,(int)y2);
	}


	private void f_zeichnen(double x,double y,Graphics g)
    {
		String Zeichen = "F";
		g.drawString(Zeichen,(int)x-1,(int)y+9);
    //line(x,y,x+4,y,g);
    //line(x,y,x,y+6,g);
    //line(x,y+2,x+3,y+2,g);
    }

	private void y_zeichnen(double x,double y,Graphics g)
    {
		String Zeichen ="y";
		g.drawString(Zeichen,(int)x-1,(int)y+9);
    //line(x,y,x+1,y+1,g);
    //line(x+2,y,x,y+2,g);
    }



	private void bild_aufbau(double a,double y,Graphics g)
    {
    double b,z;          /* a = a , a'= b , y = y , y'= z */
    double ax,ay,bx,by,xm,ym,dingbrenn,bildbrenn,xdingbrenn,xbildbrenn;



    /* Brennweite */
    if(plusminus)
        dingbrenn=maxx/6*(-1);
    else
	dingbrenn=maxx/6;
    bildbrenn=dingbrenn*(-1);


    /* Bildweite berechnen */
    if ((a==0)||(a==dingbrenn))
	b=0;
    else
        b=1/((1/(double)a)+(1/((double)bildbrenn)));


    /* Bildgroesse berechnen */
    if (a==0)
	z=y;
    else
	{
	if(a==dingbrenn)
	    z=2*maxx;
	else
            z=((double)y)*((double)b/(double)a);
	}




    /* Positionen fuer Konstruktionsstrahlen errechnen */
    /* Alle Werte in Bildschirmkoordinaten */

    /* Dingweite */
    ax=a+maxx/2;

    /* Dinghoehe */
    ay=y*(-1)+maxy/2;

    /* Bildweite */
    bx=b+maxx/2;

    /* Bildhoehe */
    by=z*(-1)+maxy/2;

    /* Hauptebene (Mitte) */
    xm=maxx/2;

    /* optische Achse (Mitte) */
    ym=maxy/2;

    /* dinseitige Brennweite */
    xdingbrenn=dingbrenn+maxx/2.0;

    /* bildseitige Brennweite */
    xbildbrenn=bildbrenn+maxx/2.0;


	/* optische Achse */
    line (0,maxy/2,maxx,maxy/2,g);

    /* Hauptebene */
    line(maxx/2,0,maxx/2,maxy,g);

    /* Brennpunkte */
    
        line(xdingbrenn,maxy*31/64,xdingbrenn,maxy*33/64,g);
        line(xbildbrenn,maxy*31/64,xbildbrenn,maxy*33/64,g);
	

    /* Brennpunktsbezeichnung */
    if(plusminus)
	{
        f_zeichnen(maxx*2/6-1,maxy/2+10,g);
        line(maxx*2/6-1,maxy/2+8,maxx*2/6+3,maxy/2+8,g);
        f_zeichnen(maxx*4/6-3,maxy/2+10,g);
		line(maxx*4/6+1,maxy/2+8,maxx*4/6+3,maxy/2+10,g);
	}
    else
	{
        f_zeichnen(maxx*2/6-1,maxy/2+10,g);
        line(maxx*4/6-3,maxy/2+8,maxx*4/6+1,maxy/2+8,g);
        f_zeichnen(maxx*4/6-3,maxy/2+10,g);
		line(maxx*2/6+3,maxy/2+8,maxx*2/6+5,maxy/2+10,g);

	}



    /* Gegenstand zeichnen */
    if(a<0)
        line(ax,ym,ax,ay,g);
    else
		lined(ax,ym,ax,ay,g);
    if (a<maxx*2/6)
		y_zeichnen(ax+3,(ay+ym)/2,g);
    else
		y_zeichnen(ax-5,(ay+ym)/2,g);



    /* Bild zeichnen */
    if(b>0)
        line(bx,ym,bx,by,g);
    else
	{
		if (a!=dingbrenn)
			lined(bx,ym,bx,by,g);
	}

    y_zeichnen(bx-6,(by+ym)/2,g);
    line(bx-3,(by+ym)/2-1,bx-2,(by+ym)/2,g);




    /* Wenn Bild- oder Gegenstandsgroesse < 2 ist */
    /* -> keine Konstruktion moeglich */

    if( !( (y>=(-2)) && (y<=2) ) )
	{

        /* Konstruktionsstrahlen zeichnen */


        /* bei Pluslinse y vor f */
        if((a<dingbrenn)&&(plusminus))
	    {

			/* Knotenpunktstrahl */
            line(ax,ay,bx,by,g);

			/* bildseitiger Brennpunktstrahl */
			line(ax,ay,xm,ay,g);
			line(xm,ay,bx,by,g);

			/* dingseitiger Brennpunktstrahl */
			line(ax,ay,xm,by,g);
			line(xm,by,bx,by,g);
		}

        /* bei Pluslinse y in f */
        if((a==dingbrenn)&&(plusminus))
	    {

			/* bildseitiger Brennpunktstrahl */
			line(ax,ay,xm,ay,g);
			if(y>0)
				line(xm,ay,(maxy*a/y*(-1))+xm,maxy+ay,g);
			else
				line(xm,ay,(maxy*a/y)+xm,(maxy*(-1))+ay,g);

			/* Knotenpunktstrahl */
			line(ax,ay,xm,ym,g);
			if(y>0)
				line(xm,ym,maxy*a/y*(-1)+xm,maxy+ym,g);
			else
				line(xm,ym,maxy*a/y+xm,maxy*(-1)+ym,g);


			/* verlaengerter bildseitiger Brennpunktstrahl */
			if(y>0)
				lined(xm,ay,maxy*a/y+xm,maxy*(-1)+ay,g);
			else	 
				lined(xm,ay,maxy*a/y*(-1)+xm,maxy+ay,g);

			/* verlaengerter Knotenpunktstrahl */
			if(y>0)
				lined(ax,ay,maxy*a/y+ax,maxy*(-1)+ay,g);
			else
				lined(ax,ay,maxy*a/y*(-1)+ax,maxy+ay,g);
		}

        /* bei Minuslinse y in f */
        if((a==dingbrenn)&&(!plusminus))
	    {

			/* bildseitiger Brennpunktstrahl */
			line(0,ay,xm,ay,g);
			if(y>0)
				line(xm,ay,maxy*a/y+xm,maxy*(-1)+ay,g);
			else
				line(xm,ay,maxy*a/y*(-1)+xm,maxy+ay,g);

			/* Knotenpunktstrahl */
			if(y>0)
				line(xm,ym,maxy*a/y*(-1)+xm,maxy+ym,g);
			else
				line(xm,ym,maxy*a/y+xm,maxy*(-1)+ym,g);
			if(y>0)
				line(xm,ym,maxy*a/y+xm,maxy*(-1)+ym,g);
			else
				line(xm,ym,maxy*a/y*(-1)+xm,maxy+ym,g);


			/* verlaengerter bildseitiger Brennpunktstrahl */
			if(y>0)
				lined(xm,ay,maxy*a/y*(-1)+xm,maxy+ay,g);
			else
				lined(xm,ay,maxy*a/y+xm,maxy*(-1)+ay,g);
			lined(xm,ay,ax,ay,g);
	    }

        /* bei Pluslinse y zwischen f und Hauptebene */
		/* bei Minuslinse y vor Hauptebene */
        if ( (((a>dingbrenn)&&(a<=0))&&(plusminus))
	     || ((a<0)&&(!plusminus)) )
	    {

			/* bildseitiger Brennpunktstrahl */
			line(ax,ay,xm,ay,g);
			if(plusminus)
			{
				line(xm,ay,xbildbrenn,ym,g);
				line(xbildbrenn,ym,xm+xbildbrenn,3*y+ym,g);
			}
			else
			{
				line(xm,ay,xm+xm,(-3)*y+ay,g);
		}

	    /* dingseitiger Brennpunktstrahl */
	    if(plusminus)
	        line(xdingbrenn,ym,xm,by,g);
	    else
			line(ax,ay,xm,by,g);
	    line(xm,by,maxx,by,g);

	    /* Knotenpunktstrahl */
	    line(ax,ay,xm,ym,g);
	    if(y>0)
			line(xm,ym,maxy*a/y*(-1)+xm,maxy+ym,g);
	    else
	        line(xm,ym,maxy*a/y+xm,maxy*(-1)+ym,g);


		/* verlaengerter bildseitiger Brennpunktstrahl */
	    if(plusminus)
	        lined(xm,ay,bx,by,g);
	    else
		{
			lined(xm,ay,xbildbrenn,ym,g);
			lined(bx,by,xm,by,g);
		}

	    /* verlaengerter dingseitiger Brennpunktstrahl */
		if(plusminus)
	        lined(xm,by,bx,by,g);
	    else
			lined(xm,by,xdingbrenn,ym,g);

	    /* verlaengerter Knotenpunktstrahl */
		if(plusminus)
	        lined(ax,ay,bx,by,g);
	}



	/* bei Pluslinse y hinter Hauptebene */
	/* bei Minuslinse y zwischen Hauptebene und Brennpunkt */
	if( ((a>0)&&(plusminus))
	    || ((a>0)&&(a<dingbrenn)&&(!plusminus)) )
	{

		/* bildseitiger Brennpunktstrahl */
	    line(0,ay,xm,ay,g);
	    if(plusminus)
	        line(xm,ay,xbildbrenn,ym,g);
	    else
			line(xm,ay,bx,by,g);

	    /* dingseitiger Brennpunktstrahl */
	    if(plusminus)
	        line(xm,by,maxx/(-2)+xm,3*z+by,g);
	    else
			if(z<maxy)
				line(xm,by,maxx/(-2)+xm,(-3)*z+by,g);
	    line(xm,by,bx,by,g);

	    /* Knotenpunktstrahl */
        line(xm,ym,bx,by,g);
	    if(y>0)
	        line(xm,ym,maxy*a/y*(-1)+xm,maxy+ym,g);
	    else
	        line(xm,ym,maxy*a/y+xm,maxy*(-1)+ym,g);


	    /* verlaengerter bildseitiger Brennpunktstrahl */
 	    lined(xm,ay,ax,ay,g);
	    if(!plusminus)
			lined(xbildbrenn,ym,xm,ay,g);

	    /* verlaengerter dingseitiger Brennpunktstrahl */
	    if(plusminus)
	        lined(xm,by,ax,ay,g);
	    else
			lined(xm,by,xdingbrenn,ym,g);

	    /* verlaengerter Knotenpunktstrahl */
	    if(plusminus)
	        lined(bx,by,ax,ay,g);
	}


	/* Bei Minuslinse y hinter f */
	if((a>dingbrenn)&&(!plusminus))
	{

		/* bildseitiger Brennpunktstrahl */
	    line(0,ay,xm,ay,g);
	    line(xm,ay,dingbrenn*4+xm,y*(-4)+ay,g);

		/* dingseitiger Brennpunktstrahl */
	    if(z*(-1)<maxx)
	        line(xm,by,bildbrenn*4+xm,z*(-4)+by,g);
	    line(xm,by,maxx,by,g);

		/* Knotenpunktstrahl */
	    line(xm,ym,ax,ay,g);
	    line(xm,ym,a*(-4)+xm,y*4+ym,g);


		/* verlaengerter bildseitiger Brennpunktstrahl */
	    lined(bx,by,xm,ay,g);
	    lined(xm,ay,ax,ay,g);

		/* verlaengerter dingseitiger Brennpunktstrahl */
	    lined(bx,by,xm,by,g);
	    lined(xm,by,ax,ay,g);
	}

	}
}

	private void Button_zeichnen(Graphics g)
	{
		g.setColor(Color.white);
		g.fillRect(Buttonx,Buttony,Buttonwidth,Buttonheight);
		g.setColor(Color.black);
		g.drawRect(Buttonx,Buttony,Buttonwidth,Buttonheight);
		g.drawLine(Buttonx+2,Buttony+Buttonheight/2,Buttonx+Buttonwidth-2,Buttony+Buttonheight/2);
		if (plusminus)
		{
			g.drawLine(Buttonx+Buttonwidth/2,Buttony+2,Buttonx+Buttonwidth/2,Buttony+Buttonheight-2);
		}
	}



}
