
function DrXmlHttp() {

	this.showLoading = function(element) {

		newDiv = document.createElement("div");
		newDiv.setAttribute("class", "loadInElement_loading");
		newDiv.setAttribute("style", " background-color: transparent; background-color: white; color: black; border: solid black 1px; filter:alpha(opacity=40); -moz-opacity:0.4; opacity: 0.4; ");
		newDiv.innerHTML = "Chargement en cours...";
		element.appendChild(newDiv);

	}

	this.options = {
		"beforeLoad" : this.showLoading,
		"afterLoad"  : null,
		"onError"    : null
	}


	// Return an xmlhttp object
	this.getXmlHttp = function() {

		var xmlhttp = false;

		/*@cc_on @*/
		/*@if (@_jscript_version >= 5)
		// JScript gives us Conditional compilation, so 
		//  we can cope with old IE versions.
		// and security blocked creation of the objects.
			try {
				xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
			} catch (e) {
				try {
					xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
				} catch (E) {
					xmlhttp = false;
				}
			}
		@end @*/
		if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
			xmlhttp = new XMLHttpRequest();
		}

		return xmlhttp;

	}

	

	// execute a HEAD request
	this.httpHeadRequest = function(url, async, params) {

		if (typeof async == 'undefined')
			async = true;

		if (typeof params == 'undefined')
			params = {};

		xmlhttp = this.getXmlHttp();

		xmlhttp.open('GET', url, async);

		options = this.options;

		if (async) {
			xmlhttp.onreadystatechange=function() {
				if (xmlhttp.readyState==4) {
					if (xmlhttp.status == 200) {
						if (params['afterFinish'] != null)
							params['afterFinish'](true);
						return true;
					} else {

						msg = xmlhttp.getResponseHeader("Status");

						if (params['afterFinish'] != null)
							params['afterFinish'](msg);

						if (options["onError"] != null)
							options["onError"](element, msg);
						else
							alert(msg);

						return false;
					}
				}
			}
		}

		xmlhttp.send(null);

		if (!async) {
			if (xmlhttp.status == 200) {
				if (params['afterFinish'] != null)
					params['afterFinish'](true);
				return true;
			} else {
				msg = xmlhttp.getResponseHeader("Status");

				if (params['afterFinish'] != null)
					params['afterFinish'](msg);

				if (options["onError"] != null)
					options["onError"](element, msg);
				else
					alert(msg);
				return false;
			}
		}

		return true;

	}

	// get values in XML format, on the form <values><key1>val1</key1><key2>val2</key2></values>
	// if asyncFunction is a given and is a function, the call is asynchronous,
	//  asynchronous(values) is called.
	// else, return the values after a synchronous call.
	this.getValues = function(url, asyncFunction) {

		// async
		if (typeof asyncFunction == 'function') {

			xmlhttp = this.getXmlHttp();

			xmlhttp.open('GET', url, true);
			xmlhttp.send(null);

			xmlhttp.onreadystatechange=function() {
				if (xmlhttp.readyState==4) {
					if (xmlhttp.status == 200) {
						xmldoc = xmlhttp.responseXML;
						if (typeof xmldoc == 'undefined' || xmldoc == null) values = {};
						else values = xmlToValues(xmldoc);
						asyncFunction(values);
					} else {
						alert(xmlhttp.getResponseHeader("Status"));
						return false;
					}
				}
			}

		// sync
		} else {

			xmlhttp = this.getXmlHttp();

			xmlhttp.open('GET', url, false);

			xmlhttp.send(null);

			if (xmlhttp.status == 200) {
				xmldoc = xmlhttp.responseXML;
				if (typeof xmldoc == 'undefined' || xmldoc == null)
					return {};
				else
					return xmlToValues(xmldoc);
			} else {
				alert(xmlhttp.getResponseHeader("Status"));
				return false;
			}

		}

	}

	// load an url content in a div popup, which will be given the id
	// return the popup.
	// Needs DrDivPopup.js
	this.loadInPopup = function(id, url, async, params) {
		if (typeof params == 'undefined')
			params = {};
		popup = new DrDivPopup(id, params);
		popup.create();
		this.loadInGivenElement(popup.content, url, async, params);
		return popup;
	}


	// load an url in the given element
	this.loadInGivenElement = function(element, url, async, params) {

		if (typeof async == 'undefined')
			async = true;

		if (typeof params == 'undefined')
			params = {};

		method = 'POST';
		if (params['method'] == 'GET')
			method = 'GET';

		if (url.indexOf("?") == -1) 
			url += "?";
		else
			url += "&";
		url += "outputXmlResponseMode=1";

		postData = null;
		if (method == 'POST') {
			pos = url.indexOf("?");
			if (pos != -1) {
				postData = url.substr(pos+1);
				url = url.substr(0, pos);
			}
		}

		xmlhttp = this.getXmlHttp();

		xmlhttp.open(method, url, async);

		var options = this.options;

		if (async) {
			xmlhttp.onreadystatechange = function() {
				if (xmlhttp.readyState == 4) {
					if (xmlhttp.status == 200) {
						xmldoc = xmlhttp.responseXML;

						if (typeof xmldoc == 'undefined' || xmldoc == null) {

							element.innerHTML = xmlhttp.responseText;

						} else {
							
							txt = base64_decode(getTextContent(xmldoc, 'xhtml'));
							element.innerHTML = txt;

							txt = base64_decode(getTextContent(xmldoc, 'javascript'));
							if (txt.length > 3)
								eval(txt);
						}

					} else {
						msg = xmlhttp.getResponseHeader("Status");
						if (options["onError"] != null)
							options["onError"](element, msg);
						else
							alert(msg);
					}

					if (options["afterLoad"] != null)
						options["afterLoad"](element);

					if (params['afterFinish'] != null)
						params['afterFinish'](element);
				}
			}
		}

		if (this.options["beforeLoad"] !== null)
			this.options["beforeLoad"](element);

		if (postData != null) {
			xmlhttp.setRequestHeader('Content-Type',
					'application/x-www-form-urlencoded');
		}
		xmlhttp.send(postData);

		if (!async) {

			if (xmlhttp.status == 200) {
				xmldoc = xmlhttp.responseXML;

				if (typeof xmldoc == 'undefined' || xmldoc == null) {

					element.innerHTML = xmlhttp.responseText;

				} else {
					
					txt = base64_decode(getTextContent(xmldoc, 'xhtml'));
					element.innerHTML = txt;

					txt = base64_decode(getTextContent(xmldoc, 'javascript'));
					if (txt.length > 3)
						eval(txt);
				}

				retVal = true;

			} else {

				msg = xmlhttp.getResponseHeader("Status");
				if (options["onError"] != null)
					options["onError"](element, msg);
				else
					alert(msg);
				retVal = false;
			}

			if (this.options["afterLoad"] != null)
				this.options["afterLoad"](element);

			if (params['afterFinish'] != null)
				params['afterFinish'](element);

			return retVal;

		}

		return true;

	}

	// load javascript and execute it
	this.loadJavaScript = function(url, async, params) {

		if (typeof async == 'undefined')
			async = true;

		if (typeof params == 'undefined')
			params = {};

		method = 'GET';
		if (params['method'] == 'POST')
			method = 'POST';

		if (url.indexOf("?") == -1) 
			url += "?";
		else
			url += "&";
		url += "outputXmlResponseMode=1";

		postData = null;
		if (method == 'POST') {
			pos = url.indexOf("?");
			if (pos != -1) {
				postData = url.substr(pos+1);
				url = url.substr(0, pos);
			}
		}

		xmlhttp = this.getXmlHttp();

		xmlhttp.open(method, url, async);

		options = this.options;

		if (async) {
			xmlhttp.onreadystatechange = function() {
				if (xmlhttp.readyState == 4) {
					if (xmlhttp.status == 200) {
						xmldoc = xmlhttp.responseXML;

						if (typeof xmldoc == 'undefined' || xmldoc == null) {

						} else {
							
							txt = base64_decode(getTextContent(xmldoc, 'javascript'));
							if (txt.length > 3)
								eval(txt);
						}

						if (params['afterFinish'] != null)
							params['afterFinish']();

					} else {

						msg = xmlhttp.getResponseHeader("Status");

						if (options["onError"] != null)
							options["onError"](element, msg);
						else
							alert(msg);

					}
				}
			}
		}

		if (postData != null) {
			xmlhttp.setRequestHeader('Content-Type',
					'application/x-www-form-urlencoded');
		}
		xmlhttp.send(postData);

		if (!async) {

			if (xmlhttp.status == 200) {
				xmldoc = xmlhttp.responseXML;

				if (typeof xmldoc == 'undefined' || xmldoc == null) {

				} else {
					
					txt = base64_decode(getTextContent(xmldoc, 'javascript'));
					if (txt.length > 3)
						eval(txt);
				}

				if (params['afterFinish'] != null)
					params['afterFinish']();

				return true;

			} else {

				msg = xmlhttp.getResponseHeader("Status");

				if (options["onError"] != null)
					options["onError"](element, msg);
				else
					alert(msg);

				return false;
			}

		}

		return true;

	}

	// Load an url content in the element given by id
	this.loadInElement = function(id, url, async, params) {

		element = document.getElementById(id);

		return this.loadInGivenElement(element, url, async, params);

	}


	// convert {'val':1,'val2':2} to GET params val=1&val2=2
	// FIXME: encoding incomplete ! use encodeURI ?
	this.valuesToParams = function(values) {
		
		params = new Array();

		for (i in values) {
			params.push(i + "=" + 
				escape(values[i]).replace(/\+/g, '%2C').replace(/\"/g,'%22').replace(/\'/g, '%27'));
		}

		params = params.join("&");
		return params;
	}

	// displays a waiting notification
	this.showNotification = function(message) {
		this.clearNotification();
		var arrayPageSize = this.getPageSize();
		var arrayPageScroll = this.getPageScroll();

		var divTop = arrayPageScroll[1]
			+ ((arrayPageSize[3] - 30) / 2);
		var divLeft = arrayPageScroll[0]
			+ ((arrayPageSize[2] - 200) / 2);

		newDiv = document.createElement("div");
		newDiv.setAttribute("class", "DrXmlHttpNotification");
		newDiv.setAttribute("id", "DrXmlHttpNotification");
		newDiv.className = "DrXmlHttpNotification";

		newDiv.style.position = "absolute";
		newDiv.style.top = (divTop < 0) ? "0px" : divTop + "px";
		newDiv.style.height = "30px";
		newDiv.style.left = (divLeft < 0) ? "0px" : divLeft + "px";
		newDiv.style.width = "200px";

		newDiv.innerHTML = message;
		document.body.appendChild(newDiv);
	}

	this.clearNotification = function() {
		element = document.getElementById("DrXmlHttpNotification");
		if (typeof element == "undefined" || element == null)
			return false;
		parentNode = element.parentNode;
		if (typeof parentNode == "undefined" || parentNode == null)
			return false;
		parentNode.removeChild(element);
		return true;

	}

	// getPageScroll()
	// Returns array with x,y page scroll values.
	// Core code from - quirksmode.org - lightbox
	//
	this.getPageScroll = function() {

		var yScroll;

		if (self.pageYOffset) {
			yScroll = self.pageYOffset;
		} else if (document.documentElement && document.documentElement.scrollTop){	 // Explorer 6 Strict
			yScroll = document.documentElement.scrollTop;
		} else if (document.body) {// all other Explorers
			yScroll = document.body.scrollTop;
		}

		arrayPageScroll = new Array('',yScroll) 
			return arrayPageScroll;
	}



	//
	// getPageSize()
	// Returns array with page width, height and window width, height
	// Core code from - quirksmode.org
	// Edit for Firefox by pHaez - lightbox
	//
	this.getPageSize = function() {

		var xScroll, yScroll;

		if (window.innerHeight && window.scrollMaxY) {	
			xScroll = document.body.scrollWidth;
			yScroll = window.innerHeight + window.scrollMaxY;
		} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
			xScroll = document.body.offsetWidth;
			yScroll = document.body.offsetHeight;
		}

		var windowWidth, windowHeight;
		if (self.innerHeight) {	// all except Explorer
			windowWidth = self.innerWidth;
			windowHeight = self.innerHeight;
		} else if (document.documentElement
				&& document.documentElement.clientHeight) { // Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) { // other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}	

		// for small pages with total height less then height of the viewport
		if(yScroll < windowHeight){
			pageHeight = windowHeight;
		} else { 
			pageHeight = yScroll;
		}

		// for small pages with total width less then width of the viewport
		if(xScroll < windowWidth){	
			pageWidth = windowWidth;
		} else {
			pageWidth = xScroll;
		}


		arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight) 
			return arrayPageSize;
	}

}

