import java.applet.*;
import java.awt.*;
import java.util.*;
import java.net.*;

public class ImageMenu extends Applet {
    
    Image image;
    Image bbuf;
    Graphics bbufG;
    boolean imageDone;
    Rectangle[] hitArea;
    Rectangle[] srcRect;
    Point[] dstPt;
    boolean[] down;
    String[] url;
    String[][] itemUrl;
    String[][] item;
    int curMenu;
    int curMenuItem;
    Rectangle[] menuItemRect;
    Color bgColor;
    Color fgMenuColor[] = new Color[2];
    Color bgMenuColor[] = new Color[2];
    int marginH, marginV;
    Font f;
    FontMetrics fm;

    public void init() {
	int[] ints;
	
        image = getImage(getCodeBase(), getParameter("image"));
        marginH = Integer.parseInt(getParameter("marginh"));
        marginV = Integer.parseInt(getParameter("marginv"));

        ints = parseInt(getParameter("bg-color"), " ");
        bgColor = new Color(ints[0], ints[1], ints[2]);
	ints = parseInt(getParameter("fg-menu-color"), " ");
        fgMenuColor[0] = new Color(ints[0], ints[1], ints[2]);
	ints = parseInt(getParameter("fg-hi-menu-color"), " ");
        fgMenuColor[1] = new Color(ints[0], ints[1], ints[2]);
	ints = parseInt(getParameter("bg-menu-color"), " ");
        bgMenuColor[0] = new Color(ints[0], ints[1], ints[2]);
	ints = parseInt(getParameter("bg-hi-menu-color"), " ");
        bgMenuColor[1] = new Color(ints[0], ints[1], ints[2]);

	setBackground(bgColor);

        bbuf = createImage(size().width, size().height);
        bbufG = bbuf.getGraphics();

        int fh = Integer.parseInt(getParameter("font-height"));
        int i = fh;
        while (i > 10) {
            f = new Font(getParameter("font"), Font.PLAIN, i);
            fm = getFontMetrics(f);
            if (fm.getHeight() <= fh) {
                break;
            }
            i--;
        } 

        for (i=0; ; i++) {
            if (getParameter("menu"+i) == null) {
                hitArea = new Rectangle[i];
                srcRect = new Rectangle[i];
                dstPt = new Point[i];
                url = new String[i];
		down = new boolean[i];
                itemUrl = new String[i][];
		item = new String[i][];

                break;
            }
        }

        for (i=0; i<hitArea.length; i++) {
	    String[] fields = parse(getParameter("menu"+i), getParameter("separator"));
            
            ints = parseInt(fields[0], " ");
            hitArea[i] = new Rectangle(ints[0], ints[1], ints[2], ints[3]);

            ints = parseInt(fields[1], " ");
            srcRect[i] = new Rectangle(ints[0], ints[1], ints[2], ints[3]);

            ints = parseInt(fields[2], " ");
            dstPt[i] = new Point(ints[0], ints[1]);
	    down[i] = fields[3].equals("d");
	    url[i] = fields[4];

            item[i] = new String[(fields.length-5)/2];
            itemUrl[i] = new String[(fields.length-5)/2];
            for (int j=0; j<item [i].length; j++) {
                item[i][j] = fields[j*2+5];
                itemUrl[i][j] = fields[j*2+6];
            }
        }
    }
    
    String[] parse(String s, String sep) {
	StringTokenizer st = new StringTokenizer(s, sep);
        String result[] = new String[st.countTokens()];

	for (int i=0; i<result.length; i++) {
            result[i] = st.nextToken();
	}
        return result;
    }

    int[] parseInt(String s, String sep) {
	StringTokenizer st = new StringTokenizer(s, sep);
        int[] result = new int[st.countTokens()];

	for (int i=0; i<result.length; i++) {
            result[i] = Integer.parseInt(st.nextToken());
	}
        return result;
    }

    public void paint(Graphics g) {
        imageDone = false;
	setBackground(bgColor);
        update(g);
    }

    public void update(Graphics g) {
        Graphics g2;

        if (!imageDone) {
            imageDone = g.drawImage(image, 0, 0, this);
            return;
        }
        
        bbufG.setColor(bgColor);
	bbufG.fillRect(0, 0, size().width, size().height);
        bbufG.drawImage(image, 0, 0, this);
        
        if (curMenu >= 0) {
            g2 = bbuf.getGraphics();
            // Paint the overlay image
            g2.clipRect(dstPt[curMenu].x, dstPt[curMenu].y,
                srcRect[curMenu].width, srcRect[curMenu].height);
            g2.drawImage(image, dstPt[curMenu].x-srcRect[curMenu].x,
                dstPt[curMenu].y-srcRect[curMenu].y, this);
            g2.dispose();

	    g2 = bbuf.getGraphics();
	    for (int i=0; i<menuItemRect.length; i++) {
		drawMenuItem(g2, i);
	    }
	    g2.dispose();
        }
        g.drawImage(bbuf, 0, 0, this);
    }

