$(document).ready(function(){
	uid.triggerRichText();
	/* Delay the initialising of collapsible text a little, so that any code that manipulates
	the dom tree on page load has finished before the initing, since the event handlers added
	during the initing otherwise are lost during the dom operations. */
	setTimeout(uid.collapseCollapsibles, 200);
	uid.initPredefChangeListeners();
	uid.initUtilButtons();
	initDataCells(); //In case this is a page that needs it. Won't do any harm otherwise.
	//$('.input_otherval').keyup(); //Force detection of initial state for the "other" input fields
	uid.initHiddenDescriptions();
	uid.collapseExpandables();
	uid.initHoverVisibleStuff();
	if(window.location.href.match(/^.*(idea.int\/uid\/admin\/|plainData\.cfm).*$/i)){ //Things intended for the admin pages only
		uid.createJumpLinks();
		if(getHashNoHash() != ''){
			window.location.hash=window.location.hash; //Refresh hash to trigger scroll now that the target anchor exists
		}
	}
});


var uid = {};

uid.editors = {};
uid.qid = -1;
uid.curButton = undefined;
uid.stayTimeout = 1500; //Number of milliseconds the popup stays visible after the mouse has left it or the triggering button.
uid.popupShowing = false;
uid.popupTimeout = 0;
uid.cursorResetTimeout = 0;
uid.openEditInNewWin = true; //The js edit links in the export previews either open in new windows/tabs or in same
uid.defaultInteractionLevel = 2; //1 = disallow editing, 2 = allow editing
uid.progressIndicatorTimeout = 0;
uid.ProgressIndicatorUpdateInterval = 3000; //milliseconds

/* This functions sets visibility to hidden instead of display to none, so that the layout should not be affected */
uid.initHoverVisibleStuff = function(){
	$('table.uidCountryTable tbody tr').mouseenter(function(){
		var me = $(this);
		me.closest('tbody').find('td.actions img').css('visibility', 'hidden').css('opacity', '.001'); //In case a mouseleave wasn't registered, which seems common.
		me.find('td.actions img').css('visibility', 'visible').fadeTo(1, 'slow');
	})
	.mouseleave(function(){
		$(this).find('td.actions img').css('visibility', 'hidden').css('opacity', '.001');
	});
}

uid.createJumpLinks = function(){
	$('body').prepend('<a name="top"></a>');
	var headings = $('#pageLayout td:first h2');
	if(headings.length > 0){
		var box = $('<div id="jumpLinks" class="jumpLinks rhmBox"></div>');
		box.append('<h2>On this page</h2>');
		var ul = $('<ul></ul>');
		box.append(ul);
		$('#rhm').prepend(box); //Maybe safest to insert it into the page already so that event handlers survive
		$('#pageLayout td:first h2').not('.noindex').each(function(){
			var me = $(this);
			var myContents = uid.stripHTML(me.html());
			var theLink = $('<a href="#' + myContents + '">' + myContents + '</a>');
			var theLi = $('<li></li>');
			theLi.append(theLink);
			ul.append(theLi);
			/* If the jump link leads to an expandable section, auto expand it if not already expanded. */
			if(me.is('.expandableTrigger') || me.find('label.expandableTrigger').length > 0){
				theLink.click(function(){
					var me = $(this);
					var jumpTarget = $('a[name=' + me.attr('href').replace('#', '') + ']'); 
					var trigger = jumpTarget.siblings('label.expandableTrigger');
					if(trigger.length === 0){ //It has no such label sibling so assume the trigger is a parent instead
						trigger = jumpTarget.closest('expandableTrigger');
					}
					trigger
						.not('.expanded')
						.click();
				});
			}
			me.append('<a class="top" name="' + myContents + '" href="#top">top</a>');
		});
	}
}

uid.collapseExpandables = function(){
	$('.expandableTrigger')
		.attr('title', 'Click to expand/collapse')
		.click(function(){
		var me = $(this);
		var expandable;
		var id = me.attr('for'); //This may be a label explicitly indicating which element it's tied to
		if (id && id != '') {
			// we know exactly which element to expand
			expandable = $('#' + id);
		} else if(me.is('label')) { // we need to work it out from context (if this is a label inside a heading)
			expandable = me.parent().next(".expandable");
		}
		else { // we need to work it out from context (this is probably the heading itself)
			expandable = me.next(".expandable");
		}
		if(expandable.is(':visible')){
			me.removeClass('expanded');
			expandable
				.slideUp('normal')
				.removeClass('expanded');
		}
		else {
			me.addClass('expanded');
			expandable
				.slideDown('normal')
				.addClass('expanded');
		}
	});
}

uid.initHiddenDescriptions = function(){
	var allDescs = $('div.hiddenDesc > div');
	/* This was meant to enable collision detection, but has no such effect and it fails to position properly */
	/*allDescs.each(function(){
		var me = $(this);
		me.position({
			my: 'top left',
			at: 'top left',
			offset: '0, 0',
			of: me.parent(),
			collision: 'none'
		});
	});*/ 
	var curTimeout;
	
	allDescs
		.parent().closest('td,th,li,h1,h2,h3,h4,div[class!=hiddenDesc]') //.parent() prevents the selector to select the inner div itself
		.css('cursor', 'help')
		.mouseenter(function(){
			var me = $(this);
			allDescs.fadeOut(200);
			curTimeout = setTimeout(function(){
				me.find('.hiddenDesc div').fadeIn('normal', uid.preventUIDOutputOverflow);			
			}, 750);
		})
		.mouseleave(function(){ 
			clearTimeout(curTimeout);
			curTimeout = 0;
			$(this).find('.hiddenDesc div').fadeOut('fast', uid.clearLeftTopMargins);
		});
}

/* Can be called both as an event handler and with an explicit jquery object */
uid.clearLeftTopMargins = function(me){
	if(!me){
		var me = $(this);
	}
	me.css('margin-left', 0);
	me.css('margin-top', 0);
};

