/*  ------------------------
*	Library classes for constructing a template
*	all functions and properties that are preceded by _ are private
*	and should not be accessed from exterior code
*
*	Overall Version : 2
*		DropDownMenu is no longer compatible with versin 1.x code
*
*	There are classes currently available. Some of these may be removed when not neccessary
*	1) TemplateUtils() 
*	This is always present and always invoked as oTplUtils. A collection of properties
*	and functions for getting navitem information and other useful information.
*	
*	2) Trail()
*	Optional. Builds a trail of navids from the selected navitem to root
*
*	3) NavigationItemMenu()
*	Optional. Builds a navigation menu from the navitem array
*
*	4) DropDownMenu()
*	Optional. Builds a drop down or slid out menu. Needs the external style sheet to work
*
*	5) FontSizer()
*	Increase the relative font size over the entire currently loaded document
*  ------------------------  */



/* ----------------- browsers DOM extensions -------------------------*/
//this is included to implement the Array.push function in ieMac
if (typeof Array.prototype.push == 'undefined') {
	Array.prototype.push=function(){
		var i=0;
	    b=this.length,a=arguments;
		for(i;i<a.length;i++)this[b+i]=a[i];
	    return this.length
	}
}

//this is included to implement the Array.inArray function
if (typeof Array.prototype.inArray == 'undefined') {
	Array.prototype.inArray = function(value){
		for (var i=0; i<=this.length-1; i++) {
			if (this[i] == value) {
				return true;
			}
		}

		return false;
	}
}
/* -----------------  end browsers DOM extensions -------------------------*/


/* =============================================================================================*/
var oTplUtils = new TemplateUtils()
function TemplateUtils() {
	
	/*  ------------------------
	*	Version 1.0
	*	Collection of utilities functins and properties for use with other
	*	classes in this package and for general use with templates.
	*  ------------------------  */
	
	/* properties that describe the browser type */
	this.BUA = navigator.userAgent;
	this.BIE = this.BUA.indexOf("MSIE");
	this.BIsIE = this.BIE>=0;
	this.BIsMaccak = this.BUA.indexOf("Mac")!=-1;
	this.BVer = this.BIE>=0 ? parseFloat(this.BUA.substring(this.BIE+5, this.BIE+6)+"."+this.BUA.substring(this.BIE+7, this.BIE+8)) : parseInt(navigator.appVersion.substring(0,1));

	/* properties for more descriptive accessing of navitems nodes */
	this.NODE_ID = 0;
	this.PARENT_NODE = 1;
	this.DISPLAY_TEXT = 2;
	this.HELP = 3;
	this.URL = 4;
	this.URL_TARGET = 5;
	
	this.hasChildren = function(navId){
		//pre:		true
		//post:		if navitem for the given navId has children then true will be returned else false
		//return:	boolean
		
		for (var i=0; i<=NavItems.length-1; i++) {
			if (NavItems[i][this.PARENT_NODE] == navId) {
				return true
			}
		}
	
		return false;
	}

	this.getNavItem = function(navId){
		//pre:		true
		//post:		An array containing the items for the navitem is returned
		//return:	boolean
	
		var navItem = Array();
	
		for (var i=0; i<NavItems.length; i++) {
			if (NavItems[i][this.NODE_ID] == navId) {
				navItem[this.NODE_ID] = NavItems[i][this.NODE_ID];
				navItem[this.PARENT_NODE] = NavItems[i][this.PARENT_NODE];
				navItem[this.DISPLAY_TEXT] = NavItems[i][this.DISPLAY_TEXT];
				navItem[this.HELP] = NavItems[i][this.HELP];
				navItem[this.URL] = NavItems[i][this.URL];
				navItem[this.URL_TARGET] = NavItems[i][this.URL_TARGET];
			}
		}
	
		return navItem;
	}

	this.navItemExists = function(id){
		//pre:		true
		//post:		if navitem for the given navId exists then true will be returned else false
		//return:	boolean

		var navItem = this.getNavItem(id)
		return navItem.length > 0;
	}
	
	this.buildAHREF = function(nodeId){
		//pre:		the navitem exists
		//post:		an <A HREF> tag string is returned based on the navitem values
		//return:	string
		
		var node = this.getNavItem(nodeId);
		
		return '<a href="'+node[this.URL]+'" '+(node[this.URL_TARGET] != '' ? 'target="'+node[this.URL_TARGET]+'"' : '')+'>'+node[this.DISPLAY_TEXT]+'</a>';
	}
}
/* =============================================================================================*/



