/**
* AJAX - Ajax calls for IHM
*
* Javascript 1.3 compliant
* Compatibility tested with :
* - Internet Explorer 6.5
* - Firefox 1.5
* If you tested with other browsers, please send and email to compatibility@pillot.fr
*
* Needs ihm.js to be included to work
*
* LICENCE: This source file is subject to version of the GPL license
* that is available through the world-wide-web at the following URL :
* http://www.gnu.org/licenses/gpl.txt.  If you did not receive a copy of
* the GPL License and are unable to obtain it through the web, please
* send a note to license@pillot.fr so we can mail you a copy immediately.
*
* @author    Baptiste Pillot <baptiste@pillot.fr>
* @copyright 2000-2006 Baptiste Pillot
* @license   http://www.gnu.org/licenses/gpl.txt
* @version   2.3
* @link      http://www.pillot.fr
*/

/** Is set to 1 while ajax call is being executed, reset to 0 when done */
var ajax_call_unsolved = 0;

/** Array containing last urls to ajax calls */
var ajax_call_last = new Array();

/** Memorize ajax infos */
var ajax_url = "";

/** Ajax popup window coords */
var ajax_x = 0;
var ajax_y = 0;

/** Set to true to cancel a pending ajax load */
var ajax_http_cancel = false;

/** destination frame where to load ajax call result */
var ajax_dest = "";

/** ajax call http object */
var ajax_http = null;

/** ajax queue when multiple-ajax clicks */
var ajax_queue = new Array();

/** ajax callback calls */
var ajax_callback_functions = new Array();

/** ajax close windows list : one list per dest */
var ajax_please_close = new Array();

