//
// Filename : DropDownMenu.js
// Author   : Wayne Howarth <wayne@pyesmeadow.com>
// Created  : 20th August 2002
//
// Routines for a drop down menu system.
//
// Copyright (c) 2002 Wayne Howarth, All Rights Reserved
//
// Browser Compatibility:
//   NS 4.x no
//	 IE 5.0 untested
//   IE 5.5	yes
//   IE 6.0 yes
//   NS 6.1	yes
//   IE 7.0 yes
//
// Interfaces:
//  DropDownMenu( elementId, objMenuRoot )
//		.Show( bShow )
//		.SetHighlightColours( strFgColour, strBgColour )
//      .SetMenuWidth( strWidth )
//		.SetCheckBox( urlSelected, urlUnselected )
//		.SetRadioButton( urlSelected, urlUnselected )
//		.SetEnabled( bEnabled )
//      .SetStyle( style )
//      .SetImage( strImageUrl )
//
//  DropDownMenuItem( strLabel, action, href, style, children )
//		.SetText( strText )
//		.GetChecked()
//      .SetChecked( bChecked )
//		.SetEnabled( bEnabled )
//      .SetImage( strImageUrl )
//
// Events:
//      'dropDownMenuItem_OnClick( objMenuItem )'
//      If this function is defined in client script then it is called whenever a
//		menu item is selected.
//
// Revision History:
//  21/08/2002
//  Added 'dropDownMenuItem_OnClick()' event.
//  Refactored code to use DropDownMenu and DropDownMenuItem objects.
//
//  22/08/2002
//  Fixed 'flickering' of selected menu items that have a graphic attached.
//  Added support for check box and radio button style menu items.
//
//  23/08/2002
//  Added support for seperators in menus.
//  Radio buttons are grouped by seperators.
//  Fixed NS6 mouse event problems.
//
//  27/08/2002
//  Added support to disable menu items.
//
//  29/08/2002
//  Added code to make overlapped <select> elements invisible for IE browsers.
//
//  30/08/2002
//  Added 'href' parameter to DropDownMenuItem objects to allow page navigation
//  when selected.
//
//  26/09/2002
//  DropDownMenu objects are by default hidden.
//  Added a SetEnabled method to the DropDownMenu object.
//
//  02/10/2002
//  Fixed bug that causes a disabled menu item to still function as a link.
//
//  07/10/2002
//  Fixed redraw bug for top-level menus with no dropdown sub-menus.
//
//  17/10/2002
//	Added support for 3D style menus.
//
//	31/10/2002
//  Fixed bug with onclick code when enabling/disabling DropDownMenuItem
//  objects.
//
//  14/11/2002
//  Added support for attaching images to menu items.
//
//  22nd November 2002
//  Fixed problem caused by clicking on a parent menu.
//
//  2nd December 2003
//  Changed the way that colours and styles are applied to menu headings
//  and menu items.
//
//  23rd October 2006
//  Added IE 7.0 compatibility.
//
// The CSS classes that are applied to the menu elements are as follows:
//
//		span.dropDownMenuHeadingLabel
//      Applied to the <span> element containing the text of each main menu's heading.
//
//		span.dropDownMenuItemLabel
//      Applied to the <span> element containing the text of each menu item.
//
//      a.dropDownMenuHeadingLink
//      Applied to the <a> element containing the link for each menu heading.
//
//      a.dropDownMenuItemLink
//      Applied to the <a> element containing the link for each menu item in a submenu.
//
//      div.dropDownSubMenu
//      Applied to the <div> element containing each sub menu.
//

var _dropDownMenus = [];	       		// References each DropDownMenu.
var _menuItems     = [];           		// References each individual DropDownMenuItem.
var _overlappedSelectElements = [];		// Holds an overlapped counter for each select element.

var _IE7 = false;
var _IE4to6 = false;
var _NS4 = false;
var _NS6 = false;

// Menu item types.
var miNormal		= 1;
var miCheckBox		= 2;
var miRadioButton	= 3;
var miSeperator		= 4;
var miGraphical     = 5;

// Menu styles.
var msFlat 			= 1;
var ms3D			= 2;

//version info
function getMenuVer()
{
	var version = "$Revision: 1.19 $"
	return version
}