uid.preventUIDOutputOverflow = function(){
	var me = $(this);
	var uidOutput = $('#uidOutput');
	var viewData = me.closest('#viewData');
	if(uidOutput.length == 1 && viewData.length == 1){ //viewData should always be a parent but something goes wrong sometimes
		var uidOutputWidth = uidOutput.innerWidth();
		var myWidth = me.childrenWidth();
		var myLeft = +me.css('left').replace(/^\D*(\d*)\.?\d*\D*$/, '$1');
		var myParentLeft = me.parent().position().left;
		var scrollLeftOffset = uidOutput[0].scrollLeft;
		var leftLimit = -(myLeft + myParentLeft);
		var uidOutputHeight = uidOutput.innerHeight();
		var myHeight = me.childrenHeight();
		var myTop = +me.css('top').replace(/^\D*(\d*)\.?\d*\D*$/, '$1');
		var myParentTop = me.parent().position().top;
		var scrollTopOffset = uidOutput[0].scrollTop;
		var myGrandParentTop = me.closest('#viewData').position().top;
		var topLimit = -(myTop + myParentTop - myGrandParentTop);

		//$.log('scrollLeft is ' + scrollLeftOffset + ', scrollTop is ' + scrollTopOffset);
		
		var xDiff = Math.min(0, Math.max(leftLimit, -(myWidth + myLeft + myParentLeft - uidOutputWidth)));
		var yDiff = Math.min(0, Math.max(topLimit, -(myHeight + myTop + myParentTop - scrollTopOffset - myGrandParentTop - uidOutputHeight)));
		
		me.animate({marginLeft: xDiff + 'px', marginTop: yDiff + 'px'}, 'fast', 'swing');
		
		//$.log('leftLimit is ' + leftLimit + ', xDiff is ' + xDiff + ' (' + myWidth + ' + ' + myLeft + ' + ' + myParentLeft + ' - ' + uidOutputWidth + ')');
		//$.log('topLimit is ' + topLimit + ', yDiff is ' + yDiff + ' (' + myHeight + ' + ' + myTop + ' + ' + myParentTop + ' - ' + scrollTopOffset + ' - ' + myGrandParentTop + ' - ' + uidOutputHeight + ')');
	}
};

/**
* todo: describe this
*/
uid.initUtilButtons = function(){
	$('#tcellmain, #uidOutput').delegate('td.d, td.n, a.utilBtn', 'click', function(e){
		var me = $(this);
		var interactionLevel;
		if(me.hasClass('noedit')){
			interactionLevel = 1;
		}
		else {
			interactionLevel = uid.getInteractionLevel();
		}
		if(me.hasClass('existing') || me.attr('id').split('_')[0] == 'd'){
			// this cell contains an existing data point with an ID
			uid.popupDataMenu(e, this, $(this).attr('id').split('_')[1], null, null, interactionLevel);
		}
		else if(interactionLevel > 1) {
			var parts = $(this).attr('id').split('_');
			if (parts[0] == 'n') {
				// this cell doesn't have a data ID yet (it's new that a user is going to fill in)
				if (parts.length == 3) {
					// we don't have any occurred year data
					uid.popupDataMenu(e, this, null, parts[1], parts[2], interactionLevel);
				} else {
					// parts[3] is the occurred
					uid.popupDataMenu(e, this, null, parts[1], parts[2], interactionLevel, parts[3]);
				}
			}	else {
				// todo: display an error
			}
		}
	});
	
	/*var set1 = $('#tcellmain').find('td.d, td.n, a.utilBtn');
	var all = $('#uidOutput').find('td.d, td.n').add(set1);
	all.each(function(){
		var me = $(this);
		var interactionLevel;
		if(me.hasClass('noedit')){
			interactionLevel = 1;
		}
		else {
			interactionLevel = uid.getInteractionLevel();
		}
		if(me.hasClass('existing') || me.attr('id').split('_')[0] == 'd'){
			// this cell contains an existing data point with an ID
			me.click(function(e) {
				uid.popupDataMenu(e, this, $(this).attr('id').split('_')[1], null, null, interactionLevel);
			});
		}
		else if(interactionLevel > 1) {
			me.click(function(e) {
				var parts = $(this).attr('id').split('_');
				if (parts[0] == 'n') {
					// this cell doesn't have a data ID yet (it's new that a user is going to fill in)
					if (parts.length == 3) {
						// we don't have any occurred year data
						uid.popupDataMenu(e, this, null, parts[1], parts[2], interactionLevel);
					} else {
						// parts[3] is the occurred
						uid.popupDataMenu(e, this, null, parts[1], parts[2], interactionLevel, parts[3]);
					}
				}	else {
					// todo: display an error
				}
			});
		}
	});*/
};

uid.getInteractionLevel = function(){
	if(!uid.interactionLevel){ //not defined so set to default
		uid.interactionLevel = uid.defaultInteractionLevel;
	}
	return uid.interactionLevel;
};

/**
* Ensure that the container for bubbleInfo exists in the DOM
*/
uid.ensurePopupExistance = function(){
	if($('#bi').length === 0) {
		$('body').append('<div class="bubbleInfo" id="bi"><div class="uidPopup" id="bic"></div></div>');
	}
};

/**
* Render a popup menu when a user has clicked on a data cell
* @param (object) event 		(the native event object)
* @param (object) button 		(the dom element that was clicked)
* @param (int) dId 				(the id of the data point for existing data)
* @param (int) fId				(the id of the field for new data)
* @param (int) cId				(the id of the country for new data)
* @param (int) interactionLevel	(the level of interaction allowed, 1=no editing, 2=editing allowed)
* @param {int} year 			(like 1999 or 2009 - no other formatting)
*/
uid.popupDataMenu = function(event, button, dId, fId, cId, interactionLevel, year) {
	if(!interactionLevel) {
		interactionLevel = uid.getInteractionLevel();
	}
	uid.ensurePopupExistance();
	$.log('popupDataMenu: clearing timeout');
	clearTimeout(uid.popupTimeout);
	if (uid.curButton != button){
		$(uid.curButton).unbind('mouseenter').unbind('mouseleave');
		uid.curButton = button;
		$(uid.curButton).add('#bi')
			.mouseenter(function(){
				$.log('clearing timeout because of mouseenter');
				clearTimeout(uid.popupTimeout);
			})
			.mouseleave(function(){
				clearTimeout(uid.popupTimeout);
				$.log('clearing and setting timeout because of mouseleave');
				uid.popupTimeout = setTimeout(function(){
					$.log('timeout over so hiding popup');
					$(uid.curButton).add('#bi').unbind('mouseenter').unbind('mouseleave');
					if(uid.popupShowing){
						$('#bi').fadeOut('slow', function(){
							var me = $(this);
							var parent = me.parent();
							parent.attr('title', parent.data('origTitle')); //Restore the title again
							uid.clearLeftTopMargins(me);
							me.appendTo($('body:first')); //Move it back to body in case parent is a temporary element
						});
						uid.curButton = null;
					}
				}, uid.stayTimeout);
			});
		$('#bi').fadeOut('fast', function(){
			var me = $(this);
			uid.clearLeftTopMargins(me);
			uid.popupShowing = false;
			if(button.nodeName.toLowerCase() != 'td' && button.nodeName.toLowerCase() != 'th'){
				me.appendTo(button.parentNode); //Move the popup to the cell containing the button
			}
			else {
				me.appendTo(button); //This is a table cell, move to popup here
			}
			uid.popupDataMenuPhase2(dId, fId, cId, interactionLevel, button.className, year);
		});
		event.stopPropagation();
	}
	else {
		$.log('curButton = button');
	}
};

