/*
	AJAX.js - script to handle submitting data via AJAX

	public functions: 
		ajax(url,target,width,done_function) 				- load a page via GET method
		ajax_post(url,parameters,target,width,done_function) - load a page via POST method
		submitFormViaAJAX(form, done_function)				- submits form via AJAX
*/

	////////////////////////////////////////////////////////////////////////////////
	// CONFIGURATION

		// encoding used for submitting AJAX queries. Possible values are "ascii", "utf8" and "none"
			// you must use have loaded conversion.js, which contains definitions of functions encode() and decode()
var g_ajax_encoding = "none";


	////////////////////////////////////////////////////////////////////////////////
	// DEFINITION OF THE MAIN AJAX OBJECT

	// __g_ajax_request should not be loaded. Display warning
if ( __g_ajax_request != undefined)
	alert("AJAX is already loaded! Please call the admin and ask him to check!");

var __g_ajax_request = null;	// main AJAX object. It's created when AJAX is needed



	////////////////////////////////////////////////////////////////////////////////
	// FUNCTIONS

/*
	ajax(url,target,width,done_function) - main function
		This function is called when the user wants to load a page via GET method
		
	parameters:
		url: 	url of the page, including parameters. Can be absolute or relative but cannot be from a different server
		target: id of the element into which the page is loaded. All loaded code becomes a part of the current page
				and it cannot contain any <html></html> etc. tags
		width:  sometimes the target element must be resized accordingly. This is optional parameter.
				Default value is "auto"
		done_function : function called after the page is completely loaded
						NOTE: if the loaded page contains any javascript code, it's not executed !!!

						values: contains reference to the function which should be executed
								"evaluate_result" - evaluates loaded code. Any JavaScript must be only at one line
													and it must be encapsulated by <script></script>
													(no parameters needed in the tag)
													Also you must insert at least one character (e.g. &nbsp;) before it

	returns:
		- false and popups a message if provided parameters are invalid
		- error message into the target element if the AJAX request faces an error
		- HTML of the loaded page which is inserted into the target element. Executes the done_function if defined.
*/

