/************************************************************************************************

Image map with pop-up text displays.

<applet code="IMap.class" width=w height=h>
<param name="mapimage" value="url" or "url,color">
<param name="fgcolor" value="color">
<param name="bgcolor" value="color">
<param name="border" value="size,color">
<param name="font" value="name,style,size">
<param name="margins" value="n,m">
<param name="outline" value="color">
<param name="toggle" value="n" or "n,color"> where n is 0 or 1 
<param name="default" value="url" or "url,target">
<param name="status" value="string">
<param name="shape-1" value="rect,x1,y1,x2,y2" 
                            or "circle,x,y,r"
                            or "ellipse,x,y,a,b" 
			    or "polygon,x1,y1,x2,y2,...,xn,yn">
<param name="url-1" value="url" or "url,target">
<param name="status-1" value="string">
<param name="text-1-1" value="string" or "indent|string">
<param name="text-1-2" value="string" or "indent|string">
<param name="text-1-3" value="string" or "indent|string">
       ...
<param name="shape-n" value="rect,x1,y1,x2,y2" or "circle,x,y,r"
                            or "ellipse,x,y,a,b" or "polygon,x1,y1,x2,y2,...,xn,yn">
<param name="url-n" value="url" or "url,target">
<param name="status-n" value="string">
<param name="text-n-1" value="string" or "indent|string">
<param name="text-n-2" value="string" or "indent|string">
<param name="text-n-3" value="string" or "indent|string">
<param name="sound-1" value="string">
       ...
</applet>

************************************************************************************************/

import java.awt.*;
import java.awt.image.*;
import java.net.*;
import java.util.*;
import java.applet.*;

/************************************************************************************************
  The LoadSound class is a thread which 
   loads sound files associated with the images.
************************************************************************************************/
class LoadSound extends Thread {
  
  public static AudioClip sound = null;
  protected IMap applet;
  public static Vector soundclips = new Vector (10,5);

    // Constructor 

  public LoadSound (AudioClip sound,IMap applet)
   {
     this.sound = sound;
     this.applet = applet;
     this.start();
   }

  public void run () 
   {
     String name = null;
     String s = null; 
     int i = 1;

     do {
        try {
            s = applet.getParameter ( "shape-" + i); // test to see if there is a shape
	    if (s != null) // if there is a shape attempt to load its sound
	  {
	    name = applet.getParameter ( "sound-" + i);
	    if ( name != null) 
	       {
	         sound = applet.getAudioClip ( new URL (applet.getDocumentBase(),name));
	         soundclips.addElement (sound); 
	       }

	    // add a null clip to fill up the index so later sounds can be accessed
	    else {
                     sound=null;
                     soundclips.addElement (sound);
	    }//end else

	   } 
	 } catch (Exception e) { }
             i++;
           } while ( s != null);
     soundclips.trimToSize( );// trim down the vector
     return;
   } //end run
} //end LoadSound

/************************************************************************************************
  The IMapArea class defines the area shape, 
  position and text for the the pop-up box.
************************************************************************************************/  
class IMapArea {

  // Constants:

  private final static int RECT    = 1;           // Shape types.
  private final static int ELLIPSE = 2;
  private final static int POLY    = 3;

  // Fields:

  private int       shape;                        // This area's shape, one of:
  private Rectangle rect;                         //   rectangle
  private int       x, y, a, b;                   //   ellipse
  private Polygon   poly;                         //   polygon

  public URL       url    = null;                 // URL: link to when clicked.
  public String    target = null;                 // Target window.
  public String    status = null;                 // Status window message.

  private Vector   text   = new Vector(10, 5);    // Text line array.
  private Vector   indent = new Vector(10, 5);    // Indent for each text line.
  private int      count  = 0;                    // Number of text lines.

  public  int      width  = 0;                    // Width of text box.
  public  int      height = 0;                    // Height of text box.





  // Constructors:

  // Create an area of the appropriate shape.

  public IMapArea(Rectangle rect) {
    this.shape = RECT;
    this.rect  = rect;
  }



  public IMapArea(int x, int y, int a, int b) {
    this.shape = ELLIPSE;
    this.x = x;
    this.y = y;
    this.a = Math.abs(a);
    this.b = Math.abs(b);
  }



