function whMenubar(settings)
{
  this.hoverclass = settings.hoverclass;
  this.menubarname = 'm' + whMenubar.menubarid++;
  this.menubarpulldirection = settings.menubarpulldirection;
  this.debug = settings.debug && typeof console != 'undefined';
  this.openmenus = [];

  whMenubar.menubars[this.menubarname] = this;

  /* Add the handlers */
  this.SetupHandlers(settings.menubarcontainer ? settings.menubarcontainer : document
                    ,settings.menubarclass
                    );
}
whMenubar.menubarid = 1;
whMenubar.menubars = [];
whMenubar.prototype.GetDropdown = function whMenubar_GetDropdown(item)
{
  var dropdown = document.getElementById('expand_' + item.id);
  if(this.debug) console.log('get dropdown for ',this, ' id: ',this.id,' result ',dropdown);
  return dropdown;
}
whMenubar.prototype.SetupHandlers = function whMenubar_SetupHandlers(baseelement, findclass)
{
  this.menuitems = whMenubar_GetElementsByClass(baseelement, findclass, "*");

  for (var i = 0; i < this.menuitems.length; ++i)
  {
    var item = this.menuitems[i];
    item.menubarname = this.menubarname;

    item.closeHandler=resetItem(item);
    item.onclick=whMenubar_Click;
    item.onmousedown=function(e)
    {
      this.onclick();
      if (document.attachEvent) //IE
        window.event.cancelBubble = true;
      else
        e.stopPropagation();
    }
//    item.onmouseout=whMenubar_MouseOut;
    item.onmouseover=whMenubar_MouseOver;
  }
}
/*
function whMenubar_MouseOut(e)
{
  var menubar = whMenubar.menubars[this.menubarname];
  if(menubar.debug) console.log('entering mouseout handler ',this, ' id: ',this.id);

  while(menubar.IsItemOpen(this))
    menubar.CloseSubmenu();
}
*/
function whMenubar_Click(e)
{
  var menubar = whMenubar.menubars[this.menubarname];
  if(menubar.debug) console.log('entering onclick handler ',this, ' id: ',this.id);

  if(menubar.hoverclass)
  {
    if(menubar.debug) console.log('set hover class: ', menubar.hoverclass);
    whMenubar_SetObjectClass(this, menubar.hoverclass, true);
  }

  var dropdown = menubar.GetDropdown(this);
  if(dropdown && !menubar.IsItemOpen(this))
  {
    var pos=whMenubar_GetBodyPos(this);
    if(menubar.menubarpulldirection == 'right' || menubar.openmenus.length>0)
    {
      pos.left += this.offsetWidth;
    }
    else //default is down
    {
      pos.top += this.offsetHeight;
    }

    openSubmenu(dropdown, pos.left, pos.top, this.closeHandler);
  }
  menubar.openmenus.push(this);
  if(this.nodeName.toUpperCase()=='A')
    return this.href != '' && this.href.split('#')[0] != location.href.split('#')[0];
  else
    return true;
}
whMenubar.prototype.IsItemOpen = function whMenubar_IsItemOpen(item)
{
  for(var i=0;i<this.openmenus.length;++i)
    if(this.openmenus[i] == item)
      return true;
  return false;
}
whMenubar.prototype.GetCurrentMenu = function whMenubar_GetCurrentMenu()
{
  if(this.openmenus.length)
    return this.openmenus[this.openmenus.length-1];
  else
    return null;
}
whMenubar.prototype.IsInsideCurrentMenu = function whMenubar_IsInsideCurrentMenu(item)
{
  var curmenu = this.GetCurrentMenu();
  if(!curmenu)
    return false;

  var curpulldown = this.GetDropdown(curmenu);
  return curpulldown && whMenubar_IsChildOf(curpulldown, item);
}
whMenubar.prototype.CloseSubmenu = function whMenubar_CloseSubmenu()
{
  var toclose = this.openmenus[this.openmenus.length-1];
  var pulldown = this.GetDropdown(toclose);
  if(pulldown)
    pulldown.style.display = 'none';

  this.openmenus.pop();
  /*

  if (submenu.style.display == "block")
  {
    submenu.style.display = "none";
    if (submenu.iframe != null)
      submenu.iframe.style.display = "none";

    if (submenu.wh_closeHandler != null)
    {
      submenu.wh_closeHandler();
    }
    //does this submenu have any submenu's of its own? If so, close them too
    if (submenu.overItem)
    {
      submenu.overItem.className = "webUI_dropdownmenuitem";
      if (submenu.overItem.submenu)
        whMenubar_closeSubmenu(submenu.overItem.submenu);
    }
    submenu.overItem = null;
  }*/
}

