function XMLHTTPObject() {
	var xmlhttp;
	if (window.ActiveXObject) {
		// Instantiate the latest Microsoft ActiveX Objects
		if (_XML_ActiveX) {
			xmlhttp = new ActiveXObject(_XML_ActiveX);
		} else {
			// loops through the various versions of XMLHTTP to ensure we're using the latest
			var versions = ["MSXML2.XMLHTTP", "Microsoft.XMLHTTP", "Msxml2.XMLHTTP.7.0", "Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0"];
			for (var i = 0; i < versions.length ; i++) {
				try {
					// Try and create the ActiveXObject for Internet Explorer, if it doesn't work, try again.
					xmlhttp = new ActiveXObject(versions[i]);
					if (xmlhttp) {
						var _XML_ActiveX = versions[i];
						break;
					}
				} catch (e) {
				// TRAP
				};
			};
		}
	}
	// Well if there is no ActiveXObject available it must be firefox, opera, or something else
	if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
		try {
			xmlhttp = new XMLHttpRequest();
		} catch (e) {
			xmlhttp = false;
		}
	}
	return xmlhttp;
}

//This function returns true or false depending on whether the browser appears to be Internet Explorer
function is_ie() {
	//Apparently the document.all property is only available in versions of IE
	if (document.all) {
		return true;
	} else {
		return false;
	}
}

function changeMode(element1, element2) {
	var element1 = document.getElementById(element1);
	var element2 = document.getElementById(element2);
	var temp;

	/*if (element2.style.display == 'none') {
		element2.style.display = element1.style.display;
		element1.style.display = 'none';
	}*/
	
	temp = element2.style.display;
	element2.style.display = element1.style.display;
	element1.style.display = temp;
}

function toggle(element) {
	var element = document.getElementById(element);
	if (element.style.display == 'none') {
		element.style.display = '';
	} else {
		element.style.display = 'none';
	}
}

function hide(element) {
	var element = document.getElementById(element);
	element.style.display = 'none';
}

function unhide(element) {
	var element = document.getElementById(element);
	element.style.display = '';
}


function changeToCreate(form) {
	var createType = form.elements["createType"].value;
	if(createType != 0){
		//Store current content of dropdown form in global variable (evil!), to be swapped back in later if form is hidden
		//FIXME: Remove use of global variable
		loadTemplate("op=getCreateTemplate&pageType="+createType);
	}
	form.elements["createType"].value = 0;
}

function changeToEdit() {
	loadTemplate("op=getEditTemplate")
}

function loadTemplate(requestData) {
	var requestHeader = 'application/x-www-form-urlencoded';
		
	//Define function if server request is successful
	var createFormDiv = document.getElementById('edit');
	var onSuccess = 
		function serverResponse(xmlHttp) {
			createFormDiv.innerHTML = xmlHttp.responseText;
			changeMode(createFormDiv.id, 'content');
			//makeXinhaEditor('Content');
			setTimeout('xinha_editors[0].initSize()',10000);
		}
		
	//Define function if server request fails
	var onFail =
		function failResponse() {
		}

	return sendRequest(requestHeader, requestData, onSuccess, onFail);

}

function deletePage(form) {
	var confirm = window.confirm('Are you sure you want to delete this page?');
	if (confirm) {
		return sendFormRequest(form);
	} else {
		return false;
	}
}

function deleteChild(id, childType) {
	var confirm = window.confirm('Are you sure you want to delete?');
	if (confirm) {
		var messageDiv = document.getElementById(childType+'ChildUserMessages');

		sendSimpleRequest('deleteChild', id, messageDiv);
	}
}

function deleteChildWithMessageDiv(id, childType, div) {
	var confirm = window.confirm('Are you sure you want to delete?');
	if (confirm) {
		var messageDiv = getElementByIdOrReference(div);

		sendSimpleRequest('deleteChild', id, messageDiv);
	}
}

function deleteBlogEntryComment(id) {
	var confirm = window.confirm('Are you sure you want to delete?');
	if (confirm) {
		var messageDiv = document.getElementById('BlogEntryCommentChildUserMessages');

		sendSimpleRequest('deleteBlogEntryComment', id, messageDiv);
	}
}

function createLandYachtsTeams(id) {
	sendSimpleRequest('createLandYachtTeams', id, 'LandYachtsParticipantChildUserMessages');
}

/* FIXME: Is it possible this can't be done in either the response code of 
 * update, or at the end of sendRequest, with div1 and div2 as null by default? 
 */
function update(form, div1, div2) {
	changeMode(div1, div2);

	return sendFormRequest(form);
}

function sendFormRequest(form) {
	var requestData = getFormValues(form);
	var requestHeader = 'application/x-www-form-urlencoded';

	//Define function if server request is successful
	//FIXME: Check that op doesn't contain any javascript injection attempts
	var op = form.elements["op"].getAttribute("value");
	var onSuccess = 
		function formResponse(xmlHttp) {
			//Interpret the response as XML (all form-request response functions deal with xml)
			//response = xmlHttp.responseXML;
			
			//Call the individual response function for this op
			eval(op + 'Response(form, xmlHttp)');
		}
	
	//Define function if server request fails
	var onFail = 
		function responseFail() { 
		}

	return sendRequest(requestHeader, requestData, onSuccess, onFail);
}