  public IMapArea(Polygon poly) {
    this.shape = POLY;
    this.poly = poly;
  }





  // Methods:

  // Determine the area shape.

  public boolean isRect() {
    if (this.shape == RECT)
      return(true);
    return(false);
  }





  public boolean isEllipse() {
    if (this.shape == ELLIPSE)
      return(true);
    return(false);
  }





  public boolean isPoly() {
    if (this.shape == POLY)
      return(true);
    return(false);
  }





  // Return the area as a shape object 
  // with the appropriate coordinates, useful for drawing.

  public Rectangle getRect() {
    if (this.isRect())
      return(this.rect);
    return(new Rectangle());
  }





  public Rectangle getEllipse() {
    if (this.isEllipse())
      return(new Rectangle(this.x - this.a, 
			   this.y - this.b, 
			   this.a * 2, 
			   this.b * 2));
    return(new Rectangle());
  }





  public Polygon getPoly() {
    if (this.isPoly())
      return(this.poly);
    return(new Polygon());
  }





  // Find the smallest rectangle that contains the shape.

  public Rectangle getBoundingBox() {
    Rectangle rect;
    rect = new Rectangle();
    if (this.isRect())
      rect = this.rect;
    if (this.isEllipse())
      rect = this.getEllipse();
    if (this.isPoly())
      rect = this.poly.getBoundingBox();
    return(rect);
  }




  // Set the URL to link to.

  public void setURL(URL url) {
    this.url = url;
  }



  // Set the URL and target frame or window to link to.

  public void setURL(URL url, String target) {
    this.url = url;
    this.target = target;
  }



  // Set the message to display in the status window when this link is active.

  public void setStatusMsg(String msg) {
    this.status = msg;
  }



  // Determine if a given point is inside the area.

  public boolean inside(int x, int y) {
    double v;

    if (this.isRect())
      return(this.rect.inside(x, y));

    if (this.isEllipse()) {
      x -= this.x;
      y -= this.y;
      if (Math.abs(x) > this.a || Math.abs(y) > b)
        return(false);
      v = (int) ((double) this.b * 
		 Math.sqrt(1.0 - (double) (x * x) 
			   / (double) (this.a * this.a)));
      if (Math.abs(y) <= v) 
        return(true);
    }

    if (this.isPoly())
      return(this.poly.inside(x, y));

    return(false);
  }



  // Add a line of text with the specified indentation.

  public void addText(int n, String s) {
    this.indent.addElement(new Integer(n));
    this.text.addElement(s);
    this.count++;
  }



  // Get a line of text.

  public String getText(int i) {
    if (i >= 0 && i < this.count)
      return((String) this.text.elementAt(i));
    else
      return((String) null);
  }




  // Get amount of indentation for a line of text.

  public int getIndent(int i) {
    if (i >= 0 && i < this.count)
      return(Integer.parseInt(this.indent.elementAt(i).toString()));
    else
      return(0);
  }




  // Get number of text lines.

  public int getCount() {
    return(this.count);
  }
}





/************************************************************************************************
  Main applet code.
************************************************************************************************/



public class IMap extends Applet {

    // Parameters and defaults.

    Image   mapImage   = null;           // Map image.
    Color   pgColor    = Color.white;    // Applet background color.
    Color   fgColor    = Color.black;    // Text color.
    Color   bgColor    = Color.white;    // Text box background color.
    int     bdSize     = 0;              // Text box border size.
    Color   bdColor;                     // Text box border color.
    String  fontName   = "Dialog";       // Text font.
    int     fontStyle  = Font.PLAIN;     // Text font style.
    int     fontSize   = 12;             // Text font size.
    int     hrznMargin = 10;             // Horizontal margin for text.
    int     vertMargin = 10;             // Verticle margin for text.
    boolean olFlag     = false;          // Area outline flag.
    Color   olColor    = Color.black;    // Area outline color.
    boolean tgFlag     = false;          // Toggle area outline flag.
    Color   tgColor    = Color.gray;    // Toggle area outline color.
    String  tgSwitch   = null;           // Double toggle area outline flag.
    int     tgThick    = 2;              // Thickness of toggled area borders.
    URL     defaultUrl = null;           // Default image map link.
    String  target     = null;     // Target window or frame for default link.
    String  status     = null;     // Status window message for default link.

