/*
 * CSS menus v0.2 by E.F. de Moor (11-2004)
 *
 * Meant to be used in combination with IE7 (see http://dean.edwards.name/IE7/)
 *
 * Menu's are built by using unordered list with list items.
 * Important: the upper UL tag must have an id.
 *
 * Javascript is used to alter the classname of menu items.
 * This happens only if the browsers is supported, otherwise the entire list is displayed
 *
 * Each menu item can have (combined) states (classes) added as follows:
 *     .parent    : The item has children
 *     .expanded  : The item has children, that are currently visible.
 *                  This means that either the parent item, or one of the children is selected.
 *     .selected  : The item is the currently selected (active) one in the browser window.
 *     .first     : The item is the first child in a row (i.e. the first subitem of this level)
 *     .last      : The item is the last child in a row (i.e. the last subitem of this level)
 *     .nolink    : The item has no associated link (not clickable, but can have sub items)
 *                  Hence it is possible to discriminate the appearance of such items.
 *
 * These statenames are applied as classnames to indicate the states, possible multiple of them.
 * CSS definitions can define then dictate the appearance and behaviour of the menu item.
 *
 * An external function makes it possible to feed back what the current page is,
 * this way the selected menu item can always follow the actual page.
 *
 * Example of applied classes:
 *
 * Suppose we have a menu item, of which one of it's children is currently selected.
 *
 * item.className = 'myMenu selected parent expanded'
 *
 * Menu items can have style properties overruled individually, in groups and automatically.
 *
 * - Individual style properties: Overrule the item at the end of the CSS file by its id.
 *   Example : #m1-11111112>.layer1:hover{color:red}
 *   Here m1 is the menu name, and 11111112 is the original item id.
 *
 * - in Groups : Make sure that the item has predefined class, and overrule the properties
 *               for the class
 *
 * - Automatically : The style has added state-classes by the system: selected, first, parent, etc.
 *
 * Typical CSS file.
 *
 * The CSS file should be built up from general specifications to specific specifications,
 * because later specifications overrule earlier specs.
 * Hence in most cases a file is built as follows:
 *
 * appearance classes for non supported browsers (small items, all visible)
 * Generic behaviour CSS specs  (hide submenu items, define behaviour for the states)
 * Generic appearance CSS specs (possible per state)
 * Class specific appearance CSS specs (possible per state)
 * Individual item CSS specs (possible per state)
 *
 * The two main modes for usage is 'folding' menu and 'popup' menu.
 * popup menu's are achieved by specifying that the submenu's appear on mouseover (the default).
 * Also the _sub class must be specified 'position:absolute'
 * Folding menu's are created by specifying that the submenu's appear on a click action.
 * The _sub class should then be specified 'position:relative'. Of course it is possible
 * to intermix these for creating folding menu's on mouse over or popup after a click.
 * The call for this: .set_event_type('click'); (or 'over').
 *
 *
 * It is possible to have an animated appearance of the menu items. There are two effects:
 *  'glow' : the item appears slowly (alpha channel effect)
 *  'grow' : the item 'grows' out of it's parent (clipping or unhiding effect).
 * To activate, call the menu's .set_animation_type('glow',5); method. The first parameter
 * is the animation type, the second is the spead. 5 is about 1 second,
 * heigher values animate faster.
 *
 * Note: because of a problem with IE7, sometimes using the 'glow' animation effect together with a popup menu
 *       (position:absolute for the _sub classes), doesn't show any submenu items. It seems especially a
 *       problem with sideway menus, that are being clipped away by IE. No solution found yet, so you may
 *       want to use the 'grow' effect instead.
 *
 *
 * Browsers tested so far:
 *     Mac OS/9 IE4          : fixed menu (not dynamic)
 *     Mac OS/9 NS4          : fixed menu (not dynamic)
 *     Mac OS/9 IE5          : fixed menu (not dynamic)
 *     Mac OS/9 NS6+         : Ok
 *     Mac OS/X NS6+         : Ok
 *     Mac OS/X IE5          : fixed menu (not dynamic)
 *     Mac OS/X Firefox 1.0  : Ok
 *     Mac OS/X Mozilla 1.7  : Ok
 *     Mac OS/X Safari 1.2   : Ok
 *     Windows IE 5.5        : Ok, sometimes problems with popup menu when mixed with the glow effect
 *     Windows IE 6.0        : Ok, sometimes problems with popup menu when mixed with the glow effect
 *     Windows Firefox 1.0   : Ok
 *     Windows Mozilla 1.7   : Ok
 *
 */

