// rohr.java

import java.awt.*;
import java.applet.Applet;
import java.util.*;
import java.io.*;


class rohr_viewport extends Canvas {
   Image img_buffer=null;
   int img_width=600,img_height=200;
   int xpoint[], ypoint[];
   int max_points=400;
   int max_lines=400;
   double time=0.0;
   double eps=10.0;
   double phase_speed=340.0;
   double time_factor=0.05;
   double freq=1.0;
   double omega;
   double line_dist=5.0;
   double wave_number=0.0;
   double duct_length=1.7;
   double scale=1.0;
   boolean repaint_flag=true;
   Graphics bgra;

   public rohr_viewport() {
      setBackground(Color.white);
      omega=2.0*Math.PI*freq;
      xpoint = new int[max_points];
      ypoint = new int[max_points];
      show();
   }

   public void set_eps(double val) {
      eps = val;
   }

   public void set_scale(double val) {
      double h;
      h = Math.pow(10.0,val/20.0);
      if (h < 1.0) h=1.0;
      scale = 1.0/h;
   }

   public void set_dist(double val) {
      line_dist = val;
   }

   public void set_speed(int ival) {
      time_factor = 0.05/ival;
   }

   public void set_freq(double val) {
      freq = val;
      omega=2.0*Math.PI*freq;
      wave_number=omega/phase_speed;
   }

   public void advance() {
      time += time_factor;
      time = time - Math.floor(time);
      repaint();
   }

   void draw_piston(int x0, int y0) {
      bgra.setColor(Color.red);
      bgra.fillRect(x0-90,y0-5,80,10);
      bgra.fillRect(x0-10,y0-50,10,100);
   }

   void draw_wave() {
      double dx;
      double h=Math.cos(2.0*Math.PI*time);
      double aa,ak;
      int i,j,x,y;

      bgra.setColor(Color.yellow);
      bgra.fillRect(395,150,10,100);
      bgra.setColor(Color.black);

      aa=Math.abs(Math.sin(wave_number*1.7));
      ak=0.0;
      if (aa != 0) {
	 ak=1.0/aa;
	 aa=omega*1.2*0.001*340.0/aa;
      }
      //System.out.println("aa: " + aa);

      double haa=0.5*scale*h*aa;
      for (i=0; i < 400; i++) {
	 dx = -i/400.0*1.7;
	 y = 200-(int)(Math.cos(wave_number*dx)*haa);
	 x=600-i;
	 bgra.drawLine(x,200,x,y);
      }

      haa=eps*h*ak;
      for (i=0; i < max_lines; i++) {
	 j = (int)(line_dist*i);
	 if (j > 400.0) {
	    break;
	 }
	 dx=-j/400.0*1.7;
	 x = 600 - j - (int)(Math.sin(wave_number*dx)*haa);
	 bgra.drawLine(x,25,x,125);
      }
      x = (int)(Math.sin(wave_number*1.7)*haa);
      draw_piston(200+x,75);
   }

   public void update (Graphics g) {
      repaint_flag=true;
      paint(g);
   }

   public void paint(Graphics g) {
      if (img_buffer == null) {
         img_width=size().width;
         img_height=size().height;
	 img_buffer = createImage(img_width, img_height);
         System.out.println("Image: " + img_width + "x" + img_height);
	 bgra = img_buffer.getGraphics();
      }
      if (repaint_flag) {
	 bgra.setColor(new Color(100,240,255));
	 bgra.fillRect(0,0,img_width,img_height);
	 draw_wave();
	 repaint_flag=false;
      }
      g.drawImage(img_buffer,0,0,this);
   }
}

class rohr_slider {
   int num_steps=400;
   double max_val, min_val;
   double fak;
   double val;
   String label_text;
   Scrollbar sb;
   Label lb1;
   Label lb2;
   public rohr_slider (Panel home,
		  String text,
		  double range,
		  double init_val,
		  double min_val) {

      max_val = min_val + range;
      this.min_val = min_val;
      val = init_val;
      fak=range/num_steps;
      int n = (int)((init_val-min_val)/range * num_steps);
      if (n < 0) n = 0;
      if (n > num_steps) n = num_steps;
      int bubb=(int)(0.2*num_steps);
      sb= new Scrollbar(Scrollbar.HORIZONTAL,n,bubb,0,num_steps);
      label_text = new String(text + ": ");
      lb1= new Label(text + ": ");
      lb1.setAlignment(Label.RIGHT);
      lb2= new Label("" + init_val);
      home.add(lb1);
      home.add(lb2);
      home.add(sb);
   }