    // Global variables.

    Vector areas = new Vector(10, 5);    // A list of all the defined areas.

    IMapArea area;                       // The currently active area.
    int      activeArea = -2;            // initialized to -2 so we can
    // detect when the applet is first started.  It changes to -1 and
    // then to other non-negative values, but never that self-same
    // -2 again.  
    int      drawAll = 0  ;            // bob: 

    boolean toggle_on = true; // kevin
    AudioClip sound = null;  //kevin
    LoadSound loadsound = null; //kevin

    Font font;                           // Font size values.
    int  xAdvance;
    int  yAscent;
    int  yHeight;

    Dimension offDimension;              // Off-screen graphic for drawing.
    Image     offImage;
    Graphics  offGraphics;




    // Applet information.

    public String getAppletInfo() 
    {
	return("IMap version 1.5\n\nCopyright 1997 by Mike Hall\n\nwith toggle coded added by\n\nRobert W. Williams Apr. 1999.");
    }




    public void init() {

	String s, t, u;
	StringTokenizer st;
	URL url;
	int i, j;
	Graphics g;
	FontMetrics fm;
	int n;

	// Take credit.

	System.out.println("This code is based primarily on");
	System.out.println("IMap version 1.5, Copyright 1997 by Mike Hall.");
	System.out.println("Toggle code added by Bob Williams, Apr. 1999");


	// Get the map image and optional background color 
	// and start loading the image.

	try {
	    s = getParameter("mapimage");
	    if (s != null) {
		st = new StringTokenizer(s, ",");
		mapImage = getImage(new URL(getDocumentBase(), 
					    st.nextToken()));
		prepareImage(mapImage, this);
		if (st.hasMoreTokens())
		    pgColor = getColorParm(st.nextToken());
	    }
	}
	catch (Exception e) {}

       
	// Get the pop-up text box colors.

	try {
	    s = getParameter("fgcolor");
	    if (s != null)
		fgColor = getColorParm(s);
	}
	catch (Exception e) {}
	bdColor = fgColor;
	try {
	    s = getParameter("bgcolor");
	    if (s != null)
		bgColor = getColorParm(s);
	}
	catch (Exception e) {}



	// Get the pop-up text box border parameters.

	try {
	    s = getParameter("border");
	    if (s != null) {
		st = new StringTokenizer(s, ",");
		if ((n = Integer.parseInt(st.nextToken())) > 0)
		    bdSize = n;
		if (st.hasMoreTokens())
		    bdColor = getColorParm(st.nextToken());
	    }
	}
	catch (Exception e) {}



	// Get the text box font.

	try {
	    s = getParameter("font");

	    // Font name.

	    st = new StringTokenizer(s, ",");
	    t = st.nextToken();
	    if (t.equalsIgnoreCase("Courier"))
		fontName = "Courier";
	    else if (t.equalsIgnoreCase("Dialog"))
		fontName = "Dialog";
	    else if (t.equalsIgnoreCase("Helvetica"))
		fontName = "Helvetica";
	    else if (t.equalsIgnoreCase("Symbol"))
		fontName = "Symbol";
	    else if (t.equalsIgnoreCase("TimesRoman"))
		fontName = "TimesRoman";

	    // Font style.

	    t = st.nextToken();
	    if (t.equalsIgnoreCase("plain"))
		fontStyle = Font.PLAIN;
	    else if (t.equalsIgnoreCase("bold"))
		fontStyle = Font.BOLD;
	    else if (t.equalsIgnoreCase("italic"))
		fontStyle = Font.ITALIC;
	    else if (t.equalsIgnoreCase("boldItalic"))
		fontStyle = Font.BOLD + Font.ITALIC;

	    // Font size.

	    t = st.nextToken();
	    if ((n = Integer.parseInt(t)) > 0)
		fontSize = n;
	}
	catch (Exception e) {}

	// Get the pop-up text box margins.

	try {
	    s = getParameter("margins");
	    if (s != null) {
		st = new StringTokenizer(s, ",");
		if ((n = Integer.parseInt(st.nextToken())) > 0)
		    hrznMargin = n;
		if ((n = Integer.parseInt(st.nextToken())) > 0)
		    vertMargin = n;
	    }
	}
	catch (Exception e) {}

	// Get the area outline color.

	try {
	    s = getParameter("outline");
	    if (s != null) {
		olColor = getColorParm(s);
		olFlag = true;
	    }
	}
	catch (Exception e) {}



	// Get the toggle outline parameters.
	// Added by Bob Williams.
	try {
	    s = getParameter("toggle");
	    if (s != null) {
		tgFlag = true;
		st = new StringTokenizer(s, ",");
		// Thickness of outline border in pixels?
		if ((n = Integer.parseInt(st.nextToken())) > -1)
		    tgThick = n;
		if (st.hasMoreTokens())
		    tgColor = getColorParm(st.nextToken());
		// Switch all "other" outlines off when in active area?
		if (st.hasMoreTokens())
		    tgSwitch = st.nextToken();
	    }
	}
	catch (Exception e) {}




	// Get the default URL, 
	// target and status window message for the image map.

	try {
	    s = getParameter("default");
	    st = new StringTokenizer(s, ",");
	    t = st.nextToken();
	    try {
		url = new URL(getDocumentBase(), t);
		if (st.hasMoreTokens()) {
		    t = st.nextToken();
		    target = t;
		}
		defaultUrl = url;
	    }
	    catch (MalformedURLException e) {}
	}
	catch (Exception e) {}



	try {
	    s = getParameter("status");
	    if (s != null)
		status = s;
	}
	catch (Exception e) {}




	// Get data for each image map area.

	s = null;
	i = 1;
	do {
	    try {
		s = getParameter("shape-" + i);
		if (s != null) {
		    getShape(s);

		    // Get the URL, target and status window message.

		    try {
			t = getParameter("url-" + i);
			st = new StringTokenizer(t, ",");
			u = st.nextToken();
			try {
			    url = new URL(getDocumentBase(), u);
			    if (st.hasMoreTokens()) {
				u = st.nextToken();
				area.setURL(url, u);
			    }
			    else
				area.setURL(url);
			}
			catch (MalformedURLException e) {}
		    }
		    catch (Exception e) {}

		    try {
			t = getParameter("status-" + i);
			if (t != null)
			    area.setStatusMsg(t);
		    }
		    catch (Exception e) {}

		    // Get text to display in the pop-up 
                    // text box for this area.

		    t = null;
		    j = 1;
		    do {
			try {
			    t = getParameter("text-" + i + "-" + j);
			    if (t != null) {
				st = new StringTokenizer(t, "|");
				if (st.countTokens() > 1) {
				    n = Integer.parseInt(st.nextToken());
				    u = st.nextToken();
				}
				else {
				    n = 0;
				    u = t;
				}
				area.addText(n, u);
			    }
			}
			catch (Exception e) {}
			j++;
		    } while (t != null);

		    // Add the area to the list.

		    areas.addElement(area);
		}
	    }
	    catch (Exception e) {}
	    i++;
	} while (s != null);

	// Trim the areas list to reclaim unused space.

	areas.trimToSize();

	// Set size values based on the font.

	g = getGraphics();
	font = g.getFont();
	g.setFont(font = new Font(fontName, fontStyle, fontSize));
	fm = g.getFontMetrics();
	xAdvance = fm.getMaxAdvance();
	yAscent = fm.getMaxAscent();
	yHeight = fm.getHeight();

	// Calculate the size of the pop-up text box for each area.

	for (i = 0; i < areas.size(); i++) {
	    area = (IMapArea) areas.elementAt(i);
	    //		System.out.println("area.elementAt(i) = " + area);
	    for (j = 0; j < area.getCount(); j++) {
		s = area.getText(j);
		//		System.out.println("area.getText(j) = " + s);
		n = area.getIndent(j) * xAdvance + fm.stringWidth(s);
		if (n > area.width)
		    area.width  = n;
	    }
	    area.width += 2 * hrznMargin;
	    area.height = area.getCount() * yHeight + 2 * vertMargin;
	}
    }
  


