/*
 * Ritzelrechner fuer Fahrradkettenschaltungen
 *
 * Dirk Feeken  feeken@dice2.desy.de
 *
 * Das Programm stellt die Gangabstufungen und erreichbaren
 * Geschwindigkeiten fŸr frei waehlbare Kettenblatt-Ritzelkombinationen
 * grafisch dar. Der Sinn des Programms ist es, unnoetige Ueberschneidungen
 * und grosse Luecken in geplanten Kombinationen vermeiden zu helfen.
 * Es ist mein erstes Java-Programm und dementsprechend
 * zusammengestueckelt.
 */

 import  java.awt.*;
 import  java.lang.*;
 import  java.applet.Applet;

public class RitzelRechner extends Applet
{
    // class Variables
    
    Ritzelgrafik grafik;
    public static List Lkb;
    public static List Lrz;
    public Button Ok;
    public static TextField TFumf;
    public static TextField TFfreq;
    public static Choice Ceinh;
    public static  int umf,freq;

    public static final int KBMAX = 54;
    public static final int KBMIN = 20;
    public static final int RZMIN = 10;
    public static final int RZMAX = 34;
 	
    public void init()
    {
	//setLayout(new BorderLayout());
	
	GridBagLayout p = new GridBagLayout();
	GridBagConstraints pc = new GridBagConstraints();
	//setFont(new Font ("Helvetica",Font.PLAIN, 10));
        //setBackground(Color.white);
	setLayout (p);
	
	// Panel p = new Panel();
	
	pc.gridheight = 1;    //  1 Feld hoch
        pc.gridwidth = 1;     //  1 Feld breit
        pc.fill = GridBagConstraints.NONE;
        pc.weightx= 1.0;
	addTextfeld("Kettenblattausw.:", p, pc);
	addTextfeld("Ritzelauswahl:", p, pc);
        pc.gridwidth = GridBagConstraints.REMAINDER;
	addTextfeld(" ", p, pc);
        pc.weightx= 0.0;     // reset
 		
        pc.gridwidth = 1;     // Listen 1 Feld breit
	pc.gridheight = 4;    // Listen 4 Felder hoch
        pc.weighty= 0.0;     //

        // Liste der moeglichen Kettenblaetter erzeugen
        //p.add("Center",Lkb = new List(7,true));
        Lkb = new List(7,true);
        p.setConstraints(Lkb, pc);
        add(Lkb);
        Lkb.setBackground(Color.white);
        for (int i=KBMIN; i<KBMAX+1; i++)
        {
           String kbzahl = new Integer(i).toString();
           Lkb.addItem(kbzahl);
        }
        Lkb.select(24-KBMIN);  // Vorauswahl
        Lkb.select(42-KBMIN);
        Lkb.select(46-KBMIN);

	    // Liste der moeglichen Ritzel erzeugen
        //p.add("Center",Lrz = new List(7,true));
        Lrz = new List(7,true);
        p.setConstraints(Lrz, pc);
        add(Lrz);
        Lrz.setBackground(Color.white);
	    for (int i=RZMIN; i<RZMAX+1; i++)
	    {
	       String rzzahl = new Integer(i).toString();
	       Lrz.addItem(rzzahl);
     	}
	    Lrz.select(12-RZMIN);  // Vorauswahl
	    Lrz.select(14-RZMIN);
	    Lrz.select(17-RZMIN);
	    Lrz.select(20-RZMIN);
	    Lrz.select(24-RZMIN);
	    Lrz.select(28-RZMIN);
	    Lrz.select(32-RZMIN);

        pc.weighty= 0.0;
        pc.gridwidth = GridBagConstraints.RELATIVE;
 		pc.gridheight = 1;    // Buttons 1 Feld hoch
 		addTextfeld("Radumfang[mm]:", p, pc);
        pc.gridwidth = GridBagConstraints.REMAINDER;
        TFumf   = new TextField(Integer.toString(umf),4);
        p.setConstraints(TFumf, pc);
        TFumf.setBackground(Color.white);
        TFumf.setText("2200");
        add(TFumf);
        pc.gridwidth = GridBagConstraints.RELATIVE;
 		addTextfeld("Trittfrequenz[U/min]:", p, pc);
        pc.gridwidth = GridBagConstraints.REMAINDER;
        TFfreq  = new TextField(Integer.toString(freq),4);
        p.setConstraints(TFfreq, pc);
        TFfreq.setBackground(Color.white);
        TFfreq.setText("90");
        add(TFfreq);
        pc.gridwidth = GridBagConstraints.RELATIVE;
 		addTextfeld("Geschwindigkeit in:", p, pc);
        pc.gridwidth = GridBagConstraints.REMAINDER;
        Ceinh  = new Choice();
        Ceinh.addItem("km:h");
        Ceinh.addItem("mph");
        //Ceinh.addItem("m:Umdr.");
        Ceinh.select("km:h");
        p.setConstraints(Ceinh, pc);
        TFfreq.setBackground(Color.white);
        add(Ceinh);

        Ok       = new Button("OK");
        p.setConstraints(Ok, pc);
        add(Ok);

        pc.fill = GridBagConstraints.BOTH;
        pc.weighty= 10.0;

  		grafik = new Ritzelgrafik();
        p.setConstraints(grafik, pc);
        add(grafik);
 		

 		//resize (400,300);
 	}
 	