function whMenubar_IsChildOf(suspectedancestor, child)
{
  while(child)
  {
    child = child.parentNode;
    if(child == suspectedancestor)
      return true;
  }
  return false;
}
function whMenubar_MouseOver(e)
{
  var menubar = whMenubar.menubars[this.menubarname];

  if(menubar.hoverclass)
    whMenubar_SetObjectClass(this, menubar.hoverclass, true);

  if(menubar.GetCurrentMenu() == this)
    return; //over the same menu. ignore.

  /* this is only needed if clicking is not implied by hovering
  */

  //Is this menu item INSIDE the current menu? If not, find out if there is an open menu, NOT belonging to this item.
  while(!menubar.IsInsideCurrentMenu(this) && menubar.openmenus.length)
  {
    menubar.CloseSubmenu();
  }

  // open the menu beloging to the current item
  this.onclick();

  // reset all the appearance of all menu items (ADDME only needed when opening first level?!
  if(menubar.hoverclass)
    for (var i = 0; i < menubar.menuitems.length; i++)
      if(menubar.menuitems[i] != this)
        whMenubar_SetObjectClass(menubar.menuitems[i], menubar.hoverclass, false);
}

function whMenubar_GetElementsByClass(node,searchClass,tagName)
{
  var classElements = new Array();
  var els = node.getElementsByTagName(tagName); // use "*" for all elements
  var pattern = new RegExp("\\b"+searchClass+"\\b");

  for (var i = 0; i < els.length; ++i)
    if (pattern.test(els[i].className))
      classElements.push(els[i]);

  return classElements;
}
function whMenubar_SetObjectClass(obj, cssClass, adding)
{
  var cssClasses = obj.className.split(' ');
  if (cssClasses.length == 1 && cssClasses[0] == '')
    cssClasses = [];

  if (adding)
  {
    // If not added yet, add CSS class
    for (var i = 0; i < cssClasses.length; ++i)
      if (cssClasses[i] == cssClass)
        return; // already added, nothing to do
    cssClasses.push(cssClass);
  }
  else
  {
    // Remove CSS class
    var foundClass = false;
    for (var i = 0; i < cssClasses.length; ++i)
      if (cssClasses[i] == cssClass)
      {
        cssClasses.splice(i, 1);
        foundClass = true;
        break;
      }
    if (!foundClass)
      return; // class not found
  }
  obj.className = cssClasses.join(' ');
}

