// listnav.js

/* -------------------------------------------------------------------

<ul>																							+								
	<li>																+						|
		<a>...</a>			- Page						|						|
		<ul>						+									| 					|
			...						| ChildContainer	| Item			| ParentContainer
		</ul>						+									|						|
	</li>																+						|
	...																							|
</ul>																							+

---------------------------------------------------------------------- */

function getNavButtons(pageElement) 
{
	navButtonsHTML = "";
	navButtonsHTML += formatNamedPageElement(getFirstSiblingPage(pageElement), "First");
	navButtonsHTML += " ";

	navButtonsHTML += formatNamedPageElement(getPrevSiblingPage(pageElement), "Prev");
	navButtonsHTML += " ";

	navButtonsHTML += formatNamedPageElement(getContainerTitlePage(pageElement), "Up");
	navButtonsHTML += " ";


	navButtonsHTML += formatNamedPageElement(getNextSiblingPage(pageElement), "Next");
	navButtonsHTML += " ";

	navButtonsHTML += formatNamedPageElement(getLastSiblingPage(pageElement), "Last");

	return navButtonsHTML;
}

function getSectionContainer(containerElement) {
	
}

function getBreadcrumbList(pageElement, rootPageElement, divider) 
{
	// get breadcrumb elements
	bcElements = getBreadcrumbPageList(pageElement, rootPageElement);

	// format breadcrumb list
	bcTrailHTML = formatPageList(bcElements, divider);
	
	return bcTrailHTML;
}

function getTitleBarList(pageElement, rootPageElement, divider) 
{
	// get breadcrumb elements
	tbElements = getBreadcrumbPageList(pageElement, rootPageElement);

	// format breadcrumb list
	tbHTML = formatPageTitleList(tbElements, divider);
	
	return tbHTML;
}



function getSiblingPageList(pageElement, divider) {
	if (!divider) divider = "";

	// get parent UL
	parentSectionUL = getParentContainer(pageElement);

	return formatContainerTopLevelChildren(parentSectionUL, divider);
}

function getBreadcrumbPageList(pageElement, rootElement) {
	breadcrumbElements = new Array();

	// if rootElement is specifed, get it's href
	rootHref = '';

	if (rootElement && isElementNode(rootElement))
	{
		rootHref = rootElement.getAttribute('href');
	}
	
	// starting with the current page, get all ancestor pages [up to rootElement]
	breadcrumbElement = pageElement;
	
	while (breadcrumbElement) {
		// add element to list
		breadcrumbElements[breadcrumbElements.length] = breadcrumbElement;

		// stop if current element is the rootElement
		if (breadcrumbElement.getAttribute('href') == rootHref) {
			break;
		}
		else {  // otherwise continue up ancestory
			breadcrumbElement = getContainerTitlePage(breadcrumbElement);
		}
	}

	// reverse elements, so that top ancestor appears first
	breadcrumbElementsReversed = breadcrumbElements.reverse();
	
	return breadcrumbElementsReversed;
}

function getContainerTitlePage(pageElement) {
	// get the parent LI
	containingUL = getParentContainer(pageElement);
	parentLI = containingUL.parentNode;

	// get the A Element of the parentLI
	if (parentLI.nodeName != "li")	
	{
		return null;
	}
	else {
		parentA = parentLI.firstChild;
		parentA = skipTextNodesForwards(parentA);
		
		return parentA;
	}
}

function getTopLevelChildrenList(containerElement) {
	// starting with the first child LI, get all child LIs
	sibElements = new Array();
	currentLI = containerElement.firstChild;
	while (currentLI) {
		// skip text nodes
		currentLI = skipTextNodesForwards(currentLI);

		if (currentLI) {
			// get A Element contained with LI 
			childA = getContainedPage(currentLI);
			
			// add A Element to list
			sibElements[sibElements.length] = childA;
			
			// proceed to next LI
			currentLI = currentLI.nextSibling;
		}
	}

	return sibElements;
}

function getPrevSiblingPage(pageElement) {
	// get previous sibling of containing LI
	containgLI = getContainingItem(pageElement);
	prevLI = containgLI.previousSibling;

	// skip text nodes
	prevLI = skipTextNodesBackwards(prevLI);
	
	prevA = null;
	
	// get A Element contained with LI
	if (prevLI) {
		prevA = getContainedPage(prevLI);
	}
	
	return prevA;
}

