﻿// IE fix to prevent the background images being constantly loaded at each mouseover
try {document.execCommand("BackgroundImageCache", false, true);} catch(err) {}

// timer to clear away the menus
var _timersDelay = 600; // delay in the timer firing in milliseconds
var _timers = Array();  // reference to the timer
var _menuCurrentPath = Array();  // currently selected path of indexes
var _menuStartPath = Array(); // path of the starting menu item
var _subMenuRefs = Array();
var _menuHoverRefs = Array();
var _minSubMenuPanelWidth = 150;

Event.onReady(initMenu);

// build a menu item for the menu - adds it to the container
function buildMenuItem (menuDefItem, menuItemPath, level, index, container) 
{
    // container is a table in this case
    var menuItem = document.createElement("LI");
    
    container.appendChild(menuItem);
    
    $(menuItem).addClassName('menu_item_l'+level);
    
    // add the active class if the item is selected / path matches the location
    //if (window.location.toString().indexOf(menuDefItem.link.replace('.aspx','')) > -1) {
    
    if(menuDefItem.id == _currentPageId)
    {
        $(menuItem).addClassName('active');
    }
    
    if (menuDefItem.last != null)
    {
        $(menuItem).addClassName('last');
    }
    
    var link = document.createElement("A");
    link.href = menuDefItem.link;
    link.appendChild(document.createTextNode(menuDefItem.name));
    menuItem.appendChild(link);
    
    // in case the visitor won't click on the link directly, add onclick event for the cell    
    menuItem.onclick = function()
    {
        window.location.href = link;
    }    
    
    // if we have sub items, then show it
    if ((menuDefItem.subItems != null) && (menuDefItem.subItems.length > 0)) {
        $(menuItem).addClassName('has_sub_menu');
    }
    
    // wire up for events the menu item
    newMenuItemPath = menuItemPath.slice(0);
    newMenuItemPath.push(index);
    initMenuItem (menuItem, newMenuItemPath, level);
}


// build the menu, be it popup or original - return the root element ready for insertion
function buildMenu(menuDef, menuItemPath, level, container)
{
    logFunctionDetails();
    // create the inner table with the rows
    var menuOuter = document.createElement("UL");
    $(menuOuter).addClassName('menu_items');
    $(menuOuter).setStyle({width: '135px'});
    // JP TO DO - ADD THIS TO THE STYLE SHEET INSTEAD
    $(menuOuter).setStyle({position: 'absolute'});
    // loop through the items in the menuDef and add the rows
    $A(menuDef).each(function(menuDefItem, index) {buildMenuItem(menuDefItem, menuItemPath, level, index, menuOuter);});

    //if the level is tier 1, add a title to the top of the menu
    if (level == 1)
    {
        var menuTitle = document.createElement("div");
        $(menuTitle).addClassName('menuTitle');
        $(menuTitle).setStyle({width: '115px', padding: '0px 10px', position: 'absolute'});
        menuTitle.innerHTML = _menuDef[menuItemPath[0]].name;
        container.appendChild(menuTitle);
        initMenuBackground (menuTitle, menuItemPath, level);  
    }
    //// alert('tedst' + menuOuter.outerHTML);
    // insert the menu into the container     
    container.appendChild(menuOuter);
}

// bespoke function to position the submenu - this can be based on the level and the parent item
function positionSubMenu(parentItem, menu, level)
{
    $(menu).setStyle({position: 'absolute'});
    // get the first child UL of the menu div - we only have one, and this contains the list items
    var menuItems = $(menu).select('UL')[0];
    // show the drop down list
    switch (level) {
        case 1:
            var logoWidth = $('logo').getWidth();
            $(menu).setStyle({left: ($('header').cumulativeOffset().left) + logoWidth + 'px', top: '0px', height: $('header').getHeight() + 'px'});
            $(menuItems).setStyle({position: 'absolute'});
            $(menuItems).clonePosition($(parentItem), {setTop: true, setLeft: false, setWidth: false, setHeight: false});
            
            if($(menuItems).cumulativeOffset().top + $(menuItems).getHeight() > $('header').getHeight())
            {
                $(menuItems).setStyle({top: 266 - $(menuItems).getHeight()  + 'px'});
            }
        break;
        default:
            $(menu).clonePosition($(parentItem), {setTop: true, setLeft: false, setWidth: false, setHeight: false});
            $(menu).setStyle({left: (($(parentItem).cumulativeOffset().left + $(parentItem).getWidth())) + 'px'});
            
            $(menu).setStyle({width: '135px', height: $('header').getHeight() - $(menu).cumulativeOffset().top - $(menu).getStyle('paddingTop').gsub('px', '') + 'px'});
            $(menuItems).setStyle({width: $(menu).getWidth() + 'px', top: '20px'});
            
            if($(menuItems).cumulativeOffset().top + $(menuItems).getHeight() > $('header').getHeight())
            {
                $(menu).setStyle({top: (($('header').getHeight() - $(menuItems).getHeight()) - 20) + 'px'});
                $(menu).setStyle({height: $('header').getHeight() - $(menu).cumulativeOffset().top - $(menu).getStyle('paddingTop').gsub('px', '') + 'px'});
            }
        break;
    }
}