/**
* Fetch the popup content from AJAX
*
* @param {String} dId the ID of the datapoint (undefined is this is for missing/new data)
* @param {String} fId the field ID
* @param {String} cId the country ID
* @param {String} interactionLevel todo??
* @param {String} classes todo???
* @param {int} year The year the event occurred (optional). Useful for adding new data
*/
uid.popupDataMenuPhase2 = function(dId, fId, cId, interactionLevel, classes, year){
	if(dId){
		// we're editing existing data
		uid.popupFetchHtml('bic', '/uid/customcf/dataMenu.cfm?id=' + dId + '&interactionLevel=' + interactionLevel + '&classes=' + classes);
	}
	else if(year) {
		// we're going to create some new data with a known occurred year
		uid.popupFetchHtml('bic', '/uid/customcf/dataMenu.cfm?fid=' + fId + '&cid=' + cId + '&interactionLevel=' + interactionLevel + '&year=' + year);
	}
	else {
		// we're going to create some new data with an unknown occurred year
		uid.popupFetchHtml('bic', '/uid/customcf/dataMenu.cfm?fid=' + fId + '&cid=' + cId + '&interactionLevel=' + interactionLevel);	
	}
};

uid.popupFetchHtml = function(id, url) {
	$('body:first, #uidOutput td.d').css('cursor', 'wait');
	uid.cursorResetTimeout = setTimeout(function(){$('body:first, #uidOutput td.d').css('cursor', '');}, 10000); //Reset the cursor in 10s in case the ajax call never returns
	requestAJAXWithCallBack(url, 'uid.popupSetInnerHtml', '\'' + id + '\'');
};

uid.popupSetInnerHtml = function(ajaxRequest, id) {
  if (ajaxRequest.readyState == 4 && ajaxRequest.status == 200) {
	  clearTimeout(uid.cursorResetTimeout);
	  $('body:first, #uidOutput td.d').css('cursor', '');  
	  $('#' + id).html(ajaxRequest.responseText);
	  uid.popupShowing = true;
	  $('#bi').fadeIn('normal', function(){
		var parent = $(this).parent();
		$.log('parent has title ' + parent.attr('title') + ' and is a ' + parent[0].nodeName);
		parent
			.data('origTitle', parent.attr('title')) //Save away the title...
			.attr('title', ''); //...and remove it so that it doesn't appear now that the popup is already visible
		//uid.preventUIDOutputOverflow.call(this);
	  });
	  ajaxRequest.onreadystatechange = null;
  }
 else if(ajaxRequest.readyState == 4) { //Errors etc
	$('#' + id).html($('#' + id).html() + '<p class="error">An error occurred and the requested operation could not be completed.<br />' +
		'The error code was ' + ajaxRequest.status);
 }
};

uid.scrollLegends = function(){
	var div = $('#uidOutput'); 
	div.animate({scrollTop: (div.attr('scrollHeight') - $('#legends', div).height() - 20)}, 
		750,
		'swing');
};

uid.initPredefChangeListeners = function(){
	//Only apply this logic if there is an "other" textfield and there are predefined options too
	if($('#form .input_otherval').length == 1 && $('#form input[name=data]').length > 0){
		if($.trim($('#form .input_otherval').val()).length !== 0){
			$('#otherVal').attr('checked', true);
		}
		else {
			$('#form .input_otherval').attr('disabled', true);
		}
		$('#form input[name=data][type=radio]').not('#otherVal').click(function(){
			$('#form .input_otherval').attr('disabled', true);
		});
		$('#otherVal').click(function(){
			if($(this).attr('checked')){
				$('#form .input_otherval').attr('disabled', false);
			}
			else if($(this).attr('type') == 'checkbox'){
				$('#form .input_otherval').attr('disabled', true);
			}
		})
		.change();
	}
};
 
/* Populates a field select with the fields belonging to a selected theme.
 * An array named thefields containing objects on the below format is assumed to exist:
 * {
 *  id: id,
 * 	name: name,
 *  code: code,
 *  theme: theme
 * }
 * Such an array can be created like this:
 * var thefields = #uid.getFieldsJSLiteral()#;
 * where uid is an instance of uidcore.cfc
 */
uid.populateFieldsFromTheme = function(e, themeSelect, fieldSelect, nodummy){
	if(!themeSelect){
		themeSelect = $('select[name=theme]'); //Assume the theme select is named "theme" ($(this) approach didn't work for some reason
	}
	if(!fieldSelect){
		fieldSelect = $('select[name=field]'); //Assume the field select is named "field"
	}
	if(!nodummy){
		nodummy = false;
	}
	var selectedTheme = themeSelect.val();
	var dummy;
	if(!nodummy){
		dummy = fieldSelect.children(':first'); //Save the dummy before clearing (let's hope there was a dummy...)
	}
	var selectedField = fieldSelect.val(); //If there was a selected field already, save it for later
	fieldSelect.empty();
	if(!nodummy){
		fieldSelect.append(dummy[0]); //Add it back in
	}
	for(var i=0; i<thefields.length;i++){
		if(selectedTheme == -1 || thefields[i].theme == selectedTheme){
			fieldSelect.append(new Option(thefields[i].name, thefields[i].id, thefields[i].id == selectedField));
		}
	}
};

uid.populatePredefValuesFromField = function(e, fieldSelect, valueSelect, values){
	if(!fieldSelect){
		fieldSelect = $(this); //Assume this function is used as eventhandler on the field select
	}
	if(!valueSelect){
		valueSelect = $('select[name=value]'); //Assume the value select is named "value"
	}
	var selectedField = fieldSelect.val();
	var dummy = valueSelect.children(':first'); //Save the dummy before clearing
	valueSelect.empty();
	valueSelect.append(dummy[0]); //Add it back in
	for(var i=0; i<values.length;i++){
		if(selectedField == -1 || fields[i].theme == selectedField){
			valueSelect.append(new Option(fields[i].name + ' (' + fields[i].code + ')', fields[i].id, false, false));
		}
	}
};

uid.populateCountriesFromRegion = function(e, regionSelect, countrySelect, countries){
	if(!regionSelect){
		regionSelect = $(this); //Assume this function is used as eventhandler on the region select
	}
	if(!countrySelect){
		countrySelect = $('select[name=country]'); //Assume the country select is named "country"
	}
	var selectedRegion = regionSelect.val();
	var dummy = countrySelect.children(':first'); //Save the dummy before clearing
	countrySelect.empty();
	countrySelect.append(dummy[0]); //Add it back in
	for(var i=0; i<countries.length;i++){
		if(selectedRegion == -1 || countries[i].reg == selectedRegion || countries[i].preg == selectedRegion){
			countrySelect.append(new Option(countries[i].name, countries[i].id, false, false));
		}
	}
};

uid.renderSourceIcon = function(source){
	if($.trim(source) !== ''){
		return '<img src="/style/img/source.png" alt="Source: ' + source + '" title="Source: ' + source + '" />';
	}
	else {
		return '';
	}
};

uid.renderHelpIcon = function(info){
	if($.trim(info) !== ''){
		return '<img src="/vt/images/question_mark_small_2.gif" alt="' + info + '" title="' + info + '" />';
	}
	else {
		return '';
	}
};

uid.renderLastChangedIcon = function(time, relative){
	if($.trim(time) !== ''){
		if(relative){
			// TODO: Add code converting the time to a XX days ago or similar value
		}
		return '<img src="/style/img/time.png" alt="Last changed ' + time + '" title="Last changed ' + time + '" />';	
	}
	else {
		return '';
	}
};	