function DropDownMenu( elementId, objMenuRoot )
{
    this.id           = _dropDownMenus.length;         		// Unique drop down menu id.
    this.root         = objMenuRoot;                   		// Root DropDownMenuItem object.
    this.timerId      = -1;                            		// For closing submenu.
    this.layerId      = elementId;                     		// Id of <div> element containing this drop down menu.
    this.lastMenuItem = null;                          		// Menu item that previous has MouseOver.
    this.visible      = false;                         		// Visibility flag.
    this.style		  = msFlat;

    // This is where the checkbox and radio button images are held.
    this.images = new Array();
    this.images[miCheckBox]    = [null, null];
    this.images[miRadioButton] = [null, null];

    // Attach methods for each object instance.
    this.Show           	 = DropDownMenu_Show;
 	this.SetHighlightColours = DropDownMenu_SetHighlightColours
 	this.SetMenuWidth        = DropDownMenu_SetMenuWidth
 	this.SetCheckBox    	 = DropDownMenu_SetCheckBox;
    this.SetRadioButton 	 = DropDownMenu_SetRadioButton;
    this.SetEnabled          = DropDownMenu_SetEnabled;
    this.SetImage            = DropDownMenu_SetImage;
    this.SetStyle			 = DropDownMenu_SetStyle;

    // Set the default values for the DropDownMenu object.
    this.SetHighlightColours( "white", "#6A9CCA" );
    this.SetMenuWidth( "170px" );

    objMenuRoot.SetOwner( this );
    _dropDownMenus[_dropDownMenus.length] = this;

	// Determine browser version.
	if( !_IE4to6 && !_NS4 && !_NS6 && !_IE7 )
	{
		var ieVersion = getInternetExplorerVersion();
		if( ieVersion != -1 )
		{
			if( ieVersion >= 7 )
				_IE7 = true;
			else if( ieVersion >= 4 )
				_IE4to6 = true;
		}
		else
		{
			if( document.getElementById )
				_NS6 = true;
			else if( document.layers )
				_NS4 = true;
		}
	}
	
	this.Show( false );
    return this;
}

function getInternetExplorerVersion()
{
	//
	// Returns the version of Internet Explorer or a -1
	// (indicating the use of another browser).
	//

  	var rv = -1; // Return value assumes failure
  	
  	if (navigator.appName == 'Microsoft Internet Explorer')
  	{
  		var ua = navigator.userAgent;
    	var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
    	if( re.exec(ua) != null )
      		rv = parseFloat( RegExp.$1 );
  	}
  	
	return rv;
}

function DropDownMenuItem( strLabel, action, href, style, children )
{
    this.id             = _menuItems.length;                // Unique id.
    this.label          = strLabel.replace(/ /g, "&nbsp;"); // Text of menu item.
    this.itemElementId  = "";                               // Id of <a> element containing menu item's.
    this.itemLabelId    = "";								// If of <span> element containing the menu item's label.
    this.subMenuLayerId = "";                               // Id of <div> element holding sub menu (if present).
    this.imgElementId   = "";                               // Id of <img> element for associated image.
    this.owner          = null;                             // Owning DropDownMenu object.
    this.parent         = null;                             // Parent DropDownMenuItem or null for root menu.
    this.children       = children;                         // Array of child menu items if it has a sub menu.
    this.usageCounter   = 0;                                // If it is a parent menu item with a sub menu.
    this.action         = action;                           // Action to perform when selected.
    this.href           = href;                             // Possible page to navigate to when selected.
    this.style          = style;                            // Type of menu item.
    this.checked        = false;                            // For checkbox or radio button menu items.
    this.group 			= 0;								// Which group it belongs to.
    this.enabled        = true;								// Enabled by default.
    this.selectIndexes  = [];								// Indexes of <select> elements this menu item overlaps.
    this.strImageUrl    = "";                               // Url of associated image.

    // Attach methods for each object instance.
    this.SetText            = DropDownMenuItem_SetText;
    this.SetChecked         = DropDownMenuItem_SetChecked;
    this.GetChecked         = DropDownMenuItem_GetChecked;
    this.SetEnabled         = DropDownMenuItem_SetEnabled;
    this.SetImage           = DropDownMenuItem_SetImage;
    this.OnMouseOver        = DropDownMenuItem_OnMouseOver;
    this.OnMouseLeave       = DropDownMenuItem_OnMouseLeave;
    this.OpenSubMenu        = DropDownMenuItem_OpenSubMenu;
    this.LeaveMenuItem      = DropDownMenuItem_LeaveMenuItem;
    this.IncrementUsage     = DropDownMenuItem_IncrementUsage;
    this.DecrementUsage     = DropDownMenuItem_DecrementUsage;
    this.SetOwner           = DropDownMenuItem_SetOwner;
    this.OnClick            = DropDownMenuItem_OnClick;
    this.HideSelectElements = DropDownMenuItem_HideSelectElements;
    this.ShowSelectElements = DropDownMenuItem_ShowSelectElements;
    this.CloseUnwanted      = DropDownMenuItem_CloseUnwanted;

    if( children )
    {	if( this.style != miNormal && this.style != miGraphical )
        	this.style = miNormal;
    	this.href = "javascript:;";

    	var group = 0;

    	// Set the parent of each child menu item.
    	for( var i = 0; i < children.length; i++ )
    	{
    		// Keep track of each child menu item's group.
    		if( children[i].style == miSeperator )
    			++group;

    		children[i].parent = this;
    		children[i].group = group;
    	}
    }

    if( this.href == "" )
		this.href = "javascript:;";

    _menuItems[_menuItems.length] = this;
    return this;
}

