/**
 * Keep all functionality relevant to the top navigation in this object.
 */
function TopNav() {

   // Array of all menu elements.
   var $menus = $("div.topnav-menu");
   // Array of all openers for menu elements.
   var $openers = $("a.topnav-opener");
   // Array of all non-openers (don"t have a menu attached).
   var $nonOpeners = $("a.topnav-nonopener");

   // Create an emtpy object to keep track of the timeouts - there should only
   // ever be one at a time.
   var menuTimeout;

   // For use in loops where "this" refers to something else.
   var topNav = this;

   /**
    * Render menu opener with "mouse in" effect and display menu for it.
    * This function will always be called from a opener"s mouseover.
    *
    * @param opener - span with class "topnav-opener" that user hovers over to
    *       open menu.
    */
   this.openMenu = function (opener) {
      // Get the menu for this opener.
      $menu = $(opener).next(".topnav-menu");

      // Cancel timeOut when the mouse is over the menu.
      if (menuTimeout) {
         clearTimeout(menuTimeout);
         menuTimeout = undefined;
      }

      // Hide all other menus.
      $menus.hide();
      $openers.addClass("topnav-mouseout");

      // Show selected one.
      $menu.show();
      $(opener).removeClass("topnav-mouseout").addClass("topnav-mouseover");
   }

   /**
    * Keep rendering menu opener with "mouse in" effect and displaying menu.
    * This function will always be called from a menu"s mouseover.
    *
    * @param menu - div with class "topnav-menu" that is displayed when user
    *       hovers over an opener.
    */
   this.keepMenuOpen = function (menu) {
      if (menuTimeout) {
         clearTimeout(menuTimeout);
         menuTimeout = undefined;
      }
   }

   /**
    * Render menu opener with "mouse out" effect and hide menu for it. This
    * function will be called from a menu or opener - send null for the other
    * arg.
    *
    * @param theOpener - span with class "topnav-opener" that user hovers over
    *       to open menu. (Send null if calling this from a menu.)
    * @param theMenu - div with class "topnav-menu" that is displayed when user
    *       hovers over opener. (Send null if calling this from an opener.)
    */
   this.closeMenu = function (theOpener, theMenu, from) {
      // Make sure we have menu and opener.
      var $menu;
      var $opener;
      if (theOpener) {
         $menu = $(theOpener).next(".topnav-menu");
         $opener = $(theOpener);
      } else {
         $opener = $(theMenu).prev(".topnav-opener");
         $menu = $(theMenu);
      }

      // Set timeout to close menu.
      menuTimeout = setTimeout(function () {
         //fade the menu out after 2 seconds
         $menu.fadeOut("fast");
         $opener.removeClass("topnav-mouseover", "fast").addClass("topnav-mouseout");
      }, 100);

   }

   /**
    * Initialise handlers.
    */
   this.init = function () {
      // Hide all of the menus.
      $menus.hide();
      this.bindOpeners();
      this.bindMenus();
      this.bindNonOpeners();
   }

   /**
    * Bind mouse handlers to As with class "topnav-opener".
    */
   this.bindOpeners = function () {
      // Bind mouseout/mouseover to all menus and openers.
      $openers.each(function(index) {
         $(this).bind("mouseout", function() {
            topNav.closeMenu(this, null, "from opener");
            return false;
         });
         $(this).bind("mouseover", function() {
            topNav.openMenu(this);
            // Removed as this causes errors some times, and will in IE
            return false;
         });
      });
   }

   /**
    * Bind mouse handlers to DIVs with class "topnav-menu".
    */
   this.bindMenus = function () {
      $menus.each(function(index) {
         $(this).bind("mouseout", function() {
            topNav.closeMenu(null, this, "from menu");
            return false;
         });
         $(this).bind("mouseover", function() {
            topNav.keepMenuOpen(this);
            return false;
         });
      });
   }

   /**
    * Bind mouse handlers to As with class "topnav-nonopener".
    */
   this.bindNonOpeners = function () {
      $nonOpeners.each(function(index) {
         $(this).bind("mouseout", function() {
            $(this).removeClass("topnav-mouseover").addClass("topnav-mouseout");
            return false;
         });
         $(this).bind("mouseover", function() {
            $(this).removeClass("topnav-mouseout").addClass("topnav-mouseover");
            return false;
         });
      });
   }


} // end function TopNav()

// Run this when page has finished loading.
$(document).ready(function() {
   var topNavObj = new TopNav();
   topNavObj.init();
});