// Keep track of all menus and menu items
var menus;
var num_menus=0;
var last_selected_id;
var CSSMenuItems=new Array();
var IE_caching_fixed = 0;

/***************************** Menu class implementation *****************************/
/* CSSMenu constructor */
function CSSMenu(min_level, max_level, ul_id, follow_cms_selection) {
  this.browser_supported = menu_supported();
  if(!this.browser_supported)
    return;
  if(typeof(follow_cms_selection) == 'undefined')
    this.follow_cms_selection = 1;      // Default behaviour: follow main selection
  else
    this.follow_cms_selection = follow_cms_selection;
  if(typeof(ul_id) == 'undefined')
    ul_id = 'menu';
  if(ul_id) {
    this.tree_id = ul_id;
    this.tree_element = document.getElementById(ul_id);
    if(this.tree_element)
      this.tree_element.style.visibility='hidden';
  }
  if(this.follow_cms_selection && this.tree_element && !top.css_menu)
    top.css_menu = this.tree_element;
  this.min_level = 1;
  if(min_level)
    this.min_level = min_level;
  this.max_level = 0;
  if(max_level)
    this.max_level = max_level;
  if(!menus) {
    menus = new Array();
  }
  menus[num_menus] = this;
  this.menu_num = ++num_menus;
  this.menu_id = 'm'+this.menu_num;
  this.event_type='over';               // Default menu is "show on mouse over"
  this.mouseOutTimeout = 500;           // Default Mouse out timeout of half a second.
  this.layers = new Array();
};

// The type of events the menu reacts on (by showing submenu items)
// Possibilities:
//   'over' : show submenu items on mouse over
//   'click' : show submenu items on mouse click
CSSMenu.prototype.set_event_type=function(type) {
  this.event_type=type;
};

// Specify how the menu animates to visible
// Possibilities:
//   ''     : displayed immediately (no animation)
//   'glow' : For glowing up (opacity)
//   'grow' ; For growing (clipping)
CSSMenu.prototype.set_animation_type=function(type, speed) {
  this.animation_type=type;
  this.animation_speed=speed;
  if(!this.animation_speed)
    this.animation_speed=10;
};

// Set the mouseout timeout to a new value in miliseconds.
CSSMenu.prototype.mouseout_timeout=function(timeout) {
  this.mouseOutTimeout = timeout;
};

// Add a (textual) layer to the menu items
CSSMenu.prototype.addTextLayer=function() {
  this.layers[this.layers.length] = 'text';
}

// Add an (empty) layer to the menu items
CSSMenu.prototype.addBackgroundLayer=function() {
  this.layers[this.layers.length] = 'background';
};

// Add an rendered (text) layer to the menu items
CSSMenu.prototype.addRenderedLayer=function() {
  this.layers[this.layers.length] = 'rendered';
  // EMO 20080815: Fix the buffer problem of IE, for rendered menu's
  if (navigator.appName == 'Microsoft Internet Explorer') {
    var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
    if (re.exec(navigator.userAgent) != null) {
      var rv = parseFloat( RegExp.$1 );
      if(rv < 7)  { // All internet explorers before 7 have this bug
        if(!IE_caching_fixed) {
          try {
            document.execCommand("BackgroundImageCache", false, true);
          } catch(err) {}
          IE_caching_fixed = true;
        }
      }
    }
  }
};

/**** Static functions below ****/

// Setup the menu tree.
CSSMenu.prototype.setup=function(org_this) {
  // Note: this is not kept after a timer function, therefore use the parameter if given
  if(this) mythis = this;
  else mythis = org_this;
  if(!mythis || !this.browser_supported)
    return;
  // If there is no valid tree_element, and it is the global menu (no tree_id specified), then use the global css menu.
  if(!mythis.tree_element && mythis.follow_cms_selection)
    mythis.tree_element = top.css_menu;
  if(!mythis.tree_element && mythis.follow_cms_selection) {
    // If there is no valid css menu yet, try again within half a second.
    setTimeout(function(){mythis.setup(mythis);}, 500);
    return;
  }
  // If there are no layers specified, create an automatic text layer
  if(!this.layers.length)
    this.layers[0] = 'text';
  // Work through the entire tree
  mythis.num_items = 0;
  mythis.tree_element.style.display='none'; // Make sure the original tree doesn't occupy space.
  var menu_root = new CSSMenuItem('div', this, 0, this.menu_id ,this.menu_id);
  if(menu_root && !menu_root.existed)
      document.body.appendChild(menu_root.object);
  mythis.process_tree(mythis.tree_element,0,menu_root.object,menu_root.object);
};

