//------------------------------------------------------------------------------
// Java Web Applet
// Copyright (C) 1999,2001 Alexander Adam
// NO WARRANTY OF ANY KIND.
//------------------------------------------------------------------------------

/**
 * Spider Web Applet
 */

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class Web
  extends Applet
  implements Runnable
{
  /**
  Instance Variables
  */

  boolean refreshUpdate = true;         // Flag for update() function

  final int lines = 6;                  // Number of Web Crossing Lines

  Thread spider;                        // Spider Thread

  int sx;                               // Applet (Image) size - width
  int sy;                               // Applet (Image) size - height
  int mx;                               // SpiderWeb middle x
  int my;                               // SpiderWeb middle y
  int rx;                               // := sx - mx
  int ry;                               // := sy - my

                                        // Angles of Web Crossing Lines
  int    angleDeg[] = new int[lines];
  double angleRad[] = new double[lines];

                                        // Intersection Points ( Lines / Frame )
  int lx1[] = new int[lines];
  int lx2[] = new int[lines];
  int ly1[] = new int[lines];
  int ly2[] = new int[lines];

  int workingLine;                      // working line
  int workingRound;                     // working round
  int workingDistance;                  // working distance from (mx,my)

  Polygon webPolygon;                   // The Web Points (not a real Polygon)

  /**
  init()
  */
  public void init()
  {
    /**
    Set  Layout
    */
    setLayout(new BorderLayout());
    Button initButton = new Button("Applet neu starten");
    Button stopButton = new Button("Applet anhalten");
    initButton.addActionListener(new initListener());
    stopButton.addActionListener(new stopListener());

    add("North",initButton);
    add("South",stopButton);
  }

  /**
  start()
  */
  public void start()
  {
    /**
    Start Spider Thread
    */
    if (spider == null)
    {
      // Refresh Screen
      refreshUpdate = true;
      repaint();

      /**
      Initialize Variables
      */
      sx = getSize().width;                  // get Applet width
      sy = getSize().height;                 // get Applet height

      // Calculate Web Centerpoint
      mx = (int)Math.round( ( sx - (sx * Math.random()) / 4 + sx / 8 ) / 2 );
      my = (int)Math.round( ( sy - (sy * Math.random()) / 4 + sy / 8 ) / 2 );

      rx = sx - mx;
      ry = sy - my;

      /*
      * Calculate Web Crossing Lines
      */
      double angleEdge1 = Math.asin( my / Math.sqrt( rx * rx + my * my ) );
      double angleEdge2 = Math.PI - Math.asin( my / Math.sqrt( mx * mx + my * my ) );

      for ( int i = 0; i < lines; i++ )
      {
        // Genrate (random) angles from 0 .. 180 Degrees
        angleDeg[i] = (int)Math.round( 180 * i / lines + Math.random() * 4 );
        angleRad[i] = Math.PI * angleDeg[i] / 180;

        // Calculate Points of Intersection for Lines and Applet Frame
        if ( angleRad[i] < angleEdge1 )
        {
          // Line cuts left and right, calculate y-values
          double fact = Math.sin( angleRad[ i ] );
          fact = fact * fact;
          fact = Math.sqrt( fact / ( 1 - fact ) );

          lx1[i] = 0;
          ly1[i] = (int)Math.round( my + fact * mx );
          lx2[i] = sx - 1;
          ly2[i] = (int)Math.round( my - fact * rx );
        }
        else if ( angleRad[i] > angleEdge2 )
        {
          // Line cuts left and right, calculate y-values
          double fact = Math.sin( angleRad[ i ] );
          fact = fact * fact;
          fact = Math.sqrt( fact / ( 1 - fact ) );

          lx1[i] = 0;
          ly1[i] = (int)Math.round( my - fact * mx );
          lx2[i] = sx - 1;
          ly2[i] = (int)Math.round( my + fact * rx );
        }
        else if ( angleRad[i]*2 > Math.PI )
        {
          // Line cuts top and bottom, calculate x-values
          double fact = Math.cos( angleRad[ i ] );
          fact = fact * fact;
          fact = Math.sqrt( fact / ( 1 - fact ) );

          lx1[i] = (int)Math.round( mx - fact * my );
          ly1[i] = 0;
          lx2[i] = (int)Math.round( mx + fact * ry );
          ly2[i] = sy - 1;
        }
        else
        {
          // Line cuts top and bottom, calculate x-values
          double fact = Math.cos( angleRad[ i ] );
          fact = fact * fact;
          fact = Math.sqrt( fact / ( 1 - fact ) );

          lx1[i] = (int)Math.round( mx + fact * my );
          ly1[i] = 0;
          lx2[i] = (int)Math.round( mx - fact * ry );
          ly2[i] = sy - 1;
        }
      }

      // Initialize the rest
      workingLine = 0;
      workingRound = 1;
      workingDistance = 1;

      webPolygon = new Polygon();
      spider = new Thread(this);
      spider.start();
    }
  }

  /**
  stop()
  */
  public void stop()
  {
    /**
    Stop Spider Tread
    */
    spider = null;
  }

  /**
  run()
  */
  public void run()
  {
    double lAngle;                      // for current line angle
    boolean runsOutOfApplet = false;    // termination condition

    Thread currentThread = Thread.currentThread();

    while (spider == currentThread && !runsOutOfApplet)
    {
      // Continnue Web Polygon

      // Determine new working Distance
      if ( workingRound < 5 )
      {
        if ( workingLine % 2 == 0 )
        {
          workingDistance++;
        }
      }
      else if ( workingRound < 8 )
      {
        workingDistance++;
      }
      else
      {
        workingDistance++;
        if ( workingLine % 4 == 0 )
        {
          workingDistance--;
        }
      }

      if ( workingLine < lines )
      {
        lAngle = angleRad[workingLine];
      }
      else
      {
        lAngle = Math.PI + angleRad[workingLine-lines];
      }

      // Calculate new point on workingLine
      int px = mx + (int)Math.round( Math.sin( lAngle ) * workingDistance );
      int py = my + (int)Math.round( Math.cos( lAngle ) * workingDistance );

      // Check termination Condition ( Spider out of Frame )
      if ( px < 0 || px >= sx || py < 0 || py >= sy )
      {
        runsOutOfApplet = true;
      }
      else
      {
        // Add new point
        webPolygon.addPoint( px, py );
      }

      // ... jump to next line
      workingLine++;

      if ( workingLine == lines * 2 )
      {
        workingLine = 0;
        workingRound++;
      }

      // Do a repaint
      repaint();

      // Give the spider a sleep
      try {
          Thread.sleep(100);
      } catch (InterruptedException e) { }
    }
  }

  /**
  update()
  */
  public void update(Graphics screen)
  { 
    if ( refreshUpdate ) 
    {
      screen.setColor(getBackground());
      screen.fillRect(0,0,getSize().width,getSize().height);
      screen.setColor(getForeground());
      refreshUpdate = false;
    }
    paint(screen);
  }

  /**
  paint()
  */
  public void paint(Graphics screen)
  {
    int n = 0;                          // for webPolygon.npoints
    int x1;
    int y1;
    int x2;
    int y2;

    setBackground( Color.white );

    if ( webPolygon != null )
    {
      n = webPolygon.npoints;
    }

    if ( n > 2 )
    {
      // Clear 'old' Spider
      x2 = webPolygon.xpoints[n-2];
      y2 = webPolygon.ypoints[n-2];

      screen.setColor( Color.white );
      screen.drawLine( x2-2, y2-2, x2+2, y2+2 );
      screen.drawLine( x2+2, y2-2, x2-2, y2+2 );
      screen.drawLine( x2-2, y2, x2+2, y2-2 );
    }

    screen.setColor( Color.black );
    for ( int l = 0; l < lines; l++ )
    {
      // Draw Web Crossing Lines
      screen.drawLine( lx1[l], ly1[l], lx2[l], ly2[l] );
    }

    if ( n > 1 )
    {
      // Draw Web
      for ( int i = 1; i < webPolygon.npoints; i++ )
      {
        x1 = webPolygon.xpoints[i-1];
        y1 = webPolygon.ypoints[i-1];
        x2 = webPolygon.xpoints[i];
        y2 = webPolygon.ypoints[i];
        screen.drawLine( x1, y1, x2, y2 );
      }

      // Draw 'new' Spider
      x2 = webPolygon.xpoints[n-1];
      y2 = webPolygon.ypoints[n-1];
      screen.drawLine( x2-2, y2-2, x2+2, y2+2 );
      screen.drawLine( x2+2, y2-2, x2-2, y2+2 );
      screen.drawLine( x2-2, y2, x2+2, y2-2 );
    }
  }

  /**
  initListener()
  */
  private class initListener implements ActionListener {

    public void actionPerformed(ActionEvent evt) {
      stop();
      start();
    }
  }

  /**
  stopListener()
  */
  private class stopListener implements ActionListener {

    public void actionPerformed(ActionEvent evt) {
      stop();
    }
  }
}