/* General function for making requests that only need an op and an object id.
   These are much simpler than functions that send all the data contained in 
   a form, with several additional fields entered by the user. */
function sendSimpleRequest(op, id, messageDiv) {
	var requestData = 'op='+op+'&Id='+id;
	var requestHeader = 'application/x-www-form-urlencoded';

	//Define function if server request is successful
	//FIXME: Check that op doesn't contain any javascript injection attempts
	var onSuccess = 
		function simpleResponse(xmlHttp) {
			//Call the individual response function for this op
			eval(op + 'Response(id, messageDiv, xmlHttp)');
		}
	
	//Define function if server request fails
	var onFail = 
		function responseFail() { 
		}

	return sendRequest(requestHeader, requestData, onSuccess, onFail);
}

function sendRequest(requestHeader, requestData, onSuccess, onFail) {
	//Create xmlHttp object
	xmlHttp = XMLHTTPObject();

	//Send data to server
	postData(xmlHttp, document.location.pathname, requestHeader, requestData);

	//Create response function
	xmlHttp.onreadystatechange = 
		function generalResponse() {
			if (xmlHttp.readyState == 4) {
				if(xmlHttp.status == 200) {
					//If response status is OK, call the unique function to handle the response
					//The xmlHttp object is given so the response function can choose how to interpret the response data (XML or plain text)
					//DEBUGGING: alert(xmlHttp.responseText);
					onSuccess(xmlHttp);
				} else {
					//If the POST itself failed
					//FIXME: Somehow get a standard POST with the form data to occur (ie as would occur if sendRequest returned true)
					onFail();
				}
			}
		}
	
	return false;
}


function postData(xmlHttp, path, header, data) {
	xmlHttp.open("POST", path, true);
	xmlHttp.setRequestHeader('Content-Type', header);
	xmlHttp.send(data);
}

function getFormValues(form) {  
	var fields = new Array();

	//loop through form elements and retrieve field names and Values
	for (var x = 0; x < form.elements.length; ++x){
		if (form.elements[x].type == "checkbox") {
			fields.push(form.elements[x].name+"="+escape(form.elements[x].checked));
		} else {
			fields.push(form.elements[x].name+"="+escape(form.elements[x].value));
		}
	}
	return fields.join('&');
}


/* Display the error/response messages in the messageDiv that is in all server-
 * submitted forms, then call the appropriate onSuccess/onErrors function,
 * using the responseDisplay function).
 */
function formResponse(request, xmlHttp, onSuccess, onErrors) {
	//Get div for displaying all messages
	var messageDiv = document.getElementById(request.id+"UserMessages");
	
	return responseDisplay(messageDiv, xmlHttp, onSuccess, onErrors);
}

/* Puts errors from response in given div if they exist, otherwise put message 
 * from response in given div. Then call the onSuccess or onErrors function,
 * depending on whether no errors were found.
 */
function responseDisplay(messageDiv, xmlHttp, onSuccess, onErrors) {
	//DEBUGGING: alert("'errors', before anything has even been assigned:"+errors);
	//DEBUGGING: 'errors' seems to be reserved word in IE's implementation of JavaScript

	//Check if errors have occurred, and display appropriate message
	errorsFound = responseErrors(xmlHttp);
	if (errorsFound != false) {
		//Show error message in form
		if (is_ie()) {
			messageDiv.innerText = errorsFound;
		} else {
			messageDiv.textContent = errorsFound;
		}
		//Call given onErrors function, passing the messageDiv
		return onErrors(messageDiv);
	} else {
		//Show message in form
		if (is_ie()) {
			messageDiv.innerText = responseMessage(xmlHttp);
		} else {
			messageDiv.textContent = responseMessage(xmlHttp);
		}
		//Call given onSuccess function, passing the messageDiv
		return onSuccess(messageDiv);
	}
}

// Returns the error message from the response XML, or false if no error tag is found
function responseErrors(xmlHttp) {
	//Attempt to interpret response as XML and find an error tag
	var responseXML = xmlHttp.responseXML;
	var error = responseXML.getElementsByTagName('error')[0];
	
	if (error != null) {
		//Return error description
		if (is_ie()) {
			//This returns fine: return "Errors found"; 
			return error.firstChild.data; //This doesn't seem to return anything
		} else {
			return error.textContent;
		}
	} else {
		//Return false for no error
		return false;
	}
}

function responseMessage(xmlHttp) {
	var responseXML = xmlHttp.responseXML;
	var message = responseXML.getElementsByTagName('message')[0];
	if (is_ie()) {
			return message.firstChild.data;
	} else {
			return message.textContent;
	}
}

