﻿///////////////////////////// START AJAX-FUNKTIONEN ////////////////////////////////////////
dode.ajax = {
	getXmlRequestVersion : null,
	// Queue-Konstruktor
	queue : function () {
		var queue = [];
		var addQueueObj = function (obj) {
			queue[queue.length] = obj;
			return true;
		};
		var isInQueue = function (obj) {
			var position = [];
			for (var i = 0; i < queue.length; i++) {
				if (queue[i] === obj) {
					position[position.length] = i;
				}
			}
			if (position.length > 0) {return position;} else {return false;}
		};
		var removeAllQueueObj = function (obj) {
			if (queue.length >= 1) {
				var position = isInQueue (obj);
				if (position) {
					var offset = 0;
					for (var i = 0; i < position.length; i++) {
						queue.splice(position[i]-offset,1);
						offset++;
					}
				}
			}
			return true;
		};
		var nextQueueObj = function () {
			if (queue.length >= 1) {
				var actualObj = queue[0];
				queue.shift();
				return actualObj;
			}
			return false;
		};
		var backObj = [];
		backObj.setNewObj = function (obj) {
			addQueueObj(obj);
			return true;
		};
		backObj.setRemoveAllObj = function (obj) {
			removeAllQueueObj(obj);
			return true;
		};
		backObj.getNextObj = function () {
			return nextQueueObj();
		};
		backObj.getQueue = function () {
			return queue;
		}
		return backObj;
	},
	// AJAX-Konstruktor
	showAjaxDataObject : function (confDataObj,my) {
		if (!dode.ajax.queue) { alert("Objekt QUEUE nicht eingebunden.");return false; }
		// confDataObj -> Konfigurationsobjekt
		if (!confDataObj || typeof confDataObj != "object") { alert("Konfigurationsobjekt nicht da!");return false;	}
		if (!confDataObj.requestUrl) { alert("Keine Ziel-URL angegeben");return false; }
		if (!confDataObj.fnAfterReceive) { alert("Keine Ausgabe-Verarbeitung angegeben");return false; }
		// Private Eigenschaften
		// Neues Queue-Objekt für dieses Request-Objekt erzeugen
		var requestQueue = dode.ajax.queue();
		var workObjConstructor = function () {
			var workObj = {
				requestUrl : confDataObj.requestUrl,
				requestQuery : "",
				requestType : "GET",
				requestAsynch : "TRUE",
				dataOutContainerId : document.getElementsByTagName("BODY")[0],
				receiveDataType : "TEXT",
				fnAfterReceive : null,
				fnAfterFinished : null,// Funktion die am Ende aufgerufen wird?
				fnRequestStartWorking : null
			};
			return workObj;
		};		
		// Voreinstellungen aus Konstruktor-Objekt
		var workObj = workObjConstructor();
		// Überschreiben der Voreinstellungen
		if (confDataObj.requestQuery) {workObj.requestQuery = confDataObj.requestQuery;}
		if (confDataObj.requestType) {workObj.requestType = confDataObj.requestType;}
		if (confDataObj.requestAsynch) {workObj.requestAsynch = confDataObj.requestAsynch;}
		if (confDataObj.dataOutContainerId) {workObj.dataOutContainerId = confDataObj.dataOutContainerId;}
		if (confDataObj.receiveDataType) {workObj.receiveDataType = confDataObj.receiveDataType;}
		if (confDataObj.fnAfterReceive) {workObj.fnAfterReceive = confDataObj.fnAfterReceive;}
		if (confDataObj.fnAfterFinished) {workObj.fnAfterFinished = confDataObj.fnAfterFinished;}
		if (confDataObj.fnRequestStartWorking) {workObj.fnRequestStartWorking = confDataObj.fnRequestStartWorking;}
		if (workObj.receiveDataType != "TEXT" && workObj.receiveDataType != "XML") {workObj.receiveDataType = "TEXT";}
		if (workObj.requestType != "GET" && workObj.requestType != "POST" && workObj.requestType != "HEAD") {workObj.requestType = "GET";}
		if (workObj.requestAsynch != "TRUE" && workObj.requestAsynch != "FALSE") {workObj.requestAsynch = "TRUE";}		
		// Einstellungsobjekt für geänderte Anfragen -> temporäre Nutzung
		var newConfigObj = {};		
		// Objekteinstellungen
		var requestStatus = null;
		var timerTimeOut = null;
		var timeOut = 10000;
		var requestData = null;
		var dataLoad = false;
		var request = false;
		var requestIsWorking = false;
		var isQueueRunning = false;

		// Private Methoden
		// HTTP-Request-Objekt für dieses Objekt erzeugen
		var requestObject = function () {
			try { request = new XMLHttpRequest(); dode.ajax.getXmlRequestVersion = "XMLHttpRequest"; }
			catch (tryIE) {
				//Reihenfolge der Request-Module nach Stabilität.
				//Microsoft.XMLHTTP points to Msxml2.XMLHTTP.3.0 and is redundant
		  		var msXmlHttp = ["Msxml2.XMLHTTP.6.0","Msxml2.XMLHTTP.3.0","Msxml2.XMLHTTP"];
				var i = 0;
				var msXmlHttpVersion = null;
				while (msXmlHttp[i]) {
					try { request = new ActiveXObject(msXmlHttp[i]); dode.ajax.getXmlRequestVersion = msXmlHttp[i]; break;} 
					catch (e) { request = false;}
					i++;
				}
			}
			return request;
		}();// requestObject erzeugen, sobald ein neues Objekt erzeugt wird!
		// HTTP-Request schicken!
		var sendHttpXmlRequest = function () {
			// Ein abgeschlossener Request hinterlässt im readyState eine 4 und keine 0
			if (!requestObject) {return false;}
			var sendParam = null;
			if (!checkReceiveUrl(workObj.requestUrl)) {
				requestError("Url nicht in Domain oder URL nicht vollständig.");
				return false;
			}
			if (workObj.requestType === "GET") {
				// Cache IE überwinden
				var rnd= parseInt(Math.random()*99999999);
				var query = workObj.requestQuery+"&rnd="+rnd;
				var getUrl = workObj.requestUrl+"?"+dode.util.parseQuery(query);
				requestObject.open(workObj.requestType,getUrl,workObj.requestAsynch);
			}
			if (workObj.requestType === "POST") {
				requestObject.open(workObj.requestType,workObj.requestUrl,workObj.requestAsynch);
				requestObject.setRequestHeader ('Content-Type', 'application/x-www-form-urlencoded');
				sendParam = dode.util.parseQuery(workObj.requestQuery);
			}
			if (workObj.requestType === "HEAD") {
				requestObject.open(workObj.requestType,workObj.requestUrl,workObj.requestAsynch);
			}
			// Eine erneute Anfrage mit dem selben RequestObject erzeugt im readyState im IE8 hier eine 0 und keine 1!
			// Andere Browser erzeugen hier wieder eine 1
			requestObject.onreadystatechange = receiveData;
			try { requestObject.send(sendParam); }
			catch (e) {
				requestError("Fehler bei der Anfrage.");
				return false;
			}
			return true;
		};
		
		var requestError = function (text) {
			dode.util.stringToDom(document.getElementById(workObj.dataOutContainerId),"<div style=\"color:red;font-weight:bold;\">"+text+"</div>");
			requestEnd();
			return true;
		};
		
		var requestEnd = function () {
			if (timerTimeOut) { deleteTimeout(timerTimeOut); }
			requestIsWorking = false;
			if (workObj.fnAfterFinished) {
				workObj.fnAfterFinished();
			}
			if (requestObject.readyState != 4 && requestObject.readyState != 0) {
				requestError("ReadyState nicht wieder auf 0 oder 4!<br>");
			}
			runQueue();//window.setTimeout(runQueue, 100); // Zu schnell für FireBug ohne Zeitverzögerung?
			return true;
		}
		
		var checkReadyState = function (rO) {
			var out = rO.readyState;
			return out;
		};
		
		var checkReceiveUrl = function (url) {
			// Prüfen ob Url in Domain
			// URL ohne domain nicht zugelassen
			var pattern = /^(http:\/\/)?(([\w-]+\.){2}[\w]{2,4}(:\d{4})?)\//i;
			var ergebnis = pattern.exec(url);
			if (ergebnis) {
				if (!ergebnis[1]) { return false; }
				if (ergebnis[2] != location.host) { return false; }
			} else { return false; }
			return true;
		};
		
		var deleteTimeout = function (t) {
				window.clearTimeout(t);
				t = null;
				return true;
		};
		
		var checkTimeOut = function () {
			if (requestObject.status != 4) {
				requestError("Abbruch wegen Zeitüberschreitung.");
			}
			return true;
		};
		
		var receiveData = function () {
			// Timer für Abbruch bei Zeitüberschreitung starten
			if (!timerTimeOut) {
				timerTimeOut = window.setTimeout(checkTimeOut,timeOut);
			}
			if (requestObject.readyState === 3) {
				// Daten werden geladen
				// Meldung ausgeben -> Daten werden geladen
			}
			if (requestObject.readyState === 4) {
				// Rückgabe Anfrage erfolgreich
				if (requestObject.status === 200) {
					// Seite wurde geliefert
					// Daten holen
					if (workObj.requestType === "GET" || workObj.requestType === "POST") {
						if (workObj.receiveDataType === "TEXT") {
							requestData = requestObject.responseText;
						} else {
							requestData = requestObject.responseXML;
						}
						dataLoad = true;
						workObj.fnAfterReceive(workObj.dataOutContainerId,requestData);
					} else if (workObj.requestType === "HEAD") {
						requestData = requestObject.getAllResponseHeaders();
						dataLoad = true;
						workObj.fnAfterReceive(workObj.dataOutContainerId,requestData);
					} else {
						requestError("Anfrage-Header nicht korrekt.");
						dataLoad = false;
					}
					requestEnd();
					return true;
				} else {
					if (requestObject.status === 404) {
						requestError("Url nicht vorhanden.");
					} else if (requestObject.status === 403) {
						requestError("Zugriff verweigert.");
					} else if (requestObject.status === 400) {
						requestError("Anfrage fehlerhaft.");
					} else if (requestObject.status === 301) {
						requestError("301");
					} else if (requestObject.status === 302) {
						requestError("302");
					} else {
						requestError("Anfrage nicht erfolgreich. Status: "+requestObject.status);
					}
					return false;
				}
			}
			return true;
		};
		
		var runQueue = function () {
			isQueueRunning = true;
			var actualWorkObj = requestQueue.getNextObj();
			if (actualWorkObj) { 
				requestIsWorking = true;
				// Funktion aufrufen für 
				if (workObj.fnRequestStartWorking) {				
					workObj.fnRequestStartWorking();
				}
				// "Instanzobjekt" in Arbeitsobjekt "kopieren"
				workObj = actualWorkObj;
				sendHttpXmlRequest();
				return true;
			} else {
				isQueueRunning = false;
				return false;
			}
		};
		
		var unloadSite = function (e) {
			requestObject.abort();
		};
		
		dode.newevent.addEvent(window,"unload",unloadSite);
		
		// Öffentliche Eigenschaften und Methoden
		var backObj = {};
		backObj.getRequestObject = function () {
			return request;
		};
		backObj.setRequestUrl = function (requestUrl) {
			newConfigObj.requestUrl = requestUrl;
			return true;
		};
		backObj.setRequestQuery = function (requestQuery) {
			newConfigObj.requestQuery = requestQuery;
			return true;
		};
		backObj.setRequestType = function (requestType) {
			newConfigObj.requestType = requestType;
			return true;
		};
		backObj.setRequestAsynch = function (requestAsynch) {
			newConfigObj.requestAsynch = requestAsynch;
			return true;
		};
		backObj.setfnAfterReceive = function (fnAfterReceive) {
			newConfigObj.fnAfterReceive = fnAfterReceive;
			return true;
		};
		backObj.sendRequest = function () {
			// Jetzt muss aus den bisherigen Veränderungen am Konfigurationsobjekt ein neues Objekt erzeugt werden.
			// Dieses wird der queue zugeordnet!
			//var newWorkObj = workObjConstructor();
			var newWorkObj = workObj;
			// Geänderte Werte dem neuen Objekt zuordnen!
			if (newConfigObj.requestUrl) {newWorkObj.requestUrl = newConfigObj.requestUrl}
			if (newConfigObj.requestQuery) {newWorkObj.requestQuery = newConfigObj.requestQuery;}
			if (newConfigObj.requestType) {newWorkObj.requestType = newConfigObj.requestType;}
			if (newConfigObj.requestAsynch) {newWorkObj.requestAsynch = newConfigObj.requestAsynch;}
			if (newConfigObj.dataOutContainerId) {newWorkObj.dataOutContainerId = newConfigObj.dataOutContainerId;}
			if (newConfigObj.receiveDataType) {newWorkObj.receiveDataType = newConfigObj.receiveDataType;}
			if (newConfigObj.fnAfterReceive) {newWorkObj.fnAfterReceive = newConfigObj.fnAfterReceive;}
			if (newConfigObj.fnAfterFinished) {newWorkObj.fnAfterFinished = newConfigObj.fnAfterFinished;}
			if (newConfigObj.fnRequestStartWorking) {newWorkObj.fnRequestStartWorking = newConfigObj.fnRequestStartWorking;}			
			// Der Queue die neuen Objekeingenschaften mitteilen und diese merken
			requestQueue.setNewObj(newWorkObj);
			// Wenn die Queue noch nicht rennt, dann anstoßen
			if (!isQueueRunning) {runQueue();}
			return true;
		};
		return backObj;		
	}
};
///////////////////////////// ENDE AJAX-FUNKTIONEN /////////////////////////////////////////
