// ********************** world clocks *************************

var tmr;
var clocks = new Array();

//set timezones
var timezones = new Array();
timezones["London"] = 0;
timezones["Paris"] = 2;
timezones["Tokyo"] = 9;
timezones["New York"] = -5;

//calculate if daylight savings is in effect
var dstBegin = new Array();
var dstEnd = new Array();

/***** the below may need updating in future as dst can change from year to year *****/

//europe, begins 1am last sunday in march, ends 2am last sunday in October.
dstBegin["London"] = getLastSundayInMonth(2,1);
dstEnd["London"] = getLastSundayInMonth(9,1);
dstBegin["Paris"] = getLastSundayInMonth(2,1);
dstEnd["Paris"] = getLastSundayInMonth(9,1);

//new york, begins 2am first sunday in april, ends 2am last sunday in october
// From 2007 (until further notice) this is now: begins 2am second sunday in march, ends 2am first sunday in november
dstBegin["New York"] = getSecondSundayInMonth(2,2);
dstEnd["New York"] = getFirstSundayInMonth(10,1);

//tokyo, no dst adjustments required at present

/*************************** end of dst adjustments **********************************/

var months = new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');

function getFirstSundayInMonth(month,time) {
	//return the date of the first sunday in the given month
	var d = new Date();
	d.setMonth(month);
	d.setDate(1);
	var day = d.getDay();
	while (day > 0) {
		d.setDate(d.getDate()+1);
		day = d.getDay();
	}
	d.setHours(time);
	d.setMinutes(0);
	d.setSeconds(0);
	return d;
}

function getSecondSundayInMonth(month,time) {
	//return the date of the second sunday in the given month
	var d = new Date();
	d.setMonth(month);
	d.setDate(8);
	var day = d.getDay();
	while (day > 0) {
		d.setDate(d.getDate()+1);
		day = d.getDay();
	}
	d.setHours(time);
	d.setMinutes(0);
	d.setSeconds(0);
	return d;
}

function getLastSundayInMonth(month,time) {
	//return the date of the last sunday in the given month
	var d = new Date();
	d.setMonth(month);
	var match = new Date();
	match.setMonth(month);
	match.setDate(1);
	while (d.getMonth() == month) {
		if (d.getDay() == 0) match.setDate(d.getDate());
		d.setDate(d.getDate()+1);
	}
	match.setHours(time);
	match.setMinutes(0);
	match.setSeconds(0);
	return match;
}

function getHand(clock,hand) {
	var index;
	if (hand == 'hours') index = 1;
	else if (hand == 'minutes') index = 3;
	else if (hand == 'seconds') index = 5;
	return clock.childNodes[0].childNodes[index];
}

function setTime(clock, time) {

	//compensate for daylight savings
	tzOffset = clock.tzOffset;
	if (clock.dstBegin && clock.dstEnd) {
		if (time > clock.dstBegin && time <= clock.dstEnd) tzOffset ++;
	}

	//apply timezone offset
	time.setTime(time.getTime() + 3600*1000*(tzOffset + time.getTimezoneOffset()/60));

	//set analogue time
	getHand(clock,'hours').style.backgroundPosition = Math.floor(time.getHours() % 12)*-15 + 'px 0px'
	getHand(clock,'minutes').style.backgroundPosition = Math.floor(time.getMinutes()/2.5)*-15 + 'px 0px'
	getHand(clock,'seconds').style.backgroundPosition = Math.floor(time.getSeconds()/2.5)*-15 + 'px 0px'

	//set city
	clock.childNodes[1].innerHTML = '<strong>' + clock.city + '</strong>: ' + (time.getHours() % 24) + ':'
																+ padNumber(time.getMinutes(),2) + ', ' + time.getDate() + ' '
																+ months[time.getMonth()];
}

function getClassName(city) {
	return city.replace(' ','-').toLowerCase();
}

function updateClocks() {

	for (var c in clocks) {
		var now = new Date();
		setTime(clocks[c],now);
	}

}

