// Requires utils.js  and browser.js

// MenuBar, Menu and MenuItem implement
// a typical menubar with drop-down menus.
// This implementation uses native <select>
// and <option> elements, without the need to download
// any frames/pages, hence the name "lite".
//
// There can be only one menubar in a page, and
// all menus must be in this bar.
// Menus are static, they are all added to
// the MenuBar, then rendered. Once rendered, they
// cannot be modified.
// However, the MenuItems within a Menu may be modified at run time.
// To close a menu popup, click anywhere on the menu bar.
//
// Alexander Yap

// ************************************************************
// Class MenuBar

// Creates a MenuBar
// jsRef : The name of Javascript variable in the page that references this MenuBar.
// id    : The id of the HTML <div> tag rendered by the MenuBar.
function MenuBar( jsRef, id) {
    this.jsRef = jsRef;
    this.id = id;
    this.menuShown = false;
    this.menuLast = -1;
    this.enabled=true;
    this.menus = new Array();
}

// Adds a Menu object to this MenuBar.
// This must be called before calling render().
// menu  : Menu object
MenuBar.prototype.add = function( menu ) {
    menu.menuBar = this;
    menu.index = this.menus.length;
    this.menus[ this.menus.length ] = menu;
}

// Adds a Menu object at special position in MenuBar.
// This must be called before calling render().
// menu  : Menu object
MenuBar.prototype.insert = function( idx, menu ) {
	if (idx > this.menus.length || idx < 0)
		idx = this.menus.length;
	menu.menuBar = this;
	menu.index = idx;
	for (var i = this.menus.length - 1; i >= idx; i--) {
		this.menus[i].index++;
		this.menus[i+1] = this.menus[i];
	}
	this.menus[idx] = menu;
}

// Renders this MenuBar and all its menus on the page.
MenuBar.prototype.render = function() {
    // Better not to highlight menus in menubar on mouseover/mouseout in Mozilla, due to painting problems.
    // Its not worth the problems!.

    document.writeln("<div id=\""+this.id+"\" class=\"menuBarDiv\" style=\"\">" + this.generateHtmlString() + "</div>");
    document.writeln("<div id=\"divMenu\" style=\"position:absolute; left:0px; top:0px; z-index:6000; visibility:hidden;\">");
    document.writeln("<select id=\"menuSel\" class=\"selector\" onchange=\"menuSelChanged(this,"+this.jsRef+")\" ></select>");
    document.writeln("</div>");
}

// Refresh the MenuBar when menus have been changed.
// This must be called after calling render().
MenuBar.prototype.refresh = function() {
	var menuBar = getElemById(self, this.id);
	if (menuBar == null) return; // ignore if this MenuBar didn't be rendered
	menuBar.innerHTML = this.generateHtmlString();
}

MenuBar.prototype.generateHtmlString = function() {
	var html = "<table width=\"100%\" height=\"100%\" cellpadding=\"0\" cellspacing=\"0\"><tr><td width=\"99%\" onclick=\""+this.jsRef+".closeMenu()\" >&nbsp;</td>";
	for (var m=0; m<this.menus.length; m++) {
		html += "<td width=\"1%\" id=\"menu"+m+"\" class=\"menuBarText\" nowrap=\"nowrap\" onclick=\""+this.jsRef+".menuClicked("+m+")\"";
		html += " onmouseover=\""+this.jsRef+".hiliteMenu(1,this)\" onmouseout=\""+this.jsRef+".hiliteMenu(0,this)\"";
		html += " >&nbsp;&nbsp;"+this.menus[m].name+"&nbsp;&nbsp;</td>";
	}
	html += "</tr></table>";
	return html;
}

function menuSelChanged(  menuSel, menuBar ) {
    if (menuBar.menuLast>=0) {
        menuBar.menus[menuBar.menuLast].menuItemClicked( menuSel.selectedIndex );
    }
}

// Closes the opened menu.
// Must only be called after MenuBar is rendered.
MenuBar.prototype.closeMenu = function() {
    getElemById(self, "divMenu").style.visibility="hidden";
    this.menuShown = false;
}

// Sets whether this MenuBar is enabled. If disabled, it doesn't respond to any mouse events,
// and any opened menu is closed.
// Must only be called after MenuBar is rendered.
MenuBar.prototype.setEnabled = function(en) {
    this.enabled = en;
    if (!en) {
        this.closeMenu();
    }
}

// Gets reference to Menu object at specified index
MenuBar.prototype.getMenu = function(idx) {
    if (idx < this.menus.length) {
        return this.menus[idx];
    }
    return null;
}

// Gets reference to Menu object at specified name
MenuBar.prototype.findMenu = function(name) {
	for (var m=0; m<this.menus.length; m++) {
		if (this.menus[m].name == name) {
			return this.menus[m];
		}
	}
	return null;
}