drXmlHttp = new DrXmlHttp();


// convert 1-level xml values to object
function xmlToValues(xmldoc) {
	isIE = navigator.appVersion.indexOf("MSIE") > 0;
	valuesTag = xmldoc.getElementsByTagName('values')[0].childNodes;
	values = {};
	for (i = 0; i < valuesTag.length; i++) {
		if (isIE) value = valuesTag[i].text;
		else      value = valuesTag[i].textContent;
		values[valuesTag[i].nodeName] = base64_decode(value);
	}
	return values;
}


// get text for a first element of tag name
function getTextContent(xmldoc, tagName) {
	isIE = navigator.appVersion.indexOf("MSIE") > 0;
	if (isIE) {
		return xmldoc.getElementsByTagName(tagName)[0].text;
	} else {
		return xmldoc.getElementsByTagName(tagName)[0].textContent;
	}
}

// decode base 64 text
function base64_decode(txt) {

	//First things first, set up our array that we are going to use.
	var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + //all caps
	"abcdefghijklmnopqrstuvwxyz" + //all lowercase
	"0123456789+/="; // all numbers plus +/=

	var out = ""; //This is the output
	var chr1, chr2, chr3 = ""; //These are the 3 decoded bytes
	var enc1, enc2, enc3, enc4 = ""; //These are the 4 bytes to be decoded
	var i = 0; //Position counter

	// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
	txt = txt.replace(/[^A-Za-z0-9\+\/\=]/g, "");

	do {

		//Grab 4 bytes of encoded content.
		enc1 = keyStr.indexOf(txt.charAt(i++));
		enc2 = keyStr.indexOf(txt.charAt(i++));
		enc3 = keyStr.indexOf(txt.charAt(i++));
		enc4 = keyStr.indexOf(txt.charAt(i++));

		//Heres the decode part. There's really only one way to do it.
		chr1 = (enc1 << 2) | (enc2 >> 4);
		chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
		chr3 = ((enc3 & 3) << 6) | enc4;

		//Start to output decoded content
		out = out + String.fromCharCode(chr1);

		if (enc3 != 64) {
		out = out + String.fromCharCode(chr2);
		}
		if (enc4 != 64) {
		out = out + String.fromCharCode(chr3);
		}

		//now clean out the variables used
		chr1 = chr2 = chr3 = "";
		enc1 = enc2 = enc3 = enc4 = "";

	} while (i < txt.length); //finish off the loop

	//Now return the decoded values.
	return out;

}
