// gruppe.java

// Copyright (C) 1999 by Klaus Ehrenfried
// ehrenfri@hobo.pi.tu-berlin.de

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

class gruppe_viewport extends Canvas {
   Image img_buffer=null;
   int img_width=600,img_height=200;
   int array_len=0;
   int num=0;
   double eps=0.01;
   double time_factor=0.05;
   double c0=10.0;
   double k0=1.0;
   double vgr=1.0;
   double w[];
   double g[];
   double phase[];
   double omega[];
   double kwelle[];
   int max_wellen;
   boolean repaint_flag=true;
   Graphics bgra;

   public gruppe_viewport(int max_wellen, double delay_time) {
      setBackground(Color.white);
      this.max_wellen = max_wellen;
      time_factor = delay_time/1000.0;

      g = new double[max_wellen];
      phase = new double[max_wellen];
      omega = new double[max_wellen];
      kwelle = new double[max_wellen];
      show();
   }

   synchronized void update_param() {
      double dkn = 2.0 * eps/(num+1);
      for (int j=0; j < num; j++) {
	 kwelle[j] = k0*(1.0 - eps + (j+1) * dkn);
	 omega[j] = c0*k0 + vgr * (kwelle[j]-k0);
      }
   }

   public void set_param(String name, double val) {
      if ("eps".equals(name)) {
	 eps = val;
      } else if ("vgr".equals(name)) {
	 vgr = val;
      } else if ("lambda".equals(name)) {
	 k0 = 2.0*Math.PI/val;
      } else if ("c0".equals(name)) {
	 c0 = val;
      }
      update_param();
   }

   public void set_num(int val) {
      num = val;
      double h = 2.0 * Math.PI/(num + 1);
      double sum = 0.0;
      for (int m=0; m < num; m++) {
	 g[m] = 1.0 - Math.cos((m+1)*h);
	 sum += g[m];
      }
      //System.out.println("g: ");
      for (int m=0; m < num; m++) {
	 g[m] /= sum;
	 phase[m] = 0.0;
	 //System.out.println(m + " " + g[m]);
      }
      update_param();
   }

   public synchronized void advance() {
      for (int m=0; m < num; m++) {
	 phase[m] += omega[m] * time_factor;
	 if (phase[m] > 0.0) phase[m] -= 2.0 * Math.PI;
      }
      repaint();
   }

   synchronized void draw_wave() {
      
      double yscale = 50.0;
      int ybase = img_height/2;
      int i,j;
      int x,y;

      for (i=0; i < array_len; i++) {
	 w[i] = 0.0;
      }

      for (j=0; j < num; j++) {
	 double k = kwelle[j];
	 double phi = -phase[j] - 0.5*array_len*k;
	 double h = g[j] * yscale;

	 for (i=0; i < array_len; i++) {
	    w[i] += h * Math.cos(phi);
	    phi += k;
	 }
      }
      
      bgra.setColor(Color.orange);
      for (i=0; i < array_len; i++) {
	 x=20+i;
	 y=(int)(w[i]);
	 bgra.drawLine(x,ybase,x,ybase-y);
      }

      int y0,y1;
      bgra.setColor(Color.black);
      y0=ybase-(int)(w[0]);
      for (i=1; i < array_len; i++) {
	 y1=ybase-(int)(w[i]);
	 bgra.drawLine(19+i,y0,20+i,y1);
	 y0=y1;
      }

   }

   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();
	 array_len = img_width-40;
	 w = new double [array_len];
      }
      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 gruppe_slider extends Panel {
   int num_steps=400;
   double max_val, min_val;
   double fak;
   double val;
   Scrollbar sb;
   Label lb1;
   Label lb2;
   String name;

   public gruppe_slider (String name,
			 String text,
			 double range,
			 double init_val,
			 double min_val,
			 int num_steps) {

      this.name = new String(name);
      setLayout(new GridLayout(1,3));
      this.num_steps = num_steps;
      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+bubb);
      lb1= new Label(text + ": ");
      lb1.setAlignment(Label.RIGHT);
      lb2= new Label("" + init_val);
      add(lb1);
      add(lb2);
      add(sb);
   }

   public void set_val(int n) {
      val = (n * fak) + min_val;
      if (val > max_val) val = max_val;
      if (val < min_val) val = min_val;
      lb2.setText((val+"        ").substring(0,6));
   }
}

public class gruppe extends Applet implements Runnable {
   gruppe_viewport vp=null;
   Thread engine=null;
   gruppe_slider s[];
   int delay_time=75;
   int max_item=10;
   int max_wellen=10;
   int num_wellen=2;
   Label lb;
   Button ba[];

   public void init () {
      setLayout(new BorderLayout());
      setBackground(Color.lightGray);
      Panel leiste = new Panel();

      Panel button_leiste = new Panel();
      button_leiste.setLayout(new GridLayout(1,max_wellen-1));
      ba = new Button[max_wellen-1];
      for (int i=0; i < (max_wellen-1); i++) {
	 ba[i] = new Button("" + (i+2));
	 ba[i].setBackground(Color.lightGray);
	 button_leiste.add(ba[i]);
      }
      ba[num_wellen-2].setBackground(Color.orange);

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

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

      s = new gruppe_slider[4];
      s[0] = new gruppe_slider("eps","eps", 0.2, 0.08, 0.0, 200);
      s[1] = new gruppe_slider("lambda",
			       "Wellenlänge [pix]",
			       80.0, 25.0, 10.0, 160);
      s[2] = new gruppe_slider("vgr",
			       "Gruppengeschw. [pix/sek]",
			       200.0, 20.0, -100.0, 200);
      s[3] = new gruppe_slider("c0",
			       "Phasengeschw. [pix/sek]",
			       200.0, 20.0, -100.0, 200);

      //grid.add(new Label("Parameter:"));
      grid.add(s[0]);
      grid.add(s[1]);
      grid.add(s[2]);
      grid.add(s[3]);

      Panel pp = new Panel();
      pp.setLayout(new GridLayout(1,3));
      Label lb = new Label("Anzahl der Wellen: ");
      lb.setAlignment(Label.RIGHT);
      pp.add(lb);
      pp.add(button_leiste);
      pp.add(new Label(""));

      grid.add(pp);

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

      vp = new gruppe_viewport(max_wellen, delay_time);
      add ("Center", vp);

      if (vp != null) {
	 for (int i=0; i < 4; i++) {
	    vp.set_param(s[i].name, s[i].val);
	 }
      }
      vp.set_num(num_wellen);
   }

   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);
      if (evt.arg != null) {
	 if ("Start".equals(arg)) {
	    stop();
	    engine_start();
	 }
	 else if ("Stop".equals(arg)) {
	    stop();
	 }
	 else if ("||>".equals(arg)) {
	    if (vp != null) vp.advance();
	 }
         for (int i=2; i <= max_wellen; i++) {
            if ((""+i).equals(arg)) {
	       ba[num_wellen-2].setBackground(Color.lightGray);
	       num_wellen=i;
	       ba[i-2].setBackground(Color.orange);
	       vp.set_num(i);
	       vp.repaint();
            }
         }
      }
      return true;
   }

   public boolean handleEvent(Event evt) {
      //System.out.println(evt);
      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);
	       vp.set_param(s[i].name, s[i].val);
	       vp.repaint();
	       return true;
	    }
	 }
      }
      return super.handleEvent(evt);
   }
}

