//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// js/imagemapmenu.js
// CMS Version 1.5, nevermind, 13/07/2007
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

/**
 * Creates a new menu bar based on an imagemap. Each area in the imagemap can
 * have a popup menu, assigned by the addMenu() method.
 * The popup menu must have a width and height defined in the CSS style attribute.
 *
 * @param imageid The ID of the imagemap element
 * @param position Must be one of "above" or "below"
 * @param padding The space between the area and the popup menu
 * @param popup_timeout The time in seconds after the popup menu appears after it gets the focus
 * @param vanish_timeout The time in seconds after the popup menu vanishs after it lost the focus
 **/
function ImageMapMenuBar(imageid, position, padding, popup_timeout, vanish_timeout)
{
    var self = this;

    // This is the image map element
    this.element    = getElement(imageid);
    // This array stores all assigned menus
    this.menus      = new Array();

    // Get the absolute position of the image map in the document
    this.position   = getElementPositionAbsolute(imageid);
    // Get the dimensions of the image from it's CSS values
    this.width      = parseInt(this.element.style.width);
    this.height     = parseInt(this.element.style.height);

    /**
     * Assigns a new menu to the menubar.
     *
     * @param menuname The ID of the menu.
     **/
    this.addMenu = function(menuname)
    {
        // Create a new menu object
        var menu = new ImageMapMenu(menuname);

        // Calculate the best position for the popupmenu
        // The popup will be placed centered below the image area that triggers the mouseover events
        var x = this.position.x + menu.area.x + menu.area.width / 2 - menu.popup.width / 2;

        if (position == "below")
        {
            var y = this.position.y + menu.area.y + menu.area.height + padding;
        }
        else
        {
            var y = this.position.y + menu.area.y - menu.popup.height - padding;
        }


        // If the centered menu overlaps the image map, move the menu a bit to
        // the right (or to the left) so it will be complete below the map
        x = Math.max(this.position.x, Math.min(this.position.x + this.width - menu.popup.width, x));

        menu.popup.setPosition(x, y);

        // Register the event handlers
        menu.addEventListener("mouseover", this.showMenu);
        menu.addEventListener("mouseout", this.hideMenu);

        this.menus.push(menu);
    }

    /**
     * Event-callback: This is called when a menu losts the focus.
     * The menu will be closed after the timeout.
     *
     * @param e The event object.
     * @param menu The menu that triggered the event.
     **/
    this.hideMenu = function(e, menu)
    {
        menu.shown = false;
        window.setTimeout(menu.update, vanish_timeout * 1000);
    }

    /**
     * Event-callback: This is called when a menu gets the focus.
     * The menu will be shown immediately and all other open menus will be closed.
     *
     * @param e The event object.
     * @param menu The menu that triggered the event.
     **/
    this.showMenu = function(e, menu)
    {
        for (var i in self.menus)
        {
            if (self.menus[i] != menu)
            {
                self.menus[i].setVisible(false);
                self.menus[i].update();
            }
            else
            {
                self.menus[i].setVisible(true);
                window.setTimeout(menu.update, popup_timeout * 1000);
            }
        }
    }
}

/**
 * An ImageMapMenu consists of two components: the area in the image map that
 * triggers the appearance of the popupmenu and the popupmenu itself.
 * Both components must have an ID that is named as follows: menuname_area for
 * the area tag and menuname_popup for the popup menu. The menuname must be
 * passed to the constructor.
 *
 * @param menuname The ID of the menu.
 **/
function ImageMapMenu(menuname)
{
    var self = this;

    // Indicates weather the menu is shown or not
    this.shown = false;
    // A list off all registered event listeners
    var eventListeners = new Array();

    /**
     * Adds a new event listener.
     *
     * @param type The event type that should be captured.
     * @param func The listener func that will be called when an event is triggered.
     **/
    this.addEventListener = function(type, func)
    {
        eventListeners.push({"type" : type, "func" : func});
    }

    /**
     * Call the registered event listeners when an event is triggered.
     *
     * @param e The event object.
     **/
    this.eventTriggered = function(e)
    {
        if (!e)
        {
            e = window.event;
        }

        // Loop through all listeners
        for (var i in eventListeners)
        {
            // If the event type matches the listener type call the listener function
            if (e.type == eventListeners[i].type)
            {
                eventListeners[i].func(e, self);
            }
        }
    }

    /**
     * Sets the visibility of the popup menu. You have to call update() to
     * proceed changes.
     **/
    this.setVisible = function(visible)
    {
        self.shown = visible;
    }

    /**
     * Updates the visibility of the popupmenu.
     **/
    this.update = function()
    {
        self.popup.setVisible(self.shown);
    }

    // The area and popup elements
    this.area   = new ImageMapArea(menuname, this.eventTriggered);
    this.popup  = new ImageMapPopup(menuname, this.eventTriggered);
}

/**
 * The ImageMapArea object represents an area tag of the image map.
 * It provides information about his position and dimension.
 *
 * @param menuname The id prefix of the menu.
 **/
function ImageMapArea(menuname, eventListener)
{
    // The image area element
    this.element                = getElement(menuname + "_area");
    this.element.onmouseover    = eventListener;
    this.element.onmouseout     = eventListener;

    // Calculate the dimensions of the image map element
    var coords      = this.element.coords.split(",");
    this.x          = parseInt(coords[0]);
    this.y          = parseInt(coords[1]);
    this.width      = parseInt(coords[2]) - parseInt(coords[0]);
    this.height     = parseInt(coords[3]) - parseInt(coords[1]);
}

/**
 * The ImageMapPopup object provides information about the popup menu and
 * methods to manipulate it's appearance. The popup menu must have a width
 * and height defined in the CSS style attribute.
 *
 * @param menuname The id prefix of the menu.
 **/
function ImageMapPopup(menuname, eventListener)
{
    // The popup menu element
    this.element                = getElement(menuname + "_popup");
    this.element.onmouseover    = eventListener;
    this.element.onmouseout     = eventListener;

    // Calculate the dimensions of the menu
    this.width      = parseInt(this.element.style.width);
    this.height     = parseInt(this.element.style.height);

    /**
     * Sets the abolute position of the menu.
     *
     * @param x The x coordinate relative to the document.
     * @param y The y coordinate relative to the document.
     **/
    this.setPosition = function(x, y)
    {
        this.element.style.position = 'absolute';
        this.element.style.left     = x + 'px';
        this.element.style.top      = y + 'px';
    }

    /**
     * Shows or hides the popup menu.
     *
     * @param visible Pass true to show the popup, false to hide it.
     **/
    this.setVisible = function(visible)
    {
        if (visible)
        {
            this.element.style.display = 'block';
        }
        else
        {
            this.element.style.display = 'none';
        }
    }
}