addLoadEvent('topnav',function() {

	var divs = getElementsByTagName(document,'div');
	for (var d = divs.length-1;d > -1;d--) {
		var clockdiv = divs[d];
		if (clockdiv.className && clockdiv.className.indexOf('world-clock') > -1) {

			//add div to clocks array
			clocks.push(clockdiv);

			//add clock markup to div
			clockdiv.innerHTML = '<div class="clock-container">'
												 + '  <div class="hour-hand"><\/div>'
												 + '  <div class="minute-hand"><\/div>'
												 + '  <div class="second-hand"><\/div>'
												 + '<\/div>'
												 + '<span><\/span>'

			//get city and timezone
			for (var city in timezones) {
				var zoneClass = getClassName(city);
				if (clockdiv.className.indexOf(zoneClass) > -1) {
					clockdiv.city = city;
					clockdiv.tzOffset = timezones[city];
					clockdiv.dstBegin = dstBegin[city];
					clockdiv.dstEnd = dstEnd[city];
				}
			}

			//set intitial time
			setTime(clockdiv,new Date());

		}
	}
	tmr = window.setInterval("updateClocks()",1000);

});

// *********************** remember me *************************

function initRememberMe() {

	var remember = getElementById('remember-me');
	if (remember) {

		remember.style.visibility = 'visible';
		var form = getElementById('login-form');

		var username = getCookie('hemscottLoginDetails');
		if (username && username != '') {

			form.username.value = username;
			form.rememberme.checked = true;

		}

		var password = getCookie('hemscottPasswordDetails');
		if (password && password != '') {

			form.password.value = password;

		}

		addEvent(form,'submit',function () {

			var form = getElementById('login-form');

			if(form.rememberme.checked) {

				var expires = new Date();
				expires.setDate(expires.getDate()+3650); //expires after 10 years
				setCookie('hemscottLoginDetails',form.username.value,expires,'/');
				setCookie('hemscottPasswordDetails',form.password.value,expires,'/');

			} else {

				deleteCookie('hemscottLoginDetails');
				deleteCookie('hemscottPasswordDetails');

			}

		});

	}

}

// ************************* adverts ***************************

var tile = 1;
var pos = new Object();
var adTags = new Array();
var popupExclusions = new Array();
var ord = Math.random() * 100000000000000000;
var queryParams = getQueryParams(document.location.search);

//pages from which to exclude popups
popupExclusions.push('/');
popupExclusions.push('/home.do');
popupExclusions.push('/news/news-alerts-home.do');
popupExclusions.push('/news/news-alerts.do');
popupExclusions.push('/companies.do');
popupExclusions.push('/news/latest-news.do');
popupExclusions.push('/markets.do');
popupExclusions.push('/my-time.do');
popupExclusions.push('/news/rna.do');

//exclude popups from selected pages
for (var i in popupExclusions) {
	if (document.location.pathname == popupExclusions[i]) {
		adTags['!category'] = 'nopopup';
		break;
	}
}

addLoadEvent('disclaimer',function() {

	if (typeof(queryParams.showAdTags) != 'undefined') {
		var tags = '';
		for (var i in adTags) tags += i + '=' + adTags[i] + ';'
		alert(tags);
	}

	setInterval('refreshFeatures()', 120000);
	setInterval('refreshAds()', 120000);
});

function getAdFrame(type,tile,pos,includeIst) {

	//get ad tags parameters
	var misc = '';
	for (var i in adTags) misc += i + '=' + adTags[i] + ';'

	//show test ads for debugging purposes
	if (typeof(queryParams.testAds) != 'undefined') misc += 'test=testfiller;';

	return '<iframe allowtransparency="true" scrolling="no" frameborder="0" align="middle" src="/hsretail/jsp/adframe.jsp?type='
		+ type + '&ad=' + queryParams[type] + '&tile=' + tile + '&misc=' + escape(misc) + '&ord=' + ord + '&pos=' + pos + '&ist='
		+ includeIst + ((typeof(queryParams.showAdURL) != 'undefined')?'&showAdURL=true':'') + '"></iframe>';

}


function deleteCookie(name) {
	//delete a cookie
	document.cookie = name + '=; expires=-1; path=/';
}