function getNextSiblingPage(pageElement) {
	// get next sibling of containing LI
	containgLI = getContainingItem(pageElement);
	nextLI = containgLI.nextSibling;

	// skip text nodes
	nextLI = skipTextNodesForwards(nextLI);
	
	nextA = null;
	
	// get A Element contained with LI
	if (nextLI) {
		nextA = getContainedPage(nextLI);
	}
	
	return nextA;
}

function getFirstSiblingPage(pageElement) {
	// get first LI of parent UL
	parentSectionUL = getParentContainer(pageElement);
	firstLI = parentSectionUL.firstChild;
	
	// skip text nodes
	firstLI = skipTextNodesForwards(firstLI);
	
	firstA = null;
	
	// get A Element contained with LI
	if (firstLI) {
		firstA = getContainedPage(firstLI);

		// disable link if this is already the first page
		if (firstA.getAttribute('href')== pageElement.getAttribute('href')) {
			firstA = null;
		}
	}
	
	return firstA;
}

function getLastSiblingPage(pageElement) {
	// get last LI of parent UL
	parentSectionUL = getParentContainer(pageElement);
	lastLI = parentSectionUL.lastChild;
	
	// skip text nodes
	lastLI = skipTextNodesBackwards(lastLI);

	lastA = null;
	
	// get A Element contained with LI
	if (lastLI) {
		lastA = getContainedPage(lastLI);

		// disable link if this is already the last page
		if (lastA.getAttribute('href')== pageElement.getAttribute('href')) {
			lastA = null;
		}
	}
	
	return lastA;
}

function getAncestorContainerOfClass(pageElement, className) {
	// get the parent UL
	parentUL = getParentContainer(pageElement);
	
	el = null;
	if (parentUL != null) {
		// test if it matches specifed class
		if (hasCssClass(parentUL, className)) {
			el	= parentUL;
		}
		else { // recurse up ancestory
			el = getAncestorContainerOfClass(parentUL, className);
		}
	}
	
	return el;
}



function getTitlePage(pageElement) {
	// expects a container UL
	
	// get the title LI
	titleA = pageElement.previousSibling;

	// skip text nodes
	titleA = skipTextNodesBackwards(titleA);

	// skip over description div
	if (titleA.nodeName == 'div') {
		// skip over description
		titleA = titleA.previousSibling;
	
		// skip text nodes
		titleA = skipTextNodesBackwards(titleA);
	}


	return titleA;
}


function getParentContainer(pageElement) {
	// get the parent UL
	containingLI = pageElement.parentNode;
	containingUL = containingLI.parentNode;

	return containingUL;
}

function getChildContainer(pageElement) {
	// get the child container UL (of this A)
	childUL = pageElement.nextSibling;
	childUL = skipTextNodesForwards(childUL);

	// skip over description div
	if (childUL.nodeName == 'div') {
		childUL = childUL.nextSibling;
		childUL = skipTextNodesForwards(childUL);
	}
		
	return childUL;
}

function getContainingItem(pageElement) {
	// get the container LI of this A element
	containingLI = pageElement.parentNode;

	return containingLI;
}

function getContainedPage(itemElement) {
	// get the contained A element of this LI
	currentEl = itemElement.firstChild;
	currentEl = skipTextNodesForwards(currentEl);
	
	return currentEl;
}

function skipForwardsTo(element, tagName, className) {
	while (element && (element.nodeName != tagName) && (element.getAttribute('class') != className))
	{
		element = element.nextSibling;
	}
}

function skipBackwardsTo(element, tagName, className) {
	while (element && (element.nodeName != tagName) && (element.getAttribute('class') != className))
	{
		element = element.previousSibling;
	}
}


function skipTextNodesForwards(element) {
	while (element && (isTextNode(element) || isCommentNode(element) || (element.getAttribute('class') == "NoNav")))
	{
		element = element.nextSibling;
	}

	return element;
}