// Process a subtree recursively
var first=0;
CSSMenu.prototype.process_tree=function(source, level, parent, source_parent) {
  if(source.nodeName != 'UL' && source.nodeName != 'LI' && source.nodeName != 'A')
    return;
  if(!parent)
    parent = document.body;
  if(source.nodeName=='UL')
    level++;
  if((!this.max_level || level<=this.max_level) && (!this.min_level || level>=this.min_level))
    var visible=1;
  if(source.nodeName=='UL') {
    if(source_parent && !source.id)
      source.id = source_parent.id+'_sub';
    // If this is a frame where level 1 is not displayed, we should create a surrounding div to bind the classname.
    var sub_root=0;
    if(this.min_level>1 && level==this.min_level) {
      sub_root=1;
    }
    if(visible || sub_root) {
      var new_item = new CSSMenuItem('div', this, level, source.className,this.menu_id+'-'+source.id);
      if(source_parent && (!this.max_level || level<=this.max_level)) {
        new_item.addClass('level'+(level-1)+'_sub');
      }
      if(sub_root || level > this.min_level) {
        new_item.object.style.display='none';
        new_item.required_display='none';
      }
    }
    first=1;
  }
  if(source.nodeName=='LI') {
    if(!source.id)
      source.id = 'i'+(++this.num_items);
    if(visible) {
      var new_item = new CSSMenuItem('div', this, level, source.className,this.menu_id+'-'+source.id);
      var uls = source.getElementsByTagName('ul');
      if(uls.length)
        new_item.addClass('parent');
      // Add event listeners (item events are routed to the menu class).
      new_item.addListener('mouseover',this.mouseOver);
      new_item.addListener('mouseout',this.mouseOut);
      new_item.addListener('click',this.mouseClick);
      if(source_parent)
        new_item.parent_id = source_parent.id;
      new_item.addClass("level"+level);
      // Find if it is the first sub-item
      if(first) {
        new_item.addClass("first");
      }
      // Find if it is the last sub-item
      next = source.nextSibling;
      while(next && next.nodeName=='#text')
        next = next.nextSibling;
      if(!next)
        new_item.addClass("last");
    }
    first=0;
  }
  if(source.nodeName=='A') {
    if(visible) {
      for(var i=0; i<this.layers.length; i++) {
        var new_item = new CSSMenuItem('a', this, level, source.className);
        // Prevent a dotted selection box around a menu item
        new_item.addListener('focus',new_item.onFocus);
        new_item.addListener('click',this.onClick);
        if(source.href) {
          var new_target;
          var new_href;
          if(source.target)
            new_target=source.target;
          else
            new_target='content';
          // If it is a local call, and there was a target...
          var new_href;

          if(source.protocol && source.hostname)
            new_href = source.protocol+'//'+source.hostname;
          if(source.port && source.port!=80 && source.port!=0)
            new_href += ':'+source.port;
          if ((!source.protocol || source.protocol==top.location.protocol)
            && (!source.hostname || source.hostname==top.location.hostname)
            && new_target.substr(0,1) != '_') {
            new_href += '/p-'+new_target;
          }
          if(source.pathname.substr(0,1) != '/')
            new_href += '/';
          new_href += source.pathname+source.search;
          if(source.hash != '#')
            new_href += source.hash;

          // AvD on nov 14th 2007: Also allow javascript for anchors...
          if(source.protocol=='javascript:' && source.href)
            new_href = source.href;
            
          new_item.object.href=new_href;
          new_item.object.target=new_target;
        }
        else {
          // AvD july 6th 2006: Made unconditional to facilitate mouse-over CSS classes for level1 buttons
          // that only facilitate fly-out of a popup menu (level2) and don't have paragraphs themselves...
          //if(this.event_type == 'click') { // Make sure there is something to click
            new_item.object.href = 'javascript:void(0);';
          //}
          new_item.addClass("nolink");
        }
        if(new_item && !new_item.existed)
          parent.appendChild(new_item.object);
        if(this.layers[i] == 'background')
          new_item.object.innerHTML = '';
        else if(this.layers[i] == 'rendered')
          new_item.text = source.innerHTML;
        else     // text
          new_item.object.innerHTML = source.innerHTML;
        if(source.className)
          new_item.addClass(source.className);
        new_item.addClass('layer'+(i+1));
        if(new_item && !new_item.existed)
          new_item = null;  // Prevent double addition, and it has no children anyway.
      }
    }
  }
  if(new_item && !new_item.existed)
    parent.appendChild(new_item.object);
  var children = source.childNodes;
  if(source.id) var theparent = source;
  else var theparent = source_parent;
  for (var i=0; i<children.length; i++) {
    if(new_item)
      this.process_tree(children[i],level,new_item.object,theparent);
    else
      this.process_tree(children[i],level,parent,theparent);
  }
}