    public void start() {
	// init() gets called only once per a browser session while start()
	// gets called every time there is a reload
	// Start loading the sound files with the LoadSound thread
                loadsound = new LoadSound (sound,this);
    }

    public void stop() {
	// reset all variables, kill the thread if it is alive
	if ( loadsound != null && loadsound.isAlive())
	    loadsound.stop();
	loadsound = null;
	sound = null;
	loadsound.soundclips.removeAllElements();
    }






    private Color getColorParm(String s) 
    {
	int r, g, b;

	// Check if a pre-defined color is specified.

	if (s.equalsIgnoreCase("black"))
	    return(Color.black);
	if (s.equalsIgnoreCase("blue"))
	    return(Color.blue);
	if (s.equalsIgnoreCase("cyan"))
	    return(Color.cyan);
	if (s.equalsIgnoreCase("darkGray"))
	    return(Color.darkGray);
	if (s.equalsIgnoreCase("gray"))
	    return(Color.gray);
	if (s.equalsIgnoreCase("green"))
	    return(Color.green);
	if (s.equalsIgnoreCase("lightGray"))
	    return(Color.lightGray);
	if (s.equalsIgnoreCase("magenta"))
	    return(Color.magenta);
	if (s.equalsIgnoreCase("orange"))
	    return(Color.orange);
	if (s.equalsIgnoreCase("pink"))
	    return(Color.pink);
	if (s.equalsIgnoreCase("red"))
	    return(Color.red);
	if (s.equalsIgnoreCase("white"))
	    return(Color.white);
	if (s.equalsIgnoreCase("yellow"))
	    return(Color.yellow);

	// If the color is specified in HTML format, 
	// build it from the red, green and blue values.

	if (s.length() == 7 && s.charAt(0) == '#') {
	    r = Integer.parseInt(s.substring(1,3),16);
	    g = Integer.parseInt(s.substring(3,5),16);
	    b = Integer.parseInt(s.substring(5,7),16);
	    return(new Color(r, g, b));
	}
	// If we can't figure it out, default to black.
	return(Color.black);
    }






