//
// Javascript popup menu
//
// Created on: <10-Mar-2004 16:35:43 gl>
//
// Copyright (C) 1999-2004 eZ systems as. All rights reserved.
//


/*! \file javascriptmenu.js
  A JavaScript-based popup menu designed for eZ publish navigation.
*/

/*
  Handles multilevel popup menus. Writes menu content after the document is loaded, so browsers without
  javascript does not see the menu content.
  Requieres DOM support, which should be available in 5th generation browsers.
  Author: Gunnstein Lye <gl@ez.no>
  Additional code from http://www.quirksmode.org is used with permission.

  Allows sorting by index if you uncomment the prioritySort() call in init().

  Links:
  http://www.quirksmode.org/js/findpos.html
  http://www.howtocreate.co.uk/tutorials/index.php?tut=0&part=28

  TODO: menuArray could perhaps fetch submenu HTML from templates.
  TODO: <body onClick="hideAllMenus()"> does not work well in all browsers (opera).

  Tested and working browsers:

  Netscape 7.1
  User agent: mozilla/5.0 ... gecko/20030624 netscape/7.1

  Mozilla 1.5
  User agent: mozilla/5.0 ... gecko/20031007

  Mozilla Firefox 0.8
  User agent: mozilla/5.0 ... gecko/20040207 firefox/0.8

  Internet Explorer 6.0
  User agent: mozilla/4.0 ... msie 6.0

  Opera 7.23
  User agent: mozilla/4.0 ... msie 6.0 ... opera 7.23


  Works, but has a flicker problem:

  Konqueror 3.1.1
  User agent: mozilla/5.0 ... konqueror/3.1

*/


var menuArray = new Array();      // Contains the result from the content tree fetch


// Inserts menuArray into the document.
function init()
{
    prioritySort();

    var urlAliasForDepth = new Array();
    for ( var i in menuArray )
    {
        urlAliasForDepth[menuArray[i]['depth']] = menuArray[i]['url_alias'];

        var subMenuElement = document.getElementById( menuArray[i]['url_alias'] );
        if ( subMenuElement )
        {
            continue;
        }

        var parentElement = document.getElementById( urlAliasForDepth[Number( menuArray[i]['depth'] ) - 1] );
        // alert(urlAliasForDepth[Number( menuArray[i]['depth'] ) - 1]);
        var next = Number( i ) + 1;
        // If the item has children
        if ( next < menuArray.length &&
             menuArray[i]['depth'] < menuArray[next]['depth'] )
        {
            parentElement.innerHTML += '<div class="popuplink" onMouseOver="showMenu( this, &#39;' +
                                       menuArray[i]['url_alias'] +
                                       '&#39;, &#39;right&#39; )">\n' +
                                       '  <a href=' + menuArray[i]['url_alias_ezurl'] + '>' +
                                       menuArray[i]['name'] + ' ' + menuArrow +
                                       '</a>\n' +
                                       '</div>\n';
            parentElement.parentNode.innerHTML += '<div class="popupmenu" id="' +
                                                  menuArray[i]['url_alias'] +
                                                  '"></div>\n';
        }
        else // If the item has no children
        {
            parentElement.innerHTML += '<div class="popuplink" onMouseOver="showMenu( this, &#39;' +
                                       urlAliasForDepth[Number( menuArray[i]['depth'] ) - 1] +
                                       '&#39;, &#39;right&#39; )">\n' +
                                       '  <a href=' + menuArray[i]['url_alias_ezurl'] + '>' +
                                       menuArray[i]['name'] +
                                       '</a>\n' +
                                       '</div>\n';
        }
    }
}

// Sorts menuArray by priority (without messing with depth)
function prioritySort()
{
    var tempMenuArray = menuArray;
    menuArray = new Array();
    var depthArray = new Array();

    // Split array into arrays by depth
    var firstDepth;
    for ( var i in tempMenuArray )
    {
        if ( firstDepth == undefined )
        {
            firstDepth = tempMenuArray[i]['depth'];
        }
        if ( depthArray[tempMenuArray[i]['depth']] == undefined )
        {
            depthArray[tempMenuArray[i]['depth']] = new Array();
        }
        depthArray[tempMenuArray[i]['depth']].push( tempMenuArray[i] );
    }

    // Sort depth arrays by priority
    for ( var j in depthArray )
    {
        depthArray[j].sort( comparePriority );
    }

    // Insert top level elements
    for ( var k in depthArray[firstDepth] )
    {
        menuArray.push( depthArray[firstDepth][k] );
    }

    // Insert children
    for ( var l = firstDepth + 1; depthArray[l] != undefined; l++ )
    {
        for ( var m in depthArray[l] )
        {
            var parentNodeID = depthArray[l][m]['parent_node_id'];
            var indexForParentNodeID = new Array();
            if ( indexForParentNodeID[parentNodeID] == undefined )
            {
                indexForParentNodeID[parentNodeID] = findIndexAfterParent( depthArray[l][m] );
            }

            menuArray.splice( indexForParentNodeID[parentNodeID], 0, depthArray[l][m] );

            indexForParentNodeID[parentNodeID] += 1;
        }
    }
}