function DropDownMenu_Show( bShow )
{	//
	// DropDownMenu_Show
	// Toggles visibility of a drop down menu.
	//

	if( bShow && this.visible )
		return;

	var objElement = getElement( this.layerId );

    if( !bShow )
    {	objElement.style.display = "none";
    	objElement.innerHTML = "";
    }
    else
    {	objElement.style.display = "block";
        renderDropDownMenu( this.root, this.layerId, 0, false, true, false );
    }

    this.visible = bShow;
}

function DropDownMenu_SetHighlightColours( strFgColour, strBgColour )
{	//
	// DropDownMenu_SetHighlightColours
	// Allows an individual menus selection colours to be set.
	//
    this.highlightForeColour = strFgColour;
    this.highlightBackColour = strBgColour;
}

function DropDownMenu_SetMenuWidth( strWidth )
{	//
	// DropDownMenu_SetMenuWidth
	// Allows the width of each sub menu in the menu to be specified.
	//
	// Should be called before menu is displayed.
	//
	this.menuWidth = strWidth;
}

function DropDownMenu_SetCheckBox( urlSelected, urlUnselected )
{   //
    // DropDownMenu_SetCheckBox
    // Allows the caller to dynamically set the urls of the selected and
    // unselected check box graphic.
    //
    // Images should have a maximum size of 11 x 11 pixels.
    //
    // Should ideally be called before the menu is rendered.
    //

    if( this.images[miCheckBox][false] == null )
    	this.images[miCheckBox][false] = new Image();

    if( this.images[miCheckBox][true] == null )
	    this.images[miCheckBox][true] = new Image();

    this.images[miCheckBox][false].src = urlUnselected;
    this.images[miCheckBox][true].src = urlSelected;
}

function DropDownMenu_SetRadioButton( urlSelected, urlUnselected )
{   //
    // DropDownMenu_SetRadioButton
    // Allows the caller to dynamically set the urls of the selected and
    // unselected radio button graphic.
    //
    // Images should have a maximum size of 11 x 11 pixels.
    //
    // Should ideally be called before the menu is rendered.
    //

    if( this.images[miRadioButton][false] == null )
    	this.images[miRadioButton][false] = new Image();

    if( this.images[miRadioButton][true] == null )
    	this.images[miRadioButton][true] = new Image();

    this.images[miRadioButton][false].src = urlUnselected;
    this.images[miRadioButton][true].src = urlSelected;
}

function DropDownMenu_SetEnabled( bEnabled )
{	//
	// DropDownMenu_SetEnabled
	//
	if( this.root )
		this.root.SetEnabled( bEnabled );
}

function DropDownMenu_SetImage( strImageUrl )
{	//
	// DropDownMenu_SetImage
	// Attaches an image to the menu heading.
	//
	// The recommended size for an image is 14x14 pixels.
	//
	if( this.root )
		this.root.SetImage( strImageUrl );
}

function DropDownMenu_SetStyle( style )
{	//
	// DropDownMenu_SetStyle
	// Allows the menu style to be specified.
	//
	// Note that IE4+ only renders 3D menu styles properly.
	//
	this.style = style;
}