    private void getShape(String s) 
    {
	StringTokenizer st;
	String t;
	int x1, y1, x2, y2;
	int x, y, a, b;
	Polygon poly;

	// Set the area depending on the supplied shape parameters. 
	// (Note that a circle is a special
	// case of an ellipse where a = b.)

	st = new StringTokenizer(s, ",");
	t  = st.nextToken();
	if (t.equalsIgnoreCase("rect")) {
	    x1 = Integer.parseInt(st.nextToken());
	    y1 = Integer.parseInt(st.nextToken());
	    x2 = Integer.parseInt(st.nextToken());
	    y2 = Integer.parseInt(st.nextToken());
	    area = new IMapArea(new Rectangle(x1, y1, x2 - x1, y2 - y1));
	    return;
	}
	if (t.equalsIgnoreCase("circle")) {
	    x = Integer.parseInt(st.nextToken());
	    y = Integer.parseInt(st.nextToken());
	    a = Integer.parseInt(st.nextToken());
	    area = new IMapArea(x, y, a, a);
	    return;
	}
	if (t.equalsIgnoreCase("ellipse")) {
	    x = Integer.parseInt(st.nextToken());
	    y = Integer.parseInt(st.nextToken());
	    a = Integer.parseInt(st.nextToken());
	    b = Integer.parseInt(st.nextToken());
	    area = new IMapArea(x, y, a, b);
	    return;
	}
	if (t.equalsIgnoreCase("poly")) {
	    poly = new Polygon();
	    while (st.hasMoreTokens()) {
		x = Integer.parseInt(st.nextToken());
		y = Integer.parseInt(st.nextToken());

		poly.addPoint(x, y);
	    }
	    area = new IMapArea(poly);
	}
    }








    public boolean mouseExit(Event e, int x, int y) 
    {
	// This is called when the cursor leaves the image area,
	// and not (apparently) when the cursor leaves a hot area. 
	// Deactivate any currently active area and clear the status window.
	// System.out.println(" ");
	//System.out.println("entering mouseExit, activeArea = " + activeArea);
	// Do not draw all area outlines.
	drawAll=0;
	toggle_on = true; //outlines reappear when cursor enters image
	//	System.out.println("just set drawAll = " + drawAll);
	activeArea = -2;
	getAppletContext().showStatus("");
	repaint();
	//	System.out.println("exiting mouseExit ");
	//	System.out.println(" ");
	return true;
    }






