
/*
 *
 * File:      $RCSfile: si_dommenu.js,v $
 * Version:   $Revision: 1.0 $
 * Revised:   $Date:  $
 *            $Author: mbm $
 *
 * Created:   2006-06-01
 * Author:    sectra:mbm
 * Project:   Web
 *
 *
 * Description
 *   Dynamic menu system.
 *
 * Compatibility:
 *   IE      >= 5.0 
 *   Mozilla >= 5.0
 *   Opera   >= 7.0
 *   Firefox >= 1.0
 *   Safari  >= 1.0
 *
 * Dependencies:
 *   dom.js, 
 *   si_dommenu.css, classes defined in SIM_CONST.CLASSES
 */


SIM_CONST = {
  CLASSES: {
    MENU_TEMPLATE:           new Array(
                              {
                                tagName:    'UL',
                                attributes: null,
                                repeated:   false
                              },
                              {
                                tagName:    'LI',
                                attributes: null,
                                repeated:   true
                              },
                              {
                                tagName:    'A',
                                attributes: 
                                {
                                  className: "simmenuentry",
                                  tabIndex:  DETECT.is_opera ? "0" : "-1"
                                },
                                repeated:   true
                              }
                             ),
    
    MENU_CONTAINER:          'simmenucontainer',
    MENU_ENTRY:              'simmenuentry',
    MENU_ENTRY_CURRENT:      'simmenuentrycurrent',
    MENU_ENTRY_HOVER:        'simmenuentryhover',

    MENU_TITLE:              'simmenutitle',
    MENU_CANVAS:             'simmenucanvas',

    MENU_POPUP:              'simpopup',

    PATH_ROOT:               'simpathroot',
    PATH_FOLDER:             'simpathfolder',
    PATH_CURRENT_FOLDER:     'simpathfoldercurrent',
    PATH_CURRENT_DOCUMENT:   'simpathdocument'
  },

  ID: {
    MENU_POPUP:              'simpopup',
    TOC_CONTAINER:           'toc',
    PATH_CONTAINER:          'messageisland'
  },


  TEXT: {
    LOCATE_CURRENT:          '<img src="/common/styles/images/_sim_menuwhereami.gif" style="position: absolute; top: 2px;" title="Locate current page in menu"/>'
  },

  LOOKNFEEL: {
    FIRST_HOVER_DROP_TOUT:   1000,
    SWITCH_HOVER_DROP_TOUT:  250,
    SLIDE_OPEN:              false,
    FIRST_APPEAR_SPEED:      10,
    SUBSEQUENT_APPEAR_SPEED: 2
  }
}


SIM_ENUM = {
  MENU_GUI_ELEMENT:          1,
  MENU_STRUCT:               2,
  MENU_CHILD:                0
}




function sim_getStyle(element, name)
{
  if(element.currentStyle!=null) // Typically IE
    return(element.currentStyle ? element.currentStyle[name] : null);
  else // Typically W3C compliant
    return(document.defaultView.getComputedStyle(element,'').getPropertyValue("name"));
}


function sim_getScroller(element)
{
  var scroller;
  for(scroller=element; scroller!=null && sim_getStyle(scroller, "overflow")=="visible"; scroller=scroller.offsetParent);
  return(scroller);
}

function sim_getScrollPosition(element)
{
  var scroller;
  var offset=0;

  for(scroller=element; scroller!=null && sim_getStyle(scroller, "overflow")=="visible"; scroller=scroller.offsetParent)
    offset+=scroller.offsetTop; 

  if(scroller==null)
    return(0);
  else if(offset<scroller.scrollTop)
    return(offset - scroller.scrollTop);
  else if(offset + element.offsetHeight>scroller.offsetHeight + scroller.scrollTop)
    return(offset + element.offsetHeight - (scroller.offsetHeight + scroller.scrollTop));
  else
    return(0);
}



/*
 * x()
 *   x
 *
 * In:
 *   x
 *
 * Returns
 *   x
 */

function sim_getServerURL()
{
  return(window.location.href.replace(/([^:]*):\/\/([^\/]*).*/, '$1://$2'));
}




/*
 * x()
 *   x
 *
 * In:
 *   x
 *
 * Returns
 *   x
 */

