//MSIE does things differently
if('function'!==typeof window.getComputedStyle)
{
	window.getComputedStyle=function(element,pseudoElt)
	{
		return element.currentStyle;
	};
}

//Sort numeric arrays
if('undefined'===typeof Array.numericSort)
{
	Array.numericSort=function(a,b){if(a<b){return -1;}else if(a>b){return 1;}return 0;};
}

//Converts a number into a 'beautiful' string (two significant digits, a decimal point, sign indicator and thousands separator
if('undefined'===typeof Number.beautify)
{
	Number.beautify=function(value)
	{
		var i,negative;
		value=Number(value);
		negative=(0>value);
		if(negative)
		{
			value=Math.abs(value);
		}
		value=value.toFixed(2);
		for(i=value.indexOf('.')-3;i>0;i-=3)
		{
			value=value.substring(0,i)+','+value.substring(i);
		}
		if(negative)
		{
			value='-'+value;
		}
		return value;
	};
}

//MSIE can't do Array.indexOf without it
if('undefined'===typeof Array.prototype.indexOf)
{
	Array.prototype.indexOf=function(searchElement, fromIndex)
	{
		var i,idx;
		if('undefined'===typeof fromIndex)
		{
			idx=0;
		}
		else
		{
			idx=fromIndex;
		}
		if(idx>=this.length)
		{
			return -1;
		}
		if(0>idx)
		{
			idx=this.length+idx;
		}
		if(0>idx)
		{
			idx=0;
		}
		for(i=idx;i<this.length;i++)
		{
			if(searchElement===this[i])
			{
				return i;
			}
		}
		return -1;
	};
}

//MSIE can't do Array.lastIndexOf without it
if('undefined'===typeof Array.prototype.lastIndexOf)
{
	Array.prototype.lastIndexOf=function(searchElement, fromIndex)
	{
		var i,idx;
		if('undefined'===typeof fromIndex)
		{
			idx=this.length-1;
		}
		else
		{
			idx=fromIndex;
		}
		if(idx>=this.length)
		{
			idx=this.length-1;
		}
		if(0>idx)
		{
			idx=this.length+idx;
		}
		if(0>idx)
		{
			return -1;
		}
		for(i=idx;i>=0;i--)
		{	
			if(searchElement===this[i])
			{
				return i;
			}
		}
		return -1;
	};
}

//Constructs a generic event object
function CommonEvent(e)
{
	var evnt=e;
	if(!e)
	{
		evnt=window.event;
	}
	if('undefined'!==typeof evnt.target)
	{
		this.sender=evnt.target;
	}
	else if('undefined'!==typeof evnt.srcElement)
	{
		this.sender=evnt.srcElement;
	}
	if('undefined'!==typeof evnt.shiftKey)
	{
		this.shiftKey=evnt.shiftKey;
	}
	if('undefined'!==typeof evnt.type)
	{
		this.type=evnt.type;
	}
	if('undefined'!==typeof evnt.relatedTarget)
	{
		this.receiver=evnt.relatedTarget;
	}else if('undefined'!==typeof evnt.toElement)
	{
		this.receiver=evnt.toElement;
	}
	this.Event=evnt;
	return this;
}
//Common event members
CommonEvent.prototype.receiver=null;
CommonEvent.prototype.sender=null;
CommonEvent.prototype.shiftKey=false;
CommonEvent.prototype.type=null;
CommonEvent.prototype.Event=null;
//Allows canceling of an event
CommonEvent.prototype.cancel=function()
{
	if(this.Event.stopPropagation)
	{
		this.Event.stopPropagation();
	}
	if(this.Event.cancelable)
	{
		this.Event.preventDefault();
	}
	if('undefined'!==typeof this.Event.cancelBubble)
	{
		this.Event.cancelBubble=true;
	}
	if('undefined'!==typeof this.Event.returnValue)
	{
		this.Event.returnValue=false;
	}
};

//Attaches a function to an event fired from an object
function attachEventListener(evt,element,handler)
{
	if(null===element){return;}
	if(element.addEventListener)
	{//W3C compliant
		element.addEventListener(evt,handler,false);
	}
	else if(element.attachEvent)
	{//MSIE
		element.attachEvent('on'+evt,handler);
	}
}