//------------------------------------------------------------------------------ function ajaxCall
/** Ajax Call :
* url is the server-side script
* dest is the ID of the layer to output read html result into
* params is the optional form to send elements from,
*        or an array containing data to send to the server-size script
* mode is the sending mode of data (default is automatic, could be forced to GET or POST)
* with keep_message on, message zone will not be erased when calling ajax
* if after_what is given, content will be inserted after this html code
* if before_what is given, content will be inserted before this html code
* if queue_search is given, queue search-and-replace will be on a part of the url
* you can write in destination only between after_what and before_what */
function ajaxCall(url, dest, params, mode, keep_message, after_what, before_what, queue_search, no_callback_functions_call)
{
	var ajax_as_iframe = false;
	// add dest into getvars
	if (dest) {
		if (url.indexOf("?") == -1) {
			url = url + "?";
		} else {
			url = url + "&";
		}
		url = url + "ajax_dest=" + dest;
	}
	// enqueue if already ajax execution
	if (ajax_call_unsolved) {
		// one ajaxcall only accepted simultaneously
		// enqueue following calls (only if not the same as current)
		if (!ajax_http || url != ajax_http_url) {
			var do_replace = false;
			var is_found = false;
			for (i = 0; i < ajax_queue.length; i++) {
				if (queue_search == undefined) {
					// strict url search
					if (ajax_queue[i][0] == url) {
						is_found = true;
					}
				} else {
					// partial url search and replace
					if (ajax_queue[i][0].indexOf(queue_search) > -1) {
						if (dest == ajax_queue[i][1]) {
							is_found = true;
							do_replace = i;
						}
					}
				}
			}
			if (!is_found) {
				// enqueue only if not already in queue
				ajax_queue.reverse();
				ajax_queue.push(new Array(url, dest, params, mode, keep_message, after_what, before_what, no_callback_functions_call));
				ajax_queue.reverse();
			} else if (do_replace !== false) {
				// replace mode when partial url found
				ajax_queue[do_replace][0] = url;
			}
		}
	} else if (url.substr(0,3) == "js:") {
		// only javascript call, no ajax
		eval(url.substr(3));
	} else {
		// calculate params string
		var prm = "";
		if (params) {
			if (typeof(params) == "string") {
				// - works with simple param=value&param=value
				prm = params;
			} else if (params.elements) {
				// - can be a form element : included inputs will be sent
				prm = formToUrl(params);
				// - if form contains file fields, form will be post in a hidden iframe instead of pure-ajax
				if (formContainsFiles(params)) {
					ajax_as_iframe = true;
					ajax_as_iframe_form = params;
					if (!layerFind("ajax_file_upload_iframe")) {
						var body = document.getElementsByTagName("BODY");
						body = body[0];
						var iframe = document.createElement("iframe");
						iframe.setAttribute("id", "ajax_file_upload_iframe");
						iframe.setAttribute("name", "ajax_file_upload_iframe");
						iframe.setAttribute("style", "display:none;");
						body.appendChild(iframe);
					}
					var iframe_layer = layerFind("ajax_file_upload_iframe");
					iframe_layer.contentDocument.body.innerHTML = "ajax_file_upload_iframe";
					params.enctype = "multipart/form-data";
					params.method = "post";
					params.target = "ajax_file_upload_iframe";
					params.action = url + "&ajax_iframe=1";
					params.submit();
				}
			}
		}
		// ajax call mode
		ajax_call_unsolved++;
		if (!mode) {
			if (prm.length) mode = "POST";
			else mode = "GET";
		}
		// prepare http request
		ajax_http = null;
		try {
			if (ajax_as_iframe) {
				ajax_http = new Object();
			} else {
				ajax_http = new XMLHttpRequest();
			}
		} catch (e) {
			try {
				ajax_http  = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {
				try {
					ajax_http  = new ActiveXObject("Msxml2.XMLHTTP");
				} catch (e) {
					ajax_http = false;
					alert("AJAX Error: Your browser is not Ajax compatible !");
				}
			}
		}
		// clear messages layer
		if (!keep_message && dest != "app_messages" && layerFind("app_messages")) {
			layerWrite(layerFind("app_messages"), "");
			layerToFront(layerFind("app_messages"));
			// please wait message
			//layerWrite(layerFind(dest), "... please wait ...");
		}
		// memorize some parameters to use it on response
		ajax_http_x = mouse_x + 1;
		ajax_http_y = mouse_y + 1;
		ajax_http_dest = dest;
		ajax_http_url = url;
		ajax_http_after_what = after_what;
		ajax_http_before_what = before_what;
		ajax_http_no_callback_functions_call = no_callback_functions_call;
		//-------------------------------------------------------------------------- function ajax_http.onreadystatechange
		// ajax callback function
		ajax_http.onreadystatechange = function()
		{
			if (ajax_http.readyState == 4) {
				ajax_call_unsolved--;
				if (ajax_http.status == 200) {
					if (ajax_http_cancel) {
						// erase ajax_http object
						ajax_http_dest = "";
						// cancel
						ajax_http_cancel = false;
					} else {
						// close opened windows that depend on this dest
						if (ajax_http_dest && ajax_please_close[ajax_http_dest]) {
							var object_to_close;
							while (ajax_please_close[ajax_http_dest].length) {
								object_to_close = ajax_please_close[ajax_http_dest].pop();
								if (typeof(object_to_close) == "object") {
									object_to_close.free();
								} else if (typeof(controls.elements[object_to_close]) == "object") {
									controls.elements[object_to_close].free();
								} else if (layerFind(object_to_close)) {
									layerFind(object_to_close).parentNode.removeChild(layerFind(object_to_close));
								}
							}
						}
						// display ajax returned html
						var layer = (typeof(ajax_http_dest)) == "string" ? layerFind(ajax_http_dest) : ajax_http_dest;
						//var layer = layerFind(ajax_http_dest);
						var response_text = ajax_http.responseText;
						// extract ajax javascript
						var deb = 0;
						var fin = 0;
						var response_javascript = "";
						i = 0;
						while ((deb = response_text.indexOf("<SCRIPT", fin)) > -1) {
							var cut_deb = deb;
							deb = response_text.indexOf(">", deb) + 1;
							fin = response_text.indexOf("</SCRIPT>", deb);
							var cut_fin = fin + 9;
							response_javascript = response_javascript + response_text.substr(deb, fin - deb);
							response_text = response_text.substr(0, cut_deb) + response_text.substr(cut_fin);
							fin = cut_deb;
						}
						if (layer) {
							// with after_what and before_what options,
							// you can write wherever you want in layer
							if (ajax_http_after_what && ajax_http_before_what) {
								text  = layer.innerHTML;
								i = text.indexOf(ajax_http_after_what) + ajax_http_after_what.length;
								j = text.indexOf(ajax_http_before_what, i);
								text = text.substr(0, i)
								+ response_text
								+ text.substr(j)
								layerWrite(layer, text);
								layerToFront(layer);
							} else {
								layerWrite(layer, response_text);
								layerToFront(layer);
							}
							var app_debug = layerFind("app_debug");
							if (app_debug && !ajax_http_no_callback_functions_call) {
								app_debug.innerHTML = "&nbsp;" + Math.round((response_text.length / 1024)) + "Ko&nbsp;";
							}
						} else {
							layer = new SimpleWindow(ajax_http_dest, "",response_text, ajax_http_x, ajax_http_y);
						}
						// record last ajax call getvars
						var params = ajax_http_url.split("?");
						ajax_call_last[ajax_http_dest] = new Array();
						ajax_call_last[ajax_http_dest][""] = params[0];
						if (params.length > 1) {
							params = params[1].split("&");
							for (var i = 0; i < params.length; i++) {
								var prm = params[i].split("=");
								ajax_call_last[ajax_http_dest][prm[0]] = prm[1];
								if (prm.length > 2) {
									alert("ajax_call_last fatal error. please contact support.");
								}
							}
						}
						// erase ajax_http object
						last_ajax_http_dest = ajax_http_dest;
						ajax_http_dest = "";
						// execute ajax returned javascript
						if (response_javascript) {
							try {
								// uses htmlspecialchars_decode as we've got strange problems with iframes
								eval(htmlspecialchars_decode(response_javascript));
							} catch(e) {
								// catch javascript errors
								alert("JS error " + e.name + " " + e.message + " on ajax returned javascript code :\n" + htmlspecialchars_decode(response_javascript));
							}
						}
						// ajax callback functions call
						if (!ajax_http_no_callback_functions_call) {
							for (var i = 0; i < ajax_callback_functions.length; i++) {
								try {
									eval(ajax_callback_functions[i]);
								} catch(e) {
									alert("JS error " + e.name + " " + e.message + " on ajax callback call :\n" + ajax_callback_functions[i]);
								}
							}
						}
					}
				} else {
					alert("AJAX Error: returned status code " + ajax_http.status + " : " + ajax_http.statusText);
					// erase ajax_http object
					ajax_http_dest = "";
				}
				// pop ajax call queue, if there are enqueued calls
				if (ajax_queue.length) {
					call = ajax_queue.pop();
					ajaxCall(call[0], call[1], call[2], call[3], call[4], call[5], call[6], undefined, call[7]);
				}
			}
		}
		//-------------------------------------------------------------------------- ajaxCall (end)
		// do the call
		window.setTimeout("ajaxClock(" + ajax_as_iframe + ");", 1000);
		if (!ajax_as_iframe) {
			ajax_http.open(mode, url, true);
			if (mode == "POST") {
				ajax_http.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
			}
			ajax_http.send(prm);
		}
	}
}

//------------------------------------------------------------------------------ function ajaxClock
var ajax_clock = 0;
function ajaxClock(ajax_as_iframe)
{
	if (ajax_as_iframe) {
		var iframe_layer = layerFind("ajax_file_upload_iframe");
		if (iframe_layer.contentDocument.body.innerHTML != "ajax_file_upload_iframe") {
			ajax_http.readyState = 4;
			ajax_http.status = 200;
			ajax_http.responseText = iframe_layer.contentDocument.body.innerHTML;
			while (ajax_http.responseText.indexOf("<ajax_script") > -1) {
				ajax_http.responseText = ajax_http.responseText.replace("<ajax_script", "<SCRIPT").replace("</ajax_script", "</SCRIPT");
			}
			ajax_http.onreadystatechange();
			iframe_layer.contentDocument.body.innerHTML = "";
		}
	}
	if (!ajax_clock) {
		ajax_clock = new Control("ajax_clock", "<IMG SRC=/img/clock.gif>", mouse_x + 16, mouse_y + 16, 11, 16);
	} else {
		ajax_clock.setPosXY(mouse_x + 16, mouse_y + 16);
	}
	if (!ajax_call_unsolved) {
		ajax_clock.free();
		ajax_clock = 0;
	} else {
		window.setTimeout("ajaxClock(" + ajax_as_iframe + ");", 20);
	}
}

//------------------------------------------------------------------------------ function ajaxHintOn
/** Show hint popup, loaded with ajax */
function ajaxHintOn(url, params, mode)
{
	if (!ajax_call_unsolved) {
		// hide old popup
		ajaxHintOff();
		// when setTimeout, reload params
		if (!url) {
			url = ajax_hint_on_url;
			params = ajax_hint_on_params;
			mode = ajax_hint_on_mode;
		}
		// ajax call
		return ajaxCall(url, 'app_hint', params, mode, true);
	} else {
		// if ajax call already pending, must wait
		if (url) {
			// - save params
			ajax_hint_on_url = url;
			ajax_hint_on_params = params;
			ajax_hint_on_mode = mode;
		}
		// - try again in 1/5 sec
		setTimeout('ajaxHintOn()', 200);
	}
}

//---------------------------------------------------------------------------- function ajaxHintOff
/** Hide hint popup */
function ajaxHintOff()
{
	if (controls.app_hint) {
		// close loaded hint popup
		controls.app_hint.free();
	}
	if (ajax_http_dest == "app_hint") {
		// cancel current ajax popup load if not already displayed
		if (!ajax_http_cancel) {
			ajax_http_cancel = true;
			setTimeout("ajaxHintOff()", 200);
		}
	}
}

//-------------------------------------------------------------------------- function ajaxWillClose
/**
 * Declare that window-layer named "window" should close when "dest" is closed or reloaded
 */
function ajaxWillClose(dest, window)
{
	if (!ajax_please_close[dest]) {
		ajax_please_close[dest] = new Array();
	}
	ajax_please_close[dest].push(window);
}

//------------------------------------------------------------------------------- function dynPopup
var dyn_popup_input    = "dyn_popup_input";
var dyn_popup_value    = "dyn_popup_value";
var dyn_popup_form     = "dyn_popup_form";
var dyn_popup_id_field = "dyn_popup_id_field";
/**
 * Transforms text input into Dynamic popup, loading data from a specific url
 * Popup into correctly positionned and dimensionned window
 * Needs ajax.js library !
 */
function dynPopup(text_input, url, force_popup, id_field, post_vars)
{
	if (!controls.app_dyn_popup || !controls.app_dyn_popup.visible || force_popup) {
		if (dyn_popup_value != text_input.value
		|| dyn_popup_form != text_input.form.name
		|| dyn_popup_id_field != id_field
		|| dyn_popup_input != text_input) {
			if (!controls.app_dyn_popup) {
				// create popup control
				new Control(
					"app_dyn_popup",
					"",
					layerPosX(text_input),
					layerPosY(text_input) + layerHeight(text_input),
					layerWidth(text_input)
				);
			} else {
				controls.app_dyn_popup.write("");
			}
			// fill in content with ajax call
			ajaxCall(
				url + "&a[begin]=" + urlEncode(text_input.value) + "&a[form]=" + urlEncode(text_input.form.name) + (id_field ? "&a[view_fields]=&a[id_field]=" + urlEncode(id_field) : ""),
				"app_dyn_popup",
				post_vars,
				undefined,
				true,
				undefined,
				undefined,
				url + "&a[begin]="
			);
			// reset position and show control
			controls.app_dyn_popup.setPosXY(
				layerPosX(text_input),
				layerPosY(text_input) + layerHeight(text_input)
			);
			dyn_popup_input = text_input;
			dyn_popup_value = text_input.value;
			dyn_popup_form = text_input.form.name;
			dyn_popup_id_field = id_field;
		}
		controls.app_dyn_popup.show();
	} else {
		// release popup control
		controls.app_dyn_popup.hide();
		dyn_popup_value = "dyn_popup_value";
		dyn_popup_form = "dyn_popup_form";
	}
}
