/*
 * Ajax Injector v1.5
 * http://sourceforge.net/projects/ajaxinjector/
 *
 * Copyright (c) 2009 Masih Yeganeh
 * Licensed under the LGPL license.
 * http://www.gnu.org/licenses/lgpl-3.0.txt
 *
 * Release Date: 2009/03/12
 *
 * My Email: goodboy.php@gmail.com
 */

var ajaxInjector = {
	ajaxEnabled: true, // You can Enable/Disable Ajax by changing this variable.
	useCache: false, // You can Enable/Disable Ajax cache by changing this variable.
	forceAjaxed: false, // You can force all request to be sent by ajax and if it not possible, do not send it. (but when JavaScript is enable!)
	injectAjaxToThisPageLinks: true, // By this variable you can set if AJAX should be injected to links of current page or not.
	injectAjaxToThisPageForms: true, // By this variable you can set if AJAX should be injected to links of current page or not.
	injectAjaxToLinksOfRequestedPages: true, // By this variable you can set if AJAX should be injected to links of requested page or not.
	injectAjaxToFormsOfRequestedPages: true, // By this variable you can set if AJAX should be injected to forms of requested page or not.
	showAlerts: true, // By this variable you can set if AJAX should show messages to help user to solve problems or not.
	tryBase64: false, // By this variable you can set if AJAX should base64 contents before sending data or not.
	tryIFrame: true, // By this variable you can set if AJAX should to send data using a hidden IFrame or not.
	disableUploadFeature: false, // By this variable you can set if forms with FILE input, should be send by AJAX should or not.

	/*--------------------------------------*/
	/* Don't touch anything below this line */
	/*--------------------------------------*/

	ajax: null,
	requestStart: function() {},
	requestEnd: function() {},
	onAjaxResponse: function() {},
	onAjaxComplete: function() {},
	loadedObjects: "",
	thisObject: null,
	URL: "",
	METHOD: "",
	response: null,
	Boundary: null,
	onComplete: 1,
	fileReaderObject: null,
	preventFromSending: false,
	dontSendNow: false,
	isBinary: false,
	tempBool: false,
	isBusy: false,
	IFrameIsBusy: false,
	binaryEnabled: true,
	exists: function(obj) {
		return !(obj === null || obj === undefined || (typeof obj) == 'undefined');
	},
	initAJAX: function() {
		var ajaxOBJ;
		try
		{	// IE (JavaScript V5 or newer)
			ajaxOBJ = new ActiveXObject("Msxml2.XMLHTTP");
		}
		catch (Exception)
		{
			try
			{	// IE (JavaScript older than 5)
				ajaxOBJ = new ActiveXObject("Microsoft.XMLHTTP");
			}
			catch (Exception2)
			{
				try
				{	// IceBrowser
					ajaxOBJ = createRequest();
				}
				catch (Exception3)
				{
					if (ajaxInjector.exists(XMLHttpRequest))
					{	// Modern Browsers
						ajaxOBJ = new XMLHttpRequest();
					}
					else
					{
						ajaxInjector.ajaxEnabled = false;
					}
				}
			}
		}
		if (ajaxInjector.ajaxEnabled)
		{
			ajaxInjector.ajax = ajaxOBJ;
			ajaxInjector.binaryEnabled = ajaxInjector.exists(ajaxOBJ.sendAsBinary);
			return ajaxOBJ;
		}
	},

	/// TODO : Check if condition is right for binary-safe
	binarySafe: function (data) {
		for (var i = 0; i < data.length; i++)
		{
			if (data.charCodeAt(i) == 0 || data.charCodeAt(i) >= 128)
			{
				return false;
			}
		}
		return true;
	},
	
	showAlert: function(message, b) {
		if (b)
		{
			return true;
		}
		if (ajaxInjector.showAlerts)
		{
			alert(message);
			/// TODO : maybe we can use this, too:
			//throw new Error(message);
		}
	},

	submitNormally: function() {
		ajaxInjector.thisObject.onsubmit = "";
		if (ajaxInjector.forceAjaxed && !ajaxInjector.tryIFrame)
		{
			return false;
		}
		ajaxInjector.thisObject.submit();
	},

	makeMultiPartedField: function(el, ch) {
		var delim = "\r\n";
		var fileName;
		try
		{
			fileName = el.files[0].fileName;
		}
		catch (Exception1)
		{
			var tempNameArray = el.value.replace(/\\/gi, "/").split("/");
			fileName = tempNameArray[tempNameArray.length-1];
		}

		var content = el.value;

		if (ajaxInjector.exists(el.type) && el.type.toLowerCase() == "file")
		{
			if (ajaxInjector.disableUploadFeature)
			{
				ajaxInjector.dontSendNow = true;
				ajaxInjector.tryHiddenIFrame();
				ajaxInjector.submitNormally();
				return "";
			}
			content = el;
			if (content === false)
			{
				ajaxInjector.dontSendNow = true;
				ajaxInjector.tryHiddenIFrame();
				ajaxInjector.submitNormally();
				return "";
			}

			if (!ajaxInjector.binarySafe(content))
			{
				ajaxInjector.isBinary = true;

				var b64 = (ajaxInjector.tryBase64 && ajaxInjector.binaryEnabled);

				if (b64)
				{
					try
					{
						var tempContent = content;
						content = "";
						var i = 0;
						var l = tempContent.length;
						for (var j = 0; j < l; j++)
						{
							if (i == 76)
							{
								i = 0;
								content += delim;
							}
							content += tempContent[j];
							i++;
						}
						tempContent = "";
						ajaxInjector.isBinary = false;
					}
					catch (Exception2)
					{}
				}
			}
		}

		if (el.tagName.toLowerCase() == "option")
		{
			el.name = ch;
		}

		var req = ["Content-Disposition: form-data; name=\"" + el.name + "\""];
		if (ajaxInjector.exists(el.type) && el.type.toLowerCase() == "file")
		{
			req[0] += ("; filename=\"" + fileName + "\"");
			req.push("Content-Type: application/octet-stream");
		}
		req.push("");
		req.push((ch !== true ? content : el.checked));

		return (req.join(delim));
		//return ("Content-Disposition: form-data; name=\"" + el.name + "\"" + (el.type.toLowerCase() == "file" ? ("; filename=\"" + fileName + "\"" + delim + "Content-Type: application/octet-stream" + (b64) ? delim + "Content-transfer-encoding: base64" : "") : "") + delim + delim + (ch !== true ? content : el.checked));
	},

	makeRequestByForm: function(theForm, isMultipart) {
		var req = "";
		var el;
		var delim = "";
		var f = null;
		if (isMultipart)
		{
			delim = "\r\n";
			f = ajaxInjector.makeMultiPartedField;
		}
		else
		{
			delim = "&";
			f = encodeURIComponent;
		}

		for (var i = 0; i < theForm.elements.length; i++)
		{
			el = theForm.elements[i];

			if (el.name && !el.disabled)
			{
				var head = (isMultipart ? "--" + ajaxInjector.Boundary + delim : encodeURIComponent(el.name) + "=");
				req += head;
				switch (el.tagName.toLowerCase())
				{
					case "input":
						switch (el.type.toLowerCase())
						{
							case "radio":
							case "checkbox":
								req += (isMultipart ? f(el, true) : f(el.checked));
								break;
							default:
								req += (isMultipart ? f(el) : f(el.value));
								break;
						}
						break;
					case "textarea":
					case "select":
						if (el.multiple)
						{
							var tempReq = [];
							for (var j = 0; j < el.options.length; j++)
							{
								var opt = el.options[j];
								if (opt.selected)
								{
									tempReq.push((isMultipart ? f(opt, el.name) : f(opt.value)));
								}
							}
							req += tempReq.join(delim + head);
						}
						else
						{
							req += (isMultipart ? f(el) : f(el.value));
						}
						break;
					default:
						// Do Nothing!
						break;
				}
				req += delim;
			}
		}

		if (delim == "&")
		{
		  return (req.substr(0, req.length-1));
		}

		return (req + "--" + ajaxInjector.Boundary + "--" + delim);
	},

	/// TODO : We had this:
	/*
	handleIFrame: function() {
		if(!ajaxInjector.tempBool1)
		{
			ajaxInjector.tempBool1 = true;
			return true;
		}
		try
		{
			var response = "";
			var doc = document.getElementById("AjaxInjectorIFrame").contentWindow.document;
			if (!ajaxInjector.exists(doc.innerHTML))
			{
				if (ajaxInjector.exists(doc.firstChild.innerHTML))
				{
					doc.innerHTML = "";
					doc.firstChild.innerHTML = "";
					return false;
				}
				response = doc.firstChild.innerHTML;
				doc.firstChild.innerHTML = "";
			}
			else
			{
				response = doc.innerHTML;
				doc.firstChild.innerHTML = "";
			}	
		}
		catch (Exception) {}

		ajaxInjector.handleResponse(response);
	},
	*/

	handleIFrame: function(el) {
		if (!ajaxInjector.IFrameIsBusy)
		{
			return false;
		}
		try
		{
			var response = el.contentWindow.document.documentElement.innerHTML;
			ajaxInjector.handleResponse(response);
			ajaxInjector.IFrameIsBusy = false;
		}
		catch (Exception1) {}
		try
		{
			el.contentWindow.document.write("");
		}
		catch (Exception2) {}
	},

	addExtraParams: function(url) {
		url += (url.lastIndexOf("?") == -1 ? "?" : "&");
		url += "ajaxEnabled=" + (ajaxInjector.ajaxEnabled ? 1 : 0);
		url += (ajaxInjector.useCache ? "" : ("&r=" + new Date().getTime()));
		return url;
	},

	addHiddenIFrame: function() {
		if (!ajaxInjector.tempBool)
		{
			document.body.innerHTML += "<iframe id='AjaxInjectorIFrame' name='AjaxInjectorIFrame' style='display: none' onload='ajaxInjector.handleIFrame(window.event ? window.event.srcElement : event.currentTarget);'><\/iframe>";
			if (document.getElementById("AjaxInjectorIFrame") === null)
			{
				ajaxInjector.tryIFrame = false;
			}
			else
			{
				ajaxInjector.tempBool = true;
				try
				{
						document.getElementById("AjaxInjectorIFrame").contentWindow.document.write("");
				}
				catch (Exception) {}
			}

		}
	},

	tryHiddenIFrame: function() {
		if (ajaxInjector.tryIFrame)
		{
			ajaxInjector.IFrameIsBusy = true;
			ajaxInjector.thisObject.action = ajaxInjector.addExtraParams(ajaxInjector.thisObject.action);
			ajaxInjector.thisObject.target = "AjaxInjectorIFrame";
		}
	},

	ajax_send: function(method, url, content, extraHeaders) {
		var ajaxOBJ = ajaxInjector.ajax;
		if (ajaxInjector.preventFromSending)
		{
			ajaxInjector.preventFromSending = false;
			return false;
		}

		ajaxInjector.requestStart();

		if (ajaxInjector.dontSendNow)
		{
			ajaxInjector.dontSendNow = false;
			return false;
		}

		if (ajaxInjector.isBusy)
		{
			try
			{
				ajaxOBJ.abort();
				ajaxInjector.isBusy = false;
			}
			catch (Exception1)
			{}
		}

		try
		{
			ajaxOBJ.open(method, url, true);
		}
		catch (Exception2)
		{
			if (Exception2.message.match("denied"))
			{
				ajaxInjector.showAlert("You can't access external sites by AJAX!");
			}
			else
			{
				ajaxInjector.showAlert(Exception2.message);
			}
		}

		if (!ajaxInjector.useCache)
		{
			ajaxOBJ.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
		}

		for (var i = 0; i < extraHeaders.length; i++)
		{
			ajaxOBJ.setRequestHeader(extraHeaders[i][0], extraHeaders[i][1]);
		}

		ajaxOBJ.onreadystatechange = ajaxInjector.onReadyStateChange;

		try
		{
			if (ajaxInjector.isBinary)
			{
				if (!ajaxInjector.binaryEnabled)
				{
					ajaxInjector.tryHiddenIFrame();
					ajaxInjector.submitNormally();
				}
				else
				{
					ajaxOBJ.sendAsBinary(content);
					ajaxInjector.isBusy = true;
					ajaxInjector.isBinary = false;
				}
			}
			else
			{
				ajaxOBJ.send(content);
				ajaxInjector.isBusy = true;
			}
			return true;
		}
		catch (Exception3)
		{
			ajaxInjector.showAlert(Exception3.message);
		}
	},

	ajax_link: function(url) {
		if (ajaxInjector.ajax_send("GET", url, null, []))
		{
			return true;
		}
		ajaxInjector.thisObject.onclick = "";
		if (ajaxInjector.tryIFrame)
		{
			ajaxInjector.IFrameIsBusy = true;
			document.getElementById("AjaxInjectorIFrame").contentWindow.location = url;
		}
		else
		{
			if (!ajaxInjector.forceAjaxed)
			{
				document.location = url;
			}
		}
		return true;
	},

	ajax_form: function(url) {
		var contents;
		var extraHeaders = [];

		ajaxInjector.Boundary = (new Date()).getTime()+""+(Math.floor(Math.random()*1368));

		if (ajaxInjector.METHOD == "GET")
		{
			url += "&" + ajaxInjector.makeRequestByForm(ajaxInjector.thisObject, false);
			contents = null;
		}
		else
		{
			extraHeaders[0] = ["Content-Type", "application/x-www-form-urlencoded"];
			if (ajaxInjector.thisObject.enctype.toUpperCase() == "MULTIPART/FORM-DATA")
			{
				extraHeaders[0][1] = "multipart/form-data; boundary=" + ajaxInjector.Boundary;
				contents = ajaxInjector.makeRequestByForm(ajaxInjector.thisObject, true);
				if (!ajaxInjector.binarySafe(content))
				{
					ajaxInjector.isBinary = true;
				}
			}
			else
			{
				contents = ajaxInjector.makeRequestByForm(ajaxInjector.thisObject, false);
			}

			if (contents.length)
			{
				extraHeaders[1] = ["Content-Length", contents.length];
			}
		}

		if (ajaxInjector.ajax_send(ajaxInjector.METHOD, url, contents, extraHeaders))
		{
			return true;
		}
		ajaxInjector.tryHiddenIFrame();
		ajaxInjector.submitNormally();
		return true;
	},

	onAjaxEvent: function(obj) {
		var n;
		/// TODO : test if obj.getAttribute("x") works on all browsers
		var arr = [null, obj.getAttribute("onajaxcomplete"), obj.getAttribute("receiverelement")];
		var b = ajaxInjector.exists(obj.getAttribute("beforesend")) ? obj.getAttribute("beforesend").toString() : null;
		for (var i=0; i < obj.childNodes.length; i++)
		{
			n = obj.childNodes[i];
			if (n.id)
			{
				switch (n.id.toUpperCase())
				{
					case "ONAJAXCOMPLETE":
						arr[0] = n.innerHTML;
						break;
					case "BEFORESEND":
						b = n.innerHTML;
						break;
					default:
						//Do Nothing!
						break;
				}
			}
		}

		for (var j =0; j < 3; j++)
		{
			if (ajaxInjector.exists(arr[j]))
			{
				if (j == 2)
				{
					ajaxInjector.onComplete = "document.getElementById('"+arr[j].toString()+"').innerHTML = ajaxInjector.response;";
				}
				else
				{
					ajaxInjector.onComplete = arr[j];
				}
				break;
			}
		}

		if (ajaxInjector.exists(b))
		{
			eval(b);
		}
	},

	sandboxAllowed: function() {
	    if (ajaxInjector.URL.substr(0, 4).toLowerCase() != "http")
	    {
	        return true;
	    }
	    if (ajaxInjector.URL.substr(0, ajaxInjector.URL.indexOf("/", 8)) == window.location.href.toString().substr(0, window.location.href.toString().indexOf("/", 8)))
	    {
		    return true;
	    }
		setTimeout(function(){ajaxInjector.showAlert("You can not access external sites by AJAX!");},0);
		return false;
	},

	onAjaxEventFired: function(event) {
		if (ajaxInjector.ajaxEnabled)
		{
			ajaxInjector.dontSendNow = false;
			var action;
			ajaxInjector.thisObject = this; // It was >> window.event ? window.event.srcElement : event.currentTarget;
			var obj = ajaxInjector.thisObject;
			if (obj.tagName.toUpperCase() == "FORM")
			{
				ajaxInjector.URL = ajaxInjector.forceAjaxed ? obj.ajaxURL.toString() : obj.action.toString();
				ajaxInjector.METHOD = obj.method.toUpperCase();
				action = "ajaxInjector.ajax_form('";
			}
			else
			{
				ajaxInjector.URL = ajaxInjector.forceAjaxed ? obj.ajaxURL.toString() : obj.href.toString();
				ajaxInjector.METHOD = "GET";
				action = "ajaxInjector.ajax_link('";
			}
			if (!ajaxInjector.sandboxAllowed())
			{
				return false;
			}
			action += ajaxInjector.addExtraParams(ajaxInjector.URL) + "');";
			ajaxInjector.onAjaxEvent(obj);
			setTimeout(action,0);
			return false;
		}
		return true;
	},

	injectAjaxToLinks: function() {
		var a = document.getElementsByTagName("a");
		var l = a.length;
		for (var i = 0; i < l; i++)
		{
			if (!ajaxInjector.exists(a[i].onclick))
			{
				a[i].onclick = ajaxInjector.onAjaxEventFired;
				a[i].ajaxURL = a[i].href;
				if (ajaxInjector.forceAjaxed)
				{
					a[i].href = "#";
				}
			}
		}
	},

	injectAjaxToForms: function() {
		var f = document.getElementsByTagName("form");
		var l = f.length;
		for (var i = 0; i < l; i++)
		{
			if (!ajaxInjector.exists(f[i].onsubmit))
			{
				f[i].onsubmit = ajaxInjector.onAjaxEventFired;
				f[i].ajaxURL = f[i].action;
			}
		}
	},

	attachAjaxToggleButtonEvent: function() {
		if (document.getElementById("AjaxInjectorToggle"))
		{
			document.getElementById("AjaxInjectorToggle").onclick = function() {
				ajaxInjector.ajaxEnabled = !ajaxInjector.ajaxEnabled;
				return false;
			};
		}
	},

	attachCacheToggleButtonEvent: function() {
		if (document.getElementById("AjaxInjectorCacheToggle"))
		{
			document.getElementById("AjaxInjectorCacheToggle").onclick = function() {
				ajaxInjector.useCache = !ajaxInjector.useCache;
				return false;
			};
		}
	},

	loadObject: function() {
		var url;
		var elem;
		for (var i = 0; i < arguments.length; i++)
		{
			url = arguments[i];

			if (ajaxInjector.loadedObjects.indexOf(url+","))
			{
				return false;
			}

			switch (url.substr(url.lastIndexOf(".")+1))
			{
				case "js":  // If object is a JavaScript (js) file
					elem = document.createElement('script');
					elem.setAttribute("type","text/javascript");
					elem.setAttribute("src", url);
					break;
				case "css":  // If object is a Casacading Stylesheet (css) file
					elem = document.createElement("link");
					elem.setAttribute("rel", "stylesheet");
					elem.setAttribute("type", "text/css");
					elem.setAttribute("href", url);
					break;
				default:
					return false;
			}

			try
			{
				document.getElementsByTagName("head").item(0).appendChild(elem);
				ajaxInjector.loadedObjects += url + ","; // Remember this object as being already added to page
			}
			catch (Exception) {}
		}
	},

	handleResponse: function(response) {
		switch (ajaxInjector.onComplete)
		{
			case 1:
				switch ((typeof ajaxInjector.onAjaxResponse).toLowerCase())
				{
					case "function":
						ajaxInjector.onAjaxResponse(response);
						break;
					case "string":
						document.getElementById(ajaxInjector.onAjaxResponse).innerHTML = response;
						break;
					default:
						ajaxInjector.onAjaxResponse.innerHTML = response;
						break;
				}
				break;
			case 2:
				ajaxInjector.onAjaxComplete(response);
				break;
			default:
				ajaxInjector.response = response;
				eval(ajaxInjector.onComplete);
				break;
		}
		ajaxInjector.onComplete = 1;
		ajaxInjector.response = "";
	},

	onReadyStateChange: function() {
		var ajaxOBJ = this; /// TODO : It was "ajaxInjector.ajax"
		if (ajaxOBJ.readyState == 4)
		{
			ajaxInjector.isBusy = false;
			if (ajaxOBJ.status == 200)
			{
				ajaxInjector.requestEnd();
				ajaxInjector.handleResponse(ajaxOBJ.responseText);
				
				if (ajaxInjector.injectAjaxToLinksOfRequestedPages)
				{
					ajaxInjector.injectAjaxToLinks();
				}
				if (ajaxInjector.injectAjaxToFormsOfRequestedPages)
				{
					ajaxInjector.injectAjaxToForms();
				}
			}
			else
			{
				ajaxInjector.onComplete = 1;
				ajaxInjector.requestEnd();
				alert("There Was a problem with loading the page.\nHTTP Error (" + ajaxOBJ.status + ") : " + ajaxOBJ.statusText);
			}
		}
	},

	changeAttribute: function(elementID, attribute, value, type) {
		if (arguments.length < 3)
		{
			ajaxInjector.showAlert("Please enter three arguments at least.");
			return false;
		}
		var arr = [false];
		if (type && (type.toLowerCase() == "a" || type.toLowerCase() == "form"))
		{
			arr.push(type.toLowerCase());
		}
		else
		{
			arr = [false, "a", "form"];
		}
		var node;
		var elem = document.getElementById(elementID);
		for (var i = 0; i < elem.childNodes.length; i++)
		{
			node = elem.childNodes[i];
			if (node.tagName && arr.indexOf(node.tagName.toLowerCase()))
			{
				node.setAttribute(attribute, value);
			}
		}
	},

	toString: function() {
		return "[object AjaxInjector]\n\nCopyright (c) 2009 Masih Yeganeh\nhttp://sourceforge.net/projects/ajaxinjector/";
	},
	
	init: function() {
		ajaxInjector.initAJAX();
		ajaxInjector.addHiddenIFrame();
		ajaxInjector.attachAjaxToggleButtonEvent();
		ajaxInjector.attachCacheToggleButtonEvent();
		if (ajaxInjector.injectAjaxToThisPageLinks)
		{
			ajaxInjector.injectAjaxToLinks();
		}
		if (ajaxInjector.injectAjaxToThisPageForms)
		{
			ajaxInjector.injectAjaxToForms();
		}
	}
};