function DropDownMenuItem_SetText( strText )
{   //
    // DropDownMenuItem_SetText
    // Allows the text associated with a specific DropDownMenuItem instance
    // to be changed.
    //
    this.label = strText.replace(/ /g, "&nbsp;");

    if( this.owner.visible )
    {
    	var objLabel = getElement( this.itemLabelId );
		objLabel.innerHTML = this.label;
	}
}

function DropDownMenuItem_SetChecked( bChecked )
{   //
    // DropDownMenuItem_SetChecked
    // This method allows the state of check box and radio button style menu items
    // to be changed dynamically.
    //
    // This can be called when a menu is both visible and invisible.
    //

    if( !this.enabled )
    	return;

    if( this.style != miCheckBox && this.style != miRadioButton )
        return;

    if( this.checked == bChecked )
        return;

    // Radio buttons cannot be explicitly deselected.
    if( this.style == miRadioButton && !bChecked )
        return;

    this.checked = bChecked;

    if( this.owner.visible )
    {   // Update the menu item visually.
        var imgElement = getElement( this.imgElementId );
        imgElement.src = this.owner.images[this.style][this.checked].src;
    }

    if( this.style == miRadioButton )
    {
        // Deselect all sibling radio buttons automatically.
        for( var i = 0; i < this.parent.children.length; i++ )
            if( this.parent.children[i] != this )
            {
                var sibling = this.parent.children[i];
                if( sibling.group == this.group && sibling.style == miRadioButton && sibling.checked )
                {
                    sibling.checked = false;

				    if( this.owner.visible )
				    {	// Update the menu item visually.
                    	var imgElement = getElement( sibling.imgElementId );
                    	imgElement.src = sibling.owner.images[sibling.style][sibling.checked].src;
                   	}
                }
            }
    }
}

function DropDownMenuItem_GetChecked()
{   //
    // DropDownMenuItem_GetChecked
    // Determines whether the menu item has been checked.

    if( this.style != miCheckBox && this.style != miRadioButton )
        return( false );

    if( this.owner.visible )
    {   // Update the menu item visually.
        var imgElement = getElement( this.imgElementId );
        imgElement.src = this.owner.images[this.style][this.checked].src;
    }

    return( this.checked );
}

function DropDownMenuItem_SetEnabled( bEnabled )
{	//
	// DropDownMenuItem_SetEnabled
	//

	if( this.enabled == bEnabled )
		return;

	this.enabled = bEnabled;

	if( this.owner.visible )
	{   // Update the menu item visually.
    	var objLabel = getElement( this.itemLabelId );
	    var objLink = getElement( this.itemElementId );

    	if( this.enabled )
    	{	objLabel.style.color = "";
			objLink.href = this.href;
    	}
    	else
    	{	objLabel.style.color = "#bfbfbf";
			objLink.href = "javascript:;";
    	}
   	}
}

function DropDownMenuItem_SetImage( strUrl )
{	//
	// DropDownMenuItem_SetImage
	// Allows an image to be associated with a menu item.
	//
	// The recommended size for an image is 14x14 pixels.
	//

	if( this.style != miGraphical || this.strImageUrl == strUrl )
		return;

	this.strImageUrl = strUrl;

    if( this.owner.visible )
    {   // Update the menu item visually.
        var imgElement = getElement( this.imgElementId );
        imgElement.src = this.strImageUrl;
    }
}

function DropDownMenuItem_OnMouseOver()
{   //
    // DropDownMenuItem_OnMouseOver
    // Called whenever the mouse is moved over a menu item.
    //
    // Note that the menu item may have a sub menu, in this case it is
    // necessary to open it.
    //

    // Call OnMouseLeave() for the menu item that previously had the mouse.
    if( this.owner.lastMenuItem )
        this.owner.lastMenuItem.OnMouseLeave();

    this.owner.lastMenuItem = this;

    if( this.children == null )
    {
        var objElement = getElement( this.itemElementId );
        var objLabel = getElement( this.itemLabelId );

        if( this.parent )
           this.parent.IncrementUsage();

        // Save foreground/background colour of the menu item's html element.
        this.prevLinkBackgroundColor = objElement.style.backgroundColor;
        this.prevLinkForegroundColor = objElement.style.color;
        this.prevLabelForegroundColor = objLabel.style.color;

        //objElement.style.backgroundColor = this.owner.highlightBackColour;
        //objElement.style.color = this.owner.highlightForeColour;
        //objLabel.style.color = this.owner.highlightForeColour;
    }
    else
    {
        this.OpenSubMenu();
    }
}