function showSubMenu(item, menuDef, menuItemPath, level) 
{
    logFunctionDetails();

    // JP TO DO - BUILD THE MENU STRUCTURE AS IN THE FILE TEST.HTM
    // create the div to hold the menu
    
//    if(menuItemPath > 0)
//    {
    menuContainer = $(document.createElement("DIV"));
    menuContainer.id = 'menuL' + level;    
    menuContainer.setStyle({width: '135px', paddingLeft: '10px', backgroundRepeat: 'no-repeat', backgroundPosition: 'center left'});
    
    menuBackground = $(document.createElement("DIV"));
    // JP TO DO - SET THE HEIGHT OF THE BACKGROUND DIV CORRECTLY
    menuBackground.setStyle({width: '155px', height: '100%', position: 'absolute', top: '0px', left: '0px'});
    
    menuOpaqColourBackground = $(document.createElement("DIV"));
    menuOpaqColourBackground.addClassName(menuDef[0].style + ' menuopac');
    menuOpaqColourBackground.setStyle({width: '135px', height: '100%', position: 'absolute', top: '0px'});
        
    menuContainer.appendChild(menuOpaqColourBackground);
    menuContainer.appendChild(menuBackground);
    
    // initialise the background as the background so it acts as a mouse out area when rolling off the menu items themselves
    initMenuBackground (menuBackground, menuItemPath, level);    
    
    // build the next menu to be shown
    buildMenu(menuDef, menuItemPath, level, menuContainer);
    
    document.body.appendChild(menuContainer);
    // assign the specific class name for the ul element
    if (menuDef[0].style) menuContainer.select('UL')[0].addClassName(menuDef[0].style+'Items');

    // position the menu corrently
    positionSubMenu(item, menuContainer, level);
    
    // jamie's dodgy fix for the background colour in IE6 - just add a css class et voila!
    $(menuContainer).addClassName('ie6-css-class');   
     
    // show the menu
    $(menuContainer).show();

    // add the menu item to the reference array - assumption here is that we should not need to ever add more than one to the list
    _subMenuRefs[level] = menuContainer;
//    }
}

// removes all sub menus above and including the level
function removeSubMenus(level) 
{
    while ((_subMenuRefs.length > level) && (_subMenuRefs.length > 0)) {
        node = _subMenuRefs.pop();
        try {
            if (node != null) document.body.removeChild(node);
        } catch(e) {}
    }
}

function hideSubMenu(item) 
{
    // removes the drop down list
    //$('menuL2').hide();
    //// alert(Event.element(event).innerHTML);
}

// non generic function to show the hover highlighting
function hoverMenuItem (item, level) 
{

    // first unhover any other item at this level
    unHoverMenuItem(level); 
    // now mark ours as hover
    switch (level) {
        default:
            // if it is not already selected, then show the hover colours
            if (!$(item).hasClassName('selected')) {
                $(item).addClassName('hover');
                
                // KM - set the background image submenu marker
                if ($(item).hasClassName('has_sub_menu')) {
                    $(item).addClassName('has_sub_menu_and_hover');
                }
            }
    }           
    
    // add the hovered element to the array to unhover later
    _menuHoverRefs[level] = item;
}

// non generic function to remove the hover highlighting - should work on the level passed
function unHoverMenuItem (level) 
{
    // perform different actions depending upon the level
    switch (level) {
        default: 
            // if it is not already selected, then remove the hover colours
            if ((_menuHoverRefs[level] != null) && (!$(_menuHoverRefs[level]).hasClassName('selected'))) {
                $(_menuHoverRefs[level]).removeClassName('hover');
                // KM - remove the background image submenu marker
                if ($(_menuHoverRefs[level]).hasClassName('has_sub_menu')) {
                    $(_menuHoverRefs[level]).removeClassName("has_sub_menu_and_hover");
                }
                
                _menuHoverRefs[level] = null;
            }
    }
}