function loadAd(type, placement, key) {
	if (queryParams[type] != undefined){
		//load initial ad state
		if (typeof(pos[type]) == 'undefined') pos[type] = 1;
		document.write('<div id="' + type + pos[type] + '" class="' + tile + '">' + getAdFrame(type,tile++,type + pos[type]++,true) + '</div>');
	}else{
		var morningstarId = 665;
		var now = new Date().getTime();

		var adTypeCode;
		switch (type) {
			case "banner":
				adTypeCode = 1;
				break;
			case "button":
				adTypeCode = 94;
				break;
			case "feature":
				adTypeCode = 186;
				break;
			case "leaderboard":
				adTypeCode = 225;
				break;
			case "mpu":
				adTypeCode = 170;
				break;
			case "overlay":
				adTypeCode = 16;
				break;
			case "skyscraper":
				adTypeCode = 154;
				break;
			case "ticker":
				adTypeCode = 2471;
				break;
		}
		if (window.adgroupid == undefined) window.adgroupid = Math.round(Math.random() * 1000);

		document.write('<script src="http://adserver.adtech.de/addyn|3.0|' + morningstarId + '|' + placement + '|0|' + adTypeCode + '|ADTECH;loc=100;target=_blank;key='+key+';grp=' + window.adgroupid + ';misc=' + now + '"></script>');
	}
}

function refreshFeatures() {
	//random = Math.random() * 100000000000000000;

	//for (var i = 1;refreshAd('feature',i);i++);
}

function refreshAds() {
	//ord = Math.random() * 100000000000000000;

	//for (var i = 1;refreshAd('banner',i);i++);
	//setTimeout(function() { for (var i = 1;refreshAd('skyscraper',i);i++); },2000);
	//setTimeout(function() { for (var i = 1;refreshAd('mpu',i);i++); },4000); 
}

function refreshAd(type,pos) {
	setWide(type + pos)
	var div = getElementById(type + pos)
	if (div) div.innerHTML = getAdFrame(type,div.className,div.id,false);
	return div;
}

function setNarrow(pos) {
	//resize an ad frame to be narrow
	/*var ad = getElementById(pos);
	if (ad) ad = ad.parentNode;
	if (ad && elementHasClass(ad,'banner')) applyClass(ad,'narrow-banner');
	else if (ad && elementHasClass(ad,'skyscraper')) applyClass(ad,'narrow-sky');*/
}

function setWide(pos) {
	//resize an ad frame to be wide
	/*var ad = getElementById(pos);
	if (ad) ad = ad.parentNode;
	if (ad && elementHasClass(ad,'banner')) removeClass(ad,'narrow-banner');
	else if (ad && elementHasClass(ad,'skyscraper')) removeClass(ad,'narrow-sky');*/
}

function flipAd(pos,content) {
	//function to move the ad out of the frame into the page body
	//this function is called from within adverts.js once ad has loaded
	var ad = document.getElementById(pos);
	if (ad) ad.innerHTML = content;
}

// *********************** market tabs *************************

var marketTabLinks;
var marketTabs;

addLoadEvent('disclaimer',function() {
	var marketsDiv = getElementById('market-nav');
	if (marketsDiv) {

		marketTabLinks = getElementsByTagName(marketsDiv,'a');
		for (var i=0;i < marketTabLinks.length;i++) {
			var href= marketTabLinks[i].href;
			marketTabLinks[i].href = 'javascript:setMarketTab(' + i + ');';
		}

		marketTabs = getElementsByClassName(getElementById('world-markets'),'div','market-tab');
	}
});

function setMarketTab(index) {
	for (var i=0;i < marketTabLinks.length;i++) {
		if (i == index) marketTabLinks[i].className = 'selected';
		else marketTabLinks[i].className = '';
	}
	for (var i=0;i < marketTabs.length;i++) {
		if (i == index) marketTabs[i].style.display = 'block';
		else marketTabs[i].style.display = 'none';
	}
}

// ******************** seminars validation ********************

addLoadEvent('disclaimer',function() {
	var seminarsForm = getElementById('seminars-form');
	if (seminarsForm) {

		addEvent(getElementById('invite-friend'),'click',function() {
			getElementById('friend-contact').style.display = (getElementById('invite-friend').checked)? 'block':'none';
		});

	}
});

// ************************* toolbox ***************************

function printPage() {
	window.print();
}

function bookmarkPage() {
	alert('Press Ctrl-D to add this page to favourites');
}

addLoadEvent('tool-box',function() {

	//print button
	var printButton = getElementById('toolbox-print');
	if (printButton) {
		printButton.style.display = 'block';
		printButton.href = 'javascript:printPage();';
	}

	//bookmark page
	var bookmarkButton = getElementById('toolbox-favourites');
	if (bookmarkButton) {
		bookmarkButton.style.display = 'block';
		bookmarkButton.href = 'javascript:bookmarkPage();';
	}

});

// *************** form, login and search fields ****************