/** @short returns the absolute position an element in <body> would need to have the same position as the given element
    @param obj reference to element
    @return {left:X,top:Y}
*/
function whMenubar_GetBodyPos(obj)
{
  // getBoundingClientRect is supported by IE5+, FF3+, OP9.50+, SF4+
  if (obj.getBoundingClientRect)
  {
    var bounds = obj.getBoundingClientRect();

    var xscroll = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft;
    var yscroll = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop;

    return { left: bounds.left + xscroll - document.documentElement.clientLeft - document.body.clientLeft
           , top:  bounds.top + yscroll - document.documentElement.clientTop - document.body.clientTop
           };
  }


  // getBoxObjectFor works in FF2, deprecated in FF3/3.5, removed in FF3.6
  // Only use it for Firefox, since other Gecko based browsers may not correctly implement getBoxObjectFor
  var toddUserAgent = navigator.userAgent.toLowerCase();
  var toddUserAgentIsGecko = (toddUserAgent.indexOf('gecko') != -1); // Mozilla, Firefox or compatible, using Gecko engine
  var toddUserAgentIsFirefox = toddUserAgentIsGecko && (toddUserAgent.indexOf('firefox') != -1);
  if (toddUserAgentIsFirefox && document.getBoxObjectFor)
  {
    var box   = document.getBoxObjectFor(obj);
    var vpBox = document.getBoxObjectFor(document.documentElement);

    return { left: box.screenX - vpBox.screenX
           , top:  box.screenY - vpBox.screenY
           };
  }


  // the oldskool method of getting positions
  // Safari <4 & Opera 9.25 will use this method
  var elemx = obj.offsetLeft;
  var elemy = obj.offsetTop;
  var parent = obj.offsetParent;

  while (parent)
  {
    // add offset to content part of our offsetParent
    elemx += parent.offsetLeft;
    elemy += parent.offsetTop;

    // Quirks:
    // - Opera already adds clientTop/Left to offsetTop/Left
    // - Firefox <3 (Gecko <1.9) doesn't support clientTop/Left
    if (!toddClientTopIsAddedToOffsetTop && typeof parent.clientLeft != 'undefined')
    {
      // also add the edge size of the offsetParent
      elemx += parent.clientLeft;
      elemy += parent.clientTop;
    }

    // subtract the amount the offsetParent is scrolled, except if it's the scrollposition of the page
    if (parent != document.body && parent != document.documentElement)
    {
      elemx -= parent.scrollLeft;
      elemy -= parent.scrollTop;
    }

    parent = parent.offsetParent;
  }

  return { left: elemx
         , top:  elemy
         };
}


////////////////////////////////////////////////////////////// cut here /////////////////////////////////////////////
// (ie eliminate the code below)

function resetMenubars()
{
  menubars_openmenu = null;
  // get all dropdown menu bars
  var menuBars = getElementsByClass(document,"webUI_menubar","DIV");
  for (var i = 0; i < menuBars.length; i ++)
  {
    menuBars[i].items = getElementsByClass(menuBars[i],"webUI_menubaritem","A");
    for (var j = 0; j < menuBars[i].items.length; j++)
      menuBars[i].items[j].className = "webUI_menubaritem";
  }
  return menuBars;
}
function addDropdownMenuBarHandlers()
{
  // get all dropdown menu bars
  var menuBars = resetMenubars();

  for (var i = 0; i < menuBars.length; i ++)
  {
  }
}