// call unhover for all menu items from the level passed
function unHoverMenuItemsFromLevel (level) {
    // work through the levels
    for(var i = level; i < _menuHoverRefs.length; i++) {
        if (_menuHoverRefs[i] != null) {
            unHoverMenuItem(level);
        }
    }
}

// return the array of menudef items based on the path supplied
function getSubMenuDef(menuItemPath) 
{
    var currentItem = _menuDef;
    for (var i = 0; i < menuItemPath.length; i++) 
    {
        // -1 reference is to the menu background
        //(menuItemPath[i] != -1) && (menuItemPath[i] != 0)
        if (menuItemPath[i] != -1 && (currentItem.length > menuItemPath[i]) && (currentItem[menuItemPath[i]].subItems != null))
        {
            currentItem = currentItem[menuItemPath[i]].subItems;
        }
        else
        {
            currentItem = null;
            break;
        }
    }
    
    // return an array
    return currentItem;
}

// mouse is over the menu item - lots of processing to do
function mouseOverMenuItem (menuItemPath, level) 
{
    logFunctionDetails();
    
    // cancel the timers
    while (_timers.length > 0) 
    {
        window.clearTimeout(_timers.pop());
    }
    
    //modified code to ignore position [0] for FFE - 6/2/2008 - JP
    if(menuItemPath != 0)
    {
        // need to compare the path of this item we are over to the path of the current item as was
        maxLength = (menuItemPath.length > _menuCurrentPath.length) ? menuItemPath.length : _menuCurrentPath.length;
        for (var i = 0; i < maxLength; i++)
        {
            // need to tread carefully as either array could run out
            if (!((menuItemPath.length > i) && (_menuCurrentPath.length > i) && (menuItemPath[i] == _menuCurrentPath[i])))
            {
                // we've found a non matching item or the arrays are not the same size, therefore clear the menus from here on in and break
                removeSubMenus(i + 1);
                // remove the hover status
                unHoverMenuItemsFromLevel(i);
                break;
            }
        } 
        // check if we have changed at this level
        changeAtLevel = (_menuCurrentPath[level] != menuItemPath[level]);
        
        // either match or don't and cleared at this point, so we should be able to put in our path as the final path - slice() used to force a returned array to fix a js bug
        _menuCurrentPath = menuItemPath.slice(0);

        // if we don't match, then rebuild the highlights and menus for this level
        if (changeAtLevel) {
        
            // show the hover highlight
            hoverMenuItem(this, level);
            
            // now we need to check if we should have a submenu - the assumption here is that we can't jump a submenu, i.e. we should not need to suddenly show 2
            menuDef = getSubMenuDef(menuItemPath);
        
            // if we have any sub items, then show the submenu
            
            if ((menuDef != null) && (menuDef != '') && (menuDef.length > 0)) {
                // show the sub menu;
                showSubMenu(this, menuDef, menuItemPath, level + 1);
            }
        }
    }
}

function mouseOutMenuItem (menuItemPath, level) 
{
    logFunctionDetails();
    
    // remove the hover highlight - removed and placed on the timer
    // unHoverMenuItem(this, level);
    
    match = true;
    // check if the current menu item path is different to the path of the exited item, if it is, then don't worry as we've moved on after the mouse out
    if (menuItemPath.length == _menuCurrentPath.length)
    {
        for (var i = 0; i < menuItemPath.length; i++)
        {
            // check that the values are the same and quit if not
            if (menuItemPath[i] != _menuCurrentPath[i])
            {
                // reset the match flag
                match = false;
                break;
            }
        }
    }
    else 
    {
        match = false
    }

    // if we still have a match, then we've moused out of the area and not moused in anywhere else, therefore let's start the timer            
    if (match) 
    {
        _timers.push(setTimeout("menuTimeout(" + level + ");", _timersDelay));
    }
}

// timeout has fired, which means that the mouse has moved off any menu as no mouse over has been fired
function menuTimeout(level)
{
    // here we need to show the initial menu again - first we'll tidy up
    // clear all the menus up as we've timed out, meaning we've moved off
    clearAllMenus();
    // show the initial menu again
    showInitialMenu();
}

// basically no menu is now selected, so clear everything up and set it back to the start
function clearAllMenus()
{
    // both set to zero as we want to remove everything
    removeSubMenus(0);
    unHoverMenuItem(0);
    // reset all the values
    _menuCurrentPath = Array();
    _subMenuRefs = Array();
    _menuHoverRefs = Array();
}

function validateContainerMouseOver(e, item) {
    var fromElement = $(e.relatedTarget || e.fromElement);
    var toElement = $(e.relatedTarget || e.toElement);
  
    return true;
}