function initSidebar() {

	//sidebar login and search
	var passText = 'Password';
	passPromptFunc();
	setElementClear(getElementById('login-box-username'),'Username');
	setElementClear(getElementById('company-search-box'),'Name or EPIC');

}

function setJsHover(element) {
	//dummy stub function for ie script
}

function clonePass(oldPass) {
	//clone a subset of the properties of the password input box
	var newPass = document.createElement('input');
	newPass.name = oldPass.name;
	newPass.className = oldPass.className;
	newPass.id = oldPass.id;
	newPass.title = oldPass.title;
	return newPass;
}

function passPromptFunc() {
	var oldPass = getElementById('login-box-password');
	if (!oldPass || oldPass.value != '') return;
	var newPass = clonePass(oldPass);
	newPass.type = 'text';
	newPass.value = passText;
	addEvent(newPass,'focus',passClearFunc);
	setJsHover(newPass);
	replaceElement(oldPass,newPass);
}

function passClearFunc() {
	var oldPass = getElementById('login-box-password');
	if (!oldPass || oldPass.value != passText) return;
	var newPass = clonePass(oldPass);
	newPass.type = 'password';
	addEvent(newPass,'blur',passPromptFunc);
	setJsHover(newPass);
	replaceElement(oldPass,newPass);
	setTimeout(function() {newPass.focus();},100);
}

function setElementClear(element,clearText) {
	//set a text input field to clear when focussed
	if (!element) return;
	addEvent(element,'focus',function() {
		element.focus();
		if (element.value != clearText) return;
		element.value = '';
	});
	addEvent(element,'blur',function() {
		if (element.value != '') return;
		element.value = clearText;
	});
	if (element.value == '') element.value = clearText;
	element.blur();
}

function updateNameEpicClearText() {
	//set the cleartext for the name/epic search field
	var field = getElementById('company-search-field');
	var radio = getElementById('search-type-name');
	if (!field || !radio) return;
	if (field.value != '' && field.value != 'Enter Name' && field.value != 'Enter Epic') return;
	if (radio.checked) field.value = 'Enter Name';
	else field.value = 'Enter Epic';
}

addLoadEvent('disclaimer',function() {

	//search page name/epic search
	//clear name/epic field based on radio button settings
	var field = getElementById('company-search-field');
	if (field) {
		addEvent(field,'focus',function() {
			field.focus();
			if (field.value != 'Enter Name' && field.value != 'Enter Epic') return;
			field.value = '';
		});
		addEvent(field,'blur',updateNameEpicClearText);
		updateNameEpicClearText();
		field.blur();
	}

	//name/epic search radio buttons
	addEvent(getElementById('search-type-name'),'click',updateNameEpicClearText);
	addEvent(getElementById('search-type-epic'),'click',updateNameEpicClearText);

	//sudoku submission form
	var sudokuForm = getElementById('submission-form');
	if (sudokuForm) {
		var fields = getElementsByClassName(sudokuForm,'input','textbox');
		setElementClear(fields[0],'Name');
		setElementClear(fields[1],'Email Address');
		setElementClear(fields[2],'Telephone No.');  
	}

	//seminars form
	var seminarsForm = getElementById('seminars-form');
	if (seminarsForm) {
		setElementClear(getElementById('friend-email'),'same as above');
		setElementClear(getElementById('friend-phone'),'same as above');
	}

});

// ********************* truncated links ***********************

var untruncated;

function setUntruncateHover(element) {
	if (element && element.title && element.title != '' && element.title != element.innerHTML) {

		element.untruncated = element.title;
		element.title = '';

		var offset = (typeof(isMSIE)!='undefined')? 4:3;

		addEvent(element,'mouseover',function() {
			untruncated.innerHTML = '<a href="' + element.href + '">' + element.untruncated + '</a>';
			setElementPosition(untruncated,getOffsetLeft(element) - offset, getOffsetTop(element) - 4);
		});

	}
}

addLoadEvent('disclaimer',function() {

	untruncated = createElement('div');
	insertElementBefore(untruncated,document.getElementById('footer'));
	untruncated.id = 'untruncated';

	addEvent(untruncated,'mouseout',function() {setElementPosition(untruncated,-1000,-1000);});

	var links = getElementsByClassName(document,'a','truncated');
	for (var i=0;i < links.length;i++) setUntruncateHover(links[i]);

});

// *************** external link functionality *****************