//Detaches a function from an object's event
function detachEventListener(evt,element,handler)
{
	if(null===element){return;}
	if(element.removeEventListener)
	{//W3C compliant
		element.removeEventListener(evt,handler,false);
	}
	else if(element.detachEvent)
	{//MSIE
		element.detachEvent('on'+evt,handler);
	}
}

//Returns the checked radio button in the given group
function getCheckedRadio(radioGroup)
{
	var i,radioGroupLength;
	radioGroupLength=radioGroup.length;
	for(i=0;i<radioGroupLength;i++)
	{
		if(radioGroup[i].checked)
		{
			return radioGroup[i];
		}
	}
	return null;
}

//Inits the page, repositions the sub-menus and attaches event handlers to the menu items
function init()
{
	var i,j,nodes,nodesLength,subNodes,subNodesLength,labels,labelsLength,select;

	//Holds the help, legislation and other pop-up windows
	window.popUps={};

	nodes=document.getElementById('TopMenu').childNodes;
	nodesLength=nodes.length;
	for(i=0;i<nodesLength;i++)
	{
		if(('undefined'!==typeof nodes[i].tagName) && ('li'===nodes[i].tagName.toLowerCase()))
		{
			subNodes=nodes[i].childNodes;
			subNodesLength=subNodes.length;
			for(j=0;j<subNodesLength;j++)
			{
				if(('undefined'!==typeof subNodes[j].tagName) && ('ul'===subNodes[j].tagName.toLowerCase()))
				{
					nodes[i].id='ActiveMenu';
					subNodes[j].style.left=(nodes[i].offsetLeft-Math.abs(nodes[i].offsetWidth-subNodes[j].offsetWidth))+'px';
					if(true===window.IE)
					{
						subNodes[j].removeAttribute('style');
						subNodes[j].style.right=19+(nodes[i].offsetLeft)+'px';
					}
					else
					{
						var items=subNodes[j].childNodes;
						var maxWidth=0;
						var k;
						for(k=0;k<items.length;k++)
						{
							if(('undefined'!==typeof items[k].tagName)&&('li'===items[k].tagName.toLowerCase()))
							{
								maxWidth=(items[k].clientWidth>maxWidth)?items[k].clientWidth:maxWidth;
							}
						}
						for(k=0;k<items.length;k++)
						{
							if(('undefined'!==typeof items[k].tagName)&&('li'===items[k].tagName.toLowerCase()))
							{
								items[k].style.width=maxWidth+'px';
							}
						}
					}
					nodes[i].removeAttribute('id');
				}
			}
		}
	}
	for(i=0;i<nodes.length;i++)
	{
		if(('undefined'!==typeof nodes[i].tagName) && ('li'===nodes[i].tagName.toLowerCase()))
		{
			attachEventListener('mouseover',nodes[i],toggleMenu);
			var evt=(true===window.IE)?'leave':'out';
			attachEventListener('mouse'+evt,nodes[i],toggleMenu);
		}
	}
	//MSIE has a nasty habit of setting selects to their first index (not necessarily the defaultSelected option)
	///These lines fix that by handling the click event of every label associated with a select element.
	if(true===window.IE)
	{
		labels=document.getElementsByTagName('label');
		labelsLength=labels.length;
		for(i=0;i<labelsLength;i++)
		{
			if(''===labels[i].htmlFor){continue;}
			select=document.getElementById(labels[i].htmlFor);
			if((null!==select)&&('select'===select.tagName.toLowerCase()))
			{
				attachEventListener('click',labels[i],PreventTridentFromResettingSelects);
			}
		}
		
	}
}

//Toggles the sub menu under the menu active menu item
function toggleMenu(e)
{
	var evt=new CommonEvent(e);
	var activeMenu=document.getElementById('ActiveMenu');
	if(null===activeMenu)
	{//Show submenu
		if(
			('undefined'!==typeof evt.sender.tagName) &&
			('li'===evt.sender.tagName.toLowerCase()) &&
			(hasClass('MenuItem',evt.sender)))
		{
			evt.sender.id='ActiveMenu';
		}
	}
	else
	{//Hide submenu
		var element=evt.receiver;
		while(null!==element)
		{
			if('ActiveMenu'===element.id)
			{//Abort hide, the receiving element is a child of the menu item
				return;
			}
			element=element.parentNode;
		}
		activeMenu.removeAttribute('id');
	}
}

