// File: Universe.java 
// Written by Michael Main (main@colorado.edu) -- Mar 10, 1999

import java.applet.Applet;  // Provides Applet class
import java.awt.*       ;   // Provides Button, Canvas, Graphics class
import java.awt.event.*;    // Provides ActionListener, ActionEvent classes
import java.util.Vector;    // Provides Vector class
import Particle;            // Provides my own Particle class

public class Universe extends Applet
{  
   // Constants that tell where to draw the bounding box:
   final int TOP = 110;    // Distance of top line from top of the applet
   final int BOTTOM = 30;  // Distance of bottom line from bottom of applet
   final int SIDE = 10;    // Distance of side lines from sides of applet
 
   // Declare the button components at the top of the screen.
   Button proton = new Button("PROTON");
   Button electron = new Button("ELECTRON");
   Button pause = new Button(" PAUSE ");
   
   // The Particle threads are stored in a Vector for easy access. 
   // And there is a single Graphics object that all the threads share:
   Vector particles = new Vector( );
   Graphics shared = null;
   
   // The init method is called once before the applet starts.     
   // The responsibility of init() for an applet is to initialize any member
   // variables that are not yet initialized, and to place components in
   // the applet. However, the init() method cannot draw anything or initialize
   // the shared Graphics object because the
   // applet has not yet appeared on the screen when init is called. 
   public void init( )
   {
      ButtonListener listener;
 
      // Set Applet's background color to what the Particle wants.
      setBackground(Particle.BACKGROUND);

      // Place the buttons and other components on the applet.
      add (new Label("Michael Main presents The Particles!"));
      addNewLine( );
      add(proton);
      add(electron);
      addNewLine( );
      add(pause);
      
      // Create a new ActionListener for the proton/electron buttons.
      listener = new ButtonListener( );
      proton.addActionListener(listener);
      electron.addActionListener(listener);

      // Create a new ActionListener for the pause button.
      pause.addActionListener(new PauseListener( ));
   }        
   
   // Start is called once the applet has been placed on the screen.
   // It is recalled whenever the browser goes elsewhere and later comes
   // back to this applet.
   public void start( )
   {
      if (shared == null)
      {  // This is first activation, so get the shared Graphics object.
         shared = getGraphics( );
      }
      else synchronized(pause)
      {
         if (pause.getLabel( ).equals(" PAUSE "))
            resume_all( );
         else
            /* Leave the process suspended until user clicks RESUME. */ ;
      }
   }

   // Restart all the Particle threads.    
   private void resume_all( )
   {
      int i;
      Particle p;
      
      // Resume the processes
      for (i = 0; i < particles.size( ); i++)
      {
         p = (Particle) particles.elementAt(i);
         p.resume( );
      }
      
      // Enable the buttons
      proton.setEnabled(true);
      electron.setEnabled(true); 
   }
   
   // This function is called whenever the Applet is minimized. It
   // suspends all the Particle Threads.
   public void stop( )
   {
      synchronized(pause)
      {
         suspend_all( );
      }
   }
   
   // This function is called when the applet is stopped. It kills
   // all the Particle Threads and returns the resources of the
   // Graphics object.
   public void destroy( )
   {
      int i;
      Particle p;
      
      // Disable the buttons
      proton.setEnabled(false);
      electron.setEnabled(false);

      // Kill the processes
      for (i = 0; i < particles.size( ); i++)
      {
         p = (Particle) particles.elementAt(i);
         p.stop( );
      }
      
      // Return the resources used by the shared Graphics object.
      shared.finalize( );
   }

   // Suspend all the Particle Threads.   
   private void suspend_all( )
   {
      int i;
      Particle p;
      
      // Disable the buttons
      proton.setEnabled(false);
      electron.setEnabled(false);
      
      // Suspend the threads
      for (i = 0; i < particles.size( ); i++)
      {
         p = (Particle) particles.elementAt(i);
         p.suspend( );
      }
   }
   
   // The paint method will be called by the Java runtime system when the
   // applet is first placed on the screen. It is also called any time the 
   // applet needs to be redrawn (such as a resizing). In general, paint
   // is responsible for drawing or redrawing fixed lines and other drawings
   // that are always in the applet. On the other hand, it does not draw or
   // redraw moving objects--those need to be handled by threads that are
   // running concurrently with the applet.
   public void paint(Graphics g)
   {
      // Get the current height and width of the applet:
      int height = getSize( ).height;
      int width = getSize( ).width;
    
      // Set clip rectangle for the shared Graphics object used by all balls:
      // This is only needed if the size has changed since previous paint.  
      shared.setClip(SIDE+1, TOP+1, width-2*SIDE-2, height-TOP-BOTTOM-2);

      // Draw a black rectangle. The first two parameters are the x,y
      // coordinates of the top-left corner. The next two parameters
      // are the width and height. The actual bottom right corner is
      // at x+width, y+height.
      g.setColor(Color.black);
      g.drawRect(SIDE, TOP, width-2*SIDE, height-TOP-BOTTOM);
   }
      
   class ButtonListener implements ActionListener
   {
      public void actionPerformed(ActionEvent event)
      {  
         Particle p;
         final double P_MASS = 1000.0;
         final double P_CHARGE = 1.0;
         final double E_MASS = 1.0;
         final double E_CHARGE = -1.0;

         if (event.getActionCommand( ).charAt(0) == 'P')         
            p = new Particle(shared, particles, P_MASS, P_CHARGE);
         else
            p = new Particle(shared, particles, E_MASS, E_CHARGE);

         particles.addElement(p);
         p.start( );
      }       
   }

   class PauseListener implements ActionListener
   {  
      public void actionPerformed(ActionEvent event)
      { 
         synchronized(pause)
         { 
            if (pause.getLabel( ).equals(" PAUSE "))
            {
               pause.setLabel("RESUME");
               suspend_all( );
            }
            else
            {
               pause.setLabel(" PAUSE ");
               resume_all( );
            }     
         }
      }       
   }

   private void addHorizontalLine(Color c)
   {  
      // Add a Canvas 10000 pixels wide but only 1 pixel high, which acts as
      // a horizontal line to separate one group of components from the next.
      Canvas line = new Canvas( );
      line.setSize(10000,1);
      line.setBackground(c);
      add(line);
   }

   private void addNewLine( ) 
   {  
      // Add a horizontal line in the background color. The line itself is
      // invisible, but it serves to force the next Component onto a new line.
      addHorizontalLine(getBackground( ));
   }
}