function DropDownMenuItem_OnMouseLeave()
{   //
    // DropDownMenuItem_OnMouseLeave
    // This is called by the OnMouseOver() function for the previously selected
    // DropDownMenuItem object whenever the mouse is moved away from the menu
    // item.
    //
    // Note that the menu item may have a sub menu, in this case it is necessary
    // to flag it as not being required.
    //

    if( this.children == null )
    {
        // This may be called due to a menu being explicitly closed.
        if( this.parent && this.parent.bSubMenuOpen )
            this.parent.DecrementUsage();

        // Restore colours of the menu item's html element.
        var objElement = getElement( this.itemElementId )
        var objLabel = getElement( this.itemLabelId );

        //objElement.style.backgroundColor = this.prevLinkBackgroundColor;
        //objElement.style.color = this.prevLinkForegroundColor;
        //objLabel.style.color = this.prevLabelForegroundColor;
    }
    else
    {
        this.DecrementUsage();
    }
}

function DropDownMenuItem_OpenSubMenu()
{   //
    // DropDownMenuItem_OpenSubMenu
    // Opens the sub menu associated with a menu item instance.
    //

    this.IncrementUsage();

    if( this.enabled && !this.bSubMenuOpen )
    {
        var objSubMenu = getElement( this.subMenuLayerId );
        var objElement = getElement( this.itemElementId );
        var objLabel = getElement( this.itemLabelId );

        if( document.all )
			this.HideSelectElements();

        objSubMenu.style.visibility = "visible";
        objSubMenu.style.zIndex = 1000;
        this.bSubMenuOpen = true;

        this.prevLinkBackgroundColor = objElement.style.backgroundColor;
        this.prevLinkForegroundColor = objElement.style.color;
        this.prevLabelForegroundColor = objLabel.style.color;

   		//objElement.style.backgroundColor = this.owner.highlightBackColour;
   		//objElement.style.color = this.owner.highlightForeColour;
   		//objLabel.style.color = this.owner.highlightForeColour;
    }
}

function DropDownMenuItem_LeaveMenuItem()
{   //
    // DropDownMenuItem_LeaveMenuItem
    // Called whenever the mouse is moved out of a sub menu.
    //
    // It determines if a menu item was previously selected and if so
    // calls the DropDownMenuItem's OnMouseLeave() method.
    //

    if( this.owner.lastMenuItem )
        this.owner.lastMenuItem.OnMouseLeave();
}

function DropDownMenuItem_IncrementUsage()
{   //
    // DropDownMenuItem_IncrementUsage
    // Increments the usage counter for a given menu item's submenu.
    //

    ++this.usageCounter;

    if( this.parent )
        this.parent.IncrementUsage();
}

function DropDownMenuItem_DecrementUsage()
{   //
    // DropDownMenuItem_DecrementUsage
    // Decrements the usage counter for a given menu item's submenu.
    //

    if( --this.usageCounter <= 0 )
    {
        this.usageCounter = 0;
        //
        // Schedule a call to 'root.closeUnwanted()' if it has been determined that
        // a sub menu isn't being used.
        //
        if( this.owner.timerId == -1 )
        	this.owner.timerId = setTimeout( "_menuItems['" + this.id+ "'].owner.root.CloseUnwanted()", 200 );
    }

    if( this.parent )
        this.parent.DecrementUsage();
}

function DropDownMenuItem_SetOwner( objOwner )
{   //
    // DropDownMenuItem_SetOwner
    // Recursively sets the owner of each DropDownMenuItem in a menu.
    //

    this.owner = objOwner;

    if( this.children )
        for( var i = 0; i < this.children.length; i++ )
             this.children[i].SetOwner( objOwner );
}

function DropDownMenuItem_OnClick()
{	//
	// DropDownMenuItem_OnClick
	// Called whenever a menu item is selected.
	//

	if( !this.enabled )
		return;

	eval( this.action );

	if( typeof(dropDownMenuItem_OnClick) == "function" )
		dropDownMenuItem_OnClick( this );
}

