Intro.java

See also HotSpot.java, HotSpot_readme

package tiongson.expo;

// Intro.java

import java.applet.Applet;
import java.awt.*;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.*;

/** Intro.class
 *  I grant anyone a royalty-free license
 *  to use this applet or source code for non-commercial 
 *  use ONLY.
 *  
 *  This copyright must be included in any copies of this code.
 *
 *  All other rigths reserved. Copyright phillip r. tiongson, 1997.
 *  
 *  In other words, if you aren't making money from selling this code
 *  it is fine to use it. If you are making money, please give me some.
 *  thanks, if you want to use it, contact me, 
 *  phillip tiongson, at sdallas@mit.edu.
 *
 *  @author   Phillip R. Tiongson
 *  @version  1.0
 */
public class Intro
	extends java.applet.Applet
	implements java.lang.Runnable
{
	public static final String name    = "Intro";
	public static final String version = "1.0";

	public boolean DEBUG = false;

	Thread	runner;
	Image background;
	protected MediaTracker tracker;
	
	int[] mouseX = {200, 200, 200, 200, 200}, mouseY = {200, 200, 200, 200, 200};
    
    Vector rects;
    
    /** Performs applet initialization.
     */
	public void init()
	{
		this.setBackground(Color.black);
		this.setForeground(Color.white);
		
		if (getParameter("DEBUG") != null) {
			
			dPrint("Debugging is on");	
			DEBUG = true;
		}	
		
		offscreensize = size();
		rects = new Vector();
		
		parseHTMLFile(rects);
		
		getImages();	
		
		showStatus("ready");
		
	}

	/** to prevent flicker
	*/
	public void update (Graphics g) {
		paint(g);
	}


    // These are for the offscreen drawing buffer.
	Image offscreen;
    Dimension offscreensize;
    Graphics offgraphics;
	
	
	/** This method overrides the paint method. It double buffers the drawing by drawing first
	to the offscreen buffer, then blasting it to the Graphics g.
	*/
	int backX = 0, backY = 0;

	boolean initme = true;
	
	public void paint(Graphics g) {
		Dimension d = size();

		// if no offscreen buffer image, make a new one
		if ((offscreen == null) || (d.width != offscreensize.width) 
			|| (d.height != offscreensize.height)) {
			
			offscreen = createImage(d.width, d.height);
			offscreensize = d;
			offgraphics = offscreen.getGraphics();
			offgraphics.setFont(getFont());
		}
		
		if (initme) {
			offgraphics.setColor(getBackground());
			offgraphics.fillRect(0,0,d.width, d.height);
			offgraphics.setColor(Color.red);
			offgraphics.drawString("Loading images...please wait.", 20, 20);
			g.drawImage(offscreen, 0, 0, this);
			return;
		}
		
		offgraphics.clipRect(0,0,d.width,d.height);

		 
		offgraphics.drawImage(background, backX, backY, this);
		
		for(Enumeration e = rects.elements(); e.hasMoreElements();) {
			((HotSpot) e.nextElement()).paint(offgraphics, backX, backY, DEBUG);
		}

		
			
		// Blast image to Graphics g.
		g.drawImage(offscreen, 0, 0, this);
	
	}

    /** The main entry point for the applet.
     */
	public void start()
	{
		repaint();
		if (runner == null)
		{
			runner = new Thread(this);
			runner.start();
		}
	}

    /** Called when you create a new thread with this class.
     */
    int decay;
	float incrementX = 0, incrementY = 0;
	int idleCount = 0;
	//int lastX = 0, lastY = 0;
	//boolean hit;
	HotSpot On;
	
	public void run()
	{
		//runner.setPriority(Thread.MIN_PRIORITY);
	
		while (Thread.currentThread() == runner) {
    		try {
            	runner.sleep(100);
         	} catch (InterruptedException e) {
         		System.err.println("insomnia "+e);
         		};
			
			
			
			if (decay == 1) {
				if (Math.abs(incrementX) < 1) incrementX = 0;
				if (Math.abs(incrementY) < 1) incrementY = 0;
				incrementX *= .75f;
				incrementY *= .75f;
			} if (decay == 0) {
				incrementX = -(float)(Math.sin((mouseX[2] - mouseX[0]) * Math.PI/2000.0f) * 100.0f);
				incrementY = -(float)(Math.sin((mouseY[2] - mouseY[0]) * Math.PI/2000.0f) * 50.0f);
			} if (decay == 2) {
				incrementX = 0;
				incrementY = 0;
				
			}
			
			// System.out.println("dx = "+backX+ " inc "+incrementX);
			
			backX += (int) incrementX;
			backX = (int) Math.min(Math.max(-backW+offscreensize.width, backX), 0);

			backY += (int) incrementY;
			backY = (int)Math.min(Math.max(-backH+offscreensize.height, backY), 0);
			//boolean nohit = true;
			if (idleCount > 1) {
				if (idleCount < 25) {
					for (Enumeration e = rects.elements(); e.hasMoreElements();) {
						HotSpot h = (HotSpot) e.nextElement();
						
						
						if (h.inside(mouseX[4], mouseY[4])) { 
							dPrint("inside." +idleCount);
							On = h;
							h.show();
							//hit = true;
							//nohit = false;
							continue;
						} // if
						h.hide();	
					} // for
				} // if
				
			} // if
			
			//if (nohit) repaint();
			
			dPrint("idle = "+idleCount);
			
			if (idleCount < 0) {
				/*
				for (Enumeration e = rects.elements(); e.hasMoreElements();) {
					HotSpot h = (HotSpot) e.nextElement();
					h.hide();	
				} //for
				*/
				if (On != null) On.hide();
			} // if
			
			idleCount++;
			
			//if (!((lastX == backX) && (lastY == backY) && !hit)) {
				

				repaint();
				//hit = false;
			//}
			//lastX = backX;
			//lastY = backY;
		}
	}

    /** Stops the applet from executing.
     */
	public void stop()
	{
		if (runner != null)
		{
			runner.stop();
			runner = null;
		}
	}

    /** Free up any applet resources.
     */
	public void destroy()
	{
		background = null;
		for (Enumeration e = rects.elements(); e.hasMoreElements(); ) {
			((HotSpot) e.nextElement()).image = null;
		}
		
	}

    /** Returns a text description of the applet.
     */
	public String getAppletInfo()
	{
		return name + " version " + version;
	}

	public boolean handleEvent(Event event) {
		
		switch (event.id) {
			case Event.KEY_PRESS:

				// Utils.dPrint("Got a key: "+(char)event.key);
				switch((char) event.key){
					case 'q':
						stop();
						break;
					case 'r':
						start();
						break;
					default:
						break;
				} // switch

				repaint();
				return true;			
			
			case Event.MOUSE_DOWN:
				idleCount = -1;
				
				mouseX[0] = event.x;
				mouseY[0] = event.y;
				decay = 2;

				dPrint("mouse down (x,y): ("+mouseX[0]+","+mouseY[0]+")");
				return true;
			case Event.MOUSE_UP:
				idleCount = -1;
				mouseX[1] = event.x;
				mouseY[1] = event.y;
				
				if ((mouseX[1] == mouseX[0]) && (mouseY[1] == mouseY[0])) {
				

					mouseX[3] = mouseX[1] - backX;
					mouseY[3] = mouseY[1] - backY;
					
					for (Enumeration e = rects.elements(); e.hasMoreElements();) {
						HotSpot h = (HotSpot) e.nextElement();
						
						if (h.inside(mouseX[3], mouseY[3])) { 
							dPrint("got it.");
							h.openHREF(this); 
							// repaint();
							break; 
						}
						
					}
					
					dPrint("Clicked at abs ("+mouseX[3]+","+mouseY[3]+").");
					decay = 2;
				} else {
					decay = 1;
				}

				mouseX[2] = mouseX[0];
				mouseY[2] = mouseX[0];
	
				return true;

			case Event.MOUSE_DRAG:
				idleCount = -1;
				
				mouseX[2] = event.x;
				mouseY[2] = event.y;
				decay = 0;

				dPrint("mouse drag (x,y): ("+mouseX[2]+","+mouseY[2]+")");
				return true;	
				
			case Event.MOUSE_MOVE:
				
				// To fix netscape bug, netscape produces erroneous Mouse_move messages.
				if ((mouseX[4] == (event.x - backX)) && (mouseY[4] == (event.y - backY))) {
					//System.out.println("breaking");
					break;
				}
				
				idleCount = -1;
				mouseX[4] = event.x - backX;
				mouseY[4] = event.y - backY;

				dPrint("mouse move (x,y): ("+mouseX[4]+","+mouseY[4]+")");
			
				return true;
					

		} // switch
		
		return super.handleEvent(event);
	} // handleEvent 


	private void parseHTMLFile(Vector destination) {
		Vector nodes = new Vector();
		int number = Integer.parseInt(getParameter("NumberOfNodes"));
		
		for (int i = 0; i < number; i++) {
			String value = getParameter("Node"+i);
			
			if (value != null) { nodes.addElement(value); }
				else { System.err.println("The parameters for Node "+i+" were missing");}
		} // for
		
		
		for (Enumeration e = nodes.elements(); e.hasMoreElements(); ) {
			String text = (String) e.nextElement();
			StringTokenizer parser = new StringTokenizer(text, ",;");
			
			boolean absolute = false;
			boolean newBrowser = false;
			boolean sound = false;
			String url = "";
			int x = 0;
			int y = 0;
			Rectangle rect = null;
			Polygon poly = null;
			URL href = null;
			Image image = null;;
			
			try {
				String value = parser.nextToken();
				if (value.equals("1")) {absolute = true; dPrint("Absolute. "); }
				if (value.equals("2")) {sound = true; dPrint("sound. "); }
				if (parser.nextToken().equals("1")) {newBrowser = true; dPrint("newBrowser. "); }
				
				url = parser.nextToken();
				if (!url.equals("none")) {
					href = new URL(getDocumentBase(), url);
					dPrint("HREF = "+url+" "+href);
				}
							
				url = parser.nextToken();
				if (!url.equals("none")) {
					URL imageLoc = new URL(getDocumentBase(), url);
					image = getImage(imageLoc);
					dPrint("IMAGEURL = "+url+" "+image);
				} // if
				
				x = Integer.parseInt(parser.nextToken());
				y = Integer.parseInt(parser.nextToken());
				
				int numberLeft = parser.countTokens();
				
				if (numberLeft > 4) {
					poly = new Polygon();
					
					for (int i = 0; i < numberLeft/2; i++) {
						poly.addPoint(Integer.parseInt(parser.nextToken()), Integer.parseInt(parser.nextToken()));
					}
					
				} else {
					int x1 = Integer.parseInt(parser.nextToken());
					int y1 = Integer.parseInt(parser.nextToken());
					int w = Math.abs(x1 - Integer.parseInt(parser.nextToken()));
					int h =  Math.abs(y1 - Integer.parseInt(parser.nextToken()));
				
					rect = new Rectangle(x1, y1, w, h);
				}
				
				
				if (poly != null) {
					destination.addElement(new HotSpot(absolute, newBrowser, sound, href, image, x, y, poly));
					dPrint("added a poly");
				} else {
					destination.addElement(new HotSpot(absolute, newBrowser, sound, href, image, x, y, rect));
					dPrint("added a rect");
				}// else			
			} // try
			catch (MalformedURLException mue) { System.err.println("This is not a good url: "+url); }
			catch (NoSuchElementException nsee) { System.err.println("not enough tokens in: "+text); }
			catch (NumberFormatException mie) { System.err.println("Number not corrent "+mie); }
		
		} // for
	
	} // parseHTML 
	
	int backW = 1, backH = 1;
	
	
	private void getImages() {
	
		String toOpen = "background.jpg";
		String tempP = getParameter("background");
		if (tempP != null) toOpen = tempP;
		background = getImage(getDocumentBase(), toOpen);
		
		
		tracker = new MediaTracker(this);
		int i = 0;
	
		tracker.addImage(background, i);
		i++;
		
		for (Enumeration e = rects.elements(); e.hasMoreElements(); i++) {
			HotSpot h = (HotSpot) e.nextElement();
			
			if (h.image == null) continue;
			
			// Image temp = getImage(h.imageLoc);
			tracker.addImage(h.image, i);
		}

		try { 
			tracker.waitForAll();                        
		} // try
		
		catch (InterruptedException e) { 
			System.err.println("Got interrupted while waiting.");
			showStatus("Can't read images.");
		} // catch

		if (tracker.isErrorID(0)) {
			System.err.println("We can't get the background image sorry.");
			showStatus("Can't read background image, sorry.");
		} // if		
		
		initme = false;
		
		backW = background.getWidth(this);
		backH = background.getHeight(this);
	
		
	} // getImages

	private static Random r = new Random();
		
	/** returns a random int from 0 to i.
	if you pass it a 1, it returns 0 half the time and 1 the other half.
	
	Also, if i = -1, it computes +1 or -1 for you.
	
	*/
	public static int RandomInt(int i) {
	
		int range = Math.round((i * r.nextFloat()));

		//dPrint("int: "+i+"\t got: "+range);
		if ((i == -1) && (range == 0)) {
			//dPrint("+1 :-)");
			return 1;
		}
		
		return range;	
	}

	/** A private method to print debug statements 
	*/
	private void dPrint(String s) {
		if ( DEBUG == true )
			System.out.println(s);
	} // dPrint

} // Intro