/* =============================================================================================*/
function Trail() {
	
	/*  ------------------------
	*	Version 1.0
	*	Builds a trail of ids from the root to the selected nav id
	*	usage:
	*	1) "setSelectecNavId(x)"
	*	2) "makeTrail()"
	*  ------------------------  */
	
	this._selectedNavId = 0;
	this._trail = Array();
	this._rootNavId = -1;
	
	this.setSelectedNavId = function(navId){
		//pre:		true
		//post:		the selected nav item to build the trail from is set
		//return:	
		
		this._selectedNavId = navId;
	}

	this.makeTrail = function() {
		//pre:		the selectedNavItem is set
		//post:		the trail is contstructed
		//return:	Array
		
		if (!oTplUtils.navItemExists(this._selectedNavId)) {return this._trail;}
		this._makeTrailRc(this._selectedNavId);
		this._trail.reverse();
		return this._trail
	}

	this._makeTrailRc = function(nodeId){
		if (nodeId == this._rootNavId){
			this._trail.push(this._rootNavId);
		
		} else {
			this._trail.push(nodeId);
	
			var node = oTplUtils.getNavItem(nodeId);
			this._makeTrailRc(node[oTplUtils.PARENT_NODE]);
		}
	}
}
/* =============================================================================================*/



/* =============================================================================================*/
function NavigationItemMenu () {

	/*  ------------------------
	*	Version 1.5
	*	Builds a Treed UL menu for transforming with a style sheet
	*	Shows the children of the selected node and any children its children.
	*	The LI tag of selected nodes will have "NIMSelected" in the class attribue
	*	The LI tage of nodes that lay in the trail will have "NIMSelected" in the class attibute
	*
	*	The last LI in any list will have the "NIMLastItem" included in its class attribute
	*	This would be avoidable in css2 - oh well
	*
	*	The exsposing of sub menus is dealt with via the method 'expsoseSubMenus(option)'
	*		option == 'all' then all sub menus will be exposed. Default value
	*		option == 'trail' then only sub menus that lay in the trail will be exposed
	*		option == 'none' then no sub menus will be expopsed
	*
	*	The classes will only work if the trail is supplied
	*
	*	example of output:
	*	<ul>
	*		<li class="NIMFirstItem"><div>item 1</div></li>
	*		<li><div>item 2</div></li>
	*		<li class="NIMSelected"><div>item 3
	*			<ul>
	*				<li class="NIMSelected NIMFirstItem"><div>item 4</div></li>
	*				<li><div>item 5</div></li>
	*			</ul>
	*		</li>
	*		<li class="NIMLastItem"><div>item 5</div></li>
	*	</ul>
	*
	*	usage:
	*	1) "init(topNavId, selectedNavId)"
	*	2) 		"setTrail(trail)" - optional
	*	3) 		"includeTop()" - optional
	*	4) 		"useFirstItem()" - optional
	*	5) 		"useLastItem()" - optional
	*	6)		"exposeSubMenus('all'|'trail'|'none')" - optional
	*	7)		"setDomId('xxx')" - optional
	*	8) "buildMenu()"
	*  ------------------------  */
	
	this._topNavId = null;
	this._selectedNavId = null;
	this._trail = Array();
	this._menuDepthLimit = 10;
	this._includeTop = false;
	this._useFirstItem = false;
	this._useLastItem = false;
	this._exposeSubMenuOption = 'all';
	this._domId = '';
	
	this.init = function(topNavId, selectedNavId) {
		//pre:		true
		//post:		initates the properties of the class
		//			topNavId sets the top id of the menu
		//			selectedNavId sets what is currently selected
		//return:	
		
		this._topNavId = topNavId;
		this._selectedNavId = selectedNavId;
	}
	
	this.setTrail = function(trailArr) {
		//pre:		true
		//post:		sets the trail of node ids back to the root
		//			use the trail class to create this array
		//return:	
		
		this._trail = trailArr;
	}
	
	this.setDomId = function(domIdStr) {
		//pre:		true
		//post:		sets dom id of the top ul 
		//return:	
		
		this._domId = domIdStr;
	}
	
	this.includeTop = function() {
		//pre:		true
		//post:		will make the top li the topNav everything else will be a sub ul
		//			eg: <ul><li>top item
		//					<ul><il>rest of tree
		//				</li></ul>
		//return:	
		
		this._includeTop = true;
	}

	this.useFirstItem = function() {
		//pre:		true
		//post:		instucts the buildMenu method to use NIMFirstItem in the class for the first li in any list
		//return:	
		
		this._useFirstItem = true;
	}

	this.useLastItem = function() {
		//pre:		true
		//post:		instucts the buildMenu method to use NIMLastItem in the class for the last li in any list
		//return:	
		
		this._useLastItem = true;
	}
	
	this.exposeSubMenus = function(optionStr) {
		//pre:		a trail may need to be present
		//post:		buildMenu will expose any sub menus as tree ul lists depending on the option
		//			option == 'all' then all sub menus will be exposed
		//			option == 'trail' then only sub menus that lay in the trail will be exposed.
		//							  trail needs to be present for this option	
		//			option == 'none' then no sub menus will be expopsed
		//return:	
		
		this._exposeSubMenuOption = optionStr
	}
	
	this.buildMenu = function() {
		if (!oTplUtils.navItemExists(this._topNavId)) {
			return '';
		}
		
		if (this._includeTop) {
			var top = oTplUtils.getNavItem(this._topNavId);
			var out = '<ul><li>';
			out += '<a href="'+top[oTplUtils.URL]+'" '+(top[oTplUtils.URL_TARGET] != '' ? 'target="'+top[oTplUtils.URL_TARGET]+'"' : '')+'><div>'+top[oTplUtils.DISPLAY_TEXT]+'</div></a>';
			out += this._buildMenuRC(this._topNavId, 0);
			out += '</li></ul>';
			return out;
		} else {
			return this._buildMenuRC(this._topNavId, 0);
		}
	}
	
	this._buildMenuRC = function(navId, depth) {
		var out = Array();
		var li = '';
	
		if (!oTplUtils.hasChildren(navId) || (depth == this._menuDepthLimit)){
			return '';
		}
	
		depth++;
	
		for (var i=0; i<= NavItems.length-1; i++){
			if (NavItems[i][oTplUtils.PARENT_NODE] == navId) {
				
				if ( (NavItems[i][oTplUtils.NODE_ID] == this._selectedNavId) || 
					(this._trail.inArray(NavItems[i][oTplUtils.NODE_ID])) ) {
					var classStr = 'NIMSelected';
				} else {
					var classStr = '';
				}
				
				li = '<li class="'+classStr+'">';
				li += "<a href=\""+NavItems[i][oTplUtils.URL]+"\" "+(NavItems[i][oTplUtils.URL_TARGET] != '' ? 'target="'+NavItems[i][oTplUtils.URL_TARGET]+'"' : '')+"><div>"+NavItems[i][oTplUtils.DISPLAY_TEXT]+"</div></a>";
				
				if (this._exposeSubMenuOption == 'all') {
					li += this._buildMenuRC(NavItems[i][oTplUtils.NODE_ID], depth);
				} else if ( (this._exposeSubMenuOption == 'trail') && (this._trail.inArray(NavItems[i][oTplUtils.NODE_ID])) ) {
					li += this._buildMenuRC(NavItems[i][oTplUtils.NODE_ID], depth);
				}
				
				li += "</li>";
				out.push(li);
			}
		}
		
		if ((this._useFirstItem) && (out.length > 0)) {
			var firstLI = out[0];
			
			firstLI = firstLI.replace(new RegExp('class="','g'), 'class="NIMFirstItem ');
			out[0] = firstLI;
		}
		
		if ((this._useLastItem) && (out.length > 0)) {
			var lastLI = out[out.length-1];
			
			lastLI = lastLI.replace(new RegExp('class="','g'), 'class="NIMLastItem ');
			out[out.length-1] = lastLI;
		}
		
		if (out.length > 0) {
			if ((this._domId != '') && (depth == 1)) {
				var domId = 'id="'+this._domId+'"';
			} else {
				var domId = '';
			}
			
			out = '<ul '+domId+'>'+out.join('')+'</ul>';
		} else {
			out = '';
		}
		
		return out;		
	}
}
/* =============================================================================================*/