/* Function for handling mouseover */
CSSMenu.prototype.mouseOver=function(evt) {
  if (!evt) var evt = window.event;
  if(this.id) var el = this;
  else var el = evt.target;
  if(el && el.nodeName=='DIV') {
    var id = el.id.substr(3,el.id.length);
    // Show all necessary of the current item
    var item = getCSSMenuItemById(el.id);
    if(item)
      item.menu.call_items_and_parents('showOnMouseOver',id,0);
    item.menu.animate(item.menu);
    evt.cancelBubble = true;
    if (evt.stopPropagation) evt.stopPropagation();
  }
}

/* Function for handling mouseout */
CSSMenu.prototype.mouseOut=function(evt) {
  if (!evt) var evt = window.event;
  if(this.id) var el = this;
  else var el = evt.target;
  if(el && el.nodeName=='DIV') {
    var id = el.id.substr(3,el.id.length);
    // Show all necessary of the current item
    var item = getCSSMenuItemById(el.id);
    if(item)
      item.menu.call_items_and_parents('hideOnMouseOut',id,0);
    // Make sure the lowest level item is not removed!
    if(last_selected_id && item)
      item.menu.call_items_and_parents('showIfLowestLevel',last_selected_id);
    if(item.menu.mouseOutTimeout)
      setTimeout(function() {item.menu.animate(item.menu);}, item.menu.mouseOutTimeout);
    else
      item.menu.animate(item.menu);
    evt.cancelBubble = true;
    if (evt.stopPropagation) evt.stopPropagation();
  }
}

/* Function for handling mouseclick*/
CSSMenu.prototype.mouseClick=function(evt) {
  if (!evt) var evt = window.event;
  if(this.id) var el = this;
  else var el = evt.target;
  if(el && el.nodeName=='DIV') {
    var id = el.id.substr(3,el.id.length);
    // Show all necessary of the current item
    var item = getCSSMenuItemById(el.id);
    if(item) {
      if(last_selected_id) {
        item.menu.call_items_and_parents('hideIfLowestLevel',last_selected_id,1);
        item.menu.call_items_and_parents('hideOnClick',last_selected_id,1);
      }
      item.menu.call_items_and_parents('showOnClick',id,1);
      item.menu.call_items_and_parents('showIfLowestLevel',id,1);
    }
    item.menu.perform_select(id);
    evt.cancelBubble = true;
    if (evt.stopPropagation) evt.stopPropagation();
  }
}

/* Function for handling mouseClick on a href*/
CSSMenu.prototype.onClick=function(evt) {
  if(cms_check_formchange && !cms_check_formchange()) {  // EMO 20060430: Did the user change something in the form?
    evt.cancelBubble = true;
    if (evt.stopPropagation) evt.stopPropagation();
    evt.returnValue = false;                      // IE method
    if(evt.preventDefault) evt.preventDefault();  // W3C method
    return(false);                                // Old browser method
  }
  return(true);
}

/* Function for handling select */
CSSMenu.prototype.select=function(sel) {
  // remove the processor
  proc_sel = sel.replace(/\/?p-[^\/]*/g,'');
  if(!this.browser_supported)
    return;
  if(!this.tree_element)
    return;
  var lists = this.tree_element.getElementsByTagName('li');
  // First find the selected item!
  for (var i = 0; i < lists.length; i++) {
    if(lists[i].id) {
      if(lists[i].childNodes) {
        for(var j=0; j<lists[i].childNodes.length; j++) {
          if(lists[i].childNodes[j] && lists[i].childNodes[j].href) {
            if(lists[i].childNodes[j].href.match(new RegExp(proc_sel+"$"))
              || lists[i].childNodes[j].href.match(new RegExp(escape(proc_sel)+"$"))) {
              var selected_el = lists[i];
              break;
            }
          }
        }
      }
    }
  }
  if(selected_el && selected_el.id)
    this.perform_select(selected_el.id);
}