// checks that the mouse out is not caused by a child item
function validateMouseOut(e, item) 
{
    logFunctionDetails();
    
    var fromElement = $(e.relatedTarget || e.fromElement);
    var toElement = $(e.relatedTarget || e.toElement);
    
    // return true if we don't have a toElement (off browser), not self (from child) and not to child of self
    return ((toElement == null) || ((item != toElement) && (!$(toElement).descendantOf($(item)))));
    
    //return fromElement != item || toElement == item  && !(fromElement.descendantOf(item) || toElement.descendantOf(item));
}

// checks that the mouse over is not caused by a change of child item
function validateMouseOver(e, item) 
{
    logFunctionDetails();

    // get the to and from elements
    var toElement = e.target || e.toElement;
    var fromElement = e.relatedTarget || e.fromElement;
    
    // from valid if from is null (i.e. outside the browser) or from is not the item not a descendant of it, i.e. we don't care about events triggered by our children in terms of a mouse over
    var fromValid = (fromElement == null) || ((fromElement != item) && (!$(fromElement).descendantOf($(item))));

    // to valid if we are moving over the item or once of its descendants or, and this is a fix, or one of the descendants of it's parent    
    var toValid = (toElement == item) || ($(toElement).descendantOf($(item))) || ($(toElement).descendantOf($(item.parentNode)));
    
    return (fromValid && toValid);
}

// given the item (A) and the index, it assigns the href from the menuDef
function assignLinkHref (item, index, menuDef) {
    // get the link

    if ((item.tagName == 'A') && (menuDef.length > index) && (menuDef[index].link != null)) {
        item.href = menuDef[index].link;
    }        
}

function initMenuItem (item, menuItemPath, level) {
    // wire up the passed menu item to show the drop down

    logFunctionDetails();
    
    // mouse over
    Event.observe(item, 'mouseover', function(event) {if (validateMouseOver(event, item)) {mouseOverMenuItem.bind(item, menuItemPath, level)();}}); 
    
    // mouse out
    Event.observe(item, 'mouseout', function(event) {if (validateMouseOut(event, item)) {mouseOutMenuItem.bind(item, menuItemPath, level)();}}); 
        
    // set up the links - not for L1
    // $(item).getElementsBySelector('a').each(function(item, index) {assignLinkHref(item, index, menuDef);});
}

// little bit of a fix this - we want the background to appear as an item so that the menu does not disappear, but not actually do anything, therefore we'll set the last figure in the path to -1
function initMenuBackground (item, menuItemPath, level) {

    logFunctionDetails();
    
    // call wire up menu with altered details
    newMenuItemPath = menuItemPath.slice(0);
    newMenuItemPath.push(-1);

    initMenuItem(item, newMenuItemPath, level);
}

function initMenu()
{
/* when loading has finished, find all the tags of class topMenu
 * and add the event to shop the drop down on mouse over
 */
    // get an array of all the l1 menu items on the menu bar
    $('navi').select('.menu_item_l0').each(function(item, index){initMenuItem(item, [index], 0);});
    
    // now we have built the menu, we should show the initial one
    showInitialMenu();
}

function showInitialMenu()
{
    logFunctionDetails();

    // create a reference to the selected menu item - there should always be one, even if it is home
    var selectedItem;
    var selectedIndex = 0;
    _menuStartPath = new Array(1);

    // get the selected index and the selected item
    var naviChildren = $('navi').select('li');
    for(var i = 0; i < naviChildren.length; i++)
    {
            if(naviChildren[i].readAttribute('class').include('selected'))
            {
                selectedItem = naviChildren[i];
                selectedIndex = i;
                break;
            }          
    }

    // set the menuItemPath both for the parameter and the global variable        
    _menuCurrentPath = _menuStartPath;
    _menuStartPath[0] = selectedIndex;
    
    // if we have any sub menu items, then show the sub menu
    if (_menuDef[selectedIndex].subItems && _menuDef[selectedIndex].subItems.length > 0) {
        
        // show the sub menu for the selected main menu item
        showSubMenu(selectedItem, _menuDef[selectedIndex].subItems, _menuStartPath, 1) 
    }
}

// traces the function name and arguments
function logFunctionDetails() 
{
    var caller = logFunctionDetails.caller;
    if (caller != null) {
        var text = "Function: " + caller.name + " Arguments: ";
        for (var i = 0; i < caller.arguments.length; i++) {
            text += caller.arguments[i] + ((i < caller.arguments.length - 1) ? ", " : "");
        }
        // trace the resulting text
    }
}