function ajax(url,target,width,done_function)
{
	var tmp;

		// set width and done_function if they are not provided
	if ( arguments.length <= 2)
	{
		 width = "auto";
		 done_function = "";
	}
	else if ( arguments.length <= 3)
		 done_function = "";

		// validate provided parameters
	if ( (tmp = __validateAJAXParameters(url,target)) != true)
	{
		alert(tmp);
		return false;
	}

		// encode the URL
	if ( typeof(g_ajax_encoding) != "undefined" && g_ajax_encoding != "none")
	{
		url = unescape(url);		// must unescape any previous encodings otherwise it would encode the already encoded text
		url = url.replace(/(=([^=&#])*[&#])*(=([^=&#])*)/g, function(parameter){ return "=" + encode(parameter.substr(1), g_ajax_encoding) });
	}

		// adjust width and display "retrieving" message
	__setTargetElement(target, width);

		// create native XMLHttpRequest object
    if ( window.XMLHttpRequest)
	{
        __g_ajax_request = new XMLHttpRequest();
        __g_ajax_request.onreadystatechange = function() { __ajaxDone(target, done_function) };
        __g_ajax_request.open("GET", url, true);
        __g_ajax_request.send(null);  
    }
	else if (window.ActiveXObject)			// IE/Windows ActiveX version
	{
        __g_ajax_request = new ActiveXObject("Microsoft.XMLHTTP");

		if (__g_ajax_request)
		{
            __g_ajax_request.onreadystatechange = function() { __ajaxDone(target, done_function) };
            __g_ajax_request.open("GET", url, true);
            __g_ajax_request.send();
        }
    }
}    



/*
	ajax_post(url,parameters,target,width,done_function) - main function
		This function is called when the user wants to load a page via POST method

	parameters different from ajax():
		url: 		url of the page, without parameters. Can be absolute or relative but cannot be from a different server
		parameters: list of parameters in format "name=value&name=value"
*/

function ajax_post(url,parameters,target,width,done_function)
{
	var tmp;

		// set width and done_function if they are not provided
	if ( arguments.length <= 3)
	{
		 width = "auto";
		 done_function = "";
	}
	else if ( arguments.length <= 4)
		 done_function = "";

		// validate provided parameters
	if ( (tmp = __validateAJAXParameters(url,target)) != true)
	{
		alert(tmp);
		return false;
	}

		// encode the URL
	if ( typeof(g_ajax_encoding) != "undefined" && g_ajax_encoding != "none")
	{
		parameters = unescape(parameters);		// must unescape any previous encodings otherwise it would encode the already encoded text
		parameters = parameters.replace(/(=([^=&#])*[&#])*(=([^=&#])*)/g, function(parameter){ return "=" + encode(parameter.substr(1), g_ajax_encoding) });
	}

		// adjust width and display "retrieving" message
	__setTargetElement(target, width);

		// create native XMLHttpRequest object
	if ( window.XMLHttpRequest)		// Mozilla, Safari,...
	{
		__g_ajax_request = new XMLHttpRequest();

			// set type accordingly to anticipated content type	
		if ( __g_ajax_request.overrideMimeType)
		{
			__g_ajax_request.overrideMimeType('text/html');		// 'text/xml'
		}
	}
	else if ( window.ActiveXObject) 	// IE
	{
		try
		{
			__g_ajax_request = new ActiveXObject("Msxml2.XMLHTTP");
		}
		catch (e)
		{
			try
			{
				__g_ajax_request = new ActiveXObject("Microsoft.XMLHTTP");
			}
			catch (e) {}
		}
	}

	if (!__g_ajax_request)
	{
		alert('Cannot create XMLHTTP instance');
		return false;
	}

	__g_ajax_request.onreadystatechange = function() { __ajaxDone(target, done_function) };
	__g_ajax_request.open('POST', url, true);
	__g_ajax_request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	__g_ajax_request.setRequestHeader("Content-length", parameters.length);
	__g_ajax_request.setRequestHeader("Connection", "close");
	__g_ajax_request.send(parameters);
}



/*
	submitFormViaAJAX(form, done_function, width) - submits form via AJAX
		NOTE: it cannot be used to upload files
		
	parameters different from ajax():
		form: 	reference to the form (not its id)

	what should be set in the <form></form> tags:
		method:	it's optional. Specify if it should be sent by GET (default) or post
		action: url of the loaded page (see "url" description at ajax() for more info)
		target: id of the element into which the page is loaded (see "target" description at ajax() for more info)
*/

function submitFormViaAJAX(form, done_function, width)
{
	var i, url, method, arr_submit = new Array();
	method = form.method.toLowerCase() == "post" ? "post" : "get";

 	if ( arguments.length <= 1)
	{
		done_function = "";
		width = "auto";
	}
	else if ( arguments.length <= 2)
		width = "auto";

		// loop form elements and create array of element to submit
	for (i=0;i<form.elements.length;i++)
	{
		if ( (form.elements[i].type == "checkbox" || form.elements[i].type == "radio") && form.elements[i].checked == false)
			continue;

		if ( form.elements[i].type == "button" || form.elements[i].type == "submit" || form.elements[i].type == "reset")
			continue;

		arr_submit[ arr_submit.length ] = form.elements[i].name + "=" + __escapeWithUnixCarriageReturn(form.elements[i].value);
	}

		// set url
	if ( method == "get")
		url = form.action + ( form.action.indexOf("?") == -1 ? "?" : "&" ) + arr_submit.join("&");
	else	url = form.action;

		// validate provided parameters
	if ( (tmp = __validateAJAXParameters(url,form.target)) != true)
	{
		alert(tmp);
		return false;
	}

		// adjust width and display "retrieving" message
	__setTargetElement(form.target, width);

		// submit
	if ( done_function == "evaluate_result")
		done_function = Function("__evaluateAJAXResult('" + form.target + "')");

	if ( method == "post")
		ajax_post(form.action, arr_submit.join("&"), form.target, "auto", done_function);
	else	ajax(url,form.target,"auto",done_function);
}


	///////////////////////////////////////////////////////////////////////////////
	// INTERNAL FUNCTIONS - not called by the user

		// validates parameters (target, url) and returns error message if invalid
function __validateAJAXParameters(url,target)
{
		// check if target exists
	if ( document.getElementById(target) == undefined)
		return "Invalid AJAX target! (" + target + ")";

		// url cannot be from a different domain otherwise it cause an error, testing it
	var tmp_url_paths = __parseUri(url);

		// NOTE: considering only absolute urls in valid format
	if ( tmp_url_paths["protocol"] != "" && window.location.host != tmp_url_paths["domain"])
		return "Target must be from the same domain!";

		// all ok
	return true;
}

	// set target element width and display "retrieving" message in the target
function __setTargetElement(target, width)
{
		// display "retrieving" message in the target
    document.getElementById(target).innerHTML = '<span class="ajax">retrieving...</span>';

		// !!@ temporary fix for WAIT()
	if ( target == "waitingbox_inner")
		target = "waitingbox";

		// set target width if necessary
	if ( width != "auto")
	{
		if ( navigator.userAgent.search(/mac/i) != -1)						// setting MAC values
			document.getElementById(target).style.width = width + "px";
		else	document.getElementById(target).style.width = ( navigator.userAgent.search(/msie/i) == -1 || navigator.userAgent.search(/opera/i) != -1 ? 10 : 0 ) + width + "px";
	}
	//else	document.getElementById(target).style.width = "";	// !!@ why?
}

	// function called when page is fully loaded, executes user defined done_function
function __ajaxDone(target, done_function)
{
		// only if page is fully loaded
    if ( __g_ajax_request.readyState == 4)
	{
        	// only if "OK"
        if ( __g_ajax_request.status == 200)
		{	
            results = __g_ajax_request.responseText;
            document.getElementById(target).innerHTML = results;

				// size adjustment of the waiting dialog box
		if ( document.getElementById("waiting").style.display == "block")
				wait_final_ajax_adjustment();
/**/
				// execute done function if defined
			if ( done_function != "")
			{
				if ( done_function == "evaluate_result")
					done_function = Function("__evaluateAJAXResult('" + target + "')");

				done_function();
			}
        }
		else
		{
			if ( __g_ajax_request.status == 404)
				document.getElementById(target).innerHTML = "AJAX error: page not found!";
			else	document.getElementById(target).innerHTML = "AJAX error: " + __g_ajax_request.statusText;
    	}
	}
}

	// evaluates code within <script></script> at the loaded page
		// NOTE: Code must be at one line only
		// 		 <script></script> cannot be the firts character otherwise it's not found by IE!
		//		you must insert at least one character (e.g. &nbsp;) before it
function __evaluateAJAXResult(target)
{
	var ajax_js = "";

	if ( document.getElementById(target) == undefined)
	{
		alert("AJAX target is not valid! (" + target + ')');
		return false;
	}

	ajax_js = document.getElementById(target).innerHTML.match(/<script[^>]*>(.+)<\/script>/i)

	if ( ajax_js != null)
		eval(ajax_js[1]);
}

function __escapeWithUnixCarriageReturn(text)
{
	var text_length;

	do
	{
		text_length = text.length;
		text = text.replace(/([^\r])\n/g, "$1\r\n");
	}
	while ( text_length != text.length)

	return escape(text);
}



/* 
http://blog.stevenlevithan.com/archives/parseuri-split-url

parseUri JS v0.1.1, by Steven Levithan <http://stevenlevithan.com>
Splits any well-formed URI into the following parts (all are optional):
----------------------
- source (since the exec method returns the entire match as key 0, we might as well use it)
- protocol (i.e., scheme)
- authority (includes both the domain and port)
  - domain (i.e., host; can be an IP address)
  - port
- path (includes both the directory path and filename)
  - directory (supports directories with periods, and without a trailing backslash)
  - file
- query (does not include the leading question mark)
- anchor (i.e., fragment) */

function __parseUri(sourceUri)
{
	var uriPartNames = ["source","protocol","authority","domain","port","path","directory","file","query","anchor"],
		uriParts = new RegExp("^(?:([^:/?#.]+):)?(?://)?(([^:/?#]*)(?::(\\d*))?)((/(?:[^?#](?![^?#/]*\\.[^?#/.]+(?:[\\?#]|$)))*/?)?([^?#/]*))?(?:\\?([^#]*))?(?:#(.*))?").exec(sourceUri),
		uri = {};
	
	for(var i=0;i<10;i++)
		uri[ uriPartNames[i] ] = uriParts[i] ? uriParts[i] : "";
	
		/* Always end directoryPath with a trailing backslash if a path was present in the source URI
		Note that a trailing backslash is NOT automatically inserted within or appended to the "path" key */
	if ( uri.directory.length > 0)
		uri.directoryPath = uri.directory.replace(/\/?$/, "/");

	return uri;
}