//-*-java-*-

Worm {
  (@
   private static int counter = 0;
   private int id;
   private static Random rand = new Random();

   private Point next; // Top left corner of worm segment

   private Color color = new Color(Math.abs(rand.nextInt()) % 156, 
				   Math.abs(rand.nextInt()) % 156,
				   Math.abs(rand.nextInt()) % 156);
   private Point[] coords; // "head" at [0]
   private double direction; // radians
   private int last_turn;
   private int speed = 50;
   private Worms field;

   Worm(Worms w) {
     field = w;
     id = counter++;
     next = new Point();
     next.x = Math.abs(rand.nextInt()) % (WIDTH-WORM_THICKNESS) + LEFT;
     next.y = Math.abs(rand.nextInt()) % (HEIGHT-WORM_THICKNESS) + TOP;
     coords = new Point[WORM_LENGTH];
     for(int i=0;i<WORM_LENGTH;i++) coords[i] = new Point(next);
     direction = Math.abs(rand.nextInt()) % 16;
   }
  @)

  public void run() (@
    for(;;) {
      try { Thread.sleep(speed); }
      catch(InterruptedException e) {}
      newSpeed();
      newDirection();
      step();
      field.repaint();
    }
  @)

  private void newSpeed() (@
    if(rand.nextInt()%50 == 0) {
      speed = 50 + rand.nextInt()%30;
    } else {
      if(speed < 30) ++speed;
      else if(speed > 90 && (rand.nextInt()>0)) --speed;
      else speed += rand.nextInt()%5;
    }
  @)

  private void newDirection() (@
    int delta = rand.nextInt()%3;
    if(delta > 1) delta = 1;
    else if(delta < -1) delta = -1;
    delta += last_turn;
    if(delta < -2) delta = -2;
    else if(delta > 2) delta = 2;

    direction = (direction + delta*Math.PI/8) % (Math.PI*2);
    int new_x = (int)(next.x + Math.cos(direction)*WORM_STEP);
    int new_y = (int)(next.y - Math.sin(direction)*WORM_STEP);
    if(new_x < LEFT) {
      if(new_y < TOP) direction = Math.PI/4*7;
      else if(new_y > BOTTOM - WORM_THICKNESS) direction = Math.PI/4;
      else direction = 0;
    } else if(new_x > RIGHT - WORM_THICKNESS) {
      if(new_y < TOP) direction = Math.PI/4*5;
      else if(new_y > BOTTOM - WORM_THICKNESS) direction = Math.PI/4*3;
      else direction = Math.PI;
    } else if(new_y < TOP) {
      direction = Math.PI/2*3;
    } else if(new_y > BOTTOM - WORM_THICKNESS) {
      direction = Math.PI/2;
    }
    
    next.x = new_x;
    next.y = new_y;
  @)

  private void step() (@
    for(int i = WORM_LENGTH-1;i>0;i--) coords[i].setLocation(coords[i-1]);
    coords[0].setLocation(next);
  @)

  (@
   private static final int TOP = 24;
   private static final int BOTTOM = Worms.HEIGHT-6; // 354
   private static final int LEFT = 5;
   private static final int RIGHT = Worms.WIDTH-6; // 474
   private static final int WIDTH = RIGHT-LEFT+1;
   private static final int HEIGHT = BOTTOM-TOP+1;
   private static final int WORM_THICKNESS = 19;
   private static final int WORM_STEP = WORM_THICKNESS/3;
   private static final int WORM_LENGTH = 37;
   @)

  void draw(Graphics g) (@
    for(int i=WORM_LENGTH-1;i>=0;i--) {
      g.setColor(color);
      g.fillOval(coords[i].x, coords[i].y, WORM_THICKNESS, WORM_THICKNESS);
      //g.setColor(Color.black);
      //g.drawOval(coords[i].x, coords[i].y, WORM_THICKNESS, WORM_THICKNESS);
      // Why the size discrepancy?
    }

    int head_x = coords[0].x + WORM_THICKNESS/2;
    int head_y = coords[0].y + WORM_THICKNESS/2;

    int left_x = (int)(head_x - WORM_THICKNESS/5*Math.sin(direction));
    int left_y = (int)(head_y - WORM_THICKNESS/5*Math.cos(direction));
    int right_x = (int)(head_x + WORM_THICKNESS/5*Math.sin(direction));
    int right_y = (int)(head_y + WORM_THICKNESS/5*Math.cos(direction));

    g.setColor(Color.white);
    g.drawLine(left_x, left_y, left_x, left_y);
    g.drawLine(right_x, right_y, right_x, right_y);
  @)
}