uid.renderEditDataIcon = function(id, fromUrl){
	if(!fromUrl){
		fromUrl = '';
	}
	if(fromUrl !== ''){
		fromUrl = '&amp;fromUrl=' + fromUrl;
	}
	return '<a href="editData.cfm?id=' + id + fromUrl + '"><img src="/style/img/edit.png" alt="Edit entry" title="Edit entry" /></a>';
};

uid.handleOtherChange = function(obj) {};
	/*if($.trim($(obj).val()) === ''){
		$('#otherVal').attr('checked', false);
	}
	else {
		$('#otherVal').attr('checked', true);
	}
};*/

/*
uid.editPredef = function(valId, fieldId, tableId) {
	//console.log('editPredef... valId=' + valId + ', fieldId=' +  fieldId + ', tableId=' + tableId);
	var textInputSize = 25;
	var textareaRows = 3;
	var textareaCols = 25;
	var table = $('#' + tableId);
	if(valId != -1) { //Edit existing one
		var row = table.find('#row_' + valId);
		row.children('td.edit').each(function(){
			field = $(this);
			if (field.attr('id').indexOf('description') > -1) { //Needs textarea
				// field.html('<textarea id="' + field.attr('id') + '" rows="' + textareaRows + '" cols="' + textareaCols + '">' + field.html() + '</textarea>');
				field.html(field.html());
			}
			else { //Needs textfield
				// field.html('<input id="' + field.attr('id') + '" value="' + field.html() + '" size="' + textInputSize + '" />');
				field.html(field.html());
			}
		});
		row.find('a.editPredef').html('<a href="#" onclick="uid.savePredef(' + valId + ', ' + fieldId +', \'' + tableId + '\');return false;">Save</a>');
	}
	else { //Add new one
		row = table.find('#row_add');
		row.empty();
		var td = document.createElement('td');
		$(td).html('<input id="add_val" size="' + textInputSize + ' />"');
		row.append(td);
		td = document.createElement('td');
		$(td).html('<textarea id="add_description" rows="' + textareaRows + '" cols="' + textareaCols + '"></textarea>');
		row.append(td);
		td = document.createElement('td');
		$(td).html('<input id="add_color" size="' + textInputSize + '"');
		row.append(td);
		td = document.createElement('td');
		$(td).html('<input id="add_weight" size="' + textInputSize + '"');
		row.append(td);
		td = document.createElement('td');
		$(td).html('<a href="#" onclick="uid.savePredef(-1, ' + fieldId + ', \'' + tableId + '\');return false;">Save</a>');
		row.append(td);
	}
};

uid.savePredef = function(valId, fieldId, tableId) {
	//console.log('savePredef... valId=' + valId + ', fieldId=' +  fieldId + ', tableId=' + tableId);
	var table = $('#' + tableId);
	var row = table.find('#row_add');
	var queryString = '?field=' + fieldId;
	row.find('input, textarea').each(function() {
		queryString += '&' + $(this).attr('id').split('_')[1] + '=' + $(this).val();
	});
	//console.log('/uid/customcf/savePredef.cfm' + queryString);
	requestAJAXWithCallBack('/uid/customcf/savePredef.cfm' + queryString, 'uid.indicatePredefResult', '\'predefResult\'');		
};

uid.indicatePredefResult = function(req, outputId) {
	if(req.responseText == 'saved'){
		$('#' + outputId).html('New predefined value saved successfully');
	}
	else if(req.responseText == 'updated'){
		$('#' + outputId).html('The predefined value was successfully updated');
	}
	else {
		$('#' + outputId).html('There seems to have been an error and the predefined value may not have been saved/updated.');
	}
	setTimeout('$(\'#' + outputId + '\').html(\'\');', 4000);
};
*/

uid.fetchHtml = function(id, url) {
  requestAJAXWithCallBack(url, 'uid.setInnerHtml', '\'' + id + '\'');
};

uid.fetchHtmlPost = function(id, url, urlParam) {
  requestAJAXWithCallBackPost(url, urlParam, 'uid.setInnerHtml', '\'' + id + '\'');
};

uid.fetchHtmlToggle = function(id, url) {
  var obj = getObj(id);
  if (obj.innerHTML !== '') {
    obj.innerHTML = '';
    obj.style.display = 'none';
  } else {
    requestAJAXWithCallBack(url, 'uid.setInnerHtml', '\'' + id + '\'');
  }
};

uid.setInnerHtml = function(ajaxRequest, id) {
  if (ajaxRequest.readyState == 4 && ajaxRequest.status == 200) {
    // getObj(id).innerHTML = ajaxRequest.responseText;
  	$('#' + id).html(ajaxRequest.responseText);
    ajaxRequest.onreadystatechange = null;
    //$('.editcolor').ColorPicker({ flat: true });
	$('#add_color').focus(function(){$('#addColorPicker').show();}).blur(function(){$('#addColorPicker').hide();});
	$('#edit_color').focus(function(){$('#editColorPicker').show();}).blur(function(){$('#editColorPicker').hide();});	
	$('#addColorPicker').hide().farbtastic('#add_color');
	if($('#editColorPicker').length === 1){	
		$('#editColorPicker').hide().farbtastic('#edit_color');
	}
  }
 else if(ajaxRequest.readyState == 4) { //Errors etc
	$('#' + id).html($('#' + id).html() + '<p class="error">An error occurred and the predefined value couldn\'t be updated/saved.<br />' +
		'The error code was ' + ajaxRequest.status);
 }  
};

uid.setMessage = function(msgArea, text, cssClass){
	msgArea = $('#' + msgArea + 'MsgArea');
	msgArea.removeClass().addClass('msgArea'); //Remove any classes that may have been added and re-add the basic one
	if(cssClass) {
		msgArea.addClass(cssClass);
	}
	msgArea.html(text);
};

uid.clearMessage = function(msgArea){
	uid.setMessage(msgArea, '');
};

uid.warnDateChanged = function(original, message){
	if(uid.isDateChanged(original)){
		uid.setMessage('date', message, 'warning');
	}
	else {
		uid.clearMessage('date');
	}
};

uid.isDateChanged = function(original){
	return $('[name=occurred]').val() != original;
};

uid.richTextOptions = {
	initialContent: '',
	controls: {
	  strikeThrough : { visible : false },
	  underline     : { visible : true },
	  
	  separator00 : { visible : true },
	  
	  justifyLeft   : { visible : false },
	  justifyCenter : { visible : false },
	  justifyRight  : { visible : false },
	  justifyFull   : { visible : false },
	  
	  separator01 : { visible : false },
	  
	  indent  : { visible : false },
	  outdent : { visible : false },
	  
	  separator02 : { visible : false },
	  
	  subscript   : { visible : false },
	  superscript : { visible : false },
	  
	  separator03 : { visible : false },
	  
	  undo : { visible : true },
	  redo : { visible : true },
	  
	  separator04 : { visible : true },
	  
	  insertOrderedList    : { visible : true },
	  insertUnorderedList  : { visible : true },
	  insertHorizontalRule : { visible : false },

	  separator07 : { visible : false },
	  
	  cut   : { visible : false },
	  copy  : { visible : false },
	  paste : { visible : false }
	}
};