 	protected void addTextfeld(String name,GridBagLayout gridbag,
 	                           GridBagConstraints c)
 	{
 		Label text = new Label(name);
 		gridbag.setConstraints(text,c);
 		add(text);
 	}
 	
 	

    public boolean action(Event evt, Object arg)
    {
    	if("OK".equals(arg))
    	{
 		grafik.repaint();
    	}
    	return true;
    }

 } // end Ritzelrechner

 class Ritzelgrafik extends Panel
 {
    public KblattRitzel Combo1;     // deklariert eine Kettenblatt-Ritzelpaket-Kombination
    public Fahrdaten daten1;        // deklariert einen Satz Daten (Umfang, Frequenz,..)
    static final int breite = 650;
    static final int hoehe  = 150;
    static final int randx  = 20;
    static final int randy  = 45;
    static final int abst  = 20;
 	boolean filled;
 	
    public Ritzelgrafik()
    {
    }

    public Ritzelgrafik(boolean filled)
    {
    	this.filled = filled;
    }

    public void paint(Graphics g)
    {
       Combo1 = new KblattRitzel();
       daten1 = new Fahrdaten();

      // Rahmen zeichnen:
      g.setColor(Color.white);
      g.fillRect(randx,randy-25,breite-2*randx,
                (Combo1.Kettenblatt.anzahl+1)*abst+50);
      g.setColor(Color.black);
      g.drawRect(randx,randy-25,breite-2*randx,
                (Combo1.Kettenblatt.anzahl+1)*abst+50);
      //for (int i=1; i<Combo1.Ritzelpaket.anzahl+1;i++)
      //{
      //  int istr = randx+(breite-2*randx-
      //             30*(Combo1.Ritzelpaket.anzahl-1))/2 + 30*(i-1);
      //  g.drawString(Combo1.Ritzelpaket.zname[i],istr,randy-28);
      //}

      // Skala zeichnen:
      Combo1.skala(g, randx,randy+(Combo1.Kettenblatt.anzahl+1)*abst,
                   breite-2*randx, 25,
                   0.0, Combo1.maxUebers()*daten1.Faktor/0.9/1000,
                   10, 10,
                   true, "km/h");
      Combo1.skala(g, randx,randy+(Combo1.Kettenblatt.anzahl+1)*abst,
                   breite-2*randx, 25,
                   0.0, Combo1.maxUebers()*daten1.Faktor/0.9/1000,
                   5, 8,
                   false, "km/h");
      Combo1.skala(g, randx,randy+(Combo1.Kettenblatt.anzahl+1)*abst,
                   breite-2*randx, 25,
                   0.0, Combo1.maxUebers()*daten1.Faktor/0.9/1000,
                   1, 5,
                   false, "km/h");
      Combo1.skala(g, randx,randy-25,
                   breite-2*randx, 25,
                   0.0, Combo1.maxUebers()*daten1.Umfang/0.9/1000,
                   2, 8,
                   true, "Entfalt. m/U");
      Combo1.skala(g, randx,randy-25,
                   breite-2*randx, 25,
                   0.0, Combo1.maxUebers()*daten1.Umfang/0.9/1000,
                   1, 5,
                   false, "Entfalt. m/U");


      //System.out.println(Combo1.maxUebers());
      //System.out.println(maxGeschw);

      // Loop ueber Kettenblattanzahl:
      for (int i = 1; i < Combo1.Kettenblatt.anzahl+1; i++){
         g.setColor(Color.red);
         g.drawLine(randx,randy+abst*i,breite-randx,randy+abst*i);
         g.drawString(Combo1.Kettenblatt.zname[i],breite-randx+3,randy+abst*i+3);

         // Loop ueber Ritzelanzahl und Dreiecke zeichnen:
         for (int j=1; j < Combo1.Ritzelpaket.anzahl+1; j++){
            double x = randx + (breite-2*randx)*(0.9*Combo1.uebers(i,j)/Combo1.maxUebers());
            int ix = new Double(x).intValue();
            int iy = randy+abst*i;
//            int ixp[] = {ix,ix+3,ix-5, ix-2, 0};
            int ixp[] = {ix,ix+2,ix-3, ix-1, 0};
            int iyp[] = {iy+5,iy-5,iy-5, iy+5, 0};
            double schraeglauf =  Math.abs( 1.2*(2*i-(Combo1.Kettenblatt.anzahl+1))
                                        +(2*j-(Combo1.Ritzelpaket.anzahl+1)) );
            if      (schraeglauf>8.0){g.setColor(Color.lightGray);}
            else if (schraeglauf>7.0){g.setColor(Color.gray);}
            else if (schraeglauf>6.0){g.setColor(Color.darkGray);}
            else                   {g.setColor(Color.black);}
            g.fillPolygon(ixp,iyp,4);
            g.setColor(Color.black);
            if (i<2){
              g.setFont(new Font ("Helvetica",Font.PLAIN, 8));
//	   	      g.drawString( new Integer(Combo1.Ritzelpaket.zaehne[j]).toString(),  ix-4,iy-6);
              g.setFont(new Font ("Helvetica",Font.PLAIN, 10));
            }
         } //end Ritzelloop

      } //end Kettenblattloop
    }

 }

 class Zahnraeder extends Object{    // Klasse fuer Zahnradpakete
   public int anzahl;
   public int zaehne[];
   public String zname[];
   int i;

   Zahnraeder() { // constructor fuer leeren Aufruf
      zaehne = new int[50];
      zname = new String[50];
      anzahl = 0;
      for (i = 0; i < 10; i++){
        zaehne[i] = 0;
        zname[i] = "XX";
      }
   }

}


