/**
 * /Ben/Scripts (tm) - A collection of EMCAScript, JavaScript, ActionScript and VBScript
 *                     for enhacing web application user interfaces.
 *
 * @author    Benjamin DruShell
 * @website   http://www.drushell.net/
 * @copyright Copyright (c) 1998-2003,2005-2009, Benjamin DruShell
 * @license   /Ben/Scripts(tm) Library License
 *****************************************************
 * /Ben/Scripts(tm) Library License
 *
 * OWNERSHIP NOTICE:
 * Copyright (c) 1998-2003,2005-2009, Benjamin DruShell
 * All rights reserved by Benjamin DruShell.
 * /Ben/Scripts(tm) is a trademark of Benjamin DruShell
 *
 * DISCLAIMER:
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.  ALL RISK IS WITH YOU.
 *
 * PERMISSION NOTICE:
 * Permission is granted, free of charge, for redistribution and use of this
 * software, with or without modification, provided that the following
 * three (3) conditions are met:
 *
 *    1) This entire license must be included in the source code.
 *       This license consists of (a) the above Ownership Notice,
 *       (b) the above Disclaimer, and (c) this Permission Notice.
 *
 *    2) Condition 1 of this Permission Notice may be removed with the compensation
 *       of $1,000.00 U.S. Dollars paid to Benjamin DruShell, the copyright holder.
 *       Violation of this license is your acceptance to pay the compensation plus
 *       all legal, court, travel, and collection fees in obtaining compensation.
 *
 *    3) Neither the name of /Ben/Scripts(tm) nor the name of Benjamin DruShell
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 * END OF LICENSE
 */


// Hash Map of menuItem objects for quick-reference.
var menuHashMap = new Object();
var cHashMap = 0;

/**
 * menuBoxHide - Hide specified menu box.
 * @param String id
 */
function menuBoxHide(id) {
    var object = document.getElementById("menuItemBox"+id);
    if( object != null ) {
        object.style.visibility = 'hidden';
    }
}

/**
 * menuBoxHideSeries - Hide the current menu box and parents.
 * @param String id
 */
function menuBoxHideSeries(id) {
    menuBoxHide(id);
    if( menuHashMap[id].parent != null ) {
        menuBoxHide(menuHashMap[id].parent.id);
    }
}

/**
 * menuBoxKeep - Keeps current and parent items visible.
 * @param String id
 */
function menuBoxKeep(id) {
    menuHashMap[id].displayMenu();
    if( menuHashMap[id].parent != null ) {
        menuBoxKeep(menuHashMap[id].parent.id);
    }
}

/**
 * newId - Generate a new id for an object.
 * @return String
 */
function newId() {
    return new String(++cHashMap).concat(Math.random());
}

/**
 * sumParentOffsetLeft - Recursive function to sum up offsetLeft and find an
 *                       absolute X-position of an element.
 * @param Object target
 * @return int
 */
function sumParentOffsetLeft(target) {
    var newOffset = target.offsetParent;
    if( newOffset == null ) {
        return target.offsetLeft;
    }
    return target.offsetLeft + sumParentOffsetLeft(newOffset);
}

/**
 * sumParentOffsetTop - Recursive function to sum up offsetTop and find an
 *                      absolute Y-position of an element.
 * @param Object target
 * @return int
 */
function sumParentOffsetTop(target) {
    var newOffset = target.offsetParent;
    if( newOffset == null ) {
        return target.offsetTop;
    }
    return target.offsetTop + sumParentOffsetTop(newOffset);
}

/**
 * menuBar object constructor.
 */
function menuBar(id) {
    this.id = id;
    this.menu = new Array();
}

/**
 * Method of menuBar oject that adds item to menu.
 * @param menuItem item
 */
menuBar.prototype.addItem = function(item) {
    item.bar = this.id;
    this.menu.push(item);
}

/**
 * Method of menuBar object that displays menu.
 */
menuBar.prototype.display = function() {
    var out = new Array();
    out.push("<div id='menuBar'>");
    for(cMenu=0; cMenu < this.menu.length; ++cMenu) {
        // Display Main Items In Bar
        out.push(this.menu[cMenu].display());
    }
    out.push("</div>");
    var object = document.getElementById(this.id);
    object.innerHTML = out.join("");
}

/**
 * menuItem object constructor.
 * @param String label
 * @param String url
 */
function menuItem(label, url) {
    // Add object properties.
    this.id = newId();
    this.label = label;
    this.url = url;
    this.parent = null;
    this.rendered = false;
    this.menuRendered = false;
    this.menu = new Array();

    // Add pointer of this object to menuHashMap.
    menuHashMap[this.id] = this;
}

/**
 * menuItem object method for adding sub-menu items.
 * @param menuItem item
 */
menuItem.prototype.addChild = function(item) {
    item.parent = this;
    item.bar = this.bar;
    this.menu.push(item);
}

/**
 * menuItem object method for displaying self.
 * @return String
 */
menuItem.prototype.display = function() {
    var out = new Array();
    out.push("<a href='", this.url, "' id='menuItem", this.id, "'");
    if( this.menu.length > 0 ) {
        out.push(" onMouseOver='menuBoxKeep(\"",this.id,"\")' onMouseOut='menuBoxHide(\"",this.id,"\")'");
    }
    out.push(">",this.label,"</a>");
    return out.join("");
}

/**
 * menuItem object method for display sub-menu.
 */
menuItem.prototype.displayMenu = function() {
    var item = null;
    var itemBox = null;
    if( this.menuRendered ) {
        // Display already rendered menuItemBox.
        itemBox = document.getElementById("menuItemBox"+this.id);
        itemBox.style.visibility = "visible";
    } else {
        // Build menuItemBox
        var out = new Array();
        // Display Bar Container
        out.push("<div class='menuItemBox' id='menuItemBox",this.id,"' onMouseOver='menuBoxKeep(\"",this.id,"\")' onMouseOut='menuBoxHideSeries(\"",this.id,"\")'>");
        for(cMenu=0; cMenu < this.menu.length; ++cMenu) {
            // Render Menu Item
            out.push(this.menu[cMenu].display());
            this.menu[cMenu].rendered = true;
        }
        out.push("</div>");
        var div = document.getElementById(this.bar);
        div.innerHTML = div.innerHTML + out.join("");
        item = document.getElementById("menuItem"+this.id);
        itemBox = document.getElementById("menuItemBox"+this.id);
        xPosition = sumParentOffsetLeft(item);
        yPosition = sumParentOffsetTop(item);
        if( this.parent == null ) {
            // No parent, display under bar item.
            yPosition += item.offsetHeight;
        } else {
            // Has parent, display next to menu-item.
            xPosition += item.offsetWidth;
        }
        itemBox.style.left = xPosition + 'px';
        itemBox.style.top = yPosition + 'px';
        itemBox.style.visibility = 'visible';
        this.menuRendered = true;
    }
}