//Display hint on window.status
function textBox_Focus(e)
{
	var evt;
	evt=new CommonEvent(e);
	window.status=evt.sender.title;
}

//Clears window.status
function textBox_Blur(e)
{
	window.status='';
}
//Anchor click handler, opens the a new browser window and sets the new window's location to the href attribute of the sending anchor
function openExternalLink(e)
{
	var evt=new CommonEvent(e);
	var windowFeatures='top=0,left=0,channelmode=0,directories=1,fullscreen=0,menubar=1,location=1,resizable=1,scrollbars=1,status=1,titlebar=1,toolbar=1,width='+screen.availWidth+',height='+screen.availHeight;
	var popUp=null;
	var anchor;
	var oldHref='#';
	//We only do anchors...
	if('undefined'===typeof evt.sender.tagName){return true;}if('a'!==evt.sender.tagName.toLowerCase()){return true;}
	anchor=evt.sender;
	popUp=window.open(anchor.href,'_blank',windowFeatures);
	if(null===popUp)
	{//Popup blocker, probably - though some of them return non-null values
		anchor.target='_blank';//Fallback to this, though the new window might not have the proper width/height
		return true;
	}
	popUp.focus();
	evt.cancel();
	//Gecko workaround - prevent original window from navigating to the anchor's url.
	oldHref=anchor.href;
	anchor.removeAttribute('href');
	setTimeout(function(){anchor.href=oldHref;},0);
	return false;
}

//Adds a class name (multiple class names allowed) to the element's class attribute.
//className should be a valid css className string
//element should be a DOM element
//allowDuplicate should be boolean, although if omitted false will be used as a default
//If allowDuplicate is true, the multiple instances of the same class will be allowed, otherwise the new classes
//will only be added if none of them already exists within element.className
//Returns true on success, false otherwise
function addClass(className,element,allowDuplicate)
{
	var classes;
	var newClasses;
	if('string'!==typeof className){return false;}
	if(null===element){return false;}
	if('undefined'===typeof element){return false;}
	if('string'!==typeof element.className){return false;}
	if('undefined'===typeof allowDuplicate){allowDuplicate=false;}
	if('boolean'!==typeof allowDuplicate){return false;}
	classes=element.className.split(' ');
	newClasses=className.split(' ');
	for(var i=0;i<newClasses.length;i++)
	{
		if(
			(-1===classes.indexOf(newClasses[i])) || //No duplicate found
			(allowDuplicate))//Duplicates allowed
		{
			classes.push(newClasses[i]);
		}
		else
		{
			return false;
		}
	}
	classes=classes.join(' ');
	if(' '===classes.charAt(0))
	{
		classes=classes.substr(1);
	}
	element.className=classes;
	return true;
}

//Removes a class name (multiple class names allowed) from the element's class attribute.
//className should be a valid css className string
//element should be a DOM element
//removeAll should be boolean, although if omitted true will be used as a default
//If removeAll is true, every instance of every class within className will be removed from the element.className
//Returns true on success, false otherwise
function removeClass(className,element,removeAll)
{
	var classes;
	var existingClasses;
	var idx;
	if('string'!==typeof className){return false;}
	if(null===element){return false;}
	if('undefined'===typeof element){return false;}
	if('string'!==typeof element.className){return false;}
	if('undefined'===typeof removeAll){removeAll=false;}
	if('boolean'!==typeof removeAll){return false;}
	classes=className.split(' ');
	existingClasses=element.className.split(' ');
	for(var i=0;i<classes.length;i++)
	{
		idx=existingClasses.indexOf(classes[i]);
		while(-1!=idx)
		{
			existingClasses.splice(idx,1);
			if(!removeAll)
			{
				break;
			}
			idx=existingClasses.indexOf(classes[i]);
		}
	}
	existingClasses=existingClasses.join(' ');
	if(' '===existingClasses.charAt(0))
	{
		existingClasses=existingClasses.substr(1);
	}
	element.className=existingClasses;
	if(''===existingClasses)
	{
		element.removeAttribute('class');
	}
	return true;
}