function sim_initializeMenuTable(menuRoot)
{
  if(!menuRoot)
    return(null);
  else if(menuRoot.sim_initialized)
    return(menuRoot);
  menuRoot.sim_initialized=true;

  for(var i=0; i<menuRoot.length; i+=2)
  {
    if(menuRoot[i].charAt && menuRoot[i].charAt(0)=='@')
      menuRoot=menuRoot.slice(0, i).concat(eval('window.' + menuRoot[i].substring(1)), menuRoot.slice(i + 1));

    if(i>menuRoot.length-1 || menuRoot[i+1]==null)
      continue;

    if(menuRoot[i+1].charAt && menuRoot[i+1].charAt(0)=='@')
      menuRoot[i+1]=eval('window.' + menuRoot[i+1].substring(1));

    if(sim_isTreeNode(menuRoot[i+1]))
      menuRoot[i+1]=sim_initializeMenuTable(menuRoot[i+1]);
    else if(menuRoot[i+1])
      menuRoot[i+1]=menuRoot[i+1].replace(/index\.html$/i, '');
  }
  return(menuRoot);
}


function sim_getMenuRoot(scope)
{
  var zone = scope == null ? sip_getCurrentZone() : scope;
  zone = zone ? '_' + zone : '';
  var root = eval('window.menuTable' + zone);
  if(!root)
    root=window.menuTable;
  sim_initializeMenuTable(root);
  return(root);
}


/*
 * sim_formatLabel()
 *   Formats a menu lablel for presentation.
 *
 * In:
 *  text:   
 *  format: 'formatted': Return text with the access key character underlined
 *          'key':       Return the acces key character
 *          'plaintext': Return text without any formatting
 */

