/**
 * XMLHttpRequest objektiin liittyvät jutut
 */

/**
 * Luo uuden XMLHttpRequest-objektin. (Ensisijaisesti käyttää native objektia, muuten IE:n ActiveX versiota)
 *
 * @return Palauttaa objektin tai null jos epäonnistui.
 */
function createXMLHttpRequest() {

	var xmlHttp = null;

	if (window.XMLHttpRequest) {
		// If IE7, Mozilla, Safari, and so on: Use native object
		xmlHttp = new XMLHttpRequest();
	} else {
		if (window.ActiveXObject) {
			// ...otherwise, use the ActiveX control for IE5.x and IE6
			try {
				xmlHttp = new ActiveXObject('MSXML2.XMLHTTP.3.0');
			} catch (E) {
				xmlHttp = null;
			}
		}
	}

	return xmlHttp;
}

/**
 * Hakee annetusta datasta tietyn nimisen kommenttiblokin. Jos blokkia ei löydy
 * palauttaa tyhjän.
 *
 * @param name Blokin nimi. Jos false, niin hakee "virheet".
 *             Eli tekstin ennen ja jälkeen blokkeja. Jos ei yhtään blokkia,
 *             palauttaa koko datan.
 * @param data Tutkittava data.
 */
function getBlockFromData(name, data) {
	var regString;
	if(name) {
		regString = "<!-- " + name + " -->(([\\n\\r]|.)*)<!-- \\/" + name + " -->";
	} else {
		regString = "^(([\\n\\r]|.)*?)<!-- (?:[\\n\\r]|.)* -->(([\\n\\r]|.)*?)$";
	}
	var rx = new RegExp(regString, "i");
	var ar = data.match(rx);
	var ret = "";
	if(name) {
		// normaalisti palautetaan haettu blokki jos löytyi, tai tyhjä
		if(ar != null) {
			ret = ar[1];
		}
	} else {
		// virhehaussa palautetaan virheilmoitukset (ennen ja jälkeen blokkeja)
		if(ar != null) {
			ret = ar[1];
			if(ar[1] && ar[3]) {
				ret = ret + "\n";
			}
			ret = ret + ar[3];
		} else {
			// tai jos datassa ei ole yhtään blokkia, koko paluudata
			ret = data;
		}
	}
	return ret;
}

/**
 * Lähettää XMLHttpRequestin palvelimelle.
 *
 * @param method Metodi: POST tai GET. Tai FORM jos lähetetään lomake.
 * @param href Urli.
 * @param funcname Funktio joka suoritetaan kun request on valmis.
 * @param param Parametri funktiolle funcname.
 */
function sendXMLHttp(method, source, funcname, param) {
	var xmlhttp = createXMLHttpRequest();
	var postData = null;
	var contentType = null;
	var href;
	var async = true;

	// CHECK koko AJAX-ympäristö pitäisi rakentaa kunnolla

	if(method == "GET") {
		// source-parametri on suoraan käytettävä URL
		href = source;
	}

	if(method == "syncGET") {
		method = "GET";
		async = false;
	}

	if(method == "POST") {
		// kohdeskripti saadaan poistamalla kaikki ? merkin jälkeen
		href = source.replace(/\?.*/, "");
		// itse query-string sijoitetaan requestin runkoon
		postData = source.replace(/^.*?\?/, "");
		contentType = 'application/x-www-form-urlencoded';
	}
	//alert('postData:' + postData + "\nhref:" + href);

	if(method == "FORM") {
		// source-parametri on formin id
		
		// haetaan formin data hashiin
		var data = findFormData(source);

		if(! data) {
			alert("Error sending request: no data.");
			return false;
		}

		// näytetään alertissa koko data mitä lähetetään
		/*
		var msg = "Data to be sent:\n";
		for(var k in data) msg += k + ": " + data[k] + "\n";
		alert(msg);
		*/

		method = "POST";
		href = "index.php";
		contentType = 'application/x-www-form-urlencoded';
		// CHECK voisiko tässä käyttää jotain muutakin submit-muotoa?
		//contentType = 'application/x-www-form-data';
		// CHECK entäpä voisiko file-kentät lähettää tässä automaattisesti
		// vaikkakin erillisten iframejen kautta?
		//
		// Hmm. miten multipart ylipäätään toimii POST-requesteissa?
		// Olisiko mahdollista muodostaa esim. multipart:ssa mukana lähetettävä
		// tiedosto (vaikka tietoja ei voidakaan lukea kovalevyltä)?
		
		// koostetaan data-hashista rungossa lähetettävä datastring
		postData = "";
		for(var i in data) postData += escape(i) + "=" + escape(data[i]) + "&";

	}

	// Avataan objecti
	xmlhttp.open(method, href, async);

	if(funcname) {
		// Kutsutaan annettua funktiota kun valmista
		xmlhttp.onreadystatechange=function() {
			if (xmlhttp.readyState==4) {
				if (xmlhttp.status == 200) {
					funcname(xmlhttp, param);
				}
			}
		}
	}

	// vältetään cachetus
	xmlhttp.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");

	if(contentType) {
		xmlhttp.setRequestHeader('Content-Type', contentType);
	}

	// Lähetetään data
	xmlhttp.send(postData);

	return true;
}

