/*
  WMScrollingMenu.java

  @author Warren Sack
  @version January 2003

**/


import java.awt.*;
import java.awt.event.*;
import java.util.*;

public class WMScrollingMenu extends Panel implements MouseListener, MouseMotionListener, Observer {
    private WorldMapApplet applet;
    private Dimension size = new Dimension();
    private Dimension visibleSize;
    private int width;
    private Font font;
    private Image buffer;             
    private Graphics bufferGraphics;  
    public Vector items = new Vector();
    private Vector itemTitles = new Vector();
    private int itemHeight;
    private boolean ready = false;
    private int numberOfItems;
    private int spaceBetweenItems = 0;
    private int horizontalMargin = 5;
    private int verticalMargin = 15;
    private int lastY = 0;
    private int xOffset = 0;
    private int yOffset = 0;
    private boolean isMouseDown = false;
    private Color backgroundColor;
    private Color textColor;
    private Color selectedColor;
    private Color highlightedColor;
    private Point scrollingIncrement = new Point();

    public WMScrollingMenu (WorldMapApplet applet,
			  Vector itemTitles,
			  Dimension visibleSize, 
			  Font font,
			  Color backgroundColor,
			  Color textColor,
			  Color selectedColor,
			  Color highlightedColor) {
	this.applet = applet;
	this.itemTitles = itemTitles;
	this.numberOfItems = itemTitles.size();
	this.visibleSize = visibleSize;
	this.font = font;
	this.backgroundColor = backgroundColor;
	this.textColor = textColor;
	this.selectedColor = selectedColor;
	this.highlightedColor = highlightedColor;
    }

    public void reSize (int width, int height) {
	ready = false;
	visibleSize.width = width;
	visibleSize.height = height;
    }


    public void resetMenu (Vector itemTitles) {
	ready = false;
	this.itemTitles = itemTitles;
	this.numberOfItems = itemTitles.size();
	repaint();
    }


    public void paint (Graphics g) {
	// If ready, copy the off-screen buffer onto the screen
	if ( ready ) {
	    // Paint the image
	    bufferGraphics.setFont(font);
	    // Draw into the off-screen buffer.
	    bufferGraphics.setColor(backgroundColor);
	    // clear the buffer
	    bufferGraphics.fillRect(0, 0, size.width, size.height); 
	    // Draw each menu item
	    for ( int i = 0; i < numberOfItems; i++ ) {
		WMScrollingMenuItem item = (WMScrollingMenuItem)(items.elementAt(i));
		bufferGraphics.setColor(item.color);
		bufferGraphics.drawString(item.text,item.upperLeft.x,item.upperLeft.y);
	    }
	    // Draw the buffer onto the screen
	    g.drawImage(buffer,
			0, 0, 
			visibleSize.width, visibleSize.height, 
			xOffset, yOffset,
			visibleSize.width+xOffset, visibleSize.height+yOffset, 
			this);
	}
	// Else, if not ready, then initialize graphics
	else {
	    // Layout the items on the available space.
	    this.setLayout(null);
	    g.setFont(font);
	    FontMetrics fm = g.getFontMetrics();
	    itemHeight = fm.getHeight();
	    scrollingIncrement.x = fm.stringWidth("e");
	    scrollingIncrement.y = itemHeight + spaceBetweenItems;
	    size.height = ( ( ( itemHeight + spaceBetweenItems ) 
			      * numberOfItems )
			    +
			    ( 2 * verticalMargin ) );
	    if ( size.height < visibleSize.height ) { size.height = visibleSize.height; }
	    size.width = visibleSize.width;
	    int h = horizontalMargin;
	    int v = verticalMargin;
	    items.removeAllElements();
	    for ( int i = 0; i < numberOfItems; i++ ) {
		items.addElement(new WMScrollingMenuItem((String)(itemTitles.elementAt(i)),
						       new Point(h,v),
						       textColor));
		v = v + itemHeight;
	    }
	    // Set up an off-screen Image for double-buffering
	    buffer = createImage(size.width, size.height);
	    bufferGraphics = buffer.getGraphics();
	    ready = true;
	    repaint();
	}
    }

    // insert code here to scroll the menu automatically
    // use method from artbrain code
    public synchronized void update (Observable o, Object arg) {
	repaint();
    }

    public void unhighlightAllItems () {
	for ( int i = 0; i < items.size(); i++ ) {
	    WMScrollingMenuItem item = (WMScrollingMenuItem)(items.elementAt(i));
	    item.color = textColor;
	    item.isSelected = false;
	}
	repaint();
	return;
    }