class Fahrdaten extends Object{    // Klasse fuer ...

   int Frequenz;
   int Umfang;
   double Faktor;

   Fahrdaten() { // constructor fuer leeren Aufruf

     // Frequenz = 90;
     // Umfang = 2.20;
     // Faktor = 3.6/60.;
				
		Frequenz = Integer.parseInt(RitzelRechner.TFfreq.getText());
		Umfang = Integer.parseInt(RitzelRechner.TFumf.getText());
    	if( "km:h".equals(RitzelRechner.Ceinh.getSelectedItem()) )
    	{
			Faktor = 3.6/60*Frequenz*Umfang;
    	}
    	else if( "mph".equals(RitzelRechner.Ceinh.getSelectedItem()) )
    	{
			Faktor = 3.6/60./1.609*Frequenz*Umfang;
    	}
    	else
    	{
			Faktor = 0.001*Umfang;
    	}
    }
}

class KblattRitzel extends Object{    // Klasse fuer Zahnrad-Ritzelkombinationen

   Zahnraeder Kettenblatt;
   Zahnraeder Ritzelpaket;


   KblattRitzel() { // constructor

        Kettenblatt = new Zahnraeder();
        Ritzelpaket = new Zahnraeder();

		Kettenblatt.anzahl = RitzelRechner.Lkb.getSelectedIndexes().length;
		//System.out.println("Kbanzahl: "+Kettenblatt.anzahl);
		for (int i=0; i<Kettenblatt.anzahl; i++){
		  //System.out.println(RitzelRechner.Lkb.getSelectedItems()[i]+" "
		  //                 +RitzelRechner.Lkb.getSelectedIndexes()[i]);
	
	      Kettenblatt.zaehne[i+1]=RitzelRechner.Lkb.getSelectedIndexes()[i]+
	      RitzelRechner.KBMIN;
		}

		Ritzelpaket.anzahl= RitzelRechner.Lrz.getSelectedIndexes().length;
		//System.out.println("Ritzelanz: "+Ritzelpaket.anzahl);
		for (int i=0; i<Ritzelpaket.anzahl; i++){
		  //System.out.println(RitzelRechner.Lrz.getSelectedItems()[i]+" "
		  //                  +RitzelRechner.Lrz.getSelectedIndexes()[i]);
		  Ritzelpaket.zaehne[i+1]=RitzelRechner.Lrz.getSelectedIndexes()[i]+
		  RitzelRechner.RZMIN;
		}
				
		for (int i=1; i < Kettenblatt.anzahl+1; i++){
		  Kettenblatt.zname[i] = new Integer(Kettenblatt.zaehne[i]).toString();
		}

		for (int i=1; i < Ritzelpaket.anzahl+1; i++){
		  Ritzelpaket.zname[i] = new Integer(Ritzelpaket.zaehne[i]).toString();
		}
				
   }

