menuController = Class.create();
menuController.prototype = {
  timedHide: 0,
  activeSubmenu: 0,
  menuRoot: 0,

  //Set the menuroot and event handlers
  initialize: function(startElement) {
  
   this.menuRoot = startElement;
   if (this.menuRoot.tagName && this.menuRoot.tagName.toLowerCase() != 'ul')
    this.menuRoot = this.findChildWithTag(startElement, 'ul');

   this.recurseChildren(this.menuRoot);
  },

  recurseChildren: function(startElement) {
    var ref = this;
    $(startElement).childElements().each(function(child){
      if (child.tagName && child.tagName.toLowerCase() == 'span') {
        Event.observe(child, 'mouseover', ref.showSubMenu.bindAsEventListener(child,ref));
        Event.observe(child, 'mouseout', ref.closeAllMenus.bindAsEventListener(child,ref));
      }
      ref.recurseChildren(child);
    });
  },
  findParentWithTag: function (currentElement,tag) {
    currentElement = currentElement.parentNode; 
    while (currentElement.tagName && currentElement.tagName.toLowerCase() != tag && currentElement != this.menuRoot){
      currentElement = currentElement.parentNode; 
    }
    return currentElement;
  },
  findChildWithTag: function(currentElement,tag) {
    if (currentElement.childNodes){
      for(var i=0;i<currentElement.childNodes.length;i++) {
        if(currentElement.childNodes[i].tagName != null && currentElement.childNodes[i].tagName.toLowerCase() == tag) 
          return currentElement.childNodes[i];
      }
    }
    return null;
  },
  showSubMenu: function(event,ref) {
    clearTimeout(ref.timedHide);
    currentOption = this
    
    //exit if we are already shown
    if (ref.activeMenu != null){
      if (currentOption == ref.activeMenu)
        return;
    }
    
    if (ref.activeMenu != null)
      ref.closeSubMenus(ref.activeMenu,currentOption);
    
    clearTimeout(ref.timedShow);
    ref.timedShow=setTimeout(function(){
      ref.openMenus(currentOption);
    },100);
    ref.activeMenu = this; //currentOption;
  },
  openMenus: function(currentOption) {
    currentElement = currentOption;
    var queue = Effect.Queues.get('menuscope');
    //Travel down the tree, make sure everything is visible
    while (currentElement != this.menuRoot){
      menuOption = this.findChildWithTag(currentElement, 'span');
      subMenu = this.findChildWithTag(currentElement, 'div');
       
      if (menuOption) {
        if (!currentElement.hasClassName('hover'))
          currentElement.addClassName('hover');
      }
      if (subMenu) {
        queue.each(function(e) { 
          if (e.element == subMenu) {
            e.cancel(); 
            subMenu.setStyle({ display : '', opacity: ''});
          }

        });
        if (subMenu.getStyle('display') == 'none' ) {
          new Effect.Appear(subMenu, {duration: .3, queue: { position: 'start', scope: 'menuscope'}});
        }
      } 
      currentElement = this.findParentWithTag(currentElement,'li');
    }
  },
  closeAllMenus: function(event,ref) {
    currentOption = this; 
    ref.timedHide=setTimeout(function(){
      ref.closeSubMenus(currentOption,ref.menuRoot);
      ref.activeMenu = null;
    },400);
  },
  closeSubMenus: function(previousMenu,currentMenu) {
    currentParent = this.findParentWithTag(currentMenu,'li');
    currentMenuOption = this.findChildWithTag(currentParent,'span');
    //currentMenuOption is null when called from closeAllMenus
    if (currentMenuOption == null) 
      currentMenuOption = this.menuRoot; 

    //travel down the tree to close all open menus until we reach the menuroot or the currently opened menu
    currentElement = this.findParentWithTag(previousMenu,'li');
    while (currentElement != this.menuRoot){
      menuOption = this.findChildWithTag(currentElement, 'span');
      subMenu = this.findChildWithTag(currentElement, 'div');
      // Check if the submenu to close is the current menu 
      // Check if the currentmenu is a child of the menu to close. Stop closing in those cases
      if (menuOption != currentMenuOption && !currentMenuOption.descendantOf(currentElement)) {
        currentElement.removeClassName('hover');
        if (subMenu) {
          new Effect.Fade(subMenu, { duration: .2, delay: .3, queue: {position: 'start', scope: 'menuscope'}});
        }
        currentElement = this.findParentWithTag(currentElement,'li');
      }else{
        currentElement = this.menuRoot;
      }
    }
  }
}