function DropDownMenuItem_HideSelectElements()
{	//
	// DropDownMenuItem_HideSelectElements
	// Whenever a menu is opened all <select> elements underneath it
	// should be hidden to ensure they don't obscure the menu.
	//
	var objSubMenu = getElement( this.subMenuLayerId );

    var menuLeft   = objSubMenu.offsetLeft;
    var menuTop    = objSubMenu.offsetTop;
    var menuWidth  = objSubMenu.offsetWidth;
    var menuHeight = objSubMenu.offsetHeight;

    // Calculate the menu layer's true top and left positions.
    if( objSubMenu.offsetParent )
    {
		var objParent = objSubMenu.offsetParent
		while( objParent && objParent.tagName.toUpperCase() != "BODY" )
		{	
			menuTop += objParent.offsetTop;
		   	menuLeft += objParent.offsetLeft;
		   	objParent = objParent.offsetParent;
		}
    }

    // Loop through all elements to check for overlay.
	for( i = 0; i < document.all.tags("SELECT").length; i++ )
   	{
		// Grab elements to check one at a time
		var objElement = document.all.tags("SELECT")[i];

		var elementTop    = objElement.offsetTop;
		var elementHeight = objElement.offsetHeight;
		var elementLeft   = objElement.offsetLeft;
		var elementWidth  = objElement.offsetWidth;

		// If object has a parent find its true top and left positions
		if( objElement.offsetParent )
		{
  			var objParent = objElement.offsetParent
  			while( objParent.tagName.toUpperCase() != "BODY" )
  			{	elementTop += objParent.offsetTop;
       			elementLeft += objParent.offsetLeft;
       			objParent = objParent.offsetParent;
  			}
		}

        // Calculate extents of menu layer and the html element.
		var menuRight     = (menuLeft + menuWidth);
		var menuBottom    = (menuTop + menuHeight);
		var elementRight  = (elementLeft + elementWidth);
		var elementBottom = (elementTop + elementHeight);

		if( menuTop < elementBottom && menuBottom > elementTop )
		{
			if( menuLeft < elementRight && menuRight > elementLeft )
			{
          		if( objElement.style.visibility != "hidden" )
          		{	objElement.style.visibility = "hidden";
          			_overlappedSelectElements[i] = 1;
				}
				else
          			_overlappedSelectElements[i]++;

				// Store the index of the <select> element the menu hides.
      			this.selectIndexes[ this.selectIndexes.length ] = i;
			}
		}
    }
}

function DropDownMenuItem_ShowSelectElements()
{	//
	// showSelectElements
	// Despite it's name, this function only redisplays the <select> elements
	// that aren't being hidden by any other menu.
	//
	for( var i = 0; i < this.selectIndexes.length; i++ )
	{
		var idx = this.selectIndexes[i];
		//
		// Only make the select element visible if it isn't being
		// hidden by any other menu.
		//
		if( --_overlappedSelectElements[idx] == 0 )
		{
			var objElement = document.all.tags("SELECT")[idx];
			objElement.style.visibility = "visible";
		}
	}

	this.selectIndexes = [];
}

function DropDownMenuItem_CloseUnwanted()
{   //
    // DropDownMenuItem_CloseUnwanted
    // This is called after a short period after it has been determined
    // that a sub menu isn't being used.
    //
    // It is initially called for the root menu item and then through
    // recursion closes any unwanted sub menus.
    //

	clearTimeout( this.owner.timerId );
    this.owner.timerId = -1;

    if( this.usageCounter == 0 && this.bSubMenuOpen )
    {
        var objSubMenu = getElement( this.subMenuLayerId );
        var objElement = getElement( this.itemElementId );
        var objLabel = getElement( this.itemLabelId );

        //objElement.style.backgroundColor = this.prevLinkBackgroundColor;
        //objElement.style.color = this.prevLinkForegroundColor;
        //objLabel.style.color = this.prevLabelForegroundColor;

        objSubMenu.style.visibility = "hidden";
        objSubMenu.style.zIndex = 0;
        this.bSubMenuOpen = false;

        if( document.all )
			this.ShowSelectElements();
    }

    if( this.children )
    {
	    // Make a recursive call on each sub menu.
	    for( var i = 0; i < this.children.length; i++ )
	        if( this.children[i].children )
	            this.children[i].CloseUnwanted();
	}
}