function skipTextNodesBackwards(element) {
	while (element && (isTextNode(element) || isCommentNode(element) || (element.getAttribute('class') == "NoNav")))
  {
		element = element.previousSibling;
	}

	return element;
}

function skipCommentNodesForwards(element) {
	while (element && isCommentNode(element))
	{
		element = element.nextSibling;
	}

	return element;
}

function skipCommentNodesBackwards(element) {
	while (element && isCommentNode(element))
  {
		element = element.previousSibling;
	}

	return element;
}

function formatPageElement(pageElement) {
	aHTML = "";
	if (pageElement) {
		aHTML = "<a href=\"" + pageElement.getAttribute('href') + "\">" + pageElement.firstChild.nodeValue + "</a>";
	}

	return aHTML;
}

function formatNamedPageElement(pageElement, name) {
	aHTML = "";
	
	if (pageElement) {
		if (name) {
			aHTML = "<a href=\"" + pageElement.getAttribute('href') + "\">" + name + "</a>";
		}
		else {
			aHTML = "<a href=\"" + pageElement.getAttribute('href') + "\">" + pageElement.nodeValue + "</a>";
		}
	}
	else {
		aHTML = "<span>" + name + "</span>";
	}

	return aHTML;
}


function formatContainer(containerElement) {
	branchHTML = getXMLstring(containerElement);
	
	return branchHTML;
}

function formatContainerTopLevelChildren(containerElement, divider) {
	if (!divider) divider = "";

	pages = getTopLevelChildrenList(containerElement);

	// format list of siblings
	pagesHTML = formatPageList(pages, divider);
	
	return pagesHTML;
}

function formatPageList(pageElementList, divider) {
	if (!divider) divider = "";
	
	elListHTML = "<ul>";

	// format each list item
	first = true;

	pageElementListLength = pageElementList.length;
  for (var n = 0; n < pageElementListLength; n++) {
  	pageElement = pageElementList[n];

		if (first) {
			elListHTML += "<li>" + formatPageElement(pageElement) + "</li>";
			first = false;
		}
		else {
			elListHTML += "<li>" + divider + formatPageElement(pageElement) + "</li>";
		}
  }
	
	elListHTML += "</ul>";
	
	return elListHTML;
}

function formatPageTitleList (pageElementList, divider) {
	if (!divider) divider = "";
	
	elListHTML = "";

	// format each list item
	first = true;

	pageElementListLength = pageElementList.length;
  for (var n = 0; n < pageElementListLength; n++) {
  	pageElement = pageElementList[n];

		if (first) {
			elListHTML += formatSiteTitle(pageElement);
			first = false;
		}
		else {
			elListHTML += divider + formatPageTitle(pageElement);
		}
  }
	
	return elListHTML;
}

function formatPageTitle(pageElement) {
	return pageElement.firstChild.nodeValue;
}

function formatSiteTitle(pageElement) {
	return pageElement.getAttribute('title');
}

function getPage(targetURL, sitemapDOM) {
	// by default matchingElement is null, ie not found
	matchingEl = null;

	// find all A elements from sitemap
	aElements = sitemapDOM.getElementsByTagName('a');

	// find A tag that matches the target URL
	aElementsLength = aElements.length;
  for (var n = 0; n < aElementsLength; n++) {
  	pageElement = aElements[n];

		pageElementHref = pageElement.getAttribute('href');
		
		if (pageElement.getAttribute('href') == targetURL) {
			// matching URL found
			matchingEl = pageElement;
			break;
		}
	}

	// return matchingElement or null
	return matchingEl;
}

function hasCssClass(element, className) {
	elClasses = element.getAttribute('class');
	match = false;
	
	// todo: upgrade to support multiple class spec
	if (elClasses == className) {
		match = true;
	}
	
	return match;
}

function isTextNode(element) {
	return (element.nodeType == 3);
}


function isCommentNode(element) {
	return (element.nodeType == 8);
}


function isElementNode(element) {
	return (element.nodeType == 1);
}

var isIE = window.ActiveXObject;
var isMoz = document.implementation && document.implementation.createDocument;
var isOpera = window.opera;