function addDropdownMenuHandlers()
{
  // make sure the mousedown event destroys all menus
  if (document.attachEvent) //IE
    document.attachEvent('onmousedown',resetAllMenus);
  else // W3C
    document.addEventListener('mousedown',resetAllMenus,false);

  // get all dropdown menu's
  var dropDowns = getElementsByClass(document,"webUI_dropdownmenu","DIV");

  for (var i=0; i < dropDowns.length; i++)
  {
    // deal with the annoying fact that in IE form elements are displayed over our dropdowns, IE only
    if (document.attachEvent)
      dropDowns[i].iframe = insertIframe(dropDowns[i]);

    dropDowns[i].items = getElementsByClass(dropDowns[i],"webUI_dropdownmenuitem","DIV");
    dropDowns[i].overItem = null;
    dropDowns[i].outItem = null;

    dropDowns[i].onmouseover=function()
    {
      // the mouse has been over a menu item (the item's mouseover handler set this value)
      if (this.overItem)
      {
        // make the item look nice
        this.overItem.className = "webUI_dropdownmenuitem hover";

        // if there is a submenu, and the item is enabled, open the submenu
        if (this.overItem.submenu && this.overItem.isEnabled)
        {
          openSubmenu(this.overItem.submenu
                     ,getLeftPosition(this.overItem) + this.overItem.offsetWidth
                     ,getTopPosition(this.overItem)
                     ,null /* closehandler */
                     ,this.overItem);
        }

        // an 'old' item exists
        if (this.outItem && this.overItem != this.outItem)
        {
          // reset the look and feel of this 'old' item
          this.outItem.className = "webUI_dropdownmenuitem";

          // did the old item have a submenu? if so, close it
          if (this.outItem.submenu)
            whMenubar_closeSubmenu(this.outItem.submenu);
        }

        this.outItem  = this.overItem;
      }
    }

    for (var j=0; j < dropDowns[i].items.length; j++)
    {
      /* again an IE only hack: insert *something* in one A to hack around the
         bug that display: block isn't working properly */
      if (j==0 && document.attachEvent)
      {
        var tempdiv = document.createElement("div");
        tempdiv.style.width= "0px";
        tempdiv.style.height= "0px";
        tempdiv.style.position= "absolute";
        dropDowns[i].insertBefore(tempdiv, dropDowns[i].items[j]);
      }

      // get the submenu, if any
      var submenuname = "webUI_dropdownmenu" + dropDowns[i].items[j].id.substr("webUI_dropdownmenuitem".length,dropDowns[i].items[j].id.length);
      dropDowns[i].items[j].submenu = document.getElementById(submenuname);

      // find out if the item is enbaled (e.g. an <A> tag is available)
      dropDowns[i].items[j].isEnabled = dropDowns[i].items[j].getElementsByTagName("A").length > 0;

      dropDowns[i].items[j].onmouseover=function()
      {
        this.parentNode.overItem = this; // set the current menu item
        return false;
      }

      dropDowns[i].items[j].onmousedown=function(e)
      {
        /* nothing should happen when the mouse goes down on a menu item,
           We sould however prevent the mousedown event from bubbling up */
          if (document.attachEvent) //IE
            window.event.cancelBubble = true;
          else
            e.stopPropagation();
      }

      dropDowns[i].items[j].onclick=function(e)
      {
        // only close all menus if the menu item is enabled and does not have a submenu
        if (this.isEnabled && !this.submenu)
        {
          resetAllMenus(e);
        }

        // ignore the <a> if #
        return this.href!='#';
      }
    }
  }
}

function getViewPortDimensions()
{
  if (self.innerHeight) // all except Explorer
    return { width: self.innerWidth, height: self.innerHeight };

  if (document.documentElement && document.documentElement.clientHeight) // Explorer 6 Strict Mode
    return { width: document.documentElement.clientWidth, height: document.documentElement.clientHeight };

  return { width: document.body.clientWidth, height: document.body.clientHeight };
}

/* submenu = object reference to dropdown to opem
   leftPos and topPos= x and y position for the left top corner of the dropdown to open
   closeHandler = function to call when closing this dropdown
*/
function openSubmenu(submenu, leftPos, topPos, closeHandler, overItem)
{
  var dim = getViewPortDimensions();
  if(overItem && leftPos + submenu.offsetWidth > dim.width)
    leftPos = leftPos - submenu.offsetWidth - overItem.offsetWidth;

  submenu.style.left       = leftPos + "px";//getLeftPosition(opener) + opener.offsetWidth + "px";
  submenu.style.top        = topPos  + "px"; //getTopPosition(opener)  + "px";
  submenu.style.display = "block";
  submenu.wh_closeHandler = closeHandler;

  if (submenu.overItem)
    submenu.overItem.className = "webUI_dropdownmenuitem";

  if (submenu.iframe != null)
  {
    submenu.iframe.style.left    = submenu.style.left;
    submenu.iframe.style.top     = submenu.style.top;
    submenu.iframe.style.width   = submenu.offsetWidth + "px";
    submenu.iframe.style.height  = submenu.offsetHeight + "px";
    submenu.iframe.style.display = "";
  }
}

