/**
 * Returns the direct children of the given object with the specified
 * element name.
 */
function getChildElementsByTagName(obj, tagname) {
    tagname = tagname.toUpperCase();
	var matching = [];
    var child = obj.firstChild;
    while (child) {
        if (child.nodeType == 1 &&
            (child.nodeName.toUpperCase() == tagname)) {
            matching.push(child);
        }
        child = child.nextSibling;
    }
    return matching;
}


if (typeof CDC == "undefined") var CDC = new Object();
if (typeof CDC.LeftNav == "undefined") CDC.LeftNav = new Object();
CDC.LeftNav = function(ulTagId, parentUrl, showSiblings, showChildren) {

	//Set class-level variables
	var currentLocation = (location.hostname + location.pathname).toLowerCase();
	var directoryDefault = false;
	//default document array must be in lower case
	var documentArray = new Array("index.htm", "index.html", "default.html", 
								  "default.htm", "index.asp", "index.aspx", 
								  "default.asp", "default.aspx");
	
	var directoryDefault = false;
	if (currentLocation.substr(currentLocation.length - 1, 1) == "/") {
		directoryDefault = true;
	}
	
	this.attributes = new Array();
	if (typeof ulTagId == "undefined")
		this.setAttribute("CDC_LEFT_NAV_ID", "nav-primary");
	else
		this.setAttribute("CDC_LEFT_NAV_ID", ulTagId);
	if (typeof parentUrl == "undefined")
		this.setAttribute("parentUrl", this.normalizedUrl(currentLocation));
	else
		this.setAttribute("parentUrl", this.normalizedUrl(parentUrl));
	if (typeof showSiblings == "undefined")
		this.setAttribute("showSiblings", true);
	else
		this.setAttribute("showSiblings", showSiblings);
	if (typeof showChildren == "undefined")
		this.setAttribute("showChildren", true);
	else
		this.setAttribute("showChildren", showChildren);

	this.setAttribute("documentArray", documentArray);
	this.setAttribute("currentLocation", currentLocation);
	this.setAttribute("directoryDefault", directoryDefault);

	this.setAttribute("CDC_LEFT_NAV_HIDE_CLASS", "ulHide");
	this.setAttribute("CDC_LEFT_NAV_DISPLAY_CLASS", "ulDisplay");
	this.setAttribute("preProcessTrees", true);

}
CDC.LeftNav.prototype = {

	//**************************************************//
	// Get/set attributes
	//**************************************************//
	setAttribute: function(name, value){
		this.attributes[name] = value;
	},
	getAttribute: function(name){
		return this.attributes[name];
	},

	//**************************************************//
	//       Left nav/breadcrumbs highlight functions   //
	//**************************************************//
	render: function () {
		var id = this.getAttribute("CDC_LEFT_NAV_ID");
		var parentUrl = this.getAttribute("parentUrl");
		this.setAttribute("currentLocation", parentUrl);
		var currentLocation = this.getAttribute("currentLocation");
		var leftNav = GetElementById(id);
		if (leftNav) {
			// we'v found a left nav element so process it
			this.convertTrees(id);
			this.expandToItem(id, parentUrl);
		}
	},

	normalizedUrl: function(url) {
		var result = url.toLowerCase();
		result = result.replace("http://", "");
		result = result.replace("https://", "");
		result = result.replace(location.hostname, "");
		return result;
	},
	
	// Tests to see whether passed <a> href value is the current URL
	isSelectedLink: function(link) {
		var documentArray = this.getAttribute("documentArray");
		var directoryDefault = this.getAttribute("directoryDefault");
		var currentLocation = this.getAttribute("currentLocation").toLowerCase();
		var found = false;
		var curLink = this.normalizedUrl(link.href);
		
		// Test for directory default documents.	
		if (curLink == currentLocation) {
			found = true;
		}
		else if (directoryDefault) {
			for (doc in documentArray) {
				if (curLink == currentLocation + documentArray[doc]) {
					found = true;
				}
			}
		}
		return(found);
	},

	/*
	 * This function changes the class of the specified element to the given class.  If the class
	 * specified is the constant CDC_LEFT_NAV_HIDE_CLASS then this function also sets the display
	 * attribute to "none" to effectively hide the element.  Otherwise, it display attribute is 
	 * set to "block" so that it will appear on the rendered page.
	 */
	transformDisplay: function(currentElement, newClass) {
	
		var hideClass = this.getAttribute("CDC_LEFT_NAV_HIDE_CLASS");
		if (currentElement && currentElement.nodeName != "#text") {
			if (newClass == hideClass) {
				currentElement.className = newClass;
			}
			else {
				currentElement.className = newClass;
			}
		}
	
	},

	/**
	 * Copyright (c)2005-2007 Matt Kruse (javascripttoolbox.com)
	 * 
	 * Dual licensed under the MIT and GPL licenses. 
	 * This basically means you can use this code however you want for
	 * free, but don't claim to have written it yourself!
	 * Donations always accepted: http://www.JavascriptToolbox.com/donate/
	 * 
	 * Please do not link to the .js files on javascripttoolbox.com from
	 * your site. Copy the files locally to your server instead.
	 * 
	 */
	/*
	This code is inspired by and extended from Stuart Langridge's aqlist code:
			http://www.kryogenix.org/code/browser/aqlists/
			Stuart Langridge, November 2002
			sil@kryogenix.org
			Inspired by Aaron's labels.js (http://youngpup.net/demos/labels/) 
			and Dave Lindquist's menuDropDown.js (http://www.gazingus.org/dhtml/?id=109)
	*/
	/*
	Additional modifications were made to this code to utilize URLs (as opposed to IDs) as the
	key to locate an item in the list that should be selected.  In addition, some helper methods 
	developed in-house for CDC were used for setting styles, URL parsing, etc.
	*/
		
	//******************************************************************************************************//
	// Fully expands a tree with a given ID
	//******************************************************************************************************//
	expandTree: function(treeId) {
		var ul = GetElementById(treeId);
		if (ul == null) { return false; }
		this.expandCollapseList(ul, CDC_LEFT_NAV_DISPLAY_CLASS);
	},
	
	//******************************************************************************************************//
	// Fully collapses a tree with a given ID
	//******************************************************************************************************//
	collapseTree: function(treeId) {
		var hideClass = this.getAttribute("CDC_LEFT_NAV_HIDE_CLASS");
		var ul = GetElementById(treeId);
		if (ul == null) { return false; }
		this.expandCollapseList(ul, hideClass);
	},
	
	//******************************************************************************************************//
	// Expands enough nodes in a tree to expose an LI with an anchor that has the given URL.
	//******************************************************************************************************//
	expandToItem: function(treeId, linkUrl) {
		var displayClass = this.getAttribute("CDC_LEFT_NAV_DISPLAY_CLASS");
		var ul = GetElementById(treeId);
		if (ul == null) { return false; }
		
		// Always should expand the first level LIs.
		var liItems = getChildElementsByTagName(ul, "li");
		if (liItems && liItems.length > 0) {
			for (var i = 0; i < liItems.length; i++) {
				var liItem = liItems[i];
				this.transformDisplay(liItem, displayClass);
			}
		}
		if (this.isSelectedLink(this.getTopicLink())) {
			linkUrl = null;
		}
		var ret = this.expandUlItem(ul, linkUrl);
	},

	expandUlItem: function(theUl, linkUrl) {
		var displayClass = this.getAttribute("CDC_LEFT_NAV_DISPLAY_CLASS");
		var showSiblings = this.getAttribute("showSiblings");
		var showChildren = this.getAttribute("showChildren");
		var currentLocation = this.getAttribute("currentLocation").toLowerCase();
		var liItems = getChildElementsByTagName(theUl, "li");
		if (liItems && liItems.length > 0) {
			for (var i = 0; i < liItems.length; i++) {
				var liItem = liItems[i];
				var links = liItem.getElementsByTagName("a");			
				if (links != null && links.length > 0) {
					var theLink = links[0];
					
					if (this.isSelectedLink(theLink)) {

						this.transformDisplay(liItem, displayClass);

						var p;						
						var temp = theLink.href.toLowerCase();
						if (temp.indexOf(location.pathname.toLowerCase()) < 0 && showChildren) {
							var newUlNode = document.createElement("ul");
							var newLiNode = document.createElement("li");
							var newANode = document.createElement("a");
							newANode.href = document.location;
							newANode.className = "selected";
							var newTextNode = document.createTextNode(document.title);
							newUlNode.appendChild(newLiNode);
							newLiNode.appendChild(newANode);
							newANode.appendChild(newTextNode);
							liItem.appendChild(newUlNode);
							p = liItem;
						}
						else if (temp.indexOf(location.pathname.toLowerCase()) < 0 && !showChildren) {
							this.transformDisplay(theLink, "selected");
							p = liItem;
						}
						else {
							this.transformDisplay(theLink, "selected");
							p = liItem.parentNode;
						}

						if (showChildren) {
							var childUlItems = getChildElementsByTagName(liItem, "ul");
							if (childUlItems && childUlItems.length > 0) {
								var childUl = childUlItems[0];
								this.transformDisplay(childUl, displayClass);
								var childrenLis = getChildElementsByTagName(childUl, "li");
								if (childrenLis && childrenLis.length > 0) {
									for (k = 0; k < childrenLis.length; k++) {
										this.transformDisplay(childrenLis[k], displayClass);
									}
								}
							}
						}

						if (showSiblings) {
							if (p.nodeName.toLowerCase() == "ul") {
								var siblings = getChildElementsByTagName(p, "li");
								if (siblings && siblings.length > 0) {
									for (j = 0; j < siblings.length; j++) {
										this.transformDisplay(siblings[j], displayClass);
									}
								}
							}
							else if (p.nodeName.toLowerCase() == "li") {
								var siblings = getChildElementsByTagName(p.parentNode, "li");
								if (siblings && siblings.length > 0) {
									for (j = 0; j < siblings.length; j++) {
										this.transformDisplay(siblings[j], displayClass);
									}
								}
							}
						}
												
						// Build the breadcrumb from the hierarchy of the left nav that got us to the 
						// selected list element.
						var crumbs = new Array();
						while (p) {
							if (p.tagName.toLowerCase() != "div") {
								// Make sure the path to this element is visible.
								this.transformDisplay(p, displayClass);
								// If we have an anchor then add it to the array.
								if (p.tagName.toLowerCase() == "li") {
									var parentAnchors = p.getElementsByTagName("a");
									if (parentAnchors && parentAnchors.length > 0) {
										crumbs.push(parentAnchors[0]);
									}
								}								
							} else {
								break;
							}
							p = p.parentNode;
						}

						var bcElem = GetElementById("breadcrumbs");
						if (bcElem) {
							var tlink = this.getTopicLink();
							if (tlink != null)
								crumbs.push(tlink);
								
							var breadcrumbLis = getChildElementsByTagName(bcElem, "li");
							if (breadcrumbLis) {
								var firstBreadcrumbLi = breadcrumbLis[0];
								if (firstBreadcrumbLi.style.display.toLowerCase() == "none") {
									bcElem.removeChild(firstBreadcrumbLi);
								}
							}
							for (var j = crumbs.length - 1; j >= 0; j--) {							
								var newLiNode = document.createElement("li");
								if (j == crumbs.length - 1)
									newLiNode.className = "firstChild";
								var newANode = document.createElement("a");
								newANode.href = crumbs[j].href;
								var newTextNode = document.createTextNode(crumbs[j].innerHTML);
								bcElem.appendChild(newLiNode);
								newLiNode.appendChild(newANode);
								newANode.appendChild(newTextNode);
							}
						}

					} else {
						var childUlItems = getChildElementsByTagName(liItem, "ul");
						if (childUlItems && childUlItems.length > 0) {
							this.expandUlItem(childUlItems[0], linkUrl);
						}
					}
				}
			}
		}
	},

	//******************************************************************************************************//
	// A utility method to get the anchor element from the H3 header element within the left navigation DIV.
	// This is considered the topic "home" and the top level of the navigational hierarchy.
	//******************************************************************************************************//
	getTopicLink: function() {
		var topicLink = null;
		var navDiv = GetElementById("nav");
		if (navDiv) {
			var navHeaders = navDiv.getElementsByTagName("h3");
			if (navHeaders && navHeaders.length > 0) {
				var navHeader = navHeaders[0];
				var anchors = navHeader.getElementsByTagName("a");
				if (anchors && anchors.length > 0) {
					topicLink = anchors[0];
				}
			}
		}
		return topicLink;
	},
	
	//******************************************************************************************************//
	// Performs 3 functions:
	// a) Expand all nodes
	// b) Collapse all nodes
	// c) Expand all nodes to reach a certain LI that contains an anchor with the given URL.
	//******************************************************************************************************//
	expandCollapseList: function(ul, cName, linkUrl) {
	
		var showSiblings = true;
		var showChildren = true;
		if (!ul.childNodes || ul.childNodes.length == 0) { return false; }

		var childItems = ul.getElementsByTagName("LI");

		// Iterate LIs
		for (var itemi = 0; itemi < childItems.length; itemi++) {
	
			var childItem = childItems[itemi];
			var link = childItem.getElementsByTagName("A")[0];		

			if (linkUrl != null && this.isSelectedLink(link)) { 
	
				// We've found the LI that corresponds to the page that we are on.  Set the
				// anchor style to indicate that is is selected.
				this.transformDisplay(childItem, cName);
				this.transformDisplay(link, "selected");
	
				// If we are supposed to show the children then look to see if this LI item is a
				// parent (i.e., it contains a UL element) and display its children if it is.
				if (showChildren) {
					for (var itemj = 0; itemj < childItem.childNodes.length; itemj++) {
						var childULItem = childItem.childNodes[itemj];
						if (childULItem && childULItem.nodeName.toLowerCase() == "ul") {
							this.transformDisplay(childULItem, cName);
							for (var itemk = 0; itemk < childULItem.childNodes.length; itemk++) {
								var childLIItem = childULItem.childNodes[itemk];
								if (childLIItem && childLIItem.nodeName.toLowerCase() == "li") {						
									this.transformDisplay(childLIItem, cName);
								}
							}
						}
					}
				}
	
				// If we are supposed to show siblings then make sure the siblings that are at the 
				// same level as the selected element are turned on.
				if (showSiblings) {
					var parent = childItem.parentNode;
					if (parent) {
						for (var itemj = 0; itemj < parent.childNodes.length; itemj++) {
							var sibItem = parent.childNodes[itemj];
							if (sibItem && sibItem.nodeName.toLowerCase() == "li") {
								this.transformDisplay(sibItem, cName);
							}
						}
					}
				}
	
				// Build the breadcrumb from the hierarchy of the left nav that got us to the selected list element.
				var crumbs = new Array();
				var p = childItem.parentNode;
				while (p) {
					if (p.nodeName.toLowerCase() == "li") {
						var a = p.getElementsByTagName("a")[0];
						crumbs.push(a);
					}
					p = p.parentNode;
				}
				var bcElem = GetElementById("breadcrumbs");
				if (bcElem) {
					var tlink = this.getTopicLink();
					if (tlink != null)
						crumbs.push(tlink);
					var breadcrumbs = bcElem.innerHTML;
					for (var j = crumbs.length - 1; j >= 0; j--) {
						breadcrumbs = breadcrumbs + '<li><a href="' + crumbs[j].href + '">' + crumbs[j].innerHTML + '</a></li>';
					}
					bcElem.innerHTML = breadcrumbs;
				}
				
				// That's it.  We're done.
				return true; 
			}
			else {
				// This means we are at a topic home.  Just render/show these top-level LI elements.
				this.transformDisplay(childItem, cName);
			}

			if (linkUrl != null) {
	
				this.transformDisplay(childItem, cName);
	
				// If we have showSiblings enabled, we need to show the siblings at each level of the
				// hierarchy in addition to the selected level.
				if (showSiblings) {
					var parent = childItem.parentNode;
					if (parent) {
						for (var itemj = 0; itemj < parent.childNodes.length; itemj++) {
							var sibItem = parent.childNodes[itemj];
							if (sibItem && sibItem.nodeName.toLowerCase() == "li") {
								this.transformDisplay(sibItem, cName);
							}
						}
					}
				}
				
				// Now iterate through all of the elements in this LI
				var subLists = false;
				for (var sitemi = 0; sitemi < childItem.childNodes.length; sitemi++) {
					var sitem = childItem.childNodes[sitemi];
					if (sitem.nodeName.toLowerCase() == "ul") {
						subLists = true;
						var ret = this.expandCollapseList(sitem, cName, linkUrl);
						if (linkUrl != null && ret) {
							this.transformDisplay(sitem, cName);
							return true;
						}
					}
				}
				// Handle the expand all case when there is no linkUrl specified.
				if (subLists && (linkUrl == null)) {
					this.transformDisplay(childItem, cName);
				}
			}
			
		}
	},
	
	// Search the document for UL elements with the correct ID, then process them
	convertTrees: function(theId) {
		var displayClass = this.getAttribute("CDC_LEFT_NAV_DISPLAY_CLASS");
		var hideClass = this.getAttribute("CDC_LEFT_NAV_HIDE_CLASS");
		var preProcessTrees = this.getAttribute("preProcessTrees");
		if (preProcessTrees) {
			if (!document.createElement) { return; } // Without createElement, we can't do anything
			var uls = document.getElementsByTagName("ul");
			if (uls == null) { return; }
			var uls_length = uls.length;
			for (var uli = 0; uli < uls_length; uli++) {
				var ul = uls[uli];
				if (ul.nodeName.toLowerCase() == "ul" && ul.id == theId) {
					this.transformDisplay(ul, displayClass);
					this.processList(ul);
				}
			}
		}
	},

	// Process a UL tag and all its children, to convert to a tree.  By default,
	// everything in the tree will be hidden.
	processList: function(ul) {
		var hideClass = this.getAttribute("CDC_LEFT_NAV_HIDE_CLASS");
		if (!ul.childNodes || ul.childNodes.length == 0) { return; }
		// Iterate LIs		
		var childLis = ul.getElementsByTagName("li");		
		var childLisLength = childLis.length;
		for (var itemi = 0; itemi < childLisLength; itemi++) {
			var childLi = childLis[itemi];
			this.transformDisplay(childLi, hideClass);

			// Iterate things in this LI
			var childUls = childLi.getElementsByTagName("ul");
			var childUlsLength = childUls.length;
			if (childUlsLength > 0) {
				if (childLi.className == null || childLi.className == "") {
					this.transformDisplay(childLi, hideClass);
				}
			}
			for (var childUlIndex = 0; childUlIndex < childUlsLength; childUlIndex++) {
				var childUl = childUls[childUlIndex];
				this.transformDisplay(childUl, hideClass);
				this.processList(childUl);
			}
		}
	}

}

