/**
 * Soubor trid a metod pro pohodlnou praci s AJAX metodologii.
 * @author Honza Spurny, softwarove inzenyrstvi
 * @version 1.0
 */
 
/**
 * Trida pro reprezentaci objektu AJAX komunikace
 * @param reqUrl adresa, na kterou bude tento AJAX komunikator zasilat dotazy
 * @param paramNames pole jmen parametru, ktere se budou zretezovat ke komunikacni url adrese
 * @param handleResponse ukazatel na fci/handler, ktera spracuje vysledek requestu
 *			- tato fce je soucasti kominikatoru - je to jeho metoda (lze v ni pouzivat ukazatel this ukazujici na komunikator, jenz tuto metodu vyvolal - lze tedy pouzit volani this.lastResponse)
 *			- funkce je volana jako handleResponse(lastResponse), tedy je ji na vstup pred vysledek posledniho requestu
 *			- viz priklady uziti nize
 */
function AjaxCommunicator(reqUrl, paramNames, handleResponse) {
	this.url = reqUrl;
	this.responseObject = null;
	this.lastResponse = "";
	
	// Konstrukce pole s parametry komunikace
	this.params = new Object(); // asociativni pole
	if (paramNames instanceof Array) {
		for(i = 0; i < paramNames.length; i++) {
			this.params[paramNames[i]] = "";
		}
	}
	
	this.errMsg = {
		"ajaxNotSupported": "Váš prohlížeč nepodporuje AJAX.",	// "Ajax not supported in your browser."
		"receiveError": "Chyba komunikace."						// "Receive error."
	}
	
	// Metody
	this.handleResponse = handleResponse;
}

/**
 * Metoda pro nastaveni jednoho parametru komunikatoru
 * @param name jmeno parametru, ktery chceme nastavit
 * @param value hodnota parametru, ktery chceme nastavit
 */
AjaxCommunicator.prototype.setParam = function(name, value) {
	if(this.params.hasOwnProperty(name)) {
		this.params[name] = value;
	}
}
 
/**
 * Metoda pro nastaveni viceo parametru komunikatoru
 * @param names pole se jmeny parametru, ktere chceme nastavit
 * @param values pole s hodnotami parametru, ktere chceme nastavit (indexovano isomorfne s polem names)
 */
AjaxCommunicator.prototype.setParams = function(names, values) {
	if((names instanceof Array) && (values instanceof Array)) {
		for(i = 0; i < names.length; i++) {
			this.setParam(names[i], values[i]);
		}
	}
}

/**
 * Metoda vygeneruje url pro zaslani dotazu vcetne definovanych parametru
 * @return Vraci na vystup url pro zaslani dotazu vcetne definovanych parametru
 */
AjaxCommunicator.prototype.getRequestUrl = function() {
	var params = "";
	var first = true;
	for(var paramName in this.params) {
		params += ((first) ? ("") : ("&")) + paramName + "=" + this.params[paramName];
		first = false;
	}
	var paramSeparator = (this.url.indexOf('?') >= 0) ? ("&") : ("?");
	
	return(this.url + paramSeparator + params);
}

/**
 * Metoda provede odeslani dotazu se zadanymi parametry na komunikacni adresu.
 * Vysledek komunikace je ulozen do atributu this.lastResponse
 */
AjaxCommunicator.prototype.get = function() {
	// Pokud jeste nemame vytvoreny objekt odpovedi, vytvorime
	if (this.responseObject == null) {
		// this.responseObject = createResponseObject();
		this.responseObject = createXMLHttpObject();
	}
		
	if (this.responseObject != null) {
		// this.responseObject.onreadystatechange = this.responseStateChanged;
		// Protoze pro kazdou zmenu stavu se vytvori nova instance nasledujici fuknce handleru, nemuzeme v 
		// ni pouzit ukazatel this (ten v kazde nove vykonstruovane instanci ukazuje na tu instanci fce a 
		// nikoliv na objekt AjaxCommunicatoru). Abychom vedeli, pod jakym objektem ajaxCommunicatoru tato fce
		// (metoda) je spustena, musime si jej zapomatovat v specialni promenne thisPointer, jejiz semantika 
		// se nebude menit s konstruovanymi instancemi.
		var thisPointer = this;	
		this.responseObject.onreadystatechange = function() {
			thisPointer.responseStateChanged();
		}
		this.responseObject.open("get", this.getRequestUrl(), true);
		this.responseObject.send(null);
	} else {
		// Pokud i pres to se objekt nevytvoril, je to chyba...	
		alert(this.errMsg["ajaxNotSupported"]);
	}
}

/**
 * Pomocna metoda, ktera ulozi vysledek requestu do promenne objektu.
 */ 
AjaxCommunicator.prototype.responseStateChanged = function() {
	if (this.responseObject != null) {
		if (this.responseObject.readyState == 4) {
			// 4 = "loaded"
			if (this.responseObject.status == 200) {
				// 200 = "OK"
				this.lastResponse = this.responseObject.responseText;
				if (this.handleResponse instanceof Function) {
					this.handleResponse(this.lastResponse);					
				}
			} else {
				alert(this.errMsg["receiveError"]);
			}
		}
	}	
}

// =======================================================================

/**
 * Pomocna struktura pro vytvareni XMLHttpRequest objektu
 */
var XMLHttpFactories = [
	function () { return new XMLHttpRequest(); },
	function () { return new ActiveXObject("Msxml2.XMLHTTP"); },
	function () { return new ActiveXObject("Msxml3.XMLHTTP"); },
	function () { return new ActiveXObject("Microsoft.XMLHTTP"); }
];

/**
 * Funkce inicializuje objekt ajax odpovedi
 * @return Vraci na vystup novy objekt pro ajax odpoved.
 */
function createXMLHttpObject() {
	var xmlhttp = null;
	for (var i = 0; i < XMLHttpFactories.length; i++) {
		try {
			xmlhttp = XMLHttpFactories[i]();
		} catch (e) {
			continue;
		}
		break;
	}
	return xmlhttp;
}

// ===================================================

// :::::::::::::::::::::::::
// :::::    PRIKLAD    :::::
// :::::::::::::::::::::::::

/*
// Konstrukce komunikatoru
var ajax = new AjaxCommunicator("https://www.jipka.dev:8088/vipis/test/ajaxTest.jsp", ["param1", "param2"], ajaxResponseHandle);
// Nastaveni chybovych zprav komunikatoru
ajax.errMsg["ajaxNotSupported"] = "Ajax neni podporovan.";
ajax.errMsg["receiveError"] = "Chyba komunikace."
// Nastaveni parametru jednoho dotazu na cilovou adresu
ajax.setParam("param1", "value1");
ajax.setParams(["param1", "param2"], ["value1", "value2"]);
// Odeslani pozadavku s parametry
ajax.get();

// Handler funkce, ktera vyuziva skutecnost, ze je soucasti objektu AJAX-communicatoru
function ajaxResponseHandle() {
	alert(this.lastResponse);
}

// Handler funkce, ktera dela, ze "nevi" o tom, ze je soucasti AJAX-communcatoroveho objektu
function ajaxResponseHandle(response) {
	alert(response);
}
*/