function getSitemapDOMfromFile(sitenavFilename, callbackFn) {
	//load xml file
	// code for IE
	if (isIE) {
	  xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
	  xmlDoc.async=false;
	  xmlDoc.load(sitenavFilename);
	  callbackFn();
	}
	// code for Mozilla, etc.
	else if (isMoz)
  {
	  xmlDoc= document.implementation.createDocument("","",null);
	  xmlDoc.load(sitenavFilename);
	  xmlDoc.onload=callbackFn;
  }
}

function createXMLDocumentFromString(xmlString) {
	myDocument = null;
	
	if (isMoz) { 
		// Mozilla, create a new DOMParser 
		var parser = new DOMParser(); 
		myDocument = parser.parseFromString(xmlString, "text/xml"); 
	} 
	else if (isIE) { 
		// Internet Explorer, create a new XML document using ActiveX 
		// and use loadXML as a DOM parser. 
		myDocument = new ActiveXObject("Microsoft.XMLDOM") 
		myDocument.async="false"; 
		myDocument.loadXML(xmlString);   
	} 
	
	return myDocument;
}

function getXMLstring(el) {
	return Sarissa.serialize(el);
}

/*
function getXMLstring(el) {
	var retStr = "";

	if (isIE) {
		if (el.xml) {
			retStr = el.xml;
		}
		else if (el.outerHTML) {
			retStr = el.outerHTML;
		}
	}
	else if (isMoz || isOpera) {
	  // create serializer object
	  var xmlSerializer = new XMLSerializer();

	  // serialize
	  retStr = xmlSerializer.serializeToString(el);
	}	
	
	return retStr;
}
*/

function replaceElementContent(elementId, content) {
	el = document.getElementById(elementId);
	el.innerHTML = content;
}

function appendElementContent(elementId, content) {
	el = document.getElementById(elementId);
	el.innerHTML += content;
}

function replaceNodeContent(targetNode, content) {
	targetNode.innerHTML = content;
}

function appendNodeContent(targetNode, content) {
	targetNode.innerHTML += content;
}

function getNodeOuterHTML(targetNode) {
	tocBoxStr = "";
	if (targetNode.outerHTML) {
		outerHTMLStr = targetNode.outerHTML;
	}
	else {
		outerHTMLStr = formatContainer(targetNode);
	}
	
	return outerHTMLStr;
}

function embedClonedContent(targetElementId, contentNode, deep) {
	var targetEl = document.getElementById(targetElementId);
	var clonedNode = null;
	
	if (document.importNode) {
		clonedNode = document.importNode(contentNode, deep);
	}
	else {
		clonedNode = importNode(contentNode, deep);
	}

	removeChildren(targetEl);
	targetEl.appendChild(clonedNode);
}



function getCurrentPageRelativeURL(protocol, domain) {
	var prefixStr = protocol + domain;
	
	return location.href.substring(location.href.indexOf(prefixStr) + prefixStr.length);
}


function getURLpath(url) {
	domainStart = url.indexOf('//') + 2;
	pathStart = url.indexOf('/', domainStart);
	pathStr = url.substring(pathStart);
	
	return pathStr;
}

function getURLdomain(url) {
	domainStart = url.indexOf('//') + 2;
	pathStart = url.indexOf('/', domainStart);
	pathStr = url.substring(0, pathStart);
	
	return pathStr;
}

function getURLprotocol(url) {
	protocolEnd = url.indexOf('//') + 2;
	protocolStr = url.substring(0, protocolEnd);
	
	return protocolStr;
}


/* Compatability Functions */

/* can we use importNode()? [if not, this must be an IE client] */
if (!document.importNode) {
	function importNode(node, allChildren) {
		switch (node.nodeType) {
			case 1: /* NODE_ELEMENT */
				var newNode = document.createElement(node.nodeName);

				/* does the node have any attributes to add? */
				if (node.attributes && node.attributes.length > 0) {
					for (var i = 0, il = node.attributes.length; i < il;) {
						newNode.setAttribute(node.attributes[i].nodeName, node.getAttribute(node.attributes[i++].nodeName));
					}
				}
				
				/* are we going after children too, and does the node have any? */
				if (allChildren && node.childNodes && node.childNodes.length > 0) {
					for (var i = 0, il = node.childNodes.length; i < il;) {
						newNode.appendChild(importNode(node.childNodes[i++], allChildren));
					}
				}
				
				return newNode;
			break;
			
			case 3: /* NODE_TEXT */
			case 4: /* NODE_CDATA_SECTION */
				return document.createTextNode(node.nodeValue);
			break;
		}
	};
}