/* This function finds all textareas of class richtext and converts them to rich text areas.
It also looks up the parent form of each of these text areas and adds an onsubmit event handler
that converts any unicode characters in the contents of each rich text area to html entities,
to avoid encoding issues when submitting to the server and storing to the database. Since a form 
may contain several rich text areas and we only want the onsubmit handler to execute once per form,
any already registered submit handler is removed so that only one will remain in the end. */
uid.triggerRichText = function(){
	var rts = $('textarea.richtext');
	rts
		.addClass('rich')
		.each(function(){
			$(this).wysiwyg(uid.richTextOptions);
			$(this)
				.closest('form')
				.unbind('submit', uid.convertRichtextAreas)
				.submit(uid.convertRichtextAreas);
		});
};

uid.convertRichtextAreas = function(){
	$.log('submit handler processing ' + $(this).find('textarea.richtext').length + ' textareas');
	$(this).find('textarea.richtext').each(function(){
		$(this).val(uid.convertUnicodeToEntities($(this).val()));
	});
};

/* This function is meant to be attached as a clickhandler on a link (<a onclick="uid.toggleRichtext(this)...</a> 
 which has a single sibling label which has a for attribute corresponding to the textarea that we want to control. */
uid.toggleRichtext = function(obj) {
	var taid = $(obj).siblings('label').attr('for');
	var rta = $('#' + taid);
	if(rta.hasClass('rich')){
		rta.
			removeClass('rich')
			.wysiwyg('destroy');
		$(obj).html('Switch to rich text');
	}
	else {
		rta.
			addClass('rich')
			.prev('div.wysiwyg')
				.remove()
				.end()
			.wysiwyg(uid.richTextOptions);
		$(obj).html('Switch to plain text');				
	}
	return false;
};

uid.collapseMoreLabel = '';
uid.collapseLessLabel = '';
uid.collapsedHeight = 50; /* The height of "normal" collapsed text blocks when collapsed */

uid.collapseCollapsibles = function(){
	var intro, introText, rest, tagBalance, text, lastPos, breakPoint, target;
	var collapsibles = $('.collapsible');
	if (typeof(langcode) == 'undefined') langcode = 'en';
	switch(langcode){
		case 'fr':
			uid.collapseMoreLabel = 'plus&hellip;';
			uid.collapseLessLabel = 'moins';		
			break;
		case 'en':
		default:
			uid.collapseMoreLabel = 'more&hellip;';
			uid.collapseLessLabel = 'less';
	}

	collapsibles.filter('.pop').each(function(){
		var me = $(this);
		var myHtml = me.html();
		var plainContents = uid.stripHTML(myHtml);
		if(plainContents.length > 150){
			var newText = '<div class="short">' + plainContents.substring(0,150) + '&hellip; <a class="more">more</a></div><div class="full"><div class="closeButton" onclick="uid.hideCollapsiblePopup();">close (x)</div>' + myHtml + '</div>';
			var oldText = myHtml;
			me.html(newText);
		}
	});
	collapsibles.filter('.noMarkup').each(function(){
		$(this).html($(this).html().replace(/<.*?>/g, ''));
	});
		var wrapper = $('<div class="collapsibleWrapper"></div>');
		collapsibles.not('.coupled,.pop').each(function(){
			var me = $(this);
			if(me.height() > uid.collapsedHeight){
				me
					.wrap(wrapper)
					.data('origH', me.height())
					.height(uid.collapsedHeight)
					.addClass('collapsed')
					.append('<div class="fader"></div><div class="fader secondary"></div>');
			};
		});
		var wrappers = $('.collapsibleWrapper');
		wrappers.append('<a href="">' + uid.collapseMoreLabel + '</a>');
		wrappers.children('a').click(function(){
			var me = $(this);
			var collapsible = me.siblings('.collapsible');
			if(collapsible.hasClass('collapsed')){
				collapsible.animate({height: collapsible.data('origH')});
				me.html(uid.collapseLessLabel);
			}
			else {
				collapsible.animate({height: uid.collapsedHeight});
				me.html(uid.collapseMoreLabel);
			}
			collapsible.toggleClass('collapsed');
			return false;
		});		
	/*else {
		collapsibles.not('.coupled,.pop').each(function(){
			text = $.trim($(this).html());
			if(text.length > 150){
				breakPoint = 149;
				introText = text.substring(0, breakPoint);
				tagBalance = uid.getTagBalance(introText);
				while(tagBalance !== 0 && breakPoint > -1){
					lastPos = breakPoint;
					while(tagBalance > 0 && lastPos !== 0){
						lastPos = text.indexOf('>', lastPos) + 1;
						tagBalance--;
					}
					breakPoint = lastPos;
					introText = text.substring(0, breakPoint);
					tagBalance = uid.getTagBalance(introText);
				}
				if(tagBalance === 0 && breakPoint !== 0 && breakPoint < text.length){ //Otherwise it contains malformatted html
					//console.log('introText is ' + introText + ', tag balance is ' + tagBalance);
					intro = '<span class="collapsible_intro">' + introText + '</span>';
					//console.log('intro is ' + intro);
					rest = '<span class="collapsible_rest">' + $.trim($(this).html()).substring(breakPoint) + '</span>';
					//console.log('rest is ' + rest);
					$(this)
						.html(intro + rest + '<a class="less"> ' + uid.collapseLessLabel + '</a>') //collapseCollapsible expects a link like this to exist...
						.find('.collapsible_rest')
							.hide() //Lets hide the animation now that we're just initialising
							.end()
						.find('.less')
							.click(uid.collapseCollapsible)
							.click();
				}
			}
		});
	}*/
	collapsibles.filter('.coupled').each(function(){
		target = $('#' + $(this).attr('id') + '_target'); 
		if(target.css('display') == 'inline'){
			target.addClass('inline');
		}
		target.hide();
		$(this).append(' <a class="more">' + uid.collapseMoreLabel + '</a>')
			.find('.more')
				.click(uid.expandCoupled);
	});
	collapsibles.filter('.pop').each(function(){
		var me = $(this);
		var theshort = me.find('.short');
		if(theshort.length > 0){
			me.find('a.more').click(function(e){
				e.stopPropagation();
				var full = $(this).closest('.collapsible').find('div.full');
				full
					.show()
					.click(function(e){
						e.stopPropagation(); //Otherwise it's treated as a click on the parent cell
					})
					.css('margin-top', -Math.round(full.outerHeight()/2));
				$('#uidOutputWrapper').append('<div id="bgm_temp" style="display: block; z-index: 51;" class="backgroundMask"></div>');
				$('body').click(uid.hideCollapsiblePopup);
			});
		}
	});
};

uid.hideCollapsiblePopup = function(){
	$('#bgm_temp').remove();
	$('.collapsible div.full:visible').hide();
	$('body').unbind('click', uid.hideCollapsiblePopup);
}