//Checks whether the provided class name exists in the elements className attribute (multiple class names allowed)
//className should be a valid css className string
//element should be a DOM element
//Returns true if any of the class names exists in the className attribute of the element, false otherwise
function hasClass(className,element)
{
	var classes;
	var existingClasses;
	var idx;
	if('string'!==typeof className){return false;}
	if(null===element){return false;}
	if('undefined'===typeof element){return false;}
	if('string'!==typeof element.className){return false;}
	classes=className.split(' ');
	existingClasses=element.className.split(' ');
	for(var i=0;i<classes.length;i++)
	{
		if(-1!=existingClasses.indexOf(classes[i]))
		{
			return true;
		}
	}
	return false;
}
//Trident workaround: This function prevents a select element's selectedIndex property from changing to 0 (Zero)
//Whenever a label associated with it is clicked, This happens both on drop-down lists and multiple options selects.
function PreventTridentFromResettingSelects(e)
{
	var evt,label,select;
	evt=new CommonEvent(e);
	evt.cancel();
	label=evt.sender;
	while('label'!==evt.sender.tagName.toLowerCase())
	{
		label=label.parentNode;
		if(null===label)
		{
			return false;
		}
	}
	select=document.getElementById(label.htmlFor);
	if(true===select.disabled){return false;}//Can't focus on a disabled select element
	select.focus();
	return false;
}
//Gecko workaround: This function prevents our window from navigating to the page specified by evt.sender.href
function preventGeckoFromNavigating(evt,popUp)
{
	evt.sender.removeAttribute('href');
	setTimeout(function()
	{
		evt.sender.href=popUp.location.href;
	},0);
}