    private void resetColorOfAllItems () {
	for ( int i = 0; i < items.size(); i++ ) {
	    WMScrollingMenuItem item = (WMScrollingMenuItem)(items.elementAt(i));
	    item.color = textColor;
	}
	repaint();
	return;
    }


    private void reset () {
	for ( int i = 0; i < items.size(); i++ ) {
	    WMScrollingMenuItem item = (WMScrollingMenuItem)(items.elementAt(i));
	    item.color = textColor;
	    item.isSelected = false;
	}
	repaint();
	return;
    }


    private WMScrollingMenuItem findClosestItem (int y) {
	double closestDistance = Double.MAX_VALUE;
	WMScrollingMenuItem closest = null;
	double distance;
	WMScrollingMenuItem item;
	for ( int i = 0; i < numberOfItems; i++ ) {
	    item = (WMScrollingMenuItem)(items.elementAt(i));
	    distance = Math.abs( ( y + yOffset ) - item.upperLeft.y );
	    if ( distance < closestDistance ) { 
		closestDistance = distance; 
		closest = item;
	    }
	}
	return closest;
    }


    private int numberOfSelectedItems () {
	int number = 0;
	for ( int i = 0; i < numberOfItems; i++ ) {
	    WMScrollingMenuItem item = (WMScrollingMenuItem)(items.elementAt(i));
	    if ( item.isSelected ) { number++; }
	}
	return(number);
    }


    public WMScrollingMenuItem findItem (String text) {
	WMScrollingMenuItem foundItem = null;
	for (int i = 0; i < items.size(); i++ ) {
	    WMScrollingMenuItem item = (WMScrollingMenuItem)(items.elementAt(i));
	    if ( text.equals(item.text) ) { foundItem = item; }
	}
	return foundItem;
    }


    private void selectItem (WMScrollingMenuItem item) {
	resetColorOfAllItems();
	item.color = selectedColor;
	item.isSelected = true;
	repaint();
	return;
    }


    private void unselectItem (WMScrollingMenuItem item) {
	item.color = textColor;
	item.isSelected = false;
	repaint();
	return;
    }


    private void unselectAllItems () {
	resetColorOfAllItems();
	for ( int i = 0; i < items.size(); i++ ) {
	    WMScrollingMenuItem item = (WMScrollingMenuItem)(items.elementAt(i));
	    if ( item.isSelected ) { unselectItem(item); }
	}
	return;
    }


    // MouseListener Methods


    public void mousePressed (MouseEvent e) {
	applet.pauseDisplay();
	unselectAllItems();
	WMScrollingMenuItem nextSelectedItem = findClosestItem(e.getY());
	if ( nextSelectedItem != null ) {
	    selectItem(nextSelectedItem);
	}
    }


    public void mouseReleased (MouseEvent e) {;}


    public void mouseClicked (MouseEvent e) {;}


    public void mouseEntered (MouseEvent e) {
	applet.unsetMapAreasGridPanelFocus();
	int mousePositionLatitude = applet.getSelectedMapArea().latitude;
	int mousePositionLongitude = applet.getSelectedMapArea().longitude;
	String latitudeDirection, longitudeDirection;
	if ( mousePositionLatitude >= 0 ) { latitudeDirection = "north"; }
	else { latitudeDirection = "south"; }
	if ( mousePositionLongitude >= 0 ) { longitudeDirection = "west"; }
	else { longitudeDirection = "east"; }
	String position = "[ " + Math.abs(mousePositionLatitude) + "_" + latitudeDirection + " + " + Math.abs(mousePositionLongitude) + "_" + longitudeDirection + " ]";
	applet.positionPanel.setMousePositionString(position);
	applet.positionPanel.repaint();
	//	applet.languagesMenu.resetMenu(applet.getLanguagesForMapArea(applet.getSelectedMapArea()));
	applet.countriesMenu.resetMenu(applet.getSelectedMapArea().countries);
    }


    public void mouseExited (MouseEvent e) {;}


    // MouseMotionListener methods


    public void mouseMoved (MouseEvent e) {
	applet.pauseDisplay();
    }

    public void mouseDragged (MouseEvent e) {
	applet.pauseDisplay();
	if ( e.isShiftDown() ) {
	    int y = e.getY();
	    if ( ( y - lastY ) > 0 ) { yOffset = yOffset - scrollingIncrement.y; }
	    else { yOffset = yOffset + scrollingIncrement.y; }
	    if ( yOffset > ( size.height - visibleSize.height ) ) {
		yOffset = size.height - visibleSize.height;
	    }
	    else if ( yOffset < 0 ) { yOffset = 0; }
	    repaint();
	    lastY = y;
	}
    }


    public Dimension getPreferredSize () {
	return visibleSize;
    }

}
