﻿// 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();
var _minSubMenuPanelWidth = 150;

// build a menu item for the menu - adds it to the container
function buildMenuItem(menuDefItem, menuItemPath, level, index, container) 
{
    // generate: <div class="item"><a href="#">Total refurbishments</a></div><div class="separator">&nbsp;</div>
    var itemDiv = $(document.createElement("DIV"));
    itemDiv.addClassName("item");
    if (index == 0) itemDiv.addClassName("first");

    // add the active class if the item is selected / path matches the location
    if (window.location.toString().indexOf(menuDefItem.link.replace('.aspx','')) > -1) {
        itemDiv.addClassName("selected");
    }

    var link = document.createElement("A");
    link.href = menuDefItem.link;
    link.appendChild(document.createTextNode(menuDefItem.name));
    itemDiv.appendChild(link);
    
    // in case the visitor won't click on the link directly, add onclick event for the cell    
    itemDiv.onclick = function()
    {
        window.location.href = link;
    }
    
    // add the item to the container
    container.appendChild(itemDiv);
    
    var itemSeparator = $(document.createElement("DIV"));
    itemSeparator.addClassName("separator");
    
    // add the item separator to the container
    container.appendChild(itemSeparator);
    
    initMenuBackground(itemSeparator, menuItemPath, level);
    
    // wire up for events the menu item
    newMenuItemPath = menuItemPath.slice(0);
    newMenuItemPath.push(index);
    initMenuItem(itemDiv, newMenuItemPath, level);
}


// build the menu, be it popup or original - return the root element ready for insertion
function buildMenu(menuDef, menuItemPath, level, container)
{
    var menuContainerDiv = $(document.createElement("DIV"));
    menuContainerDiv.addClassName("menuContainerDiv");

    container.appendChild(menuContainerDiv);

    // loop through the items in the menuDef and add the div containers
    $A(menuDef).each(function(menuDefItem, index) {buildMenuItem(menuDefItem, menuItemPath, level, index, menuContainerDiv);});

    // add the last element (space filler) <div class="itemFiller">&nbsp;</div>
    var itemFillerDiv = $(document.createElement("DIV"));
    itemFillerDiv.addClassName("itemFiller");
    
    menuContainerDiv.appendChild(itemFillerDiv);
    
    initMenuBackground(itemFillerDiv, menuItemPath, level);
}

// bespoke function to position the submenu - this can be based on the level and the parent item
function positionSubMenu(parentItem, menu, level)
{
    switch (level) {
        default:
        $(menuContainer).clonePosition($('iMainMenu'), {offsetTop: $(parentItem).getHeight() + $('iTopLine').getHeight()});
        break;
    }
}

function showSubMenu(item, menuDef, menuItemPath, level, itemWidth) 
{
    var genMenu = true;
    var currentLoc = window.location.toString();
    
    var l0Def = getSubMenuDef(0);
    var parentLink = new String();
    
    // get the parent link
    for (var i = 0; i < l0Def.length; i++) {
        //console.dir(l0Def[i].subItems);
        if (l0Def[i].subItems == menuDef) parentLink = l0Def[i].link;
    }
    
    $(menuDef).each(function(menuDefItem, index) {
        if (currentLoc.indexOf(parentLink.replace('.aspx','')) > -1 || currentLoc.indexOf(menuDefItem.link.replace('.aspx','')) > -1) {
            genMenu = false;
        }    
    });
    
    if (genMenu) {
        // create the div to hold the menu
        menuContainer = $(document.createElement("DIV"));
        menuContainer.id = 'menuL' + level;
        menuContainer.addClassName("level");
        menuContainer.addClassName("l1");
        
        // treat the bg as a one of the menu 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($('menuL0'), menuContainer, level);
        
        // show the menu
        menuContainer.setStyle({display: 'none'});
        Effect.Appear(menuContainer, {duration: 0.2});
        //$(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();
        if (node != null) Effect.Fade(node, {duration: 0.2}); //document.body.removeChild(node);
    }
}

// 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
        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, itemWidth) 
{
    //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());
        //console.log("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, itemWidth);
        }
    }
}

// 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));
    }
}

// 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, item.getWidth())();        
    }}); 
    
    // mouse out
    Event.observe(item, 'mouseout', function(event) {if (validateMouseOut(event, item)) {mouseOutMenuItem.bind(item, menuItemPath, level)();}}); 
}

// 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
 */
    // get an array of all the l1 menu items on the menu bar
    $('menuL0').select('.item').each(function(item, index){initMenuItem(item, [index], 0);});
}

Event.onReady(initMenu);