    public boolean mouseMove(Event e, int x, int y) 
    {
	int last;
	int i;

	//System.out.println("entering mouseMove, activeArea = " + activeArea);
	// Save the currently active area.

	//xx	drawAll=0;

	last = activeArea;



	// If the mouse is over a area, 
	// mark it as active. (Go backwards thru the list to match the
	// behavior of image maps when areas overlap.)

	activeArea = -1;
	for (i = areas.size() - 1; i >= 0; i--) 
	    {
		area = (IMapArea) areas.elementAt(i);
		if (area.inside(x, y))
		    activeArea = i;
	    }



	// Update the display only if the active area 
	// has changed (this will save some processor
	// cycles).

	if (activeArea != last) 
	    {
		if (activeArea >= 0) 
		    {
			if (tgSwitch.equalsIgnoreCase("yes")) 
			drawAll = 0;	
			area = (IMapArea) areas.elementAt(activeArea);
			if (area.status != null)
			    getAppletContext().showStatus(area.status);
			else if (area.url != null)
			    getAppletContext().showStatus(area.url.toString());
			else
			    getAppletContext().showStatus("");
		    }
		repaint();

		// When no area is active, 
		//show the default status window message.

		if (activeArea < 0) 
		    {
			//bob
			//	System.out.println(" " );
			//	System.out.println("Repainting all" );
			// If mouseExit was called, activeArea was
			// set to -2.  Upon reentering the image area,
			// activeArea is set to -1, so a toggle takes
			// place that is seen here.
			if(toggle_on) {  // draw outlines only if user toggles them on 
			 drawAll=1;
			 repaint();
			}
			//System.out.println("drawAll shouldbe 1= " + drawAll);
			//System.out.println(" " );


			if (status != null)
			    getAppletContext().showStatus(status);
			else if (defaultUrl != null)
			    getAppletContext().showStatus(defaultUrl.toString());
			else
			    getAppletContext().showStatus("");
		    }
	    }

	return true;
    }




    public boolean mouseDrag(Event e, int x, int y) 
    {
	return true;
    }



    public boolean mouseDown(Event e, int x, int y) 
    {
	if (activeArea >= 0) {

               // If there is currently an active area with a URL, link to it.

	    area = (IMapArea) areas.elementAt(activeArea);
	    if (area.url != null)
		if (area.target != null)
		    getAppletContext().showDocument(area.url, area.target);
		else
		    getAppletContext().showDocument(area.url);
  
	// If there is currently an active area play the sounds

	    sound = (AudioClip) loadsound.soundclips.elementAt(activeArea);
	    if (sound != null)  { //if the sound is loaded :
	     sound.play(); // play it
	    }  
	}

	// Otherwise, if a defaut URL was specified, link to it.

	else if (defaultUrl != null) 
	    {
		if (target != null)
		    getAppletContext().showDocument(defaultUrl, target);
		else
		    getAppletContext().showDocument(defaultUrl);
	    }
	// No URL to link to, just return.
	// No URL to link to: toggle outlines.
	else // toggle outlines depending on last click
	    {
		//		System.out.println("New code " );
	       activeArea = -2;
		if (drawAll != 0) {
		drawAll=0;
		toggle_on = false;
		}
	              else if (drawAll != 1) {
		drawAll=1;
		toggle_on = true;
		}	
	    }
	getAppletContext().showStatus("");
	repaint();

	return true;
    }