function renderDropDownMenu( objMenuItem, idMenuBlock, nLevel, bSeperator, bFirstChild, bLeaveMargin )
{   //
    // renderDropDownMenu
    // Displays the drop down menu in the specified div element.
 	//
    // Inputs:
    //   objMenuItem  - Current DropDownMenuItem object to render.
    //   idMenuBlock  - Id of div element to insert menu items.
    //   nLevel       - Sub menu level (zero based).
    //   bSeperator   - Determines whether a seperator should appear before the menu item.
    //   bFirstChild  - Whether this is the first item in the menu.
    //   bLeaveMargin - Determines whether to leave an extra gap on the LHS due to the presence of
    //                  graphical menu items on the same level.
    //

    if( typeof(objMenuItem) != "object" )
        return;

    objMenuItem.itemElementId = "_item" + objMenuItem.id;
    objMenuItem.itemLabelId = "_lbl" + objMenuItem.id;

    // Build the html for the menu item.
  	var strHTML;

 	strHTML =  "<a ";
  	strHTML += "id=\"" + objMenuItem.itemElementId + "\" ";
  	//strHTML += "class=\"dropDownMenuItemLink\" ";
  	strHTML += "class=\"" + (nLevel == 0 ? "dropDownMenuHeadingLink" : "dropDownMenuItemLink")+ "\" ";
  	strHTML += "onmouseover=\"_menuItems['" + objMenuItem.id + "'].OnMouseOver();\" ";
  	strHTML += "onclick=\"" + buildAction(objMenuItem) + "\" ";

 	if( !objMenuItem.enabled )
 		strHTML += "href=\"javascript:;\" ";
 	else
 		strHTML += "href=\"" + objMenuItem.href + "\" ";

    switch( objMenuItem.style )
    {
        case miNormal:
	        strHTML += " onmouseout=\"_menuItems['" + objMenuItem.id + "'].LeaveMenuItem();\" ";
        	if( _IE7 )
				strHTML += "style=\"display: block; padding-top: 4px; padding-bottom: 4px;";
        	else if( _IE4to6  )
				strHTML += "style=\"display: block; padding-top: 4px; padding-bottom: 4px; width: 100%;";
			else if( _NS6 )
				strHTML += "style=\"display: block; padding-top: 4px; padding-bottom: 4px;";
			if( bLeaveMargin )
				strHTML += "padding-left: 34px;";
			else
    			strHTML += "padding-left: 26px;";
			strHTML += "\">";
            break;

        case miGraphical:
	        strHTML += " onmouseout=\"_menuItems['" + objMenuItem.id + "'].LeaveMenuItem();\" ";
			strHTML += "style=\"display: block; padding-top: 4px; padding-bottom: 4px;\">";
            objMenuItem.imgElementId = "_img" + objMenuItem.id;
	    	strHTML += "<img id=\"" + objMenuItem.imgElementId + "\" src=\"" + objMenuItem.strImageUrl + "\" border=\"0\" alt=\"" + objMenuItem.label + "\" align=\"absmiddle\" style=\"margin-left: 10px; margin-right: 10px;\">"
            break;

        case miCheckBox:
        case miRadioButton:
            objMenuItem.imgElementId = "_img" + objMenuItem.id;
            strHTML += "style=\"display: block; padding-top: 4px; padding-bottom: 4px;\">";
            strHTML += "<img id=\"" + objMenuItem.imgElementId + "\" onmouseover=\"_menuItems['" + objMenuItem.id + "'].OnMouseOver();\" alt=\"Menu Item Graphic\" border=\"0\" width=\"14\" height=\"14\" align=\"absmiddle\" style=\"margin-left: 10px; margin-right: 10px\">";
            break;
    }

    strHTML += "<span class=\"" + (nLevel == 0 ? "dropDownMenuHeadingLabel" : "dropDownMenuItemLabel") + "\" id=\"" + objMenuItem.itemLabelId + "\">" + objMenuItem.label + "</span></a>";

    var objLayer = getElement( idMenuBlock );
    objLayer.innerHTML += strHTML;

	if( objMenuItem.imgElementId != "" && (objMenuItem.style == miCheckBox || objMenuItem.style == miRadioButton))
	{	var objLink = getElement( objMenuItem.imgElementId );    	
    	objLink.src = objMenuItem.owner.images[objMenuItem.style][objMenuItem.checked].src;    	
   	}

   	if( !objMenuItem.enabled )
   	{	var objLabel = getElement( objMenuItem.itemLabelId );
    	objLabel.style.color = "#a0a0a0";
   	}

   	//
   	// Display a seperator if needed together with any 3D styles.
   	//
   	if( !bFirstChild )
   	{
		var objElement = getElement( objMenuItem.itemElementId );
	   	if( bSeperator )
	   	{ 	if( objMenuItem.owner.style == msFlat && (_IE4to6 || _IE7) )
				objElement.style.borderTop = "2px outset";
	    	else
	    		objElement.style.borderTop = "2px groove";
	   	}
	   	else
	   		if( objMenuItem.owner.style == ms3D && (_IE4to6 || _IE7) )
				objElement.style.borderTop = "2px outset";
	}

    if( objMenuItem.children )
    {   //
        // If the menu item has children then a new div element needs to
        // be created to contain the sub menu.
        //
        objMenuItem.subMenuLayerId = "_div" + objMenuItem.id;
        
        objLayer.innerHTML += "<div onmouseout=\"_menuItems['" + objMenuItem.id + "'].LeaveMenuItem()\" class=\"dropDownSubMenu\" style=\"padding: 0mm; position: absolute; visibility: hidden; z-index: 100; width: " + objMenuItem.owner.menuWidth + "\" id=\"" + objMenuItem.subMenuLayerId + "\"></div>"

        if( nLevel > 0 )
        {   var objSubMenu = getElement( objMenuItem.subMenuLayerId );
            objSubMenu.style.marginTop -= 21;
            objSubMenu.style.left = 100;
        }

		// Determine whether any child items are graphical.
		var containsGraphics = false;
        for( var i = 0; i < objMenuItem.children.length; i++ )
        	if( objMenuItem.children[i].style != miNormal )
        		containsGraphics = true;

        // Recursively display the submenu.
        var bSeperatorNeeded = false;
        for( var i = 0; i < objMenuItem.children.length; i++ )
        {	if( bSeperatorNeeded )
        	{
				renderDropDownMenu( objMenuItem.children[i], objMenuItem.subMenuLayerId, nLevel + 1, true, i == 0, containsGraphics );
				bSeperatorNeeded = false;
        	}
        	else
        	{
        		bSeperatorNeeded = (objMenuItem.children[i].style == miSeperator);
        		if( !bSeperatorNeeded )
           			renderDropDownMenu( objMenuItem.children[i], objMenuItem.subMenuLayerId, nLevel + 1, false, i == 0, containsGraphics );
           	}
        }
    }
}

