if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
  i || (i = 0);
  var length = this.length;
  if (i < 0) i = length + i;
  for (; i < length; i++)
    if (this[i] === item) return i;
  return -1;
};

var NavMenu = {
  /**
   * "Private" variables. Don't change. 
   */
  //Keep track of which div <a> tags we've added observer methods to
  //so we don't keep adding more and more.
  alreadyObserved : new Array(),
  //The order of displayed menus
  menuTree : new Array(),
  //Which menu you're currently hovering on
  currentMenu : null,
  hideTimer : null,
  
  /**
   * "Public" variables. Modify to change behavior of menu.
   */
  
  /** 
   * Set to false for a vertical menu.
   */
  horizontal : true,
  
  /**
   * 1st-level menus can have a special offset from the root menu. 
   */
  rootTopOffset: 0,
  rootLeftOffset: 0,
  
  /**
   * All subsequent menus use these offsets as they pop up from each other.
   */
  topOffset: 0,
  leftOffset: 0,
  
  /**
   * TODO: Since IE and FF differ in padding and widths, it may be necessary
   * to add an IE-specific set of offsets.
   */
  
  /**
   * Menu hide delay (ms)
   */
  hideDelay: 250,
  
  /**
   * <a> hover class
   */
  hoverClass: "navMenuHover",
  
  compact : function(ar) {
    if (ar == null || ar == undefined || (!ar instanceof Array)) {
      return ar;
    }
    var _tmp = Array();
    var pos = 0;
    for (i = 0; i < ar.length; i++) {
      if (ar[i] != null && ar[i] != '' && ar[i] != undefined) {
        _tmp[pos] = ar[i];
        pos++;
      }
    }
    return _tmp;
  },
  
  
  /**
   * Start from the last menu and hide back to pos.
   * 
   * @param {int} pos Only trim down to navMenu pos. Defaults to 0.
   */
  hideMenus : function(pos) {
    pos = (pos) ? pos : 0;
    //If pos is -1, then this was called from the timeout hideMenu. This is 
    //when we have to remove the highlighting from the root menu, too.
    if (pos == -1) {
      $("#"+NavMenu.menuTree[0]+" a").removeClass(NavMenu.hoverClass);
      pos = 0;
    }
    for (i = (NavMenu.menuTree.length-1); i > pos; i--) {
      $("#"+NavMenu.menuTree[i]).hide();
      $("#"+NavMenu.menuTree[i]+" a").removeClass(NavMenu.hoverClass);
      NavMenu.menuTree[i] = null;
    }
    NavMenu.menuTree = NavMenu.compact(NavMenu.menuTree);
  },
  
  /**
   * Trims children from the menuTree up until the current parent menu.
   * child is the submenu that should now follow parent. If the child is 
   * different, then the user has moved the cursor to another submenu. So
   * we need to trim off the tree that existed under the previous menu
   * so navMenu new one can display its children.
   * @param {string} parent
   * @param {string} child
   */
  trimTree : function(parent, child) {
    //The parent menu will at least be 0 (the top menu item)
    pos = NavMenu.menuTree.indexOf(parent);
    //The next link in the tree should be child. If it's not
    //then the user has moved to another menu option, so trim the tree
    //from that point down.
    if (NavMenu.menuTree[pos+1] != child) {
      NavMenu.hideMenus(pos);
    }
  },
  
  /**
   * Shows a menu. If the parent is the 1st item in the menuList
   * and horizontal menus is set, then the submenu is displayed
   * underneath.
   *  
   * @param {string} parent
   * @param {Object} link
   * @param {string} target
   */
  showMenu : function(parent, link, target) {
    topOffset  = (parent == NavMenu.menuTree[0])
               ? NavMenu.rootTopOffset
               : NavMenu.topOffset;
    leftOffset = (parent == NavMenu.menuTree[0])
               ? NavMenu.rootLeftOffset
               : NavMenu.leftOffset;
    parent = $("#"+parent);
    target = $("#"+target);
    linkOffset = $(link).offset();
    
    /**
     * If you're using the left:-999em option, then the div won't actually be
     * invisible. If you position it and want to add a fade in effect, the first
     * time it'll just appear and only fade after that. So, hide it if it's
     * visible and then show it.
     */
    if (target.is(":visible")) { target.hide(); }
    target.css("position", "absolute");
    if (parent.attr("id") == NavMenu.menuTree[0] && NavMenu.horizontal) {
      target.css("top", (topOffset + linkOffset.top  + $(link).height()) + "px");
      target.css("left", (leftOffset + linkOffset.left) + "px");
    } else {
      target.css("top", (topOffset + parent.attr("offsetTop") + link.offsetTop) + "px");
      target.css("left", (leftOffset + parent.attr("offsetLeft") + parent.width()) + "px");
    }
    NavMenu.initMenu(target.attr("id"));
    target.show();
  },
  
  /**
   * Initializes a menu before displaying it. Used to initialize the root menu
   * as well as all child menus as soon as you hover an an <a> tag.
   * @param {string} menuId Menu to initialize
   */
  initMenu : function(menuId) {
    //Add navMenu menu to the tree if it's not already in there.
    if (NavMenu.menuTree.indexOf(menuId) == -1) {
      NavMenu.menuTree[NavMenu.menuTree.length] = menuId;
    }
    //Once we've added all these observe events, we don't want to add
    //them again, so first check if navMenu menu item has been marked
    if (!NavMenu.alreadyObserved[menuId]) {
      NavMenu.alreadyObserved[menuId] = true;
      
      /* 
       * Get all the <a> tags in navMenu element and add a mouseover event to
       * show the submenu indicated by its rel tag. Also set its rev tag
       * to point back to the parent menu. The <a> tags essentially form 
       * a link between menus, with rev pointing to the element containing
       * the link and rel pointing to the elewent to display when it's hovered
       * on.
       */
      $("#"+menuId+" a").each(function(){
        $(this).attr("rev", menuId);
        $(this).mouseover( function(){
          $("#"+menuId+" a").removeClass(NavMenu.hoverClass);
          $(this).addClass(NavMenu.hoverClass);
          NavMenu.trimTree(menuId, $(this).attr("rel"));
          if ($(this).attr("rev") != "") {
            NavMenu.showMenu(menuId, $(this), $(this).attr("rel"));
          }
        });
      });
      
      //As long as we're hovering on one of the menu elements,
      //prevent menu hiding
      $("#"+menuId).mouseover( function() {
        clearTimeout(NavMenu.hideTimer);
        NavMenu.currentMenu = menuId;
      });
  
      //Initiate a timed menu hide. It will get stopped if
      //we move on to any other menu element. See above.   
      $("#"+menuId).mouseout( function(){
        NavMenu.hideTimer = setTimeout("NavMenu.hideMenus(-1);", NavMenu.hideDelay);
      });
    }
  }

};