uid.expandCoupled = function(){
	var parent = $(this).parents('.coupled');
	var replaceHTML; 
	var targ = $('#' + parent.attr('id') + '_target');
	targ.append(' <a class="less">' + uid.collapseLessLabel + '</a>')
		.find('.less')
			.unbind('click', uid.expandCoupled)
			.click(uid.collapseCoupled);
	targ
		.show('normal', function(){
			var jqThis = $(this);
			var id = jqThis.attr('id');
			if(jqThis.hasClass('inline')){
				replaceHTML = '<' + jqThis[0].nodeName + ' class="' + jqThis[0].className + '" id="' + id + '" style="display: inline">' +
								jqThis.html() +
								'</' + jqThis[0].nodeName + '>'; 
				jqThis.replaceWith(replaceHTML);
				$('#' + id).find('.less') //We need to add the click handler back since it's lost when copying the element
					.click(uid.collapseCoupled);
			}
		});
	$(this).remove();
};

uid.collapseCoupled = function(){
	var parent = $(this).closest('.coupled');
	parent.hide('normal')
		.find('.less')
			.remove(); 
	$('#' + parent.attr('id').split('_')[0])
		.append(' <a class="more">' + uid.collapseMoreLabel + '</a>')
		.find('.more')
			.unbind('click', uid.collapseCoupled)
			.click(uid.expandCoupled);
	$(this).remove();
};


uid.getTagBalance = function(html){
	html = html.replace(/<br>|<hr>/g, ''); //Remove the implicitly self-closing tags (may be more than those listed in this regexp)
	return (html.split('<').length-1) - ((html.split('</').length-1) * 2) + (html.split('/>').length-1); //Calculate the balance
};

uid.collapseCollapsible = function(){
	var collapsible = $(this).parents('.collapsible');
	var intro = collapsible.find('.collapsible_intro');
	var rest = collapsible.find('.collapsible_rest');
		rest.hide('normal');
	var link = $(this);
	collapsible
		.empty()
		.append(intro)
		.append(link)
		.append(rest);
	link.removeClass('less')
		.addClass('more')
		.html(uid.collapseMoreLabel)
		.unbind('click', uid.collapseCollapsible)
		.click(uid.expandCollapsible);		
};

uid.expandCollapsible = function(){
	var collapsible = $(this).parents('.collapsible');
	var intro = collapsible.find('.collapsible_intro');
	var rest = collapsible.find('.collapsible_rest');
		rest.show('normal', function(){$(this).replaceWith('<span class="collapsible_rest">' + $(this).html() + '</span>');});
	var link = $(this);
	collapsible
		.empty()
		.append(intro)
		.append(rest)
		.append(link);
	link.removeClass('more')
		.addClass('less')
		.html(uid.collapseLessLabel)
		.unbind('click', uid.expandCollapsible)
		.click(uid.collapseCollapsible);	
};

uid.updateProgressIndicator = function(){
	$.get('/uid/customcf/getExportProgress.cfm?qid=' + uid.qid, function(data){
		if(data < 2){
			var preLabel, postLabel, progress;
			if(data < 1){
				preLabel = 'Preparing... ';
				postLabel = '%<br />Rendering... 0%';
				progress = Math.round(data*100);
			}
			else {
				preLabel = 'Preparing... 100%<br />Rendering... ';
				postLabel = '%';
				progress = Math.round((data-1)*100);
			}
			$('#progress').html(preLabel + progress + postLabel);
			uid.progressIndicatorTimeout = setTimeout(function(){uid.updateProgressIndicator();}, uid.ProgressIndicatorUpdateInterval);
		}
	});
}

uid.getTimeModeString = function(){
	var timeMode = '&timemode=';
	var mode = $('#timemode input[name=timemode]:checked').val();
	timeMode += mode;
	var timeSpec = '';
	switch(mode){
		case 'highest':
		case 'lowest':
			timeSpec = '&timespec=' + $('#yearfilter option:selected').val();
			break;
		case 'range':
			timeSpec = '&firstyear=' + $('#timespan').html().split(' - ')[0] + '&lastyear=' + $('#timespan').html().split(' - ')[1];
			break;
	}
	timeMode += timeSpec;
	return timeMode;
};

uid.convertUnicodeToEntities = function(str){
	$.log('convertUnicodeToEntities called with str ' + str);
	var ret = "";
	var len = str.length;
	for (i=0; i<len; i++) {
		code = str.charCodeAt(i);
		ret += (code > 256 ? "&#" + code + ";" : str.charAt(i));
	}
	return ret;
};

uid.setupGlossaryDialogs = function(glossaryUrl, glossaryContainerId, triggerSelector, termSelector){
	glossary = $('<div></div>'); //Placeholder for the html we will load
	glossary.load(glossaryUrl + ' #' + glossaryContainerId);	
	$('body').append('<div id="glossaryDialog" style="display: none"></div>');
	$(triggerSelector).click(function(e){
		var term;
		var definition;
		var link = $(this);
		glossary.find(termSelector).each(function(){
			var me = $(this);
			if(me.html().replace(' ', '').match(new RegExp(link.attr('id'), 'i'))){
				term = me.html();
				definition = me.next().html();
				return false;
			}
		});
		$('#glossaryDialog')
			.html(definition)
			.dialog({title: term});
		e.stopPropagation();
	});
	return true;
};

uid.stripHTML = function(html){
	return html.replace(/<[^>]*>/g, '');
};

uid.initExportSummaryModeSwitch = function(){
	$('#viewData tr.legends #sumNum, #viewData tr.legends #sumPct').click(function(){
		var summaryRow = $('#viewData tr.legends');
		if($('input[name=sumDisp]:checked', summaryRow).val() == 'num'){
			summaryRow.find('span.num')
			.show()
			.siblings('.perc')
				.hide();
		}
		else {
			summaryRow.find('span.perc')
			.show()
			.siblings('.num')
				.hide();		
		}
	});
}

uid.initCountryFilter = function(){
	var filter = $('#countryFilter');
	var toggle = filter.find('#predefFilter,#freeTextFilter');
	toggle.click(function(){
		var me = $(this);
		filter.find('input,select')
			.not(me)
			.not('[type=submit]')
				.attr('disabled', !me.is(':checked'));
		filter.find('span.predefLabel').toggleClass('disabled', !me.is(':checked'));
	});
	toggle.triggerHandler('click');
};

/* Code below if pretty specific to the "viewData" views.
 * It should possibly be moved into a uid.cfc function
 * or at least be moved into the uid object in use above
 */