//Attempts to pop-up a helpful window, fallsback to target="_blank"
//The event should be fired from an anchor, the pop-up locations will be the anchor's href.
//Anchors with 'rect' as their shape attribute's value will be opened according to the anchor's coords attribute
//Anchors with their rel attribute set to anything except an empty string will create pop up named after the rel's value
//Note: Anchors without rel or with an empty string for rel will always spawn new windows,
//		Otherwise if a window with the same name (rel value) exists it will simply navigate to the anchor's href
//Note: Anchors without a valid shape/coords value will create windows stretched to fit the desktop's available width/height
//Note: An existing window will be resized to the values specified in the anchor's coords attribute
//Note: The coords should be provided as a comma separated list of lengths, So coords="50,12,100,300" means
//		top:50,left:12,width:100,height:300.
function showHelp(e)
{
	var top,left,width,height,windowFeatures,evt,anchor,name,popUp,coords;
	evt=new CommonEvent(e);
	anchor=evt.sender;
	name=anchor.rel;
	popUp=null;

	if('rect'===anchor.shape.toLowerCase())
	{
		coords=anchor.coords.split(',');
		if(4===coords.length)
		{
			top=Math.round(Number(coords[0]));
			left=Math.round(Number(coords[1]));
			width=Math.round(Number(coords[2]));
			height=Math.round(Number(coords[3]));
		}
	}
	width=(0===width)?screen.availWidth:width;
	height=(0===height)?screen.availHeight:height;
	//window.open third parameter, contains a list of features we desire
	windowFeatures='top='+top+',left='+left+',channelmode=0,directories=0,fullscreen=0,menubar=0,location=0,resizable=1,scrollbars=1,status=0,titlebar=1,toolbar=0,width='+width+',height='+height;
	if(''!==name)
	{
		popUp=window.popUps[name];
	}
	else
	{
		name='_blank';
	}
	if((null!==popUp)&&('undefined'!==typeof popUp))//Already popped
	{
		//  'unknown' is sometimes returned by MSIE, means the window is closed.
		if(('unknown'!==typeof popUp.closed)&&(true!==popUp.closed))//And still opened
		{
			popUp.location.assign(anchor.href);//Redirect the pop-up to the new location (same page, different anchor id)
			popUp.toggleDiv();//Force pop-up to show the correct div
			popUp.scrollTo(0,0);
			popUp.resizeTo(width,height);
			popUp.moveTo(top,left);
			popUp.focus();
			preventGeckoFromNavigating(evt,popUp);
			evt.cancel();
			return false;
		}
	}
	//Either the window was never opened or it was closed
	popUp=null;//Destory whatever remains of the old window and pop a new one
	popUp=window.open(evt.sender.href,evt.sender.rel,windowFeatures);
	if('_blank'!==name)
	{
		window.popUps[name]=popUp;
	}
	if(null===popUp)
	{//Popup blocker, probably - though some of them return non-null values
		evt.sender.target='_blank';
		return true;
	}
	popUp.focus();
	preventGeckoFromNavigating(evt,popUp);
	evt.cancel();
	return false;
}
//Returns a valid date representation in the form of a string. rx may be a RegExp instance or a RX string
//The dateObj is an optional parameter, upon successful execution it will contain the day,month and year 
//as integers
//Invalid dates will result in an empty string as the return value and an untouched dateObj.
function normalizeDate(date,rx,dateObj)
{
	var day,month,year,matches,tmp;
	if(!(rx instanceof RegExp))
	{
		rx=new RegExp(rx);
	}
	day='';
	month='';
	year='';
	if(/^[0-9]{5,8}$/.test(date))//this requires 5-8 date-looking digits
	//Micro date - [d]dmm[yy]yy
	{
		if((7===date.length)||(5===date.length))//Leading '0' missing from day of month
		{
			date='0'+date;
		}
		day=date.substr(0,2);
		month=date.substr(2,2);
		year=date.substr(4);
		if(2===year.length)
		{//00-30 becomes 2000-2030, 31-99 becomes 1931-1999
			tmp=Number(year);
			if((0<=tmp)&&(30>=tmp))
			{
				year=2000+tmp;
			}
			else
			{
				year=1900+tmp;
			}
		}
		date=day+'/'+month+'/'+year;
	}
	if(rx.test(date))//separated date, either from the user or from the above block
	{
		matches=rx.exec(date);
		day=matches[1];
		month=matches[7];
		if(('undefined'===typeof matches[10])||(''===matches[10]))
		{
			//00-30 becomes 2000-2030, 31-99 becomes 1931-1999
			tmp=Number(matches[11]);
			if((0<=tmp)&&(30>=tmp))
			{
				year='20';//20XX
			}
			else
			{
				year='19';//19XX
			}
		}
		else
		{
			year=matches[10];//20XX OR 19XX
		}
		year+=matches[11];
	}
	else
	{//Invalid date - returning an empty string
		return '';
	}
	if(isNaN(day)||(0==day)){day=1;}
	if(isNaN(month)||(0==month)){month=1;}
	day=Number(day);
	month=Number(month);
	year=Number(year);
	//Add leading zeros
	if(10>day){day='0'+day;}
	if(10>month){month='0'+month;}
	if(2===Number(month))
	{//Leap years....
		if(0==year%4)
		{
			if(0==year%100)
			{
				if(0==year%400)
				{
					day=Math.min(29,day);
				}
				else
				{
					day=Math.min(28,day);
				}
			}
			else
			{
				day=Math.min(29,day);
			}
		}
		else
		{
			day=Math.min(28,day);
		}
	}
	else
	{//Some months are longer
		if( -1 != [1,3,5,7,8,10,12].indexOf( 1 * month ))
		{
			day=Math.min(31,day);
		}
		else
		{
			day=Math.min(30,day);
		}
	}
	//0X/02/XXXX day need to have the leading zero re-applied
	if(10>day){day='0'+day;}
	if(('undefined'!==typeof dateObj)&&(null!==dateObj))
	{
		dateObj.day=Number(day);
		dateObj.month=Number(month);
		dateObj.year=Number(year);
	}
	return day+'/'+month+'/'+year;
}
normalizeDate.defaultRX=/^((0?[0-9]{1})|([1-2]{1}[0-9]{1})|(3{1}(0|1){1}))([-\/\.\\]{1})((0?[0-9]{1})|(1[0-2]{1}))\6(19|20)?([0-9]{2,2})$/;

//Updates the additional help anchors so they open up in popup windows
function updateHelpAnchors()
{
	var i,anchors;
	anchors=document.getElementsByTagName('a');
	for(i=0;i<anchors.length;i++)
	{
		if(hasClass('Help ImagelessHelper',anchors[i]))
		{
			detachEventListener('click',anchors[i],showHelp);//Prevent duplicates
			attachEventListener('click',anchors[i],showHelp);//Opens a pop-up window when clicked
		}
	}
}

function appendLogo(location)
{
	var search,searchLength,i,keyAndValue,logo;
	search=document.location.search.substr(1).split('&');
	searchLength=search.length;
	for(i=0;i<searchLength;i++)
	{
		keyAndValue=search[i].split('=');
		if(('logo'===keyAndValue[0].toLowerCase())&&(0!==(logo=Number(keyAndValue[1])))&&(!isNaN(logo)))
		{
			location+='&logo='+logo;
		}
	}
	return location;
}
