/**************************************************************************
* Copyright (c) 1996 Jim Crossley
*
* Although it's unlikely that anyone would actually want it,
* permission is hereby granted, without written agreement and
* without license or royalty fees, to use, copy, modify, and
* distribute this software and its documentation for any purpose,
* provided that the above copyright notice and the following three
* paragraphs appear in all copies of this software, its documentation
* and any derivative work.
*
* In no event shall Jim Crossley or Automated Design Systems, Inc. be
* liable to any party for direct, indirect, special, incidental, or
* consequential damages arising out of the use of this software and
* its documentation.
*
* The software provided hereunder is on an "as is" basis, and neither
* Jim Crossley nor Automated Design Systems, Inc. has any obligation
* to provide maintenance, support, updates, enhancements, or modifications.
*
* Derived or altered versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
***************************************************************************/
package shifter;

import java.applet.*;
import java.awt.*;
import java.net.*;
import java.util.*;

/**
 * Provides for the definition of rectangular hotspots on a given image (an image map).
 * The image is actually a collection of frames, and as the user drags the
 * mouse over various hotspots, the corresponding frame is displayed.
 * If the user releases the mouse button over a hotspot, the showDocument() method is
 * called so that the browser may display the document at the URL associated with the
 * hotspot.  There should be an exact correlation between the number of hotspots and
 * the number of frames in the image.  Each frame should be the same size as the
 * applet itself.
 * <p>
 * Necessary parameters in the HTML file:
 * <ul>
 * <li><em>image</em> - the name of the image file (either jpeg or gif).
 * </ul>
 *
 * Optional parameters [default]
 * <ul>
 * <li><em>targetframe</em> - which frame the browser should display the URL ["_top"]
 * <li><em>rect0</em> - Rectangular region parameters []
 * </ul>
 *
 * The region parameters must start with "rect" and end with an integer.  The integers
 * must be sequential starting with 0.  The format of the parameter values is as follows:
 * x, y, width, height, URL.  Something like this.
 * <p>
 * <PARAM name="rect0" value="10,10,200,100,http://www.lads.com/~jim">
 *
 * @author  Jim Crossley
 * @version 1.0, 9/17/1996
 */
public class ImageShifter extends Applet {
    protected Image image;      // image to display.
    protected Vector rects;     // list of rectangles in it.
    protected Dimension app;
    protected int frame = 0;
    protected int previousFrame = 0;
    protected String browserTarget = null;

    /**
     * Initialize member variables with applet parameters
     */
    public void init() {
        // we assume the image dimensions == the applet's
        app = this.size();

        // load the image of "frames" to be displayed.
        image = this.getImage(this.getDocumentBase(),
                      this.getParameter("image"));

        // get the browser frame name
        if ((browserTarget = this.getParameter("targetframe")) == null) {
            browserTarget = "_top";
        }

        // lookup a list of rectangular areas and the URLs they map to.
        rects = new Vector();
        URLRect r;
        int i = 0;
        while((r = getRectangleParameter("rect" + i)) != null) {
            rects.addElement(r);
            i++;
        }
    }

    /**
     * Display the correct frame of the image.
     */
    public void paint(Graphics g) {
        g.drawImage(image, (-frame * app.width), 0, this);
    }

    /**
     * Override to prevent flickering.
     */
    public void update(Graphics g) { paint(g); }

    /**
     * Find the rectangle in which we reside
     */
    private int findrect(int x, int y) {
        int i;
        URLRect r = null;
        for(i = 0; i < rects.size(); i++)  {
            r = (URLRect) rects.elementAt(i);
            if (r.inside(x, y)) break;
        }
        if (i < rects.size()) return i;
        else return -1;
    }

    /**
     * Show the correct frame when the user begins to interact with the applet.
     */
    public boolean mouseDown(Event e, int x, int y) {
        previousFrame = frame;
        frame = -1; // so that clicks on the previous rectangle show status
        return setFrame(x,y);
    }

    /**
     * Show the proper frame as the user drags in and out of various hotspots.
     */
    public boolean mouseDrag(Event e, int x, int y) {
        return setFrame(x,y);
    }

    /**
     * When the user releases the mouse button, display the appropriate document in
     * the desired target frame of the browser.  If the user does not release the
     * button within a valid hotspot, display the original frame.
     */
    public boolean mouseUp(Event e, int x, int y) {
        this.showStatus("");
        int r = findrect(x,y);
        if ((r >= 0) && (r == frame)) {
            this.getAppletContext().showDocument(((URLRect) rects.elementAt(r)).url, browserTarget);
        }
        else {
            frame = previousFrame;
            repaint();
        }
        return true;
    }

    /**
     * Display the correct frame and show the URL in the status line of the browser.
     */
    protected boolean setFrame(int x, int y) {
        int r = findrect(x, y);
        if (r < 0) {
            this.showStatus("");
        }
        else if (frame == r) {
            this.showStatus("To: " + ((URLRect) rects.elementAt(frame)).url);
        }
        else {
            frame = r;
            this.showStatus("To: " + ((URLRect) rects.elementAt(frame)).url);
            repaint();
        }
        return true;
    }

    /**
     * Parse a comma-separated list of rectangle coordinates and a URL.
     * From _Java_In_A_Nutshell_
     */
    protected URLRect getRectangleParameter(String name) {
        int x, y, w, h;
        URL url;
        String value = this.getParameter(name);
        if (value == null) return null;

        try {
            StringTokenizer st = new StringTokenizer(value, ",");
            x = Integer.parseInt(st.nextToken());
            y = Integer.parseInt(st.nextToken());
            w = Integer.parseInt(st.nextToken());
            h = Integer.parseInt(st.nextToken());
            try {
                url = new URL(this.getDocumentBase(), st.nextToken());
            }
            catch (MalformedURLException e) { url = null; }
            catch (NoSuchElementException e) { url = null; }
        }
        catch (NoSuchElementException e) { return null; }
        catch (NumberFormatException e) { return null; }

        return new URLRect(x, y, w, h, url);
    }
}

/**
 * Rectangle that knows about a URL.
 */
class URLRect extends Rectangle {
    URL url;
    public URLRect(int x, int y, int w, int h, URL u) {
        super(x, y, w, h);
        url = u;
    }
}