/* Don't run this stuff on irrelevant pages */
if(window.location.pathname.match(/viewdata\.cfm|view_data\.cfm|search-adv\.cfm|uid\/search\.cfm|elections\/vfa_search|elections\/ej\/$|elections\/ej\/index\.cfm|political-finance\/.*search\.cfm|political-finance\/region\.cfm/i)){
	var numRetrievals = 0;
	var naturalHeight = -1; //Used for storing the output popup's natural height before resizing is applied
	var resizeTimeout = 500; //Used for limiting how often the resize will occur
	var lastTimeoutID = 0;
	var pendingResize = false;
	$(document).ready(
		function(){
			/* Move the popup divs to body element. Otherwise IE6 calculates their widths relative to their parent
			even though they're absolutely positioned. */
			var popupDivs = $('#uidOutputWrapper').add('#uidBgMask');
			popupDivs[0].parentNode.removeChild(popupDivs[0]);
			popupDivs[1].parentNode.removeChild(popupDivs[1]);
			$('body:first').append(popupDivs[0]);
			$('body:first').append(popupDivs[1]);
			maintainCopyButtons();
			defaultFields();
			initClosebutton();
			if(getHashNoHash().substring(0,2) == 'cq'){
				$('#' + getHashNoHash())
					.addClass('high')
					.find('a:first').click();
			}
		}
	);
}


function handlePrebuildQuery(){
	/* Remove '&format=HTML' since this will be appended at later stage. */
	if(getHashNoHash().indexOf('prebuilt=yes') > -1){
		generateQid();
		if(!uid.url) {
			uid.url = uidOverrideUrl; //Let the error happen if uidOverrideUrl is undefined since that should not happen.
		}
		retrieveData(uid.url, getHashNoHash() //The page calling this function is responsible for setting the uid.url variable
			.replace('prebuilt=yes&', '')
			.replace(/&d=.*/, '')
			.replace(/&qid=\d*/, '') +
			getQidString() +
			getLocalTimeString());
	}
}

function getQidString(){
	return '&qid=' + getQid();
}

function getQid(){
	return uid.qid;
}

function generateQid(){
	uid.qid = Math.ceil(Math.random() * 999999);
}

function initClosebutton(){
	$('#closebutton').unbind('click').click(
		function(){
			$('body').css('overflow', 'auto');
			$('select.tempHidden')
				.removeClass('tempHidden')
				.show();
			$('#uidOutputWrapper').add('#uidBgMask').hide();
			clearTimeout(uid.progressIndicatorTimeout);
			$('#uidOutput').html(''); //Maybe good to free some memory...
			window.location.hash = '';
		}
	);
}

function retrieveData(url, queryString, title){
	numRetrievals++;
	/*
	* Remove any highlighting that may remain if this page was visited with a url hash that triggered a 
	* common query or similar. If this is the first invocation of this function though, any highlighting
	* should be kept.
	*/
	if(numRetrievals > 1){
		$('.high').removeClass('high'); //Selector should be optimized but currently this is not in use anywhere I think
	}
	
	if(title){
		$('#tableTitle').html(title);
	}
	
	if(!queryString){
		queryString = buildQueryString();
		//Build params from options on this page...
	}
	
	/* If the post contains things like foo=bar&bla&hello=world (second param missing =value part), CF throws an
	   IllegalArgumentException when trying to build the Form scope. This shouldn't happen unless user has tampered
	   with the URL so maybe we don't need this cleanup really. */
	queryString = queryString.replace(/^\w+&/, ''); //First param incomplete (missing =)
	queryString = queryString.replace(/&\w+$/, ''); //Last param incomplete (missing =)
	queryString = queryString.replace(/&\w+&/g, '&'); //Any other param incomplete (missing =)
	
	var noFormatQueryString = queryString; //Handy for passing to displayData...
	queryString += '&format=HTML';
	$('#uidOutput').addClass('loading').html('<span style="font-weight: bold">Loading data, please wait...</span> '+
			'<br/>(This could take up to a few minutes for large selections)' +
			'<div style="text-align:center;margin:20px;"><img src="http://www.idea.int/images/ajax-loading.gif" /><br />' +
			'<span id="progress"></span></div>');
	var IE = getInternetExplorerVersion();
	if(IE != -1 && IE <= 6){ //This doesn't work well for prebuilt export URLs since this code seems to be executed before the fancySelects are initialized, so limit this to old IE versions (not needed in better browsers anyway)
		$('select:visible')
			.addClass('tempHidden') //To distinguish from those that were already hidden for other reasons, such as converted fancySelects' original select elements
			.hide(); //These show through the popup in IE6 otherwise
	}
	$('#uidOutputWrapper').add('#uidBgMask').show();
	$('body').css('overflow', 'hidden');
	$('#uidOutput').css('height', ''); //Remove any set size from previous contents
	$('#excelExportDlLink').live('click', function(){
		wrapWithExportForm($(this), url, noFormatQueryString, 'Excel', null, true);
	});	
	$('#csvExportDlLink').live('click', function(){
		wrapWithExportForm($(this), url, noFormatQueryString, 'CSV', null, true);
	});	
	naturalHeight = -1;
	resizePopup(true);
	window.location.hash = 'prebuilt=yes&' + noFormatQueryString;
	$.ajax({
		type: 'post',
		url: url, 
		data: queryString,
		success: function(data, status, request){
			displayData(request, url, noFormatQueryString);
		},
		error: function(req, textStatus, errorThrown){
			clearTimeout(uid.progressIndicatorTimeout);
			$.log('clearTimeout');
			$('#uidOutput').html('<div class="error"><p>We are sorry, but an error has occurred preventing the data from being displayed.</p><p>Our technicians will be notified automatically of this error and will solve it as soon	as possible.</p></div>');
			var email = prompt('We are sorry, but an error has occurred preventing the data from being displayed. Our technicians will be notified automatically of this error and will solve it as soon as possible. If you enter an email address here we will get back to you as soon as we have looked into the issue.', '');
			$.ajax({
				type: 'post',
				url: '/uid/customcf/catchError.cfm',
				data: 'type=UIDExport&url=' + encodeURIComponent(window.location.href) 
				+ '&msg=' + encodeURIComponent(req.responseText) + 
				(email ? ('&email=' + email) : '') +
				'&extraInfo=' + (textStatus ? encodeURIComponent('Status: ' + textStatus) : '') + 
				(errorThrown ? encodeURIComponent('<br />Exception: ' + errorThrown) : ''),
				success: function(data, status, request){
					//$('#uidOutput').html(request.responseText);
				}
			});
		}
	});
	scroll(0, 0);
	uid.updateProgressIndicator();
}