function resetAllMenus(e)
{
  if (!e)
    e = window.event;

  if (e.target)
    target = e.target;
  else if (e.srcElement)
    target = e.srcElement;

  var dropDowns = getElementsByClass(document,"webUI_dropdownmenu","DIV");
  for (var i=0; i < dropDowns.length; i++)
    whMenubar_closeSubmenu(dropDowns[i]);
}


var menubar
{

};

var menubars_openmenu;


function resetItem(item)
{
  return function(e)
  {
    item.className = "webUI_menubaritem";
  }
}



function addEventHandlers(classname)
{
  var elements = getElementsByClass(document,classname,"*");

  if (!elements)
    return;

  for (var j=0; j<elements.length; j++)
  {
    elements[j].onmouseover=function()
    {
      this.className+=" hover";
    }
    elements[j].onmouseout=function()
    {
      var re = new RegExp(" hover", "g");
      this.className= this.className.replace(re, "");
      re = new RegExp(" down", "g");
      this.className= this.className.replace(re, "");
    }
    elements[j].onmousedown=function()
    {
      this.className+=" down";
    }
    elements[j].onclick=function()
    {
      this.onmouseout();
    }
  }
  return;
}

function xfindPosX(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;
}

function xfindPosY(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;
}

function getTopPosition(obj)
{
  var curtop;
  curtop = obj.offsetTop;
  if (obj.offsetParent != null)
  {
    curtop += getTopPosition(obj.offsetParent);
  }
  return curtop;
}

function getLeftPosition(obj)
{
  var curleft;

  curleft = obj.offsetLeft;
  if (obj.offsetParent != null)
  {
    curleft += getLeftPosition(obj.offsetParent);
  }

  return curleft;
}


function getMouseXPosition(e)
{
  if (!e)
    var e = window.event;

  var xpos;
  if (e.pageX) // mozilla, opera
    xpos = e.pageX;
  else if (event.clientX) // IE
    xpos = event.clientX + document.body.scrollLeft;
  return xpos;
}

function getMouseYPosition(e)
{
  if (!e)
    var e = window.event;

  var ypos;
  if (e.pageY) // mozilla, opera
    ypos = e.pageY;
  else if (event.clientY) // IE
    ypos = event.clientY + document.body.scrollTop;
  return ypos;
}

function insertIframe(obj)
{
  var iframe = document.createElement("iframe");
  iframe.frameBorder = 0;
  iframe.src = "javascript:;";
  iframe.style.display = "none";
  iframe.style.position = "absolute";
  iframe.style.filter = "progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)";
  return obj.parentNode.insertBefore(iframe, obj);
}

function insertDummy(obj)
{
  var dummy = document.createElement("img");
  dummy.border = 0;
  dummy.src = "../images/dummy.gif"; //FIXME: this should be an actual image, used in the grid to make IE A-tag behave properly
  dummy.width = "0";
  dummy.height = "0";
  dummy.alt = "";
  return obj.appendChild(dummy);
}


function addEvent( obj, type, fn )
{
  if ( obj.attachEvent )
  {
    obj['e'+type+fn] = fn;
    obj[type+fn] = function()
    {
      obj['e'+type+fn]( window.event );
    }
    obj.attachEvent( 'on'+type, obj[type+fn] );
  }

  else
    obj.addEventListener( type, fn, false );
}

function removeEvent( obj, type, fn )
{
  if ( obj.detachEvent )
  {
    obj.detachEvent( 'on'+type, obj[type+fn] );
    obj[type+fn] = null;
  }
  else
    obj.removeEventListener( type, fn, false );
}

function getKeyCode(e)
{
  var code;
  if (!e)
    var e = window.event;

  if (e.ctrlKey)
    return "CTRL";
  else if (e.shiftKey)
    return "SHIFT";
  else
    return "";
}

function stopClickBorder (event)
{
  if (document.attachEvent)
    return;

  if (event.preventDefault && event.ctrlKey)
    event.preventDefault();
}

function initdropdownmenus()
{
  if (!document.getElementById)
    return;
  addDropdownMenuHandlers();
  addDropdownMenuBarHandlers();
}