// Returns the index at which to insert children
function findIndexAfterParent( parent )
{
    for ( var i in menuArray )
    {
        if ( menuArray[i]['node_id'] == parent['parent_node_id'] )
        {
            return Number(i) + 1;
        }
    }
    return -1;
}

// Compare two items by priority
//function comparePriority( a, b )
//{
//    if ( a['priority'] < b['priority'] )
//    {
//        return 1;
//    }
//    if ( a['priority'] > b['priority'] )
//    {
//        return -1;
//    }
//    return 0;
//}

function comparePriority( a, b )
{
   if ( Number(a['priority']) < Number(b['priority']) )
   {
       return 1;
   }
   if ( Number(a['priority']) > Number(b['priority']) )
   {
       return -1;
   }
   return 0;
}

// Hides all menus.
function hideAllMenus()
{
    for ( var i in menuArray )
    {
        var subMenuElement = document.getElementById( menuArray[i]['url_alias'] );
        if ( subMenuElement )
        {
            subMenuElement.style.display = 'none';
        }
    }
}

// Hide all menus on the same or lower levels than the one we are opening.
// Menus on higher levels should stay open.
function hideOtherMenus( dontHideID )
{
    var hideMeByDepth = new Array();
    // Reverse loop, children before parents
    for ( var i = menuArray.length - 1; i >= 0; i-- )
    {
        var subMenuElement = document.getElementById( menuArray[i]['url_alias'] );
        if ( subMenuElement )
        {
            // If my ID is dontHideID, then I should not be hidden.
            if ( menuArray[i]['url_alias'] == dontHideID )
            {
                hideMeByDepth[Number( menuArray[i]['depth'] ) - 1] = false;  // Don't hide my parent
            }
            // If one of my children should not be hidden, then I should not be hidden.
            else if ( hideMeByDepth[menuArray[i]['depth']] == false )
            {
                hideMeByDepth[Number( menuArray[i]['depth'] ) - 1] = false;  // Don't hide my parent
            }
            // Otherwise, hide me
            else
            {
                hideMeByDepth[menuArray[i]['depth']] = true;
                subMenuElement.style.display = 'none';
            }
        }
    }
}

// Shows and positions the menu given by subMenuID. Hides other menus first, as necessary.
function showMenu( posElement, subMenuID, position )
{
    hideOtherMenus( subMenuID );

    var subMenuElement = document.getElementById( subMenuID );
    if ( !subMenuElement || subMenuElement.childNodes.length == 0 )  // Don't show empty menu
    {
        return;
    }
    // Show popup menu
    subMenuElement.style.display = 'block';

    // Avoid repositioning. This fixes a problem with menu items that have no submenu,
    // and therefore call showMenu() with their own id.
    // TODO: We may have to reposition menus on window resize or scroll.
    if ( subMenuElement.isPositioned )
    {
        return;
    }

    // Position popup menu correctly
    // NB: The adjustment values depend on the stylesheet
    var userAgent = navigator.userAgent.toLowerCase();
    if ( position == 'below' )
    {
        var yOffset = 5;
        var xOffset = -10;
        if ( userAgent.indexOf( 'msie' ) >= 0 )
        {
            yOffset = 16;
            xOffset = 0;
        }

        subMenuElement.style.top = findPosY( posElement ) + posElement.offsetHeight + yOffset + 'px';
        subMenuElement.style.left = findPosX( posElement ) + xOffset + 'px';
    }
    else if ( position == 'right' )
    {
        var yOffset = -1;
        var xOffset = 1;
        if ( userAgent.indexOf( 'firefox' ) >= 0 ||
           ( userAgent.indexOf( 'ie 7.' ) >= 0 ) )
        {
            yOffset = 0;
        }

        subMenuElement.style.top = findPosY( posElement ) + yOffset + 'px';
        subMenuElement.style.left = findPosX( posElement ) + posElement.offsetWidth + xOffset + 'px';
    }
    subMenuElement.isPositioned = true;
}

// Finds the X position of an element.
// From http://www.quirksmode.org/js/findpos.html
// Copied with permission
function findPosX( obj )
{
    var curleft = 0;
    if ( obj.offsetParent )
    {
        while ( obj.offsetParent )
        {
            curleft += obj.offsetLeft;
            obj = obj.offsetParent;
        }
    }
    else if ( obj.x )
    {
        curleft += obj.x;
    }
    return curleft;
}

// Finds the Y position of an element.
// From http://www.quirksmode.org/js/findpos.html
// Copied with permission
function findPosY( obj )
{
    var curtop = 0;
    if ( obj.offsetParent )
    {
        while ( obj.offsetParent )
        {
            curtop += obj.offsetTop;
            obj = obj.offsetParent;
        }
    }
    else if ( obj.y )
    {
        curtop += obj.y;
    }
    return curtop;
}