function wrapWithExportForm(jqObj, url, queryString, format, validator, autoSubmit){
	if(!autoSubmit){
		autoSubmit = false;
	}
	if(typeof validator != 'function'){
		validator = function(){return true;}; //Create a dummy one returning true for convenience
	}
	/* If autoSubmit is true it means this function was probably invoked onclick. In this case
	   it's better to validate now, before dom operations occur below, so that current click handlers
	   aren't lost.
	*/
	if(!autoSubmit || validator()){ 
		if(jqObj.closest('.wrapForm').length !== 0){ //Already wrapped, remove old form before re-wrapping
			jqObj.closest('.wrapForm').replaceWith(jqObj);
		}
		var form = $('<form style="display: inline" class="wrapForm" action="' + url + '" method="post"></form>'); 
		pairs = (queryString + '&format=' + format).split('&');
		for(var i=0; i<pairs.length; i++){
			var parts = pairs[i].split('=');
			if(parts[0] == 'logurl'){ //Special case as this is uriEncoded already but shouldn't be for the post request
				parts[1] = decodeURIComponent(parts[1]);
			}
			form.append('<input type="hidden" name="' + parts[0] + '" value="' + parts[1] + '">'); 
		}
		jqObj
			.replaceWith(form)
			.appendTo(form)
			.click(function(){
				$(this).unbind('click'); //The binding to wrapWithExportForm will survive this, since it was made using live()
				if(validator()){ //No validator was provided or validator is happy
					$(this)
						.closest('form')
						.submit();
					return false;
				}
				else {
					return false;
				}
			});
			if(autoSubmit){
				jqObj
					.click();
			}
	}
}

/**
* Display the data returned from an AJAX call
*/
function displayData(req, url, queryString){
	clearTimeout(uid.progressIndicatorTimeout);
	$('#uidOutput').removeClass('loading').html(req.responseText);
	setTimeout(function(){
		resizePopup(false);
		$.log('running initTables after delay;');
		scrollTable.initTables($('#uidOutput'));
		uid.initHiddenDescriptions(); //Has to be run after scrollTable.initTables for the closed rows to get the right behaviour		
	}, resizeTimeout); //It seems the resize has to be delayed so the browser has time to render fully
	initDataCells();
	uid.initUtilButtons();
	uid.collapseCollapsibles();
	uid.initExportSummaryModeSwitch();
	$(window).resize(function(){resizePopup(false);}); //No need to add this before first launch of popup
}

function initDataCells() {
	$('#uidOutput').mouseleave(function(){
		$('table#viewData td.d').removeClass('overed');//Since table is "invisibly overflowing" the output div, a cell's mouseleave may not trigger even thouh mouse has left the visible part of the cell
	});
	/*$('table#viewData td.d').click(function(){
		if($(this).attr('id').split('_')[0] == 'd'){ //Existing data entry
			var queryString = 'id=' + $(this).attr('id').split('_')[1];
			var title = 'Click to edit this field';
		}
		else {	//Non-existing data entry
			var field = $(this).attr('id').split('_')[1];
			var country = $(this).attr('id').split('_')[2];
			var queryString = 'field=' + field + '&country=' + country;
			var title = 'Click to add missing data';
		}
		if(uid.openEditInNewWin){
			window.open('http://www.idea.int/uid/editData.cfm?' + queryString, '_blank');
		}
		else {
			window.location.href = 'http://www.idea.int/uid/editData.cfm?' + queryString;
		}
	})*/
	$('table#viewData').delegate('td.d, td.n', 'mouseenter', function(){
		var me = $(this);
		if(uid.getInteractionLevel() > 1 || me.attr('id').split('_')[0] == 'd'){
			if(uid.getInteractionLevel() > 1 && !me.hasClass('noedit')){
				me.addClass('overed');
				me.attr('title', 'Click to view details or suggest new or updated data');
			}
			else if(me.attr('id').split('_')[0] == 'd'){
				me.addClass('overed');
				me.attr('title', 'Click to view details');
			}
		}
	})
	.delegate('td.d, td.n', 'mouseleave', function(){
		var me = $(this);
		if(uid.getInteractionLevel() > 1 || me.attr('id').split('_')[0] == 'd'){
			me.removeClass('overed');
		}
	});
}

function resizePopup(bgOnly){
	var minHeight = 160;
	if(lastTimeoutID === 0){ //No resize within resizeTimeout millis
		lastTimeoutID = setTimeout(function(){
			lastTimeoutID = 0;
			if(pendingResize){
				resizePopup(bgOnly);
				pendingResize = false;
			}
		}, resizeTimeout);
		if($('#uidOutputWrapper').is(':visible')){ //Dont do unnecessary computing if it's not visible anyway
			if(typeof(window.innerWidth) == 'number') {
				//Non-IE
				browserWidth = window.innerWidth;
				browserHeight = window.innerHeight;
			} 
			else if(document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight)) {
				//IE 6+ in 'standards compliant mode'
				browserWidth = document.documentElement.clientWidth;
				browserHeight = document.documentElement.clientHeight;
			}
			else if(document.body && (document.body.clientWidth || document.body.clientHeight)){
				//IE 4 compatible
				browserWidth = document.body.clientWidth;
				browserHeight = document.body.clientHeight;
			}
			
			/* We don't want to affect the size of #uidOutput until it's populated with all the data. */
			if(!bgOnly){
				if(!$('#uidOutput').hasClass('loading')){
					if(naturalHeight === -1){
						naturalHeight = $('#uidOutput')[0].offsetHeight;
					}			
					var availableHeight = (browserHeight - ($('#uidOutputWrapper')[0].offsetHeight - $('#uidOutput')[0].offsetHeight)) * .9;
					$('#uidOutput').css('height', Math.max(Math.min(availableHeight, naturalHeight), minHeight) + 'px');
					/*Probably means that it was measured before fully rendered.*/
				}
				else {
					pendingResize = true;
					//setTimeout(function(){resizePopup(false);}, resizeTimeout);
				}
			}
			
			var bgHeight = Math.max(document.body.offsetHeight, $('#uidOutputWrapper')[0].offsetHeight + $('#uidOutputWrapper')[0].offsetTop);
			bgHeight = Math.max(bgHeight, browserHeight);
			$('#uidBgMask').css('height', bgHeight + 'px');
		}
	}
	else {
		pendingResize = true;
	}
}

function hideRange(){
	$('#yearrange').hide();
}

function hideHighLow(){
	$('#yearfilter').hide();
}

function hideAll(){
	hideRange();
	hideHighLow();
}

function showRange(){
	$('#yearrange').show();
}

function showHighLow(){
	$('#yearfilter').show();
}

function getLocalTimeString(){
	var now = new Date();
	return '&d=' + now.getDay() + '&h=' + now.getHours() + '&m=' + now.getMinutes();
}

function checkAll(name){
	$('input[name=' + name + ']').attr('checked', true);
}

function uncheckAll(name){
	$('input[name=' + name + ']').attr('checked', false);
}

function allFields(){
	checkAll('fields');
}

function noFields(){
	uncheckAll('fields');
}

function submitForm(url, format){
	window.location.href = url + '?' + buildQueryString() + '&format=' + format;
}

function getHashNoHash(){
	var hash = window.location.hash;
		if(hash.indexOf('#') > -1){
		hash = hash.substring(1);
	}
	return hash;
}

function getLogUrlString(){
	var ret = '&logurl=' + encodeURIComponent(window.location.href);
	return ret;
}

/* Dummy functions for viewData pages that don't need to have one and thus don't implement it at all
 */
if(typeof defaultFields == 'undefined'){ //Not already defined
	defaultFields = function(){};
}
if(typeof maintainCopyButtons == 'undefined'){ //Not already defined
	maintainCopyButtons = function(){};
}
