// JavaScript code for handling the left nav
// Based on code from 
//     http://www.456bereastreet.com/archive/200705/accessible_expanding_and_collapsing_menu/

/* Here is the structure of the left nav:

        ul class="ln_menu_items"
            li id="ln_one" class="ln_toplevel"
                 ul class="ln_secondlevel"
                     li id="ln_secondlevel_one" ( if hidden, class="ln_hiddensubnav" )
                     li id="ln_secondlevel_two" ( if hidden, class="ln_hiddensubnav" )
                     li id="ln_secondlevel_three" ( if hidden, class="ln_hiddensubnav" )
            li id="ln_two" class="ln_toplevel"
                 ul class="ln_secondlevel"
                     li id="ln_secondlevel_four" ( if hidden, class="ln_hiddensubnav" )
                     li id="ln_secondlevel_five" ( if hidden, class="ln_hiddensubnav" )
                     li id="ln_secondlevel_six" ( if hidden, class="ln_hiddensubnav" )
                     li id="ln_secondlevel_seven" ( if hidden, class="ln_hiddensubnav" )
            li id="ln_three" class="ln_toplevel"
                 ul class="ln_secondlevel"
                     li id="ln_secondlevel_eight" ( if hidden, class="ln_hiddensubnav" )
                     li id="ln_secondlevel_nine" ( if hidden, class="ln_hiddensubnav" )
   
   The classes of the body tag determines what first level
      section the page is from and also what second level
      sub section the page is from. 

   So, for example, if the body has a class of "ln_twon", then
      this page is from the second section of the site.

   If it also has a class of "ln_secondlevel_threeon" then the page
      is in the third sub section.

*/
                     