   public void set_val(int n) {
      val = (n * fak) + min_val;
      //System.out.println("Ja: " + val + " " + n);
      if (val > max_val) val = max_val;
      if (val < min_val) val = min_val;
      lb2.setText("" + val);
      //lb2.setText(NumberFormat.getInstance().format(val));
   }
}

public class rohr extends Applet implements Runnable {
   rohr_viewport vp=null;
   Thread engine=null;
   rohr_slider s[];
   Choice ch;
   int delay_time=50;
   int max_item=6;

   public void init () {
      setLayout(new BorderLayout());
      Panel leiste = new Panel();

      leiste.add (new Label("Animation:"));
      leiste.add (new Button("Start"));
      leiste.add (new Button("Stop"));
      leiste.add (new Button("||>"));

      Panel grid = new Panel();
      grid.setLayout(new GridLayout(4,3,4,4));

      ch = new Choice();
      int i;
      for (i=1; i < max_item; i++) {
	ch.addItem("1/"+i);
      }
      ch.select(0);
      leiste.add(ch);

      s = new rohr_slider[4];
      s[0] = new rohr_slider(grid, "Auslenkung [Pixel]", 100.0, 10.0, 0.0);
      s[1] = new rohr_slider(grid, "Frequenz [Hz]", 400.0, 10.0, 1.0);
      s[2] = new rohr_slider(grid, "Abschw. [dB]", 50.0, 0.0, 0.0);
      s[3] = new rohr_slider(grid, "Linienabstand [Pixel]", 20.0, 5.0, 2.0);

      //leiste.add(grid);

      add ("North",leiste);
      add ("South",grid);

      vp = new rohr_viewport();
      add ("Center", vp);

      if (vp != null) {
	 vp.set_eps(s[0].val);
	 vp.set_freq(s[1].val);
	 vp.set_scale(s[2].val);
	 vp.set_dist(s[3].val);
      }
   }

   public void engine_start() {
      if (engine != null) {
         if (engine.isAlive()) {
            engine.stop();
         }
         engine = null;
      }
      engine = new Thread(this);
      engine.start();
   }

   public void stop() {
      if ((engine != null) && (engine.isAlive())) {
         engine.stop();
      }
      engine = null;
   }

   public void run() {
      Thread me = Thread.currentThread();
      me.setPriority(Thread.MIN_PRIORITY);

      while (engine != null) {
         if (vp != null) vp.advance();
         try {
            engine.sleep(delay_time);
         }
         catch (InterruptedException e) {}
      }
 
   }

   public boolean action(Event evt, Object arg) {
      //System.out.println(evt.target);
      int i;
      if (vp != null) {
	 for (i=1; i < max_item; i++) {
	    if (("1/"+i).equals(arg)) {
	       //System.out.println(evt.target);
	       vp.set_speed(i);
	    }
	 }
      }
      if ("Start".equals(arg)) {
	 stop();
	 engine_start();
      }
      else if ("Stop".equals(arg)) {
	 stop();
      }
      else if ("||>".equals(arg)) {
         if (vp != null) vp.advance();
      }
      return true;
   }

   public boolean handleEvent(Event evt) {
      //System.out.println(evt.target);
      int i;
      if ((vp != null) && (evt.arg != null)) {
	 for (i=0; i < 4; i++) {
	    if (evt.target == s[i].sb) {
	       int n = ((Integer)(evt.arg)).intValue();
	       //System.out.println("Ja: " + i + " " + n);
	       s[i].set_val(n);
	       switch (i) {
		case 0: vp.set_eps(s[i].val); break;
		case 1: vp.set_freq(s[i].val); break;
		case 2: vp.set_scale(s[i].val); break;
		case 3: vp.set_dist(s[i].val); break;
		default: break;
	       }
	       vp.repaint();
	       return true;
	    }
	 }
      }
      return super.handleEvent(evt);
   }
}