// Highlights a Menu text in the MenuBar, for mouse over events.
// This is for MenuBar's internal use only. Do not call from external code.
MenuBar.prototype.hiliteMenu = function(state,menuElem) {
    if (this.enabled) {
        menuElem.className = ( (state==1) ? 'menuElemHilite' : 'menuElemTransparent' );
    }
}

// Highlights a MenuItem in a Menu, for mouse over events.
// This is for MenuBar's internal use only. Do not call from external code.
MenuBar.prototype.hiliteMenuItem = function(state,menuItemElem) {
    if (this.enabled) {
        menuItemElem.className = ( (state==1) ? 'menuItemElemHilite' : 'menuElemTransparent' );
    }
}

// Responds to a mouse click event on the MenuBar.
// This is for MenuBar's internal use only. Do not call from external code.
MenuBar.prototype.menuClicked = function( menuIndex ) {
    if (this.enabled) {
        var menu = this.menus[menuIndex];
        if (menu.action!="") {
            eval( menu.action );
        } else {
            menu.showFrame();
        }
    }
}

// ************************************************************
// Class Menu
// Note: A Menu may also directly invoke its own action instead of opening a menu popup.

// Creates a Menu, and optionally registers an action.
// If action is not null, it is invoked when Menu is clicked, and
// no menu popup appears. So it is pointless to add MenuItems to a
// Menu that is registered with an action.
//
// name   : Text of the Menu
// action : Optional Javascript to be invoked when this Menu is clicked, in textual form. May be null or "".
function Menu( name , action ) {
    this.index = -1;
    this.menuBar = null;
    this.name = name;
    this.action = (action) ? action : "";
    this.menuItems = new Array();
}

// Adds a MenuItem object to this Menu.
// menu  : MenuItem object
Menu.prototype.add = function( menuItem ) {
    this.menuItems[ this.menuItems.length ] = menuItem;
}

// Clears all MenuItem objects from this Menu.
Menu.prototype.clear = function() {
    this.menuItems = new Array();
}

// Displays the menu popup.
// This is for MenuBar's internal use only. Do not call from external code.
Menu.prototype.showFrame = function() {
    if (window.event) {
        window.event.cancelBubble = true
    }
    if (this.menuBar.menuShown && (this.menuBar.menuLast==this.index)) {
        return;
    }

    if (this.menuBar.menuLast != this.index) {
        this.menuBar.menuLast = this.index;
    }
    var divMenu = getElemById(self, "divMenu");
    divMenu.style.visibility="hidden";

    var menuSel = getElemById(self, "menuSel" );
    for (oi=menuSel.options.length-1; oi>=0; oi--) {
        menuSel.remove(oi);
    }

    if ( this.menuItems.length > 0) {
        for (mi=0; mi<this.menuItems.length; mi++) {
            if (isIE()) {
                menuSel.add( this.getMenuOption(mi) );
            } else {
                menuSel.options[menuSel.options.length] =this.getMenuOption(mi);
            }
        }
        menuSel.setAttribute("size", this.menuItems.length+1);

        var menuElem = getElemById(self, "menu"+this.index);

        // This code is confusing but necessary to get popups appearing at correct
        // left offset for IE, Netscape 6 and Mozilla.
        var menuLeft = menuElem.offsetLeft + menuElem.offsetParent.offsetLeft;
        if (menuElem.offsetParent.offsetParent!=null) {
            menuLeft = menuLeft + menuElem.offsetParent.offsetParent.offsetLeft;
        }
        if (menuElem.offsetParent.offsetParent.offsetParent!=null) {
            menuLeft = menuLeft + menuElem.offsetParent.offsetParent.offsetParent.offsetLeft;
        }

        var fullWidth = getDocWidth(self);
        if (menuLeft + menuSel.offsetWidth > fullWidth) {
            // If the menu would appear offscreen, move it back in.
            menuLeft = fullWidth - menuSel.offsetWidth;
        }

        setElemBounds( divMenu, menuLeft, 51, "", "");
        menuSel.selectedIndex = -1;
        divMenu.style.visibility="visible";
        this.menuBar.menuShown = true;
    }
}

// Gets the HTML to be rendered for the menu popup..
// This is for MenuBar's internal use only. Do not call from external code.
Menu.prototype.getMenuOption = function(mi) {
    var optElem = document.createElement("option");
    if (isIE()) {
        optElem.text=this.menuItems[mi].name;
    } else {
        optElem.innerHTML=this.menuItems[mi].name;
    }
    return optElem;
}

// Responds to a mouse click event on the MenuItem.
// This is for MenuBar's internal use only. Do not call from external code.
Menu.prototype.menuItemClicked = function( itemIndex ) {
    if (this.menuBar.enabled) {
        var item = this.menuItems[itemIndex];
        if (item.action!="") {
            this.menuBar.closeMenu();
            eval(item.action);
        }
    }
}


// ************************************************************
// Class MenuItem

// Creates a MenuItem.
//
// name   : Text of the MenuItem.
// action : Javascript to be invoked when this MenuItem is clicked, in textual form.
function MenuItem(name,action) {
    this.name=name;
    this.action=action;
}