/* Function for handling select */
CSSMenu.prototype.perform_select=function(id) {
  var selected_el = document.getElementById(id);
  // Did we find the item?
  if(selected_el) {
    var lists = this.tree_element.getElementsByTagName('li');
    // Deselect the current selected items
    for (var i = 0; i < lists.length; i++) {
      if(lists[i].id) {
        this.item_method_in_all_menus('removeClass', lists[i].id, 'selected');
        this.item_method_in_all_menus('removeClass', lists[i].id, 'expanded');
      }
    }
    // Set the selected element
    this.item_method_in_all_menus('addClass', selected_el.id, 'selected');
    // If it has children, it is expanded too.
    var uls = selected_el.getElementsByTagName('ul');
    if(uls.length)
      this.item_method_in_all_menus('addClass', selected_el.id, 'expanded');
    // Set all parents to expanded.
    var parent = selected_el.parentNode;
    while(parent) {
      if(parent.tagName == 'LI') {
        this.item_method_in_all_menus('addClass', parent.id, 'expanded');
      }
      parent= parent.parentNode;
    }
    // Hide previous displayed topmost levels
    if(last_selected_id) {
      this.call_items_and_parents('hideIfLowestLevel',last_selected_id,1);
      this.call_items_and_parents('hideOnClick',last_selected_id,1);
      // EMO 2005-04-15 Hide mouse driven menus.
      this.call_items_and_parents('hideOnMouseOut',selected_el.id,0);
    }
    this.call_items_and_parents('showIfLowestLevel',selected_el.id,1);
    last_selected_id=selected_el.id;
    // Simulate a click, to show the proper menus.
    this.call_items_and_parents('showOnClick',selected_el.id,1);
    this.animate(this);
  }
}

// call a function in all parents of a given element
CSSMenu.prototype.call_items_and_parents=function(func, id, propagate) {
  // Call the direct submenu id
  if(propagate)
    this.item_method_in_all_menus(func, id+'_sub');
  else
    this.item_method(func, id+'_sub');
  // And all parents
  var parent = document.getElementById(id);
  while(parent) {
    parent = parent.parentNode;
    if(parent && parent.id && parent.id.match(/_sub$/)) {
      if(propagate)
        this.item_method_in_all_menus(func, parent.id);
      else
        this.item_method(func, parent.id);
    }
  }
}

CSSMenu.prototype.item_method_in_all_menus=function(func, id, parm1, parm2) {
  if(menus) {
    for(var i=0; i<menus.length; i++) {
      if(menus[i].tree_element==this.tree_element) {
        var item_id = menus[i].menu_id+'-'+id;
        var item_el = getCSSMenuItemById(item_id); 
        if(item_el && eval('item_el.'+func))
          eval('item_el.'+func+'(parm1, parm2)');
      }
    }
  }
}

CSSMenu.prototype.item_method=function(func, id, parm1, parm2) {
  var item_id = this.menu_id+'-'+id;
  var item_el = getCSSMenuItemById(item_id); 
  if(item_el && eval('item_el.'+func))
    eval('item_el.'+func+'(parm1, parm2)');
}


var timer_handle=0;
CSSMenu.prototype.animate=function (item) {
  if(!timer_handle)
    item.perform_animate(item);
}

CSSMenu.prototype.perform_animate=function(item) {
  var i;
  var ready=1;
  // Animate all menu items that are different from the required display state
  for(var i=0; i<CSSMenuItems.length; i++) {
    if(CSSMenuItems[i].tag=='div') {
      if(CSSMenuItems[i].object.style.display != CSSMenuItems[i].required_display)
        CSSMenuItems[i].in_progress=1;
      if(CSSMenuItems[i].in_progress)
      	CSSMenuItems[i].in_progress= !CSSMenuItems[i].animate(CSSMenuItems[i]);
      // Only one action per time, too prevent too restless animation
      if(CSSMenuItems[i].in_progress) {
        ready=0;
        break;
      }
    }
  }
  timer_handle = 0;
  if(!ready)
    timer_handle = setTimeout(function(){item.perform_animate(item);}, 25);
}


/***************************** Menuitem (div) implementation *****************************/

function getCSSMenuItemById(id) {
  for(var i=0; i<CSSMenuItems.length; i++) {
    if(CSSMenuItems[i].object.id == id)
      return(CSSMenuItems[i]);
  }
  return null;
}
// Create a menu item
function CSSMenuItem(tag, menu, level, className,id) {
  this.tag = tag;
  this.menu = menu;
  this.level = level;
  this.existed = 1;   // Assume we can find it in the document model
  if(id)
    this.object = document.getElementById(id);
  if(!this.object) {
    this.object = document.createElement(tag);
    this.object.id = id;
    this.existed = 0;
  }
  this.object.className = className;
  // this.setOpacity(1);              // Default opacity
  this.required_display='block';          // Default display
  this.object.style.display = this.required_display;
  CSSMenuItems[CSSMenuItems.length] = this;
}