addLoadEvent('disclaimer',function() {
	var links = getElementsByTagName(document,'a');
	for(var i=0;i < links.length;i++) {
		var link = links[i];

		if (link.innerHTML.substring(0, 4) != 'www.'){
			if (link.href != '' && link.href.indexOf('mailto:') == -1) link.href = link.href.replace(/miranda/,'www');
		}

		if ((link.href.indexOf('http://') > -1 && link.href.indexOf('http://' + document.location.host) == -1)
		 || (link.href.indexOf('https://') > -1 && link.href.indexOf('https://' + document.location.host) == -1)
		 || elementHasClass(link,'external')) {
			link.target = "_blank";
			if (link.title == '') link.title = 'opens in a new window';
			else link.title += ' (opens in a new window)';
			if (!elementHasClass(link,'no-icon')
			 && !elementHasClass(link,'feature')
			 && !elementHasClass(link,'button')
			 && !elementHasClass(link,'button-submit')
			 && !elementHasClass(link,'anchor-submit')
			 && !elementHasClass(link,'anchor-submit-arrow')
			 && link.href.indexOf('google.com/intl/en_ALL/help/terms_maps') == -1
			 && link.innerHTML.indexOf('<img') == -1
			 && link.innerHTML.indexOf('<IMG') == -1) link.className += ' external-icon';
		}
	}
});

// ******************** news alerts popup message ************************

if (document.location.pathname == '/' || document.location.pathname == '/home.do') {
	//if (!getCookie('newsAlertsPopupDontShow')) addLoadEvent('container',openPopup);
	//if (!getCookie('newsAlertsPopunderDontShow')) openPopunder();
}

function openPopunder() {
	var popup = openPopup('newsAlertsPopunder');
	popup.blur();
	window.focus();
}

function openPopup(name) {
	if (typeof(name) == 'undefined') cookie = 'newsAlertsPopup';
	var popup = window.open('/hsretail/adverts/popups/news-alerts.html?' + name + 'DontShow',name,'width=1,height=1');
	if (popup.opener == null) popup.opener = window;
	return popup;
}

function setURL(url) {
	document.location.href = url;
}

// ******************** welcome message ************************

//if (!getCookie('newsAlertsPopupDontShow')) importScript('/hsretail/js/popup.js');


// ***************** subsector dropdowns  ******************

function initSectorDropdowns() {

	sector = getElementById('sctr');
	subsector = getElementById('sbSctr');

	addEvent(sector, 'change', updateSectors);

	if (typeof(isMSIE) != 'undefined') {
		for (i=0;i<subsector.options.length;i++) subsectors[subsectors.length] = subsector.options[i];
	}

	updateSectors();

}

function updateSectors() {

	subsector.disabled = (sector.value == -1);
	if (subsector.disabled) subsector.value = -1;

	if (!subsector.disabled) {
		for (i=0;i<subsector.options.length;i++) {
			if (subsector.options[i].value != -1 && subsector.options[i].className != sector.value) {
				subsector.options[i].style.display = 'none';
				if (i == subsector.selectedIndex) subsector.value = -1;
			} else {
				subsector.options[i].style.display = '';
			}
		}
	}

}

// ***************** toggle functions  ******************

function writeExpandContractAll(title, id) {
	document.write ("&#160;<span style=\"font-weight:normal;\"><a class=\"pointer\" onclick=\"toggleAllRows('"+title+"', '"+id+"', 'show')\">Expand all</a>&#160;|&#160;<a class=\"pointer\" onclick=\"toggleAllRows('"+title+"', '"+id+"', 'hide')\">Contract all</a></span>");
}

function writeExpandContractLink(title, id, position) {
	document.write ("<a title=\"Hide this "+title+"'s consituents\" class=\"pointer\" id =\""+title+"_"+position+"\" onclick=\"toggleRows('"+title+"', '"+id+"', this.parentNode.parentNode.rowIndex)\">-</a>&#160;");
}