/* =============================================================================================*/
function FontSizer() {
	
	/*  ------------------------
	*	Version 1
	*	Increase the relative font size over the entire currently loaded document
	*	Assumes that the font size of the BODY has been set to 1em
	*
	*	Usage:
	*	All these methods can only be called after the page has loaded
	*	inc - increases 
	 *  ------------------------  */
	
	this._amount = .15;
	 
	this.setAmount = function(amount) {
		/*	Pre	:	amount is a number
		*	Post:	the amount that the the font size will increase or decreas by is changed
		*/
		
		this._amount = amount;
	}
	
	this.inc = function() {
		/*	Pre		: true
		*	Post	: the all em based values will increase by amount
		*/
		
		this._setSize(this._getSize() + this._amount);
	}
	
	this.dec = function() {
		/*	Pre		: true
		*	Post	: the all em based values will decrease by amount
		*/

		this._setSize(this._getSize() - this._amount);
	}
	
	this.reset = function() {
		/*	Pre		: true
		*	Post	: body will be set to 1em
		*/
		
		this._setSize(1);
	}
	
	this._setSize = function(size) {
		this._getBody().style.fontSize = size + 'em';
	}
	
	this._getSize = function() {
		var size = this._getBody().style.fontSize;
		var re = new RegExp(size, 'g');
		
		if (!size) {
			return 1;
		} else {
			size = size.replace('em', '');
			return parseFloat(size);
		}
	}
	
	this._getBody = function() {
		var oNodeList = document.getElementsByTagName('body'); 
		return oNodeList[0];
	}
	
}
/* =============================================================================================*/