var toggleMenu = {
	init : function (sContainerClass, sHiddenClass) {
		// This function gets called after the page is loaded
		//
        // sHiddenClass is the name of the class to assign to an element
        //    so that is is hidden.
        // sContainerClass is the class of the element which contains the
        //    menu being controlled.
        //
        // 1. Set class of subNavLIs so that all are hidden except those
        //          in the section of this page
        //       A. Look at body classes. Look for one of the form ln_secondlevel_xxxxon
        //       B. Find the matching subnav LI ( e.g. has id of the form ln_secondlevel_xxxx )
        //       C. Find the top level LI for that subnav
        //       D. Do not hide the subnavs in that top level LI
        // 2. Set the onclick handler for the subNavULs to the toggle_submenu_opening function

        var bodySubNavClass, currentSubNavLI, currentTopLevelLI, topLevelUL, topLevelLIs, topLevelLI, subNavLIs, subNavLI, i, j; 

		// Check for DOM support
		if (!document.getElementById || !document.createTextNode) {
			return;
		} 

		bodySubNavClass = null;
		currentSubNavLI = null;
        bodySubNavClass = this.get_body_subnav_class_number(); // Should return something like "one", "two",..."four"
        if ( bodySubNavClass) {
            currentSubNavLI = document.getElementById( "ln_secondlevel_" + bodySubNavClass ) ;
        }
        if ( currentSubNavLI ) {
            currentTopLevelLI = this.get_topLevelLI_of_subnavLI(currentSubNavLI) ;
        }

        // Get the top level UL for the left nav
		topLevelUL = this.getElementsByClassName(document, 'ul', sContainerClass);

        // Get the LIs below that. These are the first level sections
        topLevelLIs = topLevelUL[0].childNodes;
        // Loop through the top level LIs
		for ( i = 0; i < topLevelLIs.length; i+=1) {
            topLevelLI = topLevelLIs[i] ;

            // Set the class of the top level LI which indicates
            //   whether the LI is in the active section
            toggleMenu.set_active_state_topLevelLI( topLevelLI, topLevelLI === currentTopLevelLI ) ;

            if ( topLevelLI.nodeName === "LI" ) {
                // set the onclick handler for top level LIs
                topLevelLI.onclick = function(){toggleMenu.toggle_submenu_opening(
                                  this, sContainerClass, sHiddenClass); return true;} ;
                topLevelLI.onfocus = function(){toggleMenu.open_submenu(
				                  this, sHiddenClass); return true;} ;
				topLevelLI.onblur = function(){toggleMenu.close_submenu(
								  this, sHiddenClass); return true;} ;

                // Loop through the second level LIs, hiding them if 
                //   the current subsection is not in the same first level
                //   section. Show them if they are in the same first level section
                subNavLIs = topLevelLI.getElementsByTagName('li');
		        for ( j = 0; j < subNavLIs.length; j+=1) {
                    subNavLI = subNavLIs[j] ;
                    if ( currentTopLevelLI && ( topLevelLI === currentTopLevelLI ) ) {
                        this.showElement( subNavLI, sHiddenClass );
                    }
                    else {
                        this.hideElement( subNavLI, sHiddenClass );
                    }
                }
            }
        }

	},

	open_submenu : function (topLevelLI, sHiddenClass) {
		var subNavLIs, j, subNavLI;
		
		if ( this.has_class( topLevelLI, "ln_submenu_closed" ) ) {
            subNavLIs = topLevelLI.getElementsByTagName('li');
            for ( j = 0; j < subNavLIs.length; j+=1) {
                subNavLI = subNavLIs[j] ;
        	    this.showElement( subNavLI, sHiddenClass );
            }
        }
	},
	
	close_submenu : function (topLevelLI, sHiddenClass) {
		var subNavLIs, j, subNavLI;
		
		if ( this.has_class( topLevelLI, "ln_submenu_closed" ) ) {
            subNavLIs = topLevelLI.getElementsByTagName('li');
            for ( j = 0; j < subNavLIs.length; j+=1) {
                subNavLI = subNavLIs[j] ;
        	    this.hideElement( subNavLI, sHiddenClass );
            }
        }
	},
	
	toggle_submenu_opening : function (topLevelLIClicked, sContainerClass, sHiddenClass) {
		// This function gets called when an item is clicked in the left subnav first level
		//    That is, an LI with class="ln_toplevel"
		
        // Toggle subNav LIs below this clicked on topLevelLI
        // Set others to hidden
		
		var topLevelUL,topLevelLIs, topLevelLI, subNavLIs, subNavLI,i, j ;
		
		// Check for DOM support
		if (!document.getElementById || !document.createTextNode) {
			return;
		} 

        // Get the top level UL for the left nav
		topLevelUL = this.getElementsByClassName(document, 'ul', sContainerClass);

        // Get the LIs below that
        topLevelLIs = topLevelUL[0].childNodes;
		for ( i = 0; i < topLevelLIs.length; i+=1) {
            topLevelLI = topLevelLIs[i] ;
            if ( topLevelLI.nodeName === "LI" ) {

                if ( topLevelLI === topLevelLIClicked ) {
                    // toggle the active state of the clicked topLevelLI
                    toggleMenu.toggle_active_state_topLevelLI( topLevelLI ) ;
                }
                else {
                    // turn off the active state of the other topLevelLI's
                    toggleMenu.set_active_state_topLevelLI( topLevelLI, false ) ;
                }

                subNavLIs = topLevelLI.getElementsByTagName('li');
		        for ( j = 0; j < subNavLIs.length; j+=1) {
                    subNavLI = subNavLIs[j] ;
                    if ( topLevelLI === topLevelLIClicked ) {
                        this.toggleElementVisibility( subNavLI, sHiddenClass );
                    }
                    else { // hide all the other LIs
                        this.hideElement( subNavLI, sHiddenClass );
                    }
                }
            }
        }
	},

        /******** Some utility routines we wrote *******/

	get_topLevelLI_of_subnavLI : function(subNavLI) {
        // Given the LI element for the subnav ( second level ) 
        // menu item, return the LI element for the first
        // level menu item
        //
        return subNavLI.parentNode.parentNode ;
	},

	get_body_subnav_class_number : function() {
        // Get the class of the body tag that indicates
        // what subsection the current page is in.
        // The tag should be of the form ln_secondlevel_xxxxon
        //
        // For example, if the body has a class of "ln_secondlevel_fouron", 
        //   this function will return "four"
        //
		var bodyClasses, bodyNode, classes, regex, match, j;
		
        bodyNode = document.getElementsByTagName("body")[0];
        bodyClasses = bodyNode.className ;
        classes = bodyClasses.split(" ") ;
        regex = /^ln_secondlevel_(.*)on$/;
        for (j=0; j<classes.length; j+=1){
            match = regex.exec( classes[j]);
            if ( match ) {
                return match[1] ;
            }
        }
        return null ;
	},

	set_active_state_topLevelLI : function(topLevelLI, is_active) {
        //
		var activeClass, inactiveClass;
        
		activeClass = "ln_submenu_open" ;
        inactiveClass = "ln_submenu_closed" ;

        if ( is_active ) {
            toggleMenu.add_class( topLevelLI, activeClass ) ;
            toggleMenu.remove_class( topLevelLI, inactiveClass ) ;
        }
        else {
            toggleMenu.add_class( topLevelLI, inactiveClass ) ;
            toggleMenu.remove_class( topLevelLI, activeClass ) ;
        }
	},

	toggle_active_state_topLevelLI : function(topLevelLI) {
        //
		var activeClass, inactiveClass;

        activeClass = "ln_submenu_open" ;
        inactiveClass = "ln_submenu_closed" ;

        if ( this.has_class( topLevelLI, activeClass ) ) {
            toggleMenu.add_class( topLevelLI, inactiveClass ) ;
            toggleMenu.remove_class( topLevelLI, activeClass ) ;
        }
        else {
            toggleMenu.add_class( topLevelLI, activeClass ) ;
            toggleMenu.remove_class( topLevelLI, inactiveClass ) ;
        }
	},

	hideElement : function(el, sHiddenClass) {
        // Hide an element by adding a class
        // name sHiddenClass. It checks first to see if
        // the element already has that class before adding it
        //
		toggleMenu.add_class( el, sHiddenClass ) ;
	},

	add_class : function(el, className) {
        //
		var oRegExp = new RegExp("(^|\\s)" + className + "(\\s|$)");
        if (!oRegExp.test(el.className)) {
            el.className = el.className + ' ' + className;
        }
	},

	showElement : function(el, sHiddenClass) {
        // Show ( un hide )  an element by removing a class
        // name sHiddenClass. It checks first to see if
        // the element already has that class before removing it
        //
        toggleMenu.remove_class( el, sHiddenClass );
	},

	remove_class : function(el, className) {
		var oRegExp = new RegExp("(^|\\s)" + className + "(\\s|$)");
		
        if (oRegExp.test(el.className)) {
            el.className = el.className.replace(oRegExp, ' ');
        }
	},

	has_class : function(el, className) {
		var oRegExp = new RegExp("(^|\\s)" + className + "(\\s|$)");
		
        return oRegExp.test(el.className) ;
	},

	toggleElementVisibility : function(el, sHiddenClass) {
        // show the element if it was hidden, hide it if it was shown
		var oRegExp = new RegExp("(^|\\s)" + sHiddenClass + "(\\s|$)");
		
        // Add or remove the class name that hides the element
		el.className = oRegExp.test(el.className) ? el.className.replace(oRegExp, '') : el.className + ' ' + sHiddenClass; 
	},


    /****** These next two functions are utility functions taken from other sources *****/

    /* addEvent function from http://www.quirksmode.org/blog/archives/2005/10/_and_the_winner_1.html */
	addEvent : function(obj, type, fn) {
		if (obj.addEventListener) {
			obj.addEventListener(type, fn, false);
        }
		else 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]);
		}
	},
    /*
         Following written by Jonathan Snook, http://www.snook.ca/jonathan
         Add-ons by Robert Nyman, http://www.robertnyman.com
    */
	getElementsByClassName : function(oElm, strTagName, strClassName){
		var arrElements, arrReturnElements, oRegExp, oElement, i ;
		
	    arrElements = (strTagName === "*" && document.all)? document.all : oElm.getElementsByTagName(strTagName);
	    arrReturnElements = new Array();
	
	    strClassName = strClassName.replace(/\-/g, "\\-");
	    oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
	    for( i=0; i<arrElements.length; i+=1){
	        oElement = arrElements[i];      
	        if(oRegExp.test(oElement.className)){
	            arrReturnElements.push(oElement);
	        }   
	    }
	    return (arrReturnElements) ;
	}
};


// This gets everything started. When the page is done loading, initialize everything
toggleMenu.addEvent(window, 'load', function(){toggleMenu.init('ln_menu_items','ln_hiddensubnav');}); 