    public void paint(Graphics g) 
    {
	//System.out.println("entering paint, activeArea = " + activeArea);
	update(g);
    }






public void update(Graphics g) {

    Dimension d = size();
    int x, y;
    int i, j, k, l, m;
    int n;
    String s;
    Rectangle rect;
    Polygon poly;
    Polygon poly1;
    Polygon poly2;

    //System.out.println(" " );
    //System.out.println("entering update, activeArea = " + activeArea);
    //System.out.println("drawAll = " + drawAll);
    // Create the offscreen graphics context, if no good one exists.

    if (offGraphics == null || d.width != offDimension.width || 
	d.height != offDimension.height) 
	{
	    offDimension = d;
	    offImage = createImage(d.width, d.height);
	    offGraphics = offImage.getGraphics();
	}




    // If the image map has finished loading, 
    // fill the canvas with the background color and draw
    // the map image over it.

    if ((checkImage(mapImage, this) 
	 & ImageObserver.ALLBITS) == ImageObserver.ALLBITS) 
	{
	    offGraphics.setColor(pgColor);
	    offGraphics.fillRect(0, 0, d.width, d.height);
	    offGraphics.drawImage(mapImage, 0, 0, this);

	    // bob...added this Tue Mar 23 17:21:55 EST 1999
	    // Draw all of the area borders.
	    if (tgFlag) {
		if (drawAll > 0) {
		    //System.out.println("drawing areas ");
		    for (i = 0; i < areas.size(); i++) {
				// The argument for areas.elementAt is 
				// "activeArea".
			area = (IMapArea) areas.elementAt(i);
			rect = area.getBoundingBox();

				// white for now
			offGraphics.setColor(tgColor);
			if (area.isRect()){
			    rect = area.getRect();
				// Make the line tgThick thick.
			    for (j = 0; j < tgThick; j++) {
				k=2*j;
				offGraphics.drawRect(rect.x-j, 
						     rect.y-j, 
						     rect.width+k, 
						     rect.height+k);
			    }



			}
			else if (area.isEllipse()){
			    rect = area.getEllipse();
				// Make the line tgThick thick.
			    for (j = 0; j < tgThick; j++) {
				k=2*j;
				offGraphics.drawOval(rect.x-j, 
						     rect.y-j, 
						     rect.width+k, 
						     rect.height+k);
			    }
			}
			else if (area.isPoly()){
			    poly = area.getPoly();
				//   offGraphics.drawPolygon(poly);
			    n = poly.npoints - 1;
				// Make the line tgThick pixels wide
				// in both x and y:
			    for (j = 0; j < tgThick; j++) {
				k=j;
				if (j == 1) k= 1; 
				if (j == 2) k=-1; 
				if (j == 3) k= 2; 
				if (j == 4) k=-2; 
				if (j == 5) k= 3; 
				if (j == 6) k=-3; 
				// On x ( n is number of points in polygon:
				for (l = 0; l < n; l++) {
				    offGraphics.drawLine(poly.xpoints[l]+k, 
							 poly.ypoints[l], 
							 poly.xpoints[l+1]+k, 
							 poly.ypoints[l+1]);
				}
				// Close up polygon.
				offGraphics.drawLine(poly.xpoints[n]+k, 
						     poly.ypoints[n], 
						     poly.xpoints[0]+k, 
						     poly.ypoints[0]);
				// On y:
				for (l = 0; l < n; l++) {
				    offGraphics.drawLine(poly.xpoints[l], 
							 poly.ypoints[l]+k, 
							 poly.xpoints[l+1], 
							 poly.ypoints[l+1]+k);
				}
				// Close up polygon.
				offGraphics.drawLine(poly.xpoints[n], 
						     poly.ypoints[n]+k, 
						     poly.xpoints[0], 
						     poly.ypoints[0]+k);
			    }




			}
		    }  // end: draw all areas
		} // end: drawall
	    } // end: tgflag
	}

    // Otherwise, put up a message and return.

    else {
	offGraphics.setColor(bgColor);
	offGraphics.fillRect(0, 0, d.width, d.height);
	offGraphics.setFont(font);
	offGraphics.setColor(fgColor);
	offGraphics.drawString("Loading image...", 
			       xAdvance, 
			       yHeight + yAscent);
	g.drawImage(offImage, 0, 0, this);
	return;
    }





    // If there is a currently active area, process it.

    if (activeArea >= 0) 
	{
	    drawAll=0; 
	    area = (IMapArea) areas.elementAt(activeArea);
	    rect = area.getBoundingBox();

	    //    System.out.println("activeArea = " + activeArea);
	    //    System.out.println("area = " + area);

	    if (olFlag) {
		offGraphics.setColor(olColor);
		if (area.isRect()){
		    rect = area.getRect();
				// Make the line tgThick thick.
		    for (j = 0; j < tgThick; j++) {
			k=2*j;
			offGraphics.drawRect(rect.x-j, 
					     rect.y-j, 
					     rect.width+k, 
					     rect.height+k);
		    }



		}
		else if (area.isEllipse()){
		    rect = area.getEllipse();
				// Make the line tgThick thick.
		    for (j = 0; j < tgThick; j++) {
			k=2*j;
			offGraphics.drawOval(rect.x-j, 
					     rect.y-j, 
					     rect.width+k, 
					     rect.height+k);
		    }
		}
		else if (area.isPoly()) {
		    poly = area.getPoly();
		    //offGraphics.drawPolygon(poly);
		    n = poly.npoints - 1;
				// Make the line tgThick pixels wide
				// in both x and y:
		    for (j = 0; j < tgThick; j++) {
			k=j;
			if (j == 1) k= 1; 
			if (j == 2) k=-1; 
			if (j == 3) k= 2; 
			if (j == 4) k=-2; 
			if (j == 5) k= 3; 
			if (j == 6) k=-3; 
				// On x ( n is number of points in polygon):
			for (l = 0; l < n; l++) {
			    offGraphics.drawLine(poly.xpoints[l]+k, 
						 poly.ypoints[l], 
						 poly.xpoints[l+1]+k, 
						 poly.ypoints[l+1]);
			}
				// Close up polygon.
			offGraphics.drawLine(poly.xpoints[n]+k, 
					     poly.ypoints[n], 
					     poly.xpoints[0]+k, 
					     poly.ypoints[0]);
				// On y:
			for (l = 0; l < n; l++) {
			    offGraphics.drawLine(poly.xpoints[l], 
						 poly.ypoints[l]+k, 
						 poly.xpoints[l+1], 
						 poly.ypoints[l+1]+k);
			}
				// Close up polygon.
			offGraphics.drawLine(poly.xpoints[n], 
					     poly.ypoints[n]+k, 
					     poly.xpoints[0], 
					     poly.ypoints[0]+k);
		    }


		}
	    }








	    // Draw the pop-up text box for the active area 
	    // if there is any text.

	    if (area.getCount() > 0) {

		// Determine a starting position for the text box. 
		// An attempt is made to keep it from
		// overlaying the area if possible.

		x = 0; y = 0;

		// Get the x-coord for the text box.

		if (d.width - (rect.x + rect.width) > rect.x)
		    x = rect.x + rect.width + xAdvance;
		else
		    x = rect.x - area.width - xAdvance;
		if (x + area.width > d.width)
		    x = d.width - area.width;
		x = Math.max(0, x);
        
		// Get the y-coord for the box.

		if ((x >= rect.x && x <= rect.x + rect.width) ||
		    (x + area.width >= rect.x && x 
		     + area.width <= rect.x + rect.width)
		    ) {
		    if (d.height - (rect.y + rect.height) > rect.y)
			y = rect.y + rect.height + yHeight;
		    else
			y = rect.y - area.height - yHeight;
		}
		else {
		    if (d.height - (rect.y + rect.height) > rect.y)
			y = rect.y + rect.height / 2;
		    else
			y = rect.y + rect.height / 2 - area.height;
		}
		if (y + area.height > d.height)
		    y = d.height - area.height;
		y = Math.max(0, y);

		// Draw the pop-up box and border.

		offGraphics.setColor(bdColor);
		offGraphics.fillRect(x, y, area.width, area.height);
		offGraphics.setColor(bgColor);
		offGraphics.fillRect(x + bdSize, y + bdSize, area.width 
				     - 2 * bdSize, area.height 
				     - 2 * bdSize);

		// Add the text.

		offGraphics.setFont(font);
		offGraphics.setColor(fgColor);
		for (i = 0; i < area.getCount(); i++) {
		    j = 0;
		    s = area.getText(i);
		    n = area.getIndent(i);
		    offGraphics.drawString(s, x + hrznMargin 
					   + xAdvance * n, y 
					   + vertMargin 
					   + i * yHeight + yAscent);
		}
	    }  // end: if (area.getCount() > 0) {
	} 








    // Paint the image onto the screen.

    g.drawImage(offImage, 0, 0, this);
}


}

