/**
 * Kerää annetun formin kentät hashiin.
 *
 * @param id FORM-tagin id.
 * @return Palauttaa hashin jossa formin kenttien sisältö.
 */
function findFormData(id) {
	var el = document.getElementById(id);
	if(! el) {
		alert("Form not found!");
		return false;
	}
	if(! el.childNodes) {
		alert("Form is empty!");
		return false;
	}

	var i;
	var j = 0;
	var k = 10;
	var curr;
	var result = Array();

	// käydään formin koko elementti-puu läpi
	var list = Array(el);

	while((curr = list.shift()) != null && j < 1000) {
		if(curr.form && curr.name && curr.name != '') {
			// jos tämä on kenttä-elementti (eli sillä on form-attribuutti)
			// ja kentällä on ei-tyhjä nimi
			//alert(curr.nodeName + " " + curr.name + " " + curr.value);

			// CHECK mikä olisi "oikea" ja "paras" tapa tunnistaa halutut
			// elementit?

			// lisätään arvo palautettavaan tulokseen
			result[curr.name] = curr.value;

		} else {
			// tämä on jokin muu elementti
			if(curr.childNodes) {
				// jos elementillä on lapsia
				// lisätään ne tutkittavien listaan
				for(i in curr.childNodes) {
					if(curr.childNodes[i] != null) {
						// lisätään vain non-null arvot
						list.push(curr.childNodes[i]);
					}
				}
			}
		}

		// lasketaan montako elementtiä käydään läpi
		j++;
		if(j >= 1000) break;

		/*
		if(curr.nodeName && curr.nodeName == "INPUT") {
			alert(curr.name);
			showProps(curr, true);
			if(! confirm("jatketaanko " + j)) break;
		}
		*/

		// CHECK lisäksi täällä pitää hakea editable-kenttien sisällöt

	} //end while

	if(j >= 1000) {
		// failsafe, liian monta elementtiä tai bugi
		alert("Too many elements (" + j + ")");
		return false;
	}

	return result;
}

// Vakiofunktioita paluufunktioiksi

/**
 * Sijoittaa parametrissä määritellyt blokit datasta dokumenttiin.
 * Blokin nimi ja elementin id täytyy olla samat.
 *
 * @param param Pilkulla erotettu lista blokkien nimistä.
 */
function system_blocks(xmlhttp, param) {
	// Virheet alerttiin
	var errorText = getBlockFromData(false, xmlhttp.responseText);
	if(errorText) alert(errorText);

	var parts = param.split(',');
	var i;
	var elem;
	var contents;
	for(i in parts) {
		elem = document.getElementById(parts[i]);
		if(elem) {
			// Jos elementti löytyi
			contents = getBlockFromData(parts[i], xmlhttp.responseText);
			if(contents != "") {
				elem.innerHTML = contents;
			} else {
				// blokki on tyhjä, joten virhe tai haluttiinkin tyhjä?
				alert("Block not found: " + parts[i]);
			}
		}
	}
}

/**
 * Uudelleenohjaa sivun annettuun osoitteeseen.
 */
function system_redirect(xmlhttp, param) {
	// Virheet alerttiin
	var errorText = getBlockFromData(false, xmlhttp.responseText);
	if(errorText) alert(errorText);

	// uudelleenohjaus
	document.location.href = param;
}

/**
 * Submittaa annetun id:n omaavan lomakkeen.
 */
function system_submit(xmlhttp, param) {
	var el = document.getElementById(param);
	if(el) {
		el.submit();
	} else {
		alert("Target form not found! " + param);
	}
}