// Provide DOM Parser for Safari
if(!window.DOMParser){
  DOMParser = function() { };
  /** 
  * Construct a new DOM Document from the given XMLstring
  * @param sXml the given XML string
  * @param contentType the content type of the document the given string represents (one of text/xml, application/xml, application/xhtml+xml). 
  * @return a new DOM Document from the given XML string
  */
  DOMParser.prototype.parseFromString = function(sXml, contentType){
      var xmlhttp = new XMLHttpRequest();
      xmlhttp.open("GET", "data:text/xml;charset=utf-8," + encodeURIComponent(sXml), false);
      xmlhttp.send(null);
      return xmlhttp.responseXML;
  };
}


function refreshStylesheets() {
	var i, cacheobj
	for(i=0; (cacheobj=document.getElementsByTagName("link")[i]); i++) {
		if(cacheobj.getAttribute("rel").indexOf("style") != -1) {
			cacheobj.disabled = true;
			cacheobj.disabled = false;
		}
	}
}

function hideNoNav() {
	setStyleByClass('LI', 'NoNav', 'display', 'none');
}

function removeChildren(el) {
	while(child = el.firstChild) {
		el.removeChild(child);
	}
}

var sitemapDOM = null;

function requestSitemap(sitemapURL) {
	sitemapDOM = Sarissa.getDomDocument();
	// set loading method to synchronous
	sitemapDOM.async = false;
	sitemapDOM.load(sitemapURL);

	buildListNav();
}


/*
function requestSitemap(sitemapURL) {
	YAHOO.util.Connect.asyncRequest('GET',sitemapURL, handlers, null);
}

var handlers = {
 success: success,
 failure: failure }

var sitemapDOM = null;

function success(t) { 
	sitemapDOM = createXMLDocumentFromString(t.responseText);
	buildListNav();
}
function failure(t) {
	alert(t.statusText);
	alert('Navigation failed to load : '+ t.statusText); 
}
*/

function buildListNavChrome() {
	// Current Page
	currentPageURL = getURLpath(location.href);
	currentPage = getPage(currentPageURL, sitemapDOM);

	if (!currentPage) { // current page could not be found in sitemap
		currentPageURL = "/index.htm";  // use home instead
		currentPage = getPage(currentPageURL, sitemapDOM);
	}
	
	// Site Top
	siteTopURL = "/index.htm";
	siteTopPage = getPage(siteTopURL, sitemapDOM);
	siteTopContainer = getChildContainer(siteTopPage);

	// Remove Comments
	removeComments(siteTopContainer);

	// Remove Empty ULs
	removeEmptyContainers(siteTopContainer, sitemapDOM);


	if (currentPageURL == siteTopURL) {  // show top level siblings
		sectionRootContainer = siteTopContainer;
	}
	else {
		sectionRootContainer = getAncestorContainerOfClass(currentPage, 'SectionRoot');
	}

	// Top Nav
	headerPageURL = "/index.htm";
	headerPage = getPage(headerPageURL, sitemapDOM);

	headerContainer = getChildContainer(headerPage);
	replaceElementContent('TopNav', formatContainer(headerContainer));
	//TopNavEl = document.getElementById('TopNav');
	//Sarissa.copyChildNodes(headerContainer, TopNavEl, false);

	// LeftNav
	replaceElementContent('LeftNav', formatContainer(sectionRootContainer));
	//LeftNavEl = document.getElementById('LeftNav');
	//Sarissa.copyChildNodes(sectionRootContainer, LeftNavEl, false);

	// Page Title
	replaceElementContent('PageTitle', formatPageTitle(currentPage));

	// Breadcrumb
	sectionTitlePage = getTitlePage(headerContainer);
	replaceElementContent('Breadcrumb', getBreadcrumbList(currentPage, sectionTitlePage, " » "));

	// Title Bar
	document.title = getTitleBarList(currentPage, sectionTitlePage, " : ");

	// Footer Links	
	footerPageURL = "#footer";
	footerPage = getPage(footerPageURL, sitemapDOM);
	footerContainer = getChildContainer(footerPage);
	replaceElementContent('FooterLinks', formatContainerTopLevelChildren(footerContainer, " | "));
	
	// Footer Copyright
	replaceElementContent('FooterCopyright', footerContainer.getAttribute("copyright"));

}