// Take an argument that can be either a string or an element,
// and always returns an element - if a string is given, it is
// used as an element id to find an id
function getElementByIdOrReference(divOrId) {
	if (typeof(divOrId) == 'string') {
		divOrId = document.getElementById(divOrId);
	}
	// divOrId should now be an object (hopefully a DOM element)
	if (typeof(divOrId) == 'object') {
		return divOrId;
	} else {
		return null;
	}
}
	

function displayInDiv(div, contents) {
	div = getElementByIdOrReference(div);
	if (is_ie()) {
		div.innerText = contents;
	} else {
		div.textContent = contents;
	}
}

function delayedClearDiv(div) {
	div = getElementByIdOrReference(div);
	function clearDiv() {
		displayInDiv(div, '');
	}
	setTimeout(clearDiv, 4000);
}

//Not used at the moment
function redirect(target){
	
	if(language="JavaScript"){
		setTimeout( "window.location.href = /"+target, 2*1000 );
	}
	
	if(language="JavaScript1.1"){
		window.location.replace( target );
	}
}

function logout() {
	var file = document.location.pathname;
	//Send ajax request with form id and form values
	
	xmlHttp = XMLHTTPObject();
	xmlHttp.open("POST", file, true);
	xmlHttp.onreadystatechange = function Response() {
		if (xmlHttp.readyState == 4) {
			if(xmlHttp.status == 200){
				window.location.reload(true);
			}
		}
	}
	xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	xmlHttp.send("op=logout");
}

function stopImpersonating() {
	var file = document.location.pathname;
	//Send ajax request with form id and form values
	
	xmlHttp = XMLHTTPObject();
	xmlHttp.open("POST", file, true);
	xmlHttp.onreadystatechange = function Response() {
		if (xmlHttp.readyState == 4) {
			if(xmlHttp.status == 200){
				window.location.reload(true);
			}
		}
	}
	xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	xmlHttp.send("op=stopImpersonating");
}


var xinha_plugins = null;
var xinha_editors = new Array();

function makeXinhaEditor(textarea) {
	// List all plugins to be used in the standard editor
	xinha_plugins = 
	[
		'ContextMenu',
		'ListType',
		'SpellChecker',
		'Stylist',
		'SuperClean',
		'TableOperations'
	];
	
	/* Who knows what this does... 
	 * The second argument to loadPlugins is internally called 'callbackIfNotReady'. This line may 
	 * actually be continually calling this function (makeXinhaEditor) again until the plugins are 
	 * loaded. I have no idea if this will continue to work with makeXinhaEditor instead.
	 */
		// THIS BIT OF JAVASCRIPT LOADS THE PLUGINS, NO TOUCHING  :)
		// nathan: I touched it!
		if(!HTMLArea.loadPlugins(xinha_plugins, function() { makeXinhaEditor(textarea); })) return;
	
	// Create configuration to be used by editor
	xinha_config = new HTMLArea.Config();
	
	/* Create a replacement editor object for the textarea (returned in an array) /*
	/* Note: Although the xinha example loding code refers to the "names" of textareas to be made 
	 * editors, the internal HTMLArea code takes the given "editor names" and uses them as ids.
	 */
	var editor = new HTMLArea(textarea, xinha_config);
	editor.registerPlugins(xinha_plugins);
	editor.generate();
	xinha_editors.push(editor);
}

function createHiddenIframe(element, iframeId) {
    var frame = document.createElement('iframe');

    frame.id=iframeId;
    frame.name=iframeId;
    frame.style.display = 'none'; 

	// Add the created frame to the page
    element.appendChild(frame); 

	// BUGFIX for IE: This (somehow) prevents IE from opening a new window for form posts targeted at this frame 
	// (perhaps name attributes aren't kept when elements are appended in IE?)
	if(self.frames[iframeId].name != iframeId) {
		self.frames[iframeId].name = iframeId; 
	}

    return true;
}

function fileUploadComplete(response) {
	alert('Upload complete');
}

function fileUploadConfirmInDiv(div) {
	div = getElementByIdOrReference(div);
	return function(response) {
		displayInDiv(div, 'Upload complete');
		delayedClearDiv(div);
		setTimeout("window.location.reload(true)", 1*2000);	
	}
}

function deleteNode(node) {
	parentNode = node.parentNode;
	return parentNode.removeChild(node);
}

function deleteNodeById(nodeId) {
	node = document.getElementById(nodeId);
	return deleteNode(node);
}

function isRowHeaders(row) {
	for (var i=0; i < row.cells.length; i++) {
		if (row.cells[i].tagName == 'th') {
			return true;
		}
	}
	return false;
}

function alternateRows(table) {
	classes = ['odd', 'even'];
	current = 1;

	for (var i=0; i < table.rows.length; i++) {
		if (! isRowHeaders(table.rows[i])) {
			table.rows[i].className = classes[current];
			current = (current + 1) % 2;
		}
	}
}