function buildAction( objMenuItem )
{   //
    // buildAction
    // Builds the action commands to be executed whenever a menu item
    // is selected.
    //

    if( objMenuItem.children )
        return;

    // Obtain the action the user has specified for this menu item.
    var action;

    // Attach a call to the menu item's OnClick() method.
	action = "_menuItems['" + objMenuItem.id + "'].OnClick();";

    // Attach a call to select a radio button type of menu item.
    if( objMenuItem.style == miRadioButton )
    {   if( action == "" )
            action = "_menuItems['" + objMenuItem.id + "'].SetChecked(true);";
        else
            action = "_menuItems['" + objMenuItem.id + "'].SetChecked(true); " + action;
    }

    // Attach a call to toggle a checkbox type of menu item.
    if( objMenuItem.style == miCheckBox )
    {   if( action == "" )
            action = "_menuItems['" + objMenuItem.id + "'].SetChecked( !_menuItems['" + objMenuItem.id + "'].GetChecked() );";
        else
            action = "_menuItems['" + objMenuItem.id + "'].SetChecked( !_menuItems['" + objMenuItem.id + "'].GetChecked() ); " + action;
    }

    // Ensure menu is closed upon making a selection.
    if( action == "" )
        action = "_menuItems['" + objMenuItem.id + "'].DecrementUsage();";
    else
        action = "_menuItems['" + objMenuItem.id + "'].DecrementUsage(); " + action;

	action = "javascript: " + action;
    return( action );
}

function getElement( id )
{	//
	// getElement
	// Browser independent function to return html object on the page.
	//
	var obj = null;

	if( _IE4to6 || _IE7 )
		obj = document.all[id];
	else if( _NS6 )
		obj = document.getElementById(id);

	return( obj );
}

function ShowDropDownMenus( menus, bShow )
{   //
    // ShowDropDownMenus
    // Displays each DropDownMenu object in the array.
    //
    // Inputs:
    //   menus - Array of DropDownMenuItem objects
    //   bShow - Display flag.
    //

    for( var i = 0; i < menus.length; i++ )
        menus[i].Show( bShow );
}