   public double maxUebers() {
      double maxUebers = 0.0;
      for (int i = 1; i < Kettenblatt.anzahl+1; i++){
         for (int j = 1; j < Ritzelpaket.anzahl+1; j++){
            double u = new Integer(Kettenblatt.zaehne[i]).doubleValue()/
                       new Integer(Ritzelpaket.zaehne[j]).doubleValue();
            if (u > maxUebers) { maxUebers = u ; } ;
         }
      }
      return(maxUebers);
   }

   public double uebers(int i, int j) {
      double us = new Integer(Kettenblatt.zaehne[i]).doubleValue()/
                  new Integer(Ritzelpaket.zaehne[j]).doubleValue();
      return(us);
   }


	public void skala(Graphics g,
					  int ix, int iy,
					  int breite, int hoehe,
					  double xmin, double xmax,
					  int ticabst, int tichoehe,
					  boolean zahlplot,
					  String einheit)
	{

      for (int i=ticabst; i< new Double(xmax).intValue()+1; i=i+ticabst)
      {
      	double xtic = ix+breite*(new Integer(i).doubleValue()/xmax);
      	int ixtic = new Double(xtic).intValue();
      	int iytic = iy;
      	g.drawLine(ixtic, iytic, ixtic, iytic+tichoehe);   // tics
      	if (zahlplot){g.drawString(new Integer(i).toString(),ixtic-5,iytic+20);}
      }
      if (zahlplot){g.drawString(einheit,ix+3,iy+20);}
      g.drawRect(ix,iy, breite, hoehe);
	}


   public void Schreibe() {
      int i;

      for (i = 1; i < Kettenblatt.anzahl+1; i++){
        //System.out.println(Kettenblatt.zaehne[i]);
      }
      for (i = 1; i < Ritzelpaket.anzahl+1; i++){
        //System.out.println(Ritzelpaket.zaehne[i]);
      }

   }

}