function toggleRows(title, id, rowIndex){
	rowIndex -= 1;
	for (i = rowIndex; i < rowIndex+100; i++){
		if (i == rowIndex){
			if (elementHasClass(document.getElementById(id).tBodies[0].rows[i+1], 'hidden')){
				getElementById(title+'_'+rowIndex).innerHTML = "&ndash;";
				getElementById(title+'_'+rowIndex).title = "Hide this "+title+"'s consituents";
			}else{
				getElementById(title+'_'+rowIndex).innerHTML = "+";
				getElementById(title+'_'+rowIndex).title = "Show this "+title+"'s consituents";
			}
		}else{
			if (elementHasClass(getElementById(id).tBodies[0].rows[i], 'hidden')){
				removeClass(getElementById(id).tBodies[0].rows[i], "hidden");
				applyClass(getElementById(id).tBodies[0].rows[i], "visible");
			}else if (elementHasClass(getElementById(id).tBodies[0].rows[i], 'visible')){
				removeClass(getElementById(id).tBodies[0].rows[i], "visible");
				applyClass(getElementById(id).tBodies[0].rows[i], "hidden");
			}else{
				break;
			}
		}
	}
}

function toggleAllRows(title, id, which){
	var aRows = getElementById(id).tBodies[0].getElementsByTagName('tr');
	for(var i=0; i < aRows.length; i++ ){
		if (!elementHasClass(aRows[i], 'dark')){
			if (which == 'show'){
				if (elementHasClass(aRows[i], 'hidden')) removeClass(aRows[i], "hidden");
				applyClass(aRows[i], "visible");
			}else{
				if (elementHasClass(aRows[i], 'visible')) removeClass(aRows[i], "visible");
				applyClass(aRows[i], "hidden");
			}
		}else{
			if (which == 'show'){
				getElementById(title+'_'+i).innerHTML = "&ndash;";
				getElementById(title+'_'+i).title = "Hide this "+title+"'s consituents";
			}else{
				getElementById(title+'_'+i).innerHTML = "+";
				getElementById(title+'_'+i).title = "Show this "+title+"'s consituents";
			}
		}
	}
}

// *************** fundamentals sector dropdowns ***************

var sector;
var subsector;

function initSectors() {

	sector = getElementById('sector-dropdown');
	subsector = getElementById('subsector-dropdown');

	addEvent(sector, 'change', updateSectors);

	if (typeof(isMSIE) != 'undefined') {
		for (i=0;i<subsector.options.length;i++) subsectors[subsectors.length] = subsector.options[i];
	}

	updateSectors();

}

function updateSectors() {

	subsector.disabled = (sector.value == -1);
	if (subsector.disabled) subsector.value = -1;

	if (!subsector.disabled) {
		for (i=0;i<subsector.options.length;i++) {
			if (subsector.options[i].value != -1 && subsector.options[i].className != sector.value) {
				subsector.options[i].style.display = 'none';
				if (i == subsector.selectedIndex) subsector.value = -1;
			} else {
				subsector.options[i].style.display = '';
			}
		}
	}

}

// ***************** general utility functions ******************

function padNumber(number,width) {
	//pad a number with zeros, up to the specified width;
	var s = '' + number;
	while (s.length < width) s = '0' + s;
	return s;
}

function trim(text) {
	//trim whitespace from a string
	text = text.replace(/^\s+/g,''); //leading space
	return text.replace(/\s+$/g,''); //trailing space
}

function elementHasClass(element, className) {
	//return true if the element has the given class name
	className = className.replace(/\-/g, '\\-');
	var re = new RegExp('(^|\\s)' + className + '(\\s|$)');
	return re.test(element.className);
}

function applyClass(element, className) {
	//add a class to an element
	if (!elementHasClass(element, className)) element.className += ' ' + className;
}

function removeClass(element, className) {
	//remove a class from an element
	className = className.replace(/\-/g, '\\-');
	var re = new RegExp('(^|\\s)' + className + '(\\s|$)');
	element.className = element.className.replace(re,'');
}

function getElementById(id) {
	//get element with a given id
	return (document.all)? document.all[id] : document.getElementById(id);
}

function getElementsByTagName(container, tagName) {
	//get all html nodes of a given type within a given container
	if (container) return container.getElementsByTagName(tagName);
	else return new Array();
}

function getElementsByClassName(container, tagName, className) {
	//get all html nodes of a given type and class within a given container
	var elements = getElementsByTagName(container, tagName);
	var result = new Array();
	for(var i=0;i < elements.length;i++) {
		var e = elements[i];
		if (elementHasClass(e,className)) result.push(e);
	}
	return result;   
}