function sim_formatLabel(text, format)
{
  var reK=/([^#~]*)\~?([^#])([^#]*)#{0,1}(.*)/i;
  switch(format)
  {
    case 'formatted':
      if(text.indexOf('~')!=-1)
        text=text.replace(reK, '$1<span class="accesskey">$2</span>$3');
      else
        text=text.replace(reK, '$1$2');
      break;
    case 'key':
      if(text.indexOf('~')!=-1)
        text=text.replace(reK, '$2');
      else
        text=null;
      break;
    case 'class':
      if(text.indexOf('#')!=-1)
        text=text.replace(reK, '$4');
      else
        text=null;
      break;
    case 'plaintext':
    default:
      text=text.replace(reK, '$1$2$3');
      break;
  }
  return(text);
}



function sim_init()
{
  if(document.getElementById==null)
    return(false);

  if(window.sim_kilroy)
    return(true);

  // Get hold of the menubar:
  var menuBar=document.getElementById(SIM_CONST.ID.TOC_CONTAINER);
  if(!menuBar)
    return(false);

  if(!sim_populateMenuBar(menuBar))
    return(false);

  if(window.document.attachEvent!=null) // Typically IE
    window.document.attachEvent('onkeydown', sim_key);
  else // Typically W3C compliant
    window.document.addEventListener('keydown', sim_key, false);

  sim_populateNavigationPath();

  window.sim_isFocused=null;
  window.sim_kilroy=true;

  return(true);
}



function sim_populateMenuBar(menuBar)
{
  var menuRoot=sim_getMenuRoot();
  if(!menuRoot)
    return(false);

  // Clear old menubar content:
  menuBar.innerHTML='';

  
  menuRoot.menuElements=new Array();

  /*
   * Insert new menu before the reference element, or at the end of the 
   * menubar (referenceElement==null):
   */
  var menuBaseElem        = menuBar;
  var templateRepeatIndex = 0;

  // Loop through the menu root items, and add one extra item for creating the "where am i"-entry:
  for(var mi=0; mi<=menuRoot.length; mi+=2)
  {
    var menuText, menuItem;
    if(mi<menuRoot.length)
    {
      menuText=menuRoot[mi];
      menuItem=menuRoot[mi+1];
    }
    else
    {
      menuText=SIM_CONST.TEXT.LOCATE_CURRENT;
      menuItem=sim_showWhere;
    }

    if(menuText=='' || menuText.charAt(0)<'0')
      continue;
    
    var menuParentElem = menuBaseElem;
    var menuElem;

    for(var ti=templateRepeatIndex; ti<SIM_CONST.CLASSES.MENU_TEMPLATE.length; ti++)
    {
      tagTemplate = SIM_CONST.CLASSES.MENU_TEMPLATE[ti];

      menuElem = document.createElement(tagTemplate.tagName);
      for(var attribute in tagTemplate.attributes)
      {
        menuElem[attribute]=tagTemplate.attributes[attribute];
      }
      
      if(tagTemplate.repeated && templateRepeatIndex==0)
      {
        menuBaseElem = menuParentElem;
        templateRepeatIndex = ti;
      }
      menuParentElem.appendChild(menuElem);
      menuParentElem = menuElem;
    }

    menuElem.innerHTML=sim_formatLabel(menuText, 'formatted');
    menuElem.sim_menu=menuRoot;
    menuElem.sim_menuItem=menuItem;
    menuRoot.menuElements[mi/2]=menuElem;

    if(sim_isTreeNode(menuItem))
      menuElem.href="#";
    else if(typeof(menuItem)=="function")
      menuElem.href="#";
    else
      menuElem.href=menuItem;

    var key=sim_formatLabel(menuText, 'key');
    if(key)
      menuElem.accessKey=key;
    else
      menuElem.removeAttribute('accessKey');

    var className=sim_formatLabel(menuText, 'class');
    if(className)
      menuElem.className += ' ' + className;

    sim_assignElementEvents(menuElem);

  }
  /* 
   * Allow proper rendering in IE6 by adding a line-break (the menu height 
   * will otherwise collapse with some stylesheets applied) 
   */
  var newline = document.createTextNode("\n");
  menuBaseElem.appendChild(newline);

  return(true);
}


function sim_populateNavigationPath()
{
  var pathContaner = document.getElementById(SIM_CONST.ID.PATH_CONTAINER);
  if(!pathContaner)
    return;

  var current      = sip_getCurrentPath();
  var entryPath    = sim_getMenuPath(current, SIM_ENUM.MENU_STRUCT);

  // Skip displaying the path if 'current' is the site root or thers is no 
  // known navigation path:
  if(entryPath==null || current=='/' || sip_pathIsDynamic(current))
    return;

  var rootOpen     = '<div class="' + SIM_CONST.CLASSES.PATH_ROOT + '">';
  var folderOpen   = '<div class="' + SIM_CONST.CLASSES.PATH_FOLDER + '">';
  var curFolderOpen= '<div class="' + SIM_CONST.CLASSES.PATH_CURRENT_FOLDER + '">';
  var docOpen      = '<div class="' + SIM_CONST.CLASSES.PATH_CURRENT_DOCUMENT + '">';
  var folderClose  = '</div>';
  var folderCloses = 1;

  var rootPath     = sip_getCurrentZone();
  var rootLabel    = '';
  
  if(rootPath)
  {
    rootLabel = rootPath.charAt(0).toUpperCase() + rootPath.substring(1) + ' ';
    rootPath = '/' + rootPath + '/';
  }
  else
    rootPath = '/';

  if(rootPath == entryPath[entryPath.length-1].menu[entryPath[entryPath.length-1].index+1])
    return;

  rootLabel += 'Home';

  var html         = rootOpen + '<a title="Home page" href="' + rootPath + '">' + rootLabel + '</a>';
  var done         = false;

  for(var i=0; !done && i<entryPath.length; i++)
  {
    var nodeOpen  = '';
    var href      = '';
    var clickEvt  = '';
    var nodeLabel = null;
    var titlePrfx = 'Go to parent level: ';

    // if(sim_isTreeNode(entryPath[i].menu[entryPath[i].index+1]))
    if(i<entryPath.length-1) // == A tree node
    {
      /*
       * If the first child node is an overview node, use the label from its parent (this one) but the URL from the child. 
       * If the first child node is not an verview node, just ignore this entry in the path as it has no associated HTML document.
       */
      if(sim_isOverviewNode(entryPath[i].menu[entryPath[i].index+1], 0))
      {
        nodeLabel = entryPath[i].menu[entryPath[i].index];
        
        if((i==entryPath.length-2) && entryPath[i+1].menu[1] == current)
        {
          titlePrfx = 'Current page: ';
          nodeOpen  += curFolderOpen;
          //clickEvt = ' onclick="window.sim_showWhere(); return false"';
          //href=entryPath[i+1].menu[1];
          done=true;
        }
        else
        {
          nodeOpen += folderOpen;
          href=entryPath[i].menu[entryPath[i].index+1][1];
        }
      }
    }
    else 
    {
      /*
       * Last node in path, might point to the current page, or a virtual parent for the current page:
       */
      nodeLabel = entryPath[i].menu[entryPath[i].index];
      if(entryPath[i].menu[entryPath[i].index+1] == current)
      {
        titlePrfx = 'Current page: ';
        nodeOpen  += curFolderOpen;
        //clickEvt  = ' onclick="window.sim_showWhere(); return false"';
      }
      else
      {
        nodeOpen  = docOpen;
        href      = entryPath[i].menu[entryPath[i].index+1];
      }
    }


    if(nodeLabel!=null)
    {
      var caption = sim_formatLabel(nodeLabel, 'plaintext');
      var title   = titlePrfx + caption;
      html += nodeOpen;
      if(href)
        html += '<a title="' + title + '" href="' + href + '"' + clickEvt + '>';
      html += caption;
      if(href)
        html += '</a>'; 
      folderCloses++;
    }
  }

  for(var i=0; i<folderCloses; i++)
    html += folderClose;

  pathContaner.style.display = 'block';
  pathContaner.innerHTML='<div id="navigationpath"><h2>Page location:</h2>' + html + '</div>';
}




function sim_assignElementEvents(element)
{
  element.onmouseover=sim_onmouseover;
  element.onmouseout=sim_onmouseout;
  element.onfocus=sim_onfocus;
  element.onclick=sim_onclick;
}


function sim_getAttachedMenu(element)
{
  if(element)
    return(element.sim_menuItem);
  else
    return(null);
}


function sim_getAttachedParentMenu(element)
{
  return(element.sim_menu);
}

function sim_isTreeNode(menuNode)
{
  return(menuNode!=null && menuNode.sort!=null);
}


function sim_isOverviewNode(menu, index)
{
  var label=menu[index - index & 0x01];
  var url  =menu[index | 0x01];
  return((label.toLowerCase().indexOf('overview')!=-1) || (!sim_isTreeNode(url) && url.match(/(\/$)|(\/index\.[^\.]*$)/)));
}


function sim_showMenu(menuRoot, anchorElem, isFocused)
{
  var div;
  if(menuRoot.sim_gui)
  {
    div = menuRoot.sim_gui;
    div.style.visibility = 'hidden';
  }
  else
  {
    var menuPath=sim_getMenuPath(sip_getCurrentPath(), SIM_ENUM.MENU_CHILD);

    div = menuRoot.sim_gui = document.createElement('div');
    div.style.visibility = 'hidden';
    menuRoot.sim_anchor=anchorElem;
    div.className=SIM_CONST.CLASSES.MENU_CONTAINER;
    document.body.appendChild(div);

    var table = document.createElement("table");
    table.border=0;
    table.cellSpacing=0;
    table.cellPadding=0;
    var tbody = document.createElement("tbody");
    table.appendChild(tbody);
    div.appendChild(table);
    menuRoot.menuElements=new Array();

    for(var i=0; i<menuRoot.length; i+=2)
    {
      var tr = document.createElement("tr");
      tbody.appendChild(tr);

      var td = document.createElement("td");
      tr.appendChild(td);
      
      if(!menuRoot[i+1])
      {
        if(menuRoot[i].indexOf('<')==-1)
          td.className = SIM_CONST.CLASSES.MENU_TITLE;
        else
          td.className=SIM_CONST.CLASSES.MENU_CANVAS;
        td.innerHTML=sim_formatLabel(menuRoot[i], 'formatted');
      }
      else
      {      
        var span = document.createElement("a");
        td.appendChild(span);

        span.innerHTML=sim_formatLabel(menuRoot[i], 'formatted');

        if(sip_contains(menuPath, menuRoot[i+1]))
          td.className=SIM_CONST.CLASSES.MENU_ENTRY_CURRENT;
        else
          td.className=SIM_CONST.CLASSES.MENU_ENTRY;
        td.sim_menu=menuRoot;
        td.sim_menuItem=menuRoot[i+1];
        menuRoot.menuElements[i/2]=td;
        sim_assignElementEvents(td);

        if(sim_isTreeNode(menuRoot[i+1]))
        {
          span.href="#";
          td.className+=" simfolder";
        }
        else
          span.href=menuRoot[i+1];
      }
    }
  }

  var xOfs=0;
  var yOfs=0;
  if(sim_isTopLevelMenu(anchorElem))
    yOfs=sip_getDimension(anchorElem, true) + 2;
  else
    xOfs=sip_getDimension(anchorElem, false);

//alert(sip_getPosition(anchorElem, true))

  div.style.left=sip_getPosition(anchorElem, false)+xOfs+'px';
  div.style.top =sip_getPosition(anchorElem, true)+yOfs+'px';

  div.style.display="block";

  if(SIM_CONST.LOOKNFEEL.SLIDE_OPEN)
    sim_slideAppear(div, isFocused);
  //div.style.visibility = 'visible';
  sip_showElement(div);

  clearTimeout(anchorElem.sim_timer);
  sim_hidePopup();
}



function sim_slideAppear(elem, isFocused)
{
  var speed = isFocused ? SIM_CONST.LOOKNFEEL.SUBSEQUENT_APPEAR_SPEED : SIM_CONST.LOOKNFEEL.FIRST_APPEAR_SPEED;
  var incrX = elem.offsetWidth / speed;
  var incrY = elem.offsetHeight / speed;
  if(elem.sim_slidex==null)
  {
    elem.sim_slidex=incrX;
    elem.sim_slidey=incrY;
  }
  else
  {
    elem.sim_slidex+=incrX;
    elem.sim_slidey+=incrY;
  }

  elem.style.clip='rect(0px ' + elem.sim_slidex + 'px ' + elem.sim_slidey + 'px 0px)';

  if((elem.sim_slidex >= elem.offsetWidth) && (elem.sim_slidey >= elem.offsetHeight))
    elem.sim_slidex = elem.sim_slidetimer = null;
  else
    elem.sim_slidetimer=setTimeout('if(window.sip_setElementId!=null)window.sim_slideAppear(document.getElementById("' + window.sip_setElementId(elem) + '"), true)', 10);
}





function sim_highlight(element)
{
  if(element)
  {
    if(element.si_origClassName==null)
      element.si_origClassName=element.className;
    
    if(element.className.indexOf(SIM_CONST.CLASSES.MENU_ENTRY_HOVER)==-1)
      element.className += ' ' + SIM_CONST.CLASSES.MENU_ENTRY_HOVER;

    var scrolling=sim_getScrollPosition(element);
    if(scrolling!=0)
      sim_getScroller(element).scrollTop+=scrolling;
  }
}


function sim_unhighlight(element)
{
  if(element)
  {
    if(element.si_origClassName!=null)
      element.className=element.si_origClassName;
  }
}



function sim_hideAll()
{
  sim_blur(window.sim_isFocused);
  sim_hide();
}


function sim_hide(menuRoot)
{
  if(!menuRoot)
  { 
    menuRoot=sim_getMenuRoot();
    window.sim_isFocused=null;
  }
  for(var i=0; menuRoot!=null && i<menuRoot.length; i+=2)
  {
    if(sim_isTreeNode(menuRoot[i+1]))
    {
      if(menuRoot[i+1].sim_gui)
        menuRoot[i+1].sim_gui.style.display="none";
      sim_hide(menuRoot[i+1]);
    }
  }
}


/* Set status message:
 *   Prefer menu node title or first child title, otherwise menu node text:
 */

function sim_setStatusBar(element)
{
  var menu=sim_getAttachedMenu(element);
  var statusTxt='';

  if(element.title)
    statusTxt=element.title;
  else if(element.firstChild.title)
    statusTxt=element.firstChild.title;
  else
    statusTxt=element.innerText;

  if(sim_isTreeNode(menu))
  {
    // Tree nodes are displayed with just the text + '...':
    statusTxt += '...';
  }
  else if((menu!=null) && (typeof(menu)!="function") && (menu.indexOf('javascript:')!=0))
  {
    // Non-script nodes (links) are displayed with the URL first:
    statusTxt=sip_stripUrl(menu) + '    (' + statusTxt + ')';
  }
  
  // Yeild to override browser setting the status message (mainly for Opera):
  setTimeout('window.status="' + statusTxt + '"', 1);
}


function sim_focus(element, setCaret, delay)
{
  if(!element)
    return;

  if(window.sim_isFocused==element)
  {
    sim_setStatusBar(element);
    return;
  }

  if(delay!=null)
  {
    sim_setStatusBar(element);
    element.sim_timer=setTimeout('if(window.sip_setElementId!=null)window.sim_focus(document.getElementById("' + window.sip_setElementId(element) + '"))', delay);
    return;
  }

  var menu=sim_getAttachedMenu(element);
  var parent=sim_getAttachedParentMenu(element);
  if(parent!=null)
    sim_hide(parent);

  if(!window.sim_isFocused)
  {
    if(window.document.attachEvent!=null) // Typically IE
    {
      window.document.attachEvent('onmousedown', sim_mouseDown);
    }
    else // Typically W3C compliant
    {
      window.document.addEventListener('mousedown', sim_mouseDown, false);
    }
  }
  sim_blur(window.sim_isFocused);


  sim_highlight(element);

  var link=element;
  if(link.tagName!='A')
    link=element.getElementsByTagName('A')[0];
  if(link && setCaret)
  {
    try
    {
      link.focus();
    }
    catch(e){}
  }


  // Show sub-menu if this is a tree-node:
  if(sim_isTreeNode(menu))
  {
    // In Opera and Safari Flash obscures layers, so we need to kill Flash controls before showing the menus:
    if((DETECT.is_opera || DETECT.is_safari) && !window.sim_hasKilledSwfs)
    {
      sip_killSwfControls();
      window.sim_hasKilledSwfs=true;
    }
    sim_showMenu(menu, element, window.sim_isFocused==null);
  }

  sim_setStatusBar(element);

  window.sim_isFocused=element;
}


function sim_blur(element)
{
  if(element)
  {
    sim_unhighlight(element);
    if(element.sim_timer)
      clearTimeout(element.sim_timer);
  }
  window.status='';
}



function sim_touch(element)
{
  var menu=sim_getAttachedMenu(element);
  if(menu!=null)
  {
    if(sim_isTreeNode(menu))
    {
      sim_focus(element, true);
      return(false);
    }
    else if(typeof(menu)=="function")
    {
      menu();
      return(false);
    }
    else
      return(true);
  }
  else
    return(false);
}


function _sim_menuPathSwitch(menuRoot, index, dataSelector)
{
  switch(dataSelector)
  {
    case SIM_ENUM.MENU_GUI_ELEMENT:
      return(menuRoot.menuElements ? menuRoot.menuElements[index/2] : null);
    case SIM_ENUM.MENU_STRUCT:
      return({menu: menuRoot, index: index});
    default: // SIM_ENUM.MENU_CHILD
      return(menuRoot[index+1]);
  }
}


function _sim_getMenuPath(location, dataSelector, menuRoot)
{
  var found=null;
  for(var i=0; found==null && i<menuRoot.length; i+=2)
  {
    if(menuRoot[i+1]==location)
    {
      found=new Array(1);
      found[0]=_sim_menuPathSwitch(menuRoot, i, dataSelector);
    }
    else if(sim_isTreeNode(menuRoot[i+1]))
    {
      found=_sim_getMenuPath(location, dataSelector, menuRoot[i+1]);
      if(found!=null)
        found.unshift(_sim_menuPathSwitch(menuRoot, i, dataSelector));
    }
  }
  return(found);
}


function sim_getParent(location)
{
  while(location.charAt(location.length-1)=='/')
    location=location.substring(0, location.length-1);
  location=location.replace(/\/[^\/]*$/, '/');
  return(location);
}


function sim_getMenuPath(location, dataSelector, strictMatch)
{
  if(Array.prototype.unshift==null)
    return;

  var menuRoot=sim_getMenuRoot();
  var found   =null;

  for(;;)
  {
    found=_sim_getMenuPath(location, dataSelector, menuRoot);
    if((found==null || found.length==0) && !strictMatch && location && location.replace && location!='/')
      location=sim_getParent(location);
    else
      break;
  }

  return(found);
}



function sim_showPopup(msg, actions)
{
  var popup = document.getElementById(SIM_CONST.ID.MENU_POPUP);
  if(!popup)
  {
    popup=document.createElement('div');
    popup.id=SIM_CONST.ID.MENU_POPUP;
    popup.className=SIM_CONST.CLASSES.MENU_POPUP;
    document.body.appendChild(popup);
  }
  popup.style.display="block";
  var buttons='<div style="position: absolute; text-align: right; width: 100%; bottom: 0px; margin: 0px 12px 10px 0px;">';
  if(actions)
  {
    actions=actions.split('+');
    for(var i=0; i<actions.length; i++)
    {
      var name  =actions[i].split(':')[0];
      var action=actions[i].split(':')[1];

      if(!name)
        name='Ok';
      if(!action)
        action='sim_hidePopup()';
      if(action.indexOf('(')==-1)
        action='window.location=\'' + action + '\'';
      buttons += '<input type="button" value="' + name + '" onclick="' + action + '"/>';
    }
  }
  else
    buttons += '<input type="button" value="Close" onclick="sim_hidePopup()"/>';
  buttons += '</div>';
  popup.innerHTML=msg + buttons;
}


function sim_hidePopup()
{
  var popup = document.getElementById(SIM_CONST.ID.MENU_POPUP);
  if(popup )
    popup.style.display="none";
}


function sim_showWhere()
{
  var entryPath=sim_getMenuPath(sip_getCurrentPath(), SIM_ENUM.MENU_GUI_ELEMENT);

  if(!entryPath)
  {
    sim_showPopup("<h1>Location unknown</h1><p>The current page is not directly available from the menu.</p>");
    return(false);
  }

  for(var i=0; i<entryPath.length; i++)
  {
    if(entryPath[i]!=null)
      sim_focus(entryPath[i], false);
    else
    {
      setTimeout('if(window.sim_showWhere!=null)sim_showWhere()', 10);
      break;
    }
  }
  return(false);
}


function sim_isTopLevelMenu(anchorElem)
{
  return(anchorElem.tagName=='A');
}


function sim_onmouseover()
{
  /* [c1] */
  if(window.sim_focus==null)
    return;

  if(window.sim_highlight!=null)
    sim_highlight(this);

  var timeout;
  if(window.sim_isFocused)
  {
    if(sim_isTopLevelMenu(this))
      // "No" timout when focused and dropping menus from top:
      timeout=1;
    else
      // Short timout when focused and switching menu:
      timeout=250;
  }
  else
    // Long timout when not focused:
    timeout=1000;
  window.sim_focus(this, null, timeout);
  return(true);
}


function sim_onmouseout()
{
  if(window.sim_blur!=null)
    sim_blur(this);
  return(false);
}

function sim_onfocus()
{
  if(window.sim_focus!=null)
    window.sim_focus(this);
  return(false);
}

function sim_onclick()
{
  var rc=false;
  if(window.sim_touch!=null)
    rc=sim_touch(this);
  if(this.blur!=null)
    this.blur();
  return(rc);
}




function sim_getMenuElement(element)
{
  while(element!=null 
        && 
        (element.className==null 
         || 
         (element.className.indexOf(SIM_CONST.CLASSES.MENU_ENTRY)==-1 && element.className.indexOf(SIM_CONST.CLASSES.MENU_CONTAINER)==-1)))
  {
    element=element.parentNode;
  }
  if(element!=null && element.className!=null)
    return(element);
  else
    return(null);
}


function sim_mouseDown(event)
{
  var element;
  if(window.event!=null) // Typically IE
  {
    event=window.event;
    element=sim_getMenuElement(event.srcElement);
  }
  else // Typically W3C compliant
    element=sim_getMenuElement(event.target);

  if(element)
    sim_touch(element);
  else
    sim_hideAll();
}


/*
 *
 * Returns:
 *  -1: Element not in menu
 *   0: Top level entry (horizontal menu bar)
 *   1: First drop down level (vertical menu bar)
 *   2: ...
 */

function sim_getElementMenuLevel(element)
{
  if(element==null)
    return(-1);

  var parent = sim_getAttachedParentMenu(element);
  var path   = sim_getMenuPath(parent, SIM_ENUM.MENU_CHILD);
  return(path ? path.length : 0);
}


function sim_getNextSiblingElement(element)
{
  for(element=element.nextSibling; element!=null && element.tagName==null; element=element.nextSibling);
  return(element);
}

function sim_getPreviousSiblingElement(element)
{
  for(element=element.previousSibling; element!=null && element.tagName==null; element=element.previousSibling);
  return(element);
}

function getRelatedElement(element, direction)
{
  if(!element)
    return(null);

  var related = null;

  switch(direction)
  {
    case 'next':
      if(element.tagName=='TD' && element.parentNode.nextSibling!=null)
        related=element.parentNode.nextSibling.getElementsByTagName('TD')[0];
      else
        related=sim_getNextSiblingElement(element);
      break;
    case 'down':
      var menu = sim_getAttachedMenu(element);
      if(menu && menu.sim_gui)
        related=menu.sim_gui.getElementsByTagName('TD')[0];
      break;
    case 'previous':
      if(element.tagName=='TD' && element.parentNode.previousSibling!=null)
        related=element.parentNode.previousSibling.getElementsByTagName('TD')[0];
      else
        related=sim_getPreviousSiblingElement(element);
      break;
    case 'up':
      var parent = sim_getAttachedParentMenu(element);
      if(parent)
        related=parent.sim_anchor;
      break;
  }
  return(related);
}


function sim_key(event)
{
  if(window.sim_isFocused!=null)
  {
    if(window.event!=null) // Typically IE
      event=window.event;

    var level=sim_getElementMenuLevel(window.sim_isFocused);
    switch(event.keyCode)
    {
      case 27: // ESC
        sim_hideAll();
        break;
      case 13: // Return
      case 32: // Space
        if(window.sim_isFocused)
        {
          return(sim_touch(window.sim_isFocused));
        }
        break;

      case 38: // Up
        var related=getRelatedElement(window.sim_isFocused, 'previous');
        if(related)
          sim_focus(related, true);
        else
          sim_focus(getRelatedElement(window.sim_isFocused, 'up'), true);
        break;
      case 40: // Down
        if(level==0)
          sim_focus(getRelatedElement(window.sim_isFocused, 'down'), true);
        else
          sim_focus(getRelatedElement(window.sim_isFocused, 'next'), true);
        break;
      case 39: // Right
        var related;
        if(level==0)
          related=getRelatedElement(window.sim_isFocused, 'next');
        else
          related=getRelatedElement(window.sim_isFocused, 'down');
        if(related)
        {
          sim_focus(related, true);
          break;
        }
        related=getRelatedElement(window.sim_isFocused, 'next');
        if(related)
        {
          sim_focus(related, true);
          break;
        }
        
        for(related=getRelatedElement(window.sim_isFocused, 'up'); sim_getElementMenuLevel(related)>0 && !getRelatedElement(related, 'next'); related=getRelatedElement(related, 'up'));
        sim_focus(getRelatedElement(related, 'next'), true);
        break;
      case 37: // Left
        var related;
        if(level==0)
          related=getRelatedElement(window.sim_isFocused, 'previous');
        else
          related=getRelatedElement(window.sim_isFocused, 'up');
        sim_focus(related, true);
        break;
      default:
        return(true);
    }
    if(event.preventDefault!=null && event.stopPropagation!=null) // Typically W3C compliant
    {
      event.preventDefault();
      event.stopPropagation();
    }
    return(false);
  }
  else
    return(true);
}


function sim_siteMap()
{
  sim_hideAll();

  if(!window.sim_siteMapWindow || window.sim_siteMapWindow.closed)
    window.sim_siteMapWindow=window.open('/common/scripts/sitemap.html', 
                                         'simSiteMap',
                                         'channelmode=no,'
                                       + 'directories=no,'
                                       + 'fullscreen=no,'
                                       + 'location=no,'
                                       + 'menubar=no,'
                                       + 'resizable=yes,'
                                       + 'scrollbars=no,'
                                       + 'status=no,'
                                       + 'titlebar=yes,'
                                       + 'toolbar=no,'
                                       + 'left=64,'
                                       + 'top=32,'
                                       + 'width=' + Math.min(256, window.screen.availWidth) + ','
                                       + 'height=' + (window.screen.availHeight - 128));
  if(window.sim_siteMapWindow)
    window.sim_siteMapWindow.focus();
  else
    sim_showPopup("<h1>Sitemap window was blocked</h1><p>Your current browser settings prevents the sitmap window to display.</p><p>To use the sitemap, enable the blocked popup window by clicking the yellow blocking bar above and select a suitable option from the menu.</p>", "Close+Show in current window:/common/scripts/sitemap.html+Why?:/helps/sitemap.html");
}


function sim_confirmSitmap(mapWindow)
{
  sim_hidePopup();
  if(window.sim_siteMapWindow!=null && !window.sim_siteMapWindow.closed && window.sim_siteMapWindow!=mapWindow)
    window.sim_siteMapWindow.close();
  window.sim_siteMapWindow=mapWindow;
}



/*
 * PUBLIC:
 */


/*
 * sim_findMenu()
 *   Finds a submenu (or link) for the given pattern. The pattern may be any 
 *   text string found in the label of a menu item, to find using a class/id, 
 *   prepend the pattern with a hash-mark (#).
 *
 * In:
 *   - pattern:   pattern to search for
 *   - _menuRoot: set to null to search the whole menu tree
 * 
 * Returns: 
 *   Sub-menu array or link URL
 */


function sim_findMenu(pattern, dataSelector, _menuRoot)
{
  if(!_menuRoot)
    _menuRoot=sim_getMenuRoot();

  if(!_menuRoot)
    return(null);

  for(var i=0; i<_menuRoot.length; i+=2)
  {
    //if(_menuRoot[i].indexOf(pattern)!=-1)
    if(_menuRoot[i] == pattern)
      return(_sim_menuPathSwitch(_menuRoot, i, dataSelector));
    //else if(!sim_isTreeNode(_menuRoot[i+1]) && _menuRoot[i+1].indexOf(pattern)!=-1)
    else if(!sim_isTreeNode(_menuRoot[i+1]) && _menuRoot[i+1] == pattern)
      return(_sim_menuPathSwitch(_menuRoot, i, dataSelector));
  }
  for(var i=1; i<_menuRoot.length; i+=2)
  {
    if(sim_isTreeNode(_menuRoot[i]))
    {
      var found = sim_findMenu(pattern, dataSelector, _menuRoot[i]);
      if(found)
        return(found);
    }
  }
  return(null);
}



/*
 * sim_popupMenu()
 *   Show a sub-menu at the given element. Typically this function is used to 
 *   call up (a specific part of) the menu system upon clicking an HTML 
 *   element. Assign the onClick hanlder to this function, the menu will be 
 *   aligned to the HTML element passed. 
 *
 *   The menu pattern may be any text string found in the label of a menu item 
 *   that can be used to identify the corresponding sub-menu. To identify 
 *   using a class/id, prepend the pattern with a hash-mark (#).
 *
 *   - element:     element to align to
 *   - menuPattern: pattern to identify the menu, if null the menu root 
 *                  will be used.
 *
 */

function sim_popupMenu(element, menuPattern)
{
  if(!element || window.sim_isFocused==element)
    return(false);

  var menu;
  if(menuPattern)
    menu = sim_findMenu(menuPattern, SIM_ENUM.MENU_CHILD);
  if(!menu)
    menu = sim_getMenuRoot();

  sim_hideAll();

  if(!window.sim_isFocused)
  {
    if(window.document.attachEvent!=null) // Typically IE
      window.document.attachEvent('onmousedown', sim_mouseDown);
    else // Typically W3C compliant
      window.document.addEventListener('mousedown', sim_mouseDown, false);
  }
  sim_blur(window.sim_isFocused);

  if(sim_isTreeNode(menu))
    sim_showMenu(menu, element, window.sim_isFocused==null);

  window.sim_isFocused=element;

  return(false);
}

// EoF

