﻿// 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 = 500; // delay in the timer firing in milliseconds
var _timers = Array();  // reference to the timer
var _menuCurrentPath = Array();  // currently selected path of indexes
var _subMenuRefs = Array();
var _menuHoverRefs = Array();

// build a menu item for the menu - adds it to the container
function buildMenuItem (menuDefItem, menuItemPath, level, index, container) 
{
    traceFunctionDetails();

    // container is a table in this case
    var itemRow = container.insertRow(-1);
    var itemCell = itemRow.insertCell(-1);
    
    $(itemCell).addClassName('menu_item_l'+level);
    
    var link = document.createElement("A");
    link.href = menuDefItem.link;
    link.appendChild(document.createTextNode(menuDefItem.name));
    itemCell.appendChild(link);
    
    // in case the visitor won't click on the link directly, add onclick event for the cell    
    itemCell.onclick = function()
    {
        window.location.href = link;
    }    
    
    // if we have sub items, then show it
    if ((menuDefItem.subItems != null) && (menuDefItem.subItems.length > 0)) {
        $(itemCell).addClassName("has_sub_menu");
    }
    
    //var itemSeparatorRow = container.insertRow(-1);
    //var itemSeparatorCell = itemSeparatorRow.insertCell(-1);
    //$(itemSeparatorCell).addClassName('menu_item_separator');
    //$(itemSeparatorCell).update('&nbsp;');
    
    // wire up for events the menu item
    newMenuItemPath = menuItemPath.slice(0);
    newMenuItemPath.push(index);
    initMenuItem (itemCell, newMenuItemPath, level);
}


// build the menu, be it popup or original - return the root element ready for insertion
function buildMenu(menuDef, menuItemPath, level, container)
{
    // create the inner table with the rows
    var innerTable = document.createElement("TABLE");
    $(innerTable).addClassName('menu_items');
    innerTable.cellPadding = 0;
    innerTable.cellSpacing = 0;
    // loop through the items in the menuDef and add the rows
    $A(menuDef).each(function(menuDefItem, index) {buildMenuItem(menuDefItem, menuItemPath, level, index, innerTable);});

    // create the outer table
    var outerTable = document.createElement("TABLE");
    outerTable.cellPadding = 0;
    outerTable.cellSpacing = 0;
    var row = outerTable.insertRow(-1);
    var cell = row.insertCell(-1);
    cell.appendChild(innerTable);
    
    // add in another row for the curved bottom
//    if (level == 1) {
//        row = outerTable.insertRow(-1);
//        cell = row.insertCell(-1);
//        // mark the cell as background to the menu
//        initMenuBackground (cell, menuItemPath, level);    
////        innerTable = cell.appendChild(document.createElement("TABLE"));
////        $(innerTable).addClassName('bottom_strip');
////        innerTable.cellPadding = 0;
////        innerTable.cellSpacing = 0;
////        row = innerTable.insertRow(-1);
//    }
        
    // insert the menu into the container    
    container.appendChild(outerTable);        
    trace(container.innerHTML);
}

// bespoke function to position the submenu - this can be based on the level and the parent item
function positionSubMenu(parentItem, menu, level)
{
    // get the position of this element
    var pos = Position.cumulativeOffset(parentItem);

    // show the drop down list
    switch (level) {
        case 2:
            $(menuContainer).setStyle({left: pos[0] + $(parentItem).getWidth() + 'px', top: pos[1] + 'px'});        
            break;
        default:
            $(menuContainer).setStyle({left: pos[0] + 'px', top: pos[1] + $(parentItem).getHeight() + 'px'});
    }
}

function showSubMenu(item, menuDef, menuItemPath, level) 
{
    traceFunctionDetails();
    trace("showSubMenu - level: " + level);
        
    // create the div to hold the menu
    menuContainer = document.createElement("DIV");
    menuContainer.id = 'menuL' + level;
    
    // wire up the container to be the background
    // NOT WORKING AS IT REACTS TO THE BUBBLE UP OF ITEMS 
    // initMenuBackground (menuContainer, menuItemPath, level);
    
    // build the next menu to be shown
    buildMenu(menuDef, menuItemPath, level, menuContainer);
    document.body.appendChild(menuContainer);
    
    // position the menu corrently
    positionSubMenu(item, menuContainer, level);
    
    // 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) 
{
    traceFunctionDetails();
    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');
            }
    }           
    
    // 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');
                _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
        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) 
{
    traceFunctionDetails();
    trace("level: " + level);
    changeAtLevel = true; // used as a flag to check if there is a change at this level

    // cancel the timers
    while (_timers.length > 0) 
    {
        window.clearTimeout(_timers.pop());
        trace("Clearing timer.");
    }

    // 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 hovel status
            unHoverMenuItemsFromLevel(i);
            trace("difference in menu at level: " + 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
    _menuCurrentPath = menuItemPath.slice(0);

    // if we don't match, then rebuild the highlights and menus for this level
    if (changeAtLevel) {    
        trace("change at level");
        // 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.length > 0)) {
            showSubMenu(this, menuDef, menuItemPath, level + 1);
        }
    }
}

// mouse moves out from a menu item
function mouseOutMenuItem (menuItemPath, level) 
{
    traceFunctionDetails();
    trace("menuItemPath: " + menuItemPath + " - _menuCurrentPath: " + _menuCurrentPath);
    
    // 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));
    }

    // hide the menu
    //hideSubMenu();
}

// timeout has fired, which means that the mouse has moved off any menu as no mouse over has been fired
function menuTimeout(level)
{
    // clear all the menus up as we've timed out, meaning we've moved off
    clearAllMenus();
}

// 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();
}

// checks that the mouse out is not caused by a child item
function validateMouseOut(e, item) 
{
     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)))));
}

// checks that the mouse over is not caused by a change of child item
function validateMouseOver(e, item) 
{
    var toElement = e.target || e.toElement;
    var fromElement = e.relatedTarget || e.fromElement;
    
    var fromValid = (fromElement == null) || ((fromElement != item) && (!$(fromElement).descendantOf($(item))));
    var toValid = (toElement == item) || ($(toElement).descendantOf($(item)));
    
    //return (from = (not self and child)) && (to = (self or child))
    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
    
    // 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) {

    // call wire up menu with altered details
    newMenuItemPath = menuItemPath.slice(0);
    newMenuItemPath.push(-1);
    trace(newMenuItemPath);
    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
 */
    clearTrace();
    traceFunctionDetails();

    // get an array of all the l1 menu items on the menu bar
    $('menuL0').select('.item').each(function(item, index){initMenuItem(item, [index], 0);});
}