/* =============================================================================================*/
function DropDownMenu() {
	
	/*  ------------------------
	*	Version 2.2
	*	Generates a drop down or slide out menu.
	*	This class generates a treed UL list from the navitem array and uses
	*	the CSS file "DDMenu.css". To change colour size etc of the menu
	*	manipulate the CSS file.
	*
	*	Usage: 
	*	Before page loads
	*	1) "setStartingNavId(x)" - set the starting nav item 
	*	2) "setMenuDomId('yy')" - set the dom id of menu
	*	3) "useFirstItem()" - optional
	*	4) "this.useSelectedNavItem(navId)" - optional
	*	5) "useLastItem()" - optional
	*	6) "buildMenu()" - returns the string that contains all the html list code 
	*
	*	After page loads
	*	7) "enableMenu()"
	*  ------------------------  */
	
	this._startingNavId = 0;
	this._menuDomId = '';
	this._useDIVWrapperInsideAHREFs = false;
	this._useLastItem = false;
	this._useFirstItem = false;
	this._useSelectedNavItem = 0;
	this._selectBoxList = new Array();
	
	this._menuDepthLimit = -1;  //-1 = no limit on depth 
	this._menuULs = Array(); //internal variable for detecting menu direction


	this.setStartingNavId = function(startingNavId) {
		//pre:		true
		//post:		the navitem id to build the menu from is set
		//return:	
		
		this._startingNavId = startingNavId;
	}
	
	this.useDIVWrapperInsideAHREFs = function() {
		//pre:		true
		//post:		if you want DIV tags inside the A tags of each item in the menu then
		//			call this before the page loads
		//return:	_useDIVWrapperInsideAHREFs is true
		
		this._useDIVWrapperInsideAHREFs = true;
	}
	
	this.useSelectedNavItem = function(navId) {
		//pre:		true
		//post:		instructs the buildMenu method to use DDMSelectedItem in the class for the item id that matched navId
		//return:	
		
		this._useSelectedNavItem = navId;
	}
	
	this.useFirstItem = function() {
		//pre:		true
		//post:		instructs the buildMenu method to use DDMFirstItem in the class for the first li in the top level list
		//return:	
		
		this._useFirstItem = true;
	}
	
	this.useLastItem = function() {
		//pre:		true
		//post:		instructs the buildMenu method to use DDMLastItem in the class for the last li in the top level list
		//return:	
		
		this._useLastItem = true;
	}
	
	this.setMenuDomId = function(menuDomId) {
		//pre:		true
		//post:		the menu dom id is set
		//			do this before loading
		//return:	
		
		this._menuDomId = menuDomId;
	}
	
	this.buildMenu = function() {
		//pre:		true
		//post:		the menu is built and returned as a string
		//			do before loading
		//return:	string		
		
		var out = '';

		if (!oTplUtils.navItemExists(this._startingNavId)) {
			alert('DropDownMenu.buildMenu() : the startNavId does not exist!');
			return '';
		} else {
			out = this._buildMenuRC(this._startingNavId, 0);
			return out;
		}
	}

	this.enableMenu = function() {
		//pre:		true
		//post:		the menu is activated so sub menus roll out
		//			do after the page loads
		//return:	
		
		this._DDMHover();
		document.getElementById(this._menuDomId).style.display = "block";
	}
	
	this._buildMenuRC = function(navId, depth){
		var out = Array();
		var li = '';
	
		if (!oTplUtils.hasChildren(navId) || (depth == this._menuDepthLimit)){
			return out;
		}
	
		depth++;
	
		for (var i=0; i<= NavItems.length-1; i++){
			if (NavItems[i][oTplUtils.PARENT_NODE] == navId) {
				li = '<li class="';
				if ((this._useSelectedNavItem > 0) && (NavItems[i][oTplUtils.NODE_ID] == this._useSelectedNavItem)) {
					li += 'DDMSelectedItem';
				}
				li += '">';
				li += "<a href=\""+NavItems[i][oTplUtils.URL]+"\" "+(NavItems[i][oTplUtils.URL_TARGET] != '' ? 'target="'+NavItems[i][oTplUtils.URL_TARGET]+'"' : '')+"><div>"+NavItems[i][oTplUtils.DISPLAY_TEXT]+"</div></a>";
				li += this._buildMenuRC(NavItems[i][oTplUtils.NODE_ID], depth);
				li += "</li>";
				
				out.push(li);
			}
		}
		
		if ((this._useFirstItem) && (out.length > 0) && (depth == 1)) {
			var firstLI = out[0];
			
			firstLI = firstLI.replace(new RegExp('<li class="','g'), '<li class="DDMFirstItem ');
			out[0] = firstLI;
		}
		
		if ((this._useLastItem) && (out.length > 0) && (depth == 1)) {
			var lastLI = out[out.length-1];
			
			lastLI = lastLI.replace(new RegExp('<li class="','g'), '<li class="DDMLastItem ');
			out[out.length-1] = lastLI;
		}
		
		if (out.length > 0){
			if (depth == 1) {
				var domId = 'id="'+this._menuDomId+'" style="display:none"';
			} else {
				var domId = '';
			}
			
			out = '<ul '+domId+'>'+out.join('')+'</ul>';
		} else {
			out = '';
		}

		return out;
	}	
	
	this._DDMHover = function() {
		var menuDomId = this._menuDomId;
		var DDMEls = document.getElementById(menuDomId).getElementsByTagName("LI");
		
		for (var i=0; i<DDMEls.length; i++) {
			DDMEls[i].oDDM = this;
			
			DDMEls[i].onmouseover = function(e) {
				if (oTplUtils.BIsIE) {
					this.className += " DDMhover";
				}
				this.oDDM._hoverDetectScreenOverflow(e ? e : event);
				this.oDDM._disableSelectInputs();
			}

			DDMEls[i].onmouseout = function() {
				if (oTplUtils.BIsIE) {
					this.className = this.className.replace(new RegExp(" DDMhover\\b"), "");
				}
				this.oDDM._enableSelectInputs();
			}
			
			if (DDMEls[i].parentNode == document.getElementById(menuDomId) && oTplUtils.BIsIE) {
				if (oTplUtils.BIsIE) {
					DDMEls[i].style.width = '1px';
				}
			}
		}
	}
	
	this._disableSelectInputs = function() {
		var selectors = document.getElementsByTagName("select")
		for (var i=0; i<selectors.length; i++) {
			if (selectors[i].style.display != 'none') {
				var textInput = document.createElement('input');
				
				var obj = new Object()
				obj.selector = selectors[i];
				obj.textInput = textInput;
				
				this._selectBoxList[i] = obj;
				
				textInput.type = 'text';
				textInput.disabled = true;
				textInput.value = selectors[i].options[selectors[i].selectedIndex].text;
				textInput.style.width = selectors[i].clientWidth+'px';
				selectors[i].parentNode.insertBefore(textInput, selectors[i]);
				selectors[i].style.display = 'none';
			}
		}
	}
	
	this._enableSelectInputs = function() {
		for (var i=0; i<this._selectBoxList.length; i++) {
			if (this._selectBoxList[i] != '') {
				var selector = this._selectBoxList[i].selector
				var textInput = this._selectBoxList[i].textInput
				
				textInput.parentNode.removeChild(textInput);
				selector.style.display = 'inline';
				this._selectBoxList[i] = '';
			}
		}
	}
	
	this._hoverDetectScreenOverflow = function(e) {
		var target = e.srcElement ? e.srcElement : e.target;
		var thisUL = target;
		var menuX = 0;
		var browserWidth = 0;
		var branchWidth = 0;
		
		while ((thisUL.tagName != 'UL') && (thisUL.tagName != 'BODY')) {
			thisUL = thisUL.parentNode;
		}
		
		if (thisUL.id == this._menuDomId) {
			thisUL = target.parentNode.parentNode.childNodes[1];
			
			branchWidth = this._hoverDetectWidestBranch(thisUL);
			menuX = this._getElementXPosRelativeToScreen(thisUL);
			browserWidth = (window.innerWidth ? window.innerWidth : document.body.scrollWidth) - 20;
		
			if ((menuX + branchWidth) > browserWidth) {
				thisUL.className = ' leftAlign';
			} else if (thisUL) {
				//this may cause problems - check in future sites
				//thisUL.className = ' DDMhover';
			}
		}
	}
	
	this._hoverDetectWidestBranch = function(HTMLObj){
		if (!HTMLObj) {
			return 0;
		}
		
		var widestBranchWidth = HTMLObj.offsetWidth;
		var thisBranchesWidth = 0;
		
		this._menuULs = Array();
		this._hoverGetULsAtEndOfBranchesRC(HTMLObj);
		
		for(var i=0; i<this._menuULs.length; i++) {
			thisBranchesWidth = this._hoverDetectThisBranchesWidth(HTMLObj, this._menuULs[i]);
			if (thisBranchesWidth > widestBranchWidth) {
				widestBranchWidth = thisBranchesWidth;
			}
		}
		
		return widestBranchWidth;
	}
	
	this._hoverDetectThisBranchesWidth = function (topULObj, ULObj) {
		var width = topULObj.offsetWidth;
		
		while (ULObj != topULObj) {
			if (ULObj.tagName == 'UL') {
				width = width + ULObj.offsetWidth;
			}
			ULObj = ULObj.parentNode;
		}
		
		return width;
	}
	
	
	this._hoverGetULsAtEndOfBranchesRC = function(HTMLObj) {
		
		for (var i=0; i<HTMLObj.childNodes.length; i++) {
			var child = HTMLObj.childNodes[i];
			if (child.tagName == 'UL') {
				
				this._menuULs.push(child);
			}
			
			this._hoverGetULsAtEndOfBranchesRC(child);
		}
	}
	

	this._getElementXPosRelativeToScreen = function(elementObj) {
		var x = 0;
		
		if (!elementObj) {
			return x;
		}
		
		var element = elementObj.parentNode;
				
		while (element.tagName != 'BODY') {
			x = x + element.offsetLeft;
			element = element.parentNode;
		}
				
		return x;
	}
}
/* =============================================================================================*/