// setup buildListNav handler to build chrome
buildListNav = buildListNavChrome;

function removeEmptyContainers(rootEl, sitemapDOM) {
	// find all UL elements from sitemap
	ulElements = sitemapDOM.getElementsByTagName('ul');

	// foreach UL
	ulElementsLength = ulElements.length;
  for (var n = ulElementsLength -1; n >= 0; n--) 
  {
  	currentUL = ulElements[n];
  	
  	// todo: test has rootEl as ancestor
  	
  	// if UL is empty (has no LIs)
  	if (currentUL && isContainerEmpty(currentUL)) {
  		// remove empty UL
  		currentUL.parentNode.removeChild(currentUL);
  	}

	}
}

function isContainerEmpty(containerEl) {
	var empty = false;
	
	if (!containerEl.firstChild) {		// no children at all
		empty = true;
	}
	else {														// test if any of the nodes are LIs (others will be Template Comments)
		currentEl = containerEl.firstChild;
		currentEl = skipTextNodesForwards(currentEl);
		
		if (!currentEl) {								// there was no LI to skip to
			empty = true;
		}
	}
	
	return empty;
}

function removeComments(rootEl) {
	cArray = new Array();
	cArray = getComments(rootEl, cArray);
	
	var cArrayLength = cArray.length;
  for (var i=cArrayLength -1; i >=0; i--) 
  {
  	if (cArray[i]) {  // test existance of node
  		cArray[i].parentNode.removeChild(cArray[i]);
  	}
  }
}	

function getComments(currentNode, commentArray) {
  if (currentNode.nodeType == 8) { /* 8 indicates a commentNode type*/
    commentArray[commentArray.length] = currentNode;
  } 
  else if (currentNode.childNodes != null) {
  	var childNodesLength = currentNode.childNodes.length;
    for (var i=0; i < childNodesLength; i++) {
    	if (currentNode.childNodes.item(i)) {  // test existance of node
    		commentArray = getComments(currentNode.childNodes.item(i), commentArray);
    	}
    }
  }

	return commentArray;
}


function resizeLeftNavContainer(leftNavContainerID, leftNavRootID) {
	var leftNavRootElement = document.getElementById(leftNavRootID);
	var leftNavRootElementHeight = getTopLevelChildrenHeight(leftNavRootElement);

	var leftNavContainerElement = document.getElementById(leftNavContainerID);
	var currentLeftNavContainerHeight = leftNavContainerElement.offsetHeight;

	if (parseInt(leftNavRootElementHeight) > currentLeftNavContainerHeight) {
		leftNavContainerElement.style.height = leftNavRootElementHeight;
	}
}

function resizeTopNav(topNavID, topNavRootID) {
	var topNavRootElement = document.getElementById(topNavRootID);
	var topNavRootElementWidth = getTopLevelChildrenWidth(topNavRootElement);

	var topNavContainerElement = document.getElementById(topNavID);

	//alert('topNavRootElementWidth : '+ topNavRootElementWidth);

	topNavContainerElement.style.width = topNavRootElementWidth;
}

function getTopLevelChildrenHeight(el) {
	height = 0;
	
	currentChild = el.firstChild;
	currentChild = skipTextNodesForwards(currentChild);
	
	while (currentChild) {
		height += currentChild.offsetHeight +1;
		currentChild = currentChild.nextSibling;
		currentChild = skipTextNodesForwards(currentChild);
	}
	
	return height+"px";
}

function getTopLevelChildrenWidth(el) {
	width = 0;
	
	currentChild = el.firstChild;
	currentChild = skipTextNodesForwards(currentChild);
	
	while (currentChild) {
		width += currentChild.offsetWidth +1;
		currentChild = currentChild.nextSibling;
		currentChild = skipTextNodesForwards(currentChild);
	}
	
	return width+"px";
}