/* Add the given class to the given element*/
CSSMenuItem.prototype.addClass=function (classname) {
  if(!RegExp(' '+classname+'\\b').test(this.object.className))
    this.object.className+=' '+classname;
  // If the class has a background and there should be a text rendered upon it: Change the URL.
  if(typeof(this.text) != 'undefined') {
    var url_text = escape(this.text).replace(/\+/g, '%2C').replace(/\"/g,'%22').replace(/\'/g, '%27');
    var backgroundImageSrc = this.getStyleProperty('backgroundImage');
    if(!backgroundImageSrc)
      var backgroundImageSrc = this.getStyleProperty('background-image');
    if(backgroundImageSrc) {
      backgroundImageSrc = backgroundImageSrc.replace(/^url\(/,'');
      backgroundImageSrc = backgroundImageSrc.replace(/\)$/,'');
      backgroundImageSrc = backgroundImageSrc.replace(/^"/,'');
      backgroundImageSrc = backgroundImageSrc.replace(/"$/,'');
      if(backgroundImageSrc.match(/\?/))
        backgroundImageSrc = backgroundImageSrc+'&text='+url_text;
      else
        backgroundImageSrc = backgroundImageSrc+'?text='+url_text;
      this.object.style.backgroundImage = 'url('+backgroundImageSrc+')';
      // Add this as a preload image
      this.preload = new Image(); 
      this.preload.src = backgroundImageSrc;
    }
  }
}

/* Remove the given class from the given id */
CSSMenuItem.prototype.removeClass=function (classname) {
  if(RegExp(' '+classname+'\\b').test(this.object.className))
    this.object.className=this.object.className.replace(' '+classname,'');
}

/*Add an event listener to the given element */
CSSMenuItem.prototype.addListener=function (event, func) {
 if (this.object.addEventListener) return this.object.addEventListener(event, func, false);
 else this.object['on'+event] = func;
}

// Called on mouse over, if this menu item should be displayed.
CSSMenuItem.prototype.showOnMouseOver=function () {
  if(this.menu.event_type == 'over')
    this.doShow();
}

// Called on mouse over, if this menu item should be hidden.
CSSMenuItem.prototype.hideOnMouseOut=function () {
  if(this.menu.event_type == 'over') {
    // It seems necessary to copy the 'this' object, otherwise it will pass the window object.
    var item = this;
    this.doHide(this);
  }
}

// Called on mouse click, if this menu item should be displayed.
CSSMenuItem.prototype.showOnClick=function () {
  if(this.menu.event_type == 'click')
    this.doShow();
}

// Called on mouse click, if this menu item should be hidden.
CSSMenuItem.prototype.hideOnClick=function () {
  if(this.menu.event_type == 'click') {
      this.doHide(this);
  }
}

// Show the given menu item, if it is the lowest level of the menu.
CSSMenuItem.prototype.showIfLowestLevel=function () {
  if(this.level == this.menu.min_level && this.doShow)
    this.doShow();
}

// Show the given menu item, if it is the lowest level of the menu.
CSSMenuItem.prototype.hideIfLowestLevel=function () {
  if(this.level == this.menu.min_level && this.doHide)
    this.doHide(this);
}

// Show this menu item.
CSSMenuItem.prototype.doShow=function () {
  this.required_display = 'block';
  if(this.menu.event_type == "over")
    this.hideSelectBoxes();       // For IE below 7 only
}

// Hide this menu item
CSSMenuItem.prototype.doHide=function (item) {
  item.required_display = 'none';
  if(this.menu.event_type == "over")
    this.showSelectBoxes();       // For IE below 7 only
}

// IE selectbox bug support. Is said to be fixed in IE7 and above
CSSMenuItem.prototype.hideSelectBoxes=function () {
  if (navigator.appName == 'Microsoft Internet Explorer') {
    var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
    if (re.exec(navigator.userAgent) != null) {
      var rv = parseFloat( RegExp.$1 );
      if(rv < 7)  { // All internet explorers before 7 have this bug
        var content = document.getElementById("content");
        if(content) {
          var doc = content.contentDocument;
          if(doc==null)
            doc = content.Document;
          if(doc && doc.getElementsByTagName) {
            var selects = doc.getElementsByTagName('select');
            for (i=0; i<selects.length; i++) {
              selects[i].style.visibility = "hidden";
            }
          }
        }
      }
    }
  }
}
CSSMenuItem.prototype.showSelectBoxes=function () {
  if (navigator.appName == 'Microsoft Internet Explorer') {
    var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
    if (re.exec(navigator.userAgent) != null) {
      var rv = parseFloat( RegExp.$1 );
      if(rv < 7)  { // All internet explorers before 7 have this bug
        var content = document.getElementById("content");
        if(content) {
          var doc = content.contentDocument;
          if(doc==null)
            doc = content.Document;
          if(doc && doc.getElementsByTagName) {
            var selects = doc.getElementsByTagName('select');
            for (i=0; i<selects.length; i++) {
              selects[i].style.visibility = "visible";
            }
          }
        }
      }
    }
  }
}

CSSMenuItem.prototype.getOpacity=function () {
  // IE
  if(this.object.filters) {
    if(this.object.filters && this.object.filters.alpha)
      return(this.object.filters.alpha.opacity/100);
    else
      return(0);
  }
  // Konqueror and Safari
  if(this.object.style.KHTMLOpacity)
    return(this.object.style.KHTMLOpacity);
  if(this.object.style.KhtmlOpacity)
    return(this.object.style.KhtmlOpacity);
  // Mozilla
  if(this.object.style.MozOpacity)
    return(this.object.style.MozOpacity);
  // Default
  if(this.object.style.opacity)
    return(this.object.style.opacity);
  return(0);
}

// Modify the current opacity of this object.
CSSMenuItem.prototype.setOpacity=function (opacity) {
  if(opacity>1) opacity=1;
  if(opacity<0) opacity=0;
  if(this.object.filters) {
    // Create the opacity filter if necessary
    if(this.object.style.filter.indexOf("alpha")==-1)
      this.object.style.filter+=" alpha(opacity=0)";
    this.object.filters.alpha.opacity=100*opacity;
  }
  else
    this.object.style.opacity=this.object.style.MozOpacity=this.object.style.KhtmlOpacity=this.object.style.KHTMLOpacity=opacity;
}

// Retrieve the width of this object.
CSSMenuItem.prototype.getWidth=function () {
  if(this.object.offsetWidth)
    return parseInt('0'+this.object.offsetWidth,10);
  if(this.object.style.width)
    return parseInt('0'+this.object.style.width,10);
  if (this.object.style.pixelWidth)
    return this.object.style.pixelWidth;
}

// Retrieve the height of this object.
CSSMenuItem.prototype.getHeight=function () {
  if(this.object.offsetHeight)
    return parseInt('0'+this.object.offsetHeight,10);
  if(this.object.style.height)
    return parseInt('0'+this.object.style.height,10);
  if (this.object.style.pixelHeight)
    return this.object.style.pixelHeight;
}

// Retrieve a current style property, independent of where it was defined.
CSSMenuItem.prototype.getStyleProperty=function (property) {
  if (this.object && this.object.ownerDocument && this.object.ownerDocument.defaultView && this.object.ownerDocument.defaultView.getComputedStyle) {
    var mystyle = this.object.ownerDocument.defaultView.getComputedStyle(this.object,null);
    // EMO 20080816: Fix a Safari 2 bug, where getComputedStyle doesn't work for hidden (display:none) objects.
    if(!mystyle) {
      var node=this.object;
      while(node) {
        if(node.style && node.style.display == 'none') {
          node.olddisplay = node.style.display;
          node.style.display = 'block';
        }
        node = node.parentNode;
      }
      var mystyle = this.object.ownerDocument.defaultView.getComputedStyle(this.object,null);
    }
    // End of Safari Bugfix. Remove if support for Safari 2 is dropped
    if(mystyle)
      var val = mystyle.getPropertyValue(property);
    var node=this.object;
    // EMO 20080816: Part 2 of Safari 2 bugfix: Restore all display properties
    while(node) {
      if(node.olddisplay) {
        node.style.display = node.olddisplay;
        delete(node.olddisplay);
      }
      node = node.parentNode;
    }
    // End of Safari Bugfix. Remove if support for Safari 2 is dropped
  }
  else if (window.getComputedStyle)
    var val = window.getComputedStyle(this.object,null).getPropertyValue(property);
  else if (this.object.currentStyle)
    var val = eval('this.object.currentStyle.' + property);
  return val;
}

// Perform an animation for this item.
CSSMenuItem.prototype.animate=function (item) {
  var ready=0;
  position=item.getStyleProperty('position');
  switch(item.menu.animation_type) {
    case 'glow':
      if(position=='absolute') {
        ready = item.animate_glow();
        if(item.required_display == 'block')
         item.object.style.display = item.required_display;
      }
      else       // Glow method doesn't work with relative positioning.
        ready=1;
      break;
    case 'grow':
      if(position=='absolute') {
        if(item.required_display == 'block')
          item.object.style.display = item.required_display;
        ready = item.animate_grow_clip();
      }
      else       // Clip method doesn't work with relative positioning.
        ready = item.animate_grow_unhide();
      break;
    default:
      ready = 1;
      break;
  }
  if(ready)
    item.object.style.display = item.required_display;
  return(ready);
}

// one step of the glow animation
CSSMenuItem.prototype.animate_glow=function () {
  var cur_opacity = parseFloat(this.getOpacity());
  if(this.required_display == 'block') {  // Animate towards visibility
    if(cur_opacity >= 1)
      return(1);
    cur_opacity += parseInt(this.menu.animation_speed)/100;
  }
  else {                                  // Animate towards hidden state
    if(cur_opacity <= 0)
      return(1);
    cur_opacity -= parseInt(this.menu.animation_speed)/100;
  }
  this.setOpacity(cur_opacity);
  return(0);
}

// one step of the grow animation, for folding type menu's
CSSMenuItem.prototype.animate_grow_unhide=function () {
  var num_children = this.object.childNodes.length; 
  // Check if we should still wait
  if(!this.counter)
    this.counter = 0;
  if(this.counter < 100) {
    this.counter += 10*this.menu.animation_speed;
    return(0);    // Wait for the speed timeout
  }
  // Wait till the parent is visible
  if(this.parentNode && this.parentNode.style.display != 'block')
    return(0);
  this.counter = 0;
  if(!this.last_child)
    this.last_child= 0;
  if(this.required_display=='block' && this.last_child > num_children)
    return(1);   // Ready
  if(this.required_display=='none' && this.last_child < 0)
    return(1);   // Ready
  for(var i=0; i<num_children; i++) {
    if(i <= this.last_child)
      this.object.childNodes[i].style.display = 'block';
    else
      this.object.childNodes[i].style.display = 'none';
  }
  if(this.required_display == 'block') // Animate towards visibility
    this.last_child++;
  else
    this.last_child--;
  // Make myself visible
  this.object.style.display = 'block';
  return(0);
}

// one step of the grow animation for popup type menus
CSSMenuItem.prototype.animate_grow_clip=function () {
  var ready=1;
  var cur_height = this.getHeight();
  if(!cur_height) cur_height=0;
  var clip = new ClipObj(this);
  clip.right = 2000;  // Make sure children are not clipped!
  if(this.required_display == 'block') {  // Animate towards visibility
    if(clip.bottom < cur_height) {
      clip.bottom += parseInt(this.menu.animation_speed);
      ready=0;
    }
    else
      clip.bottom = 2000;                 // Make sure our children are not clipped.
  }
  else {                                  // Animate towards hidden state
    if(clip.bottom > cur_height)
      clip.bottom = cur_height;
    if(clip.bottom > 0) {
      clip.bottom -= parseInt(this.menu.animation_speed);
      ready=0;
    }
    else
      clip.bottom = 0;
  }
  clip.apply(this);
  return(ready);
}

/* Prevent a dotted selection box around a menu item */
CSSMenuItem.prototype.onFocus=function (evt) {
  if (!evt) var evt = window.event;
  if(this.id) var el = this;
  else var el = evt.target;
  if(el && el.blur)
    el.blur();
  return(1);
}
  

/***************************** Clip object implementation *****************************/

function ClipObj(item) {
  this.clipStr = item.object.style.clip;
  clipStr = this.clipStr;
  clipStr = clipStr.substring (clipStr.indexOf("(") + 1);
  this.top = parseInt('0'+clipStr,10);
  clipStr = clipStr.substring (clipStr.indexOf(" ") + 1);
  this.right = parseInt('0'+clipStr,10);
  clipStr = clipStr.substring (clipStr.indexOf(" ") + 1);
  this.bottom = parseInt('0'+clipStr,10);
  clipStr = clipStr.substring (clipStr.indexOf(" ") + 1);
  this.left = parseInt('0'+clipStr,10);
}

// Apply this clipping rectangle to the given object.
ClipObj.prototype.apply=function(item) {
  this.clipStr = 'rect('+this.top+'px, '+this.right+'px, '+this.bottom+'px, '+this.left+'px)';
  item.object.style.clip = this.clipStr;
}


/***************************** CMS implementation functions *****************************/

/* Function below is called by content frame, upon load of a new document */
function menu_select(sel) {
  if(menus && sel) {
    for(var i=0; i<menus.length; i++)
      menus[i].select(sel);
  }
}