    void drawMenuItem(Graphics g, int i) {
        int x, y, w, height;
        
        String[] line = parse(item[curMenu][i], getParameter("newline"));

        int hi = 0;
        if (i == curMenuItem) {
	    hi = 1;
	    getAppletContext().showStatus(itemUrl[curMenu][i]);
        }
	g.setColor(bgMenuColor[hi]);
	g.fillRect(menuItemRect[i].x, menuItemRect[i].y,
	    menuItemRect[i].width, menuItemRect[i].height);

        
	g.setColor(fgMenuColor[hi]);

        
	g.drawRect(menuItemRect[i].x, menuItemRect[i].y,
	    menuItemRect[i].width, menuItemRect[i].height);

        
        g.setFont(f);
        y = menuItemRect[i].y + marginV;
        for (i=0; i<line.length; i++) {
            g.drawString(line[i], 
                menuItemRect[i].x+menuItemRect[i].width-fm.stringWidth(line[i])-marginH,
                y + fm.getAscent());
            y += fm.getHeight();
        }
    }

    public boolean mouseExit(Event evt, int x, int y) {
        curMenuItem = curMenu = -1;
	repaint();
        return true;
    }

    public boolean mouseEnter(Event evt, int x, int y) {
        return mouseMove(evt, x, y);
    }
    
    public boolean mouseDown(Event evt, int x, int y) {
        try {
            String u = null;

            if (curMenuItem >= 0 && itemUrl[curMenu].length > 0) {
                u = itemUrl[curMenu][curMenuItem];
            } else if (curMenu >= 0) {
                u = url[curMenu];
            }
            if (u != null) {
                URL url = new URL (getDocumentBase(), u);

                if (getParameter("target") != null) {
	            getAppletContext().showDocument(url, getParameter("target"));
                } else {
	            getAppletContext().showDocument(url);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

    public boolean mouseMove(Event evt, int x, int y) {
        if (curMenu >= 0) {
            int sm = inMenu(menuItemRect, x, y);

	    if (curMenuItem != sm) {
		curMenuItem = sm;
		repaint();
	    }
            if (sm >= 0) {
                return true;
            }
            curMenu = -1;
        }

        int m = inMenu(hitArea, x, y);
        if (m != curMenu) {
            curMenu = m;

            // A new menu is now active so compute menuItemRect.
            if (m >= 0) {
                // Minimum width
                int maxWidth = 50;    
                int maxHeight = 0;    

                menuItemRect = new Rectangle[item[curMenu].length];
                for (int i=0; i<menuItemRect.length; i++) {
                    String[] line = parse(item[curMenu][i], "^");

                    for (int j=0; j<line.length; j++) {
                        int w = fm.stringWidth(line[j]);
                        if (w > maxWidth) {
                            maxWidth = w;
                        }
                    }

                    menuItemRect[i] = new Rectangle();
                    menuItemRect[i].height = 
                        parse(item[curMenu][i], "^").length * fm.getHeight()
                        + 2 * marginV;
                    maxHeight += menuItemRect[i].height;
                }

	        
		maxWidth +=  2 * marginH + 1;
                if (down[m]) {
                    y = Math.max(0, Math.min(size().height-maxHeight-1, 
                        dstPt[curMenu].y + srcRect[curMenu].height-1));
                } else {
                    y = Math.max(0, Math.min(size().height-maxHeight-1, 
                        dstPt[curMenu].y - maxHeight));
                }
		x = dstPt[curMenu].x + srcRect[curMenu].width-maxWidth-1;
	        for (int i=0; i<item[curMenu].length; i++) {
                    menuItemRect[i].x = x;
                    menuItemRect[i].y = y;
                    menuItemRect[i].width = maxWidth;
                    y += menuItemRect[i].height;
	        }
	        getAppletContext().showStatus(url[curMenu]);
            }
            repaint();
        }
        return true;
    }

    
    int inMenu(Rectangle[] rs, int x, int y) {
        if (rs != null) {
            for (int i=0; i<rs.length; i++) {
                if (rs[i].inside(x, y)) {
                    return i;
                }
            }
        }
        return -1;
    }
}