function addEvent(element, event, func) {
	//add an event to the specified element, preserving any existing events that are attached
	if (!element) return;
	if (element.addEventListener) {
		element.addEventListener(event, func, false);
		return true;  
	} else {
		var oldFn = element['on' + event];
		var fn;
		if (oldFn) {
			fn = function() {
				return oldFn();
				return func();
			}
		} else {
			fn = func;
		}
		if (element.attachEvent) return element.attachEvent('on' + event, fn);
		else element['on' + event] = fn;
	}
}

function addLoadEvent(id,func) {
	//add an onload event which will fire once the given id is located within the document
	//this is more reliable than window.onload and will happen exactly when needed

	function loadEvent() {
		var element = getElementById(id);
		if (element) func(); else window.setTimeout(loadEvent,2000);
	}

	loadEvent();

}

function createElement(tagName) {
	//create an html node of the specified type
	return document.createElement(tagName);
}

function createTextNode(text) {
	//create an html text node
	return document.createTextNode(text);
}

function replaceElement(element,replacement) {
	//replace an html node with the specified alternative
	if (element) element.parentNode.replaceChild(replacement,element);
}

function insertElement(parent,child) {
	//insert an html node within the specified parent, after the last child
	if (parent) parent.appendChild(child);
}

function removeElement(element) {
	//remove the specified node from the dom tree
	if (element && element.parentNode) element.parentNode.removeChild(element);
}

function insertElementBefore(element,before) {
	//insert an html node before the specified element
	if (before && before.parentNode) before.parentNode.insertBefore(element,before);
}

function insertElementAfter(element,after) {
	//insert an html node after the specified element
	if (after && after.parentNode) {
		if (after.nextSibling) insertElementBefore(element,after.nextSibling);
		else insertElement(after.parentNode,element);
	}
}

function showChildren(element, show) {
	//show or hide all the children of the specified element
	var display = (show)? 'inline':'none';
	if (element) for (e in element.childNodes) {
		var e = element.childNodes[e];
		if (e.style) e.style.display = display;
	}
}

function setElementPosition(element,x,y) {
	//set the absolute (document relative) position of an element in pixels
	if (element.offsetParent) { // using ie's relative positioning model
		x -= getOffsetLeft(element.parentNode);
		y -= getOffsetTop(element.parentNode);
	}
	element.style.left = x + 'px';
	element.style.top = y + 'px';
}

function getOffsetTop(element) {
	//get the absolute (document relative) position of an element in pixels
	var o = element.offsetTop;
	while (element.offsetParent) {
		element = element.offsetParent
		o += element.offsetTop;
	}
	return o;
}

function getOffsetLeft(element) {
	//get the absolute (document relative) position of an element in pixels
	var o = element.offsetLeft;
	while (element.offsetParent) {
		element = element.offsetParent
		o += element.offsetLeft;
	}
	return o;
}

function importScript(url) {
	//import an external javascript file
	document.writeln('<script type="text/javascript" src="' + url + '"></scr' + 'ipt>');
}

function getQueryParams(query) {
	//decode query parameters into an associative array
	var params = new Object();
	if (!query) return params;
	var start = query.indexOf('?');
	if (start > -1) query = query.substr(start + 1);
	var paramArray = query.split("&");
	for (var i in paramArray) {
		var param = paramArray[i];
		var splitPos = param.indexOf("=");
		var name = unescape(param.substring(0,splitPos));
		var value = unescape(param.substring(splitPos+1));
		params[name] = value;
	}
	return params;
}

function setCookie(name, value, expires, path, domain, secure) {
	//set a cookie
	document.cookie = name + '=' + escape(value) +
		((typeof(expires) != 'undefined' && expires) ? '; expires=' + expires.toGMTString() : '') +
		((typeof(path) != 'undefined' && path) ? '; path=' + path : '; path=/') +
		((typeof(domain) != 'undefined' && domain) ? '; domain=' + domain : '') +
		((typeof(secure) != 'undefined' && secure) ? '; secure' : '');
}

function deleteCookie(name) {
	//delete a cookie
	document.cookie = name + '=; expires=0; path=/';
}

function getCookie(name) {
	//get a cookie
	var dc = document.cookie;
	var prefix = name + '=';
	var begin = dc.indexOf('; ' + prefix);
	if (begin == -1) {
		begin = dc.indexOf(prefix);
		if (begin != 0) return null;
	} else begin += 2;
	var end = document.cookie.indexOf(';', begin);
	if (end == -1) end = dc.length;
	return unescape(dc.substring(begin + prefix.length, end));
}