var objXH_ = [{}]; // non usare l'indice 0!!!
var lngTO_ = 45; // 45 sec default timeout per risposta

function xhGET(strUrl, objCallBack, lngTimeOutSec, objState)
	{
	var iIdx;
	
	// istanzia XMLHttp
	
	if((iIdx = newXMLHttp_(objCallBack, objState)) == null)
		return 0;
	
	// avvia http
	
	objXH_[iIdx].XH.onreadystatechange = new Function("callBack_(" + iIdx + ");"); 
	objXH_[iIdx].XH.open("GET", strUrl, true);
	objXH_[iIdx].XH.send(null);
	
	// timeout se la risposta non arriva
	
	objXH_[iIdx].TO = setTimeout("clearCall_(" + iIdx + ", false)", (lngTimeOutSec == undefined ? lngTO_ : lngTimeOutSec) * 1000);
	
	return iIdx;
	}

function xhPOST(objFrm, strUrl, objCallBack, lngTimeOutSec, objState)
	{
	var strPost;
	var iIdx;
	var objElem;
	var strType;
	var iIdx2;
	var strName;
	
	// crea stringa post
	
	strPost = "";
	
	for(iIdx = 0; iIdx < objFrm.elements.length; iIdx++)
		{
		objElem = objFrm.elements[iIdx];
		strType = objElem.type;
		strName = objElem.name;
		
		switch(strType)
			{
			case "text":
			case "hidden":
			case "textarea":
			case "password":
			case "file":
				strPost += "&" + strName + "=" + urlEncode_(objElem.value);
				break;
			case "checkbox":
				if(objElem.checked) strPost += "&" + strName + "=" + urlEncode_(objElem.value);
				break;
			case "radio":
				if(objElem.checked) strPost += "&" + strName + "=" + urlEncode_(objElem.value);
				break;
			case "select-one":
				objElem = objElem.options;
				for(iIdx2 = 0; iIdx2 < objElem.length; iIdx2++)
					if(objElem[iIdx2].selected)
						{
						strPost += "&" + strName + "=" + urlEncode_(objElem[iIdx2].value);
						break;
						}
				break;
			}
		}
	
	if(strPost != "")
		strPost = strPost.substr(1);
	
	// istanzia XMLHttp
	
	if((iIdx = newXMLHttp_(objCallBack, objState)) == null)
		return 0;
	
	// avvia http
	
	objXH_[iIdx].XH.onreadystatechange = new Function("callBack_(" + iIdx + ");"); 
	objXH_[iIdx].XH.open("POST", strUrl, true);
	objXH_[iIdx].XH.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	
	objXH_[iIdx].XH.send(strPost);
	
	// timeout se la risposta non arriva
	
	objXH_[iIdx].TO = setTimeout("clearCall_(" + iIdx + ", false)", (lngTimeOutSec == undefined ? lngTO_ : lngTimeOutSec) * 1000);
	
	return iIdx;
	}

function xhClearAll()
	{
	var iIdx;
	for(iIdx = 0; iIdx < objXH_.length; iIdx++) 
		clearCall_(iIdx, true);
	}

function newXMLHttp_(objCallBack, objState)
	{
	var iIdx;
	
	iIdx = objXH_.length;
	
	objXH_[iIdx] = {};
	objXH_[iIdx].XH = null;
	
	if(window.XMLHttpRequest)
		{
		try 
			{ 
			objXH_[iIdx].XH = new XMLHttpRequest();
			}
		catch(objErr_) 
			{
			objXH_[iIdx].XH = null;
			}
		}
	else if(window.ActiveXObject)
		{
		try 
			{
			objXH_[iIdx].XH = new ActiveXObject("MSXML2.XMLHTTP");
			}
		catch(objErr_)
			{
			try 
				{ 
				objXH_[iIdx].XH = new ActiveXObject("Microsoft.XMLHTTP");
				}
			catch(objErr_)
				{
				objXH_[iIdx].XH = null;
				}
			}
		}
	
	if(objXH_[iIdx].XH == null) return null;
	
	objXH_[iIdx].FN = objCallBack;
	objXH_[iIdx].TO = null;
	objXH_[iIdx].Res = null;
	objXH_[iIdx].Err = null;
	objXH_[iIdx].Birth = new Date();
	objXH_[iIdx].State = objState;
	
	return iIdx;
	}

function urlEncode_(strValue)
	{
	strValue = escape(strValue);
	strValue = strValue.replace(/\+/g, "%2B");
	strValue = strValue.replace(/%20/g, "+");
	return strValue;
	}

function callBack_(iIdx)
	{
	var strRes = "";
	var strErr = "";
	var vntTO = null;
	
	if(objXH_[iIdx].XH.readyState != 4) return;
	
	// riposta arrivata: annulla il timeout di attesa
	
	vntTO = objXH_[iIdx].TO;
	if(vntTO != null) clearTimeout(vntTO);
	
	// risposta o errore
	
	if(objXH_[iIdx].XH.status == 200)
		strRes = objXH_[iIdx].XH.responseText;
	else
		strErr = objXH_[iIdx].XH.responseText;
	
	// restituisce i risultati al chiamante
	
	objXH_[iIdx].Res = strRes;
	objXH_[iIdx].Err = strErr;
	
	setTimeout("schedCallBack_(" + iIdx + ")", 10);
	
	objXH_[iIdx].XH = null;
	}

function schedCallBack_(iIdx) // invoca la callback schedulata
	{
	var objCallBack = objXH_[iIdx].FN;
	
	if(typeof(objCallBack) == "string") 
		objCallBack = eval(objCallBack); //eval(objCallBack + '(objXH_[iIdx].Res, objXH_[iIdx].Err)');
		
	if(objCallBack != null)
		objCallBack(objXH_[iIdx].Res, objXH_[iIdx].Err, objXH_[iIdx].State);
	
	objXH_[iIdx] = null; // dealloca tutto
	}

function clearCall_(iIdx, bSilent)
	{
	if(objXH_[iIdx] == null || objXH_[iIdx].XH == null) return;
	
	// annulla la richiesta se ancora in attesa
	
	if(objXH_[iIdx].XH.readyState != 4)
		objXH_[iIdx].XH.abort(); 
	
	// restituisce messaggio di errore al chiamante
	
	if(!bSilent)
		{
		objXH_[iIdx].Res = "";
		objXH_[iIdx].Err = "Timeout nelle comunicazioni di rete.";
		
		setTimeout("schedCallBack_(" + iIdx + ")", 10);
		
		objXH_[iIdx].XH = null;
		}
	else
		objXH_[iIdx] = null; // dealloca tutto
	}

function xhLookUp(strFields, strTables, strWhere, objCallBack, lngTimeOutSec, objState)
	{
	var iIdx;
	
	// istanzia XMLHttp
	
	if((iIdx = newXMLHttp_(objCallBack, objState)) == null)
		return 0;
	
	// avvia http
	
	objXH_[iIdx].XH.onreadystatechange = new Function("callBack_(" + iIdx + ");"); 
	objXH_[iIdx].XH.open("POST", strBaseUrl_ + "/lookup.asp", true);
	objXH_[iIdx].XH.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	objXH_[iIdx].XH.send("fld=" + urlEncode_(strFields) + "&tab=" + urlEncode_(strTables) + "&whe=" + urlEncode_(strWhere));
	
	// timeout se la risposta non arriva
	
	objXH_[iIdx].TO = setTimeout("clearCall_(" + iIdx + ", false)", (lngTimeOutSec == undefined ? lngTO_ : lngTimeOutSec) * 1000);
	
	return iIdx;
	}

function xhValidate(strAnswer, strError, objState, strFields, strTable, strInput, strWhere, strOnEnd)
	{
	var strVal;
	var strKeys;
	var strInps;
	var iIdx;
	var objFrm;
	var objRes;
	var objImp;
	
	objFrm = document.forms[0];
	
	// richiesta
	
	if(strAnswer == null && strError == null)
		{ 
		strInps = String(strInput).split(","); // separa la lista dei campi a video
		
		strVal = trim(objFrm[strInps[0]].value); // ricava la chiave
		
		for(iIdx = 0; iIdx < strInps.length; iIdx++) // azzera i campi
			objFrm[strInps[iIdx]].value = "";
		
		if(String(strVal) == "") // nessun valore da validare
			{
			if(dVal(strOnEnd, "") != "") setTimeout(strOnEnd, 10); // eventuale chiamata ad una funzione finale
			return; 
			}
		
		strKeys = String(strFields).split(","); // separa i campi del db
		
		// nella query aggiunge anche le liste dei nomi dei controlli di input, dei corrispondenti campi
		// e della eventuale funzione da chiamare alla fine,
		// perchč altrimenti nella callback di risposta queste informazioni non saranno pił disponibili
		
		strOnEnd = dVal(strOnEnd, "");
		
		xhLookUp(
			strFields, 
			strTable, 
			strKeys[0] + " = '" + strVal + "' AND " + notDeleted(strTable) + (strWhere == undefined || strWhere == "" ? "" : "AND " + strWhere), 
			xhValidate,
			null,
			{ctls__:strInput, flds__:strFields, mycb__:strOnEnd}
			);
		
		return;
		}
	
	// risposta callback
	
	if(String(strError) == "")
		{
		objRes = strAnswer.parseJSON();
		
		if(objRes instanceof Object)
			{
			if(objState.ctls__ != null && objState.flds__ != null)
				{
				strInps = objState.ctls__.split(","); // separa la lista dei campi a video
				strFields = objState.flds__.split(","); // separa la lista dei campi del recordset
				
				for(iIdx = 0; iIdx < strInps.length; iIdx++) // setta i campi
					{
					strVal = objRes[strFields[iIdx]];
					if(strVal == undefined) strVal = "";
					
					objImp = objFrm[strInps[iIdx]]; // cerca il campo nella form
					if(objImp != null) objImp.value = strVal; // se il campo esiste, lo imposta
					}
				
				strVal = objState.mycb__; // eventuale chiamata ad una funzione finale
				if(strVal != "") setTimeout(strVal, 10);
				}
			else if(objRes.err__ instanceof Object)
				alert("(" + objRes.err__.number + ") " + objRes.err__.description);
			}
		}
	}

function xhRunning(iWaitMs)
	{
	var iIdx;
	var dtNow = new Date();
	
	if(iWaitMs == undefined) iWaitMs = 3000; // default aspetta max per 3 sec
	
	for(iIdx = 0; iIdx < objXH_.length; iIdx++)
		if(objXH_[iIdx] != null && objXH_[iIdx].XH != null && (dtNow.getTime() - objXH_[iIdx].Birth.getTime()) <= iWaitMs)
			return true;
	
	return false;
	}

function xhAnswerMe(strAnswer, strError, objState) // callback standard
	{
	var objRes;
	
	xhWait(false);
	
	if(String(strError) != "")
		{
		alert(strError);
		return null;
		}
	
	if((objRes = strAnswer.parseJSON()) instanceof Object)
		if(objRes.err__ instanceof Object)
			alert("(" + objRes.err__.number + ") " + objRes.err__.description);
		else if(typeof(objRes.run__) == "string")
			eval(objRes.run__);
		else
			return {res__:objRes, state__:objState}; // questa serve solo se chiamata da altre callback
	
	return null;
	}

function xhWait(bWait) // modifica la videata durante la chiamata ajax
	{
	var objDOM;
	if(bWait)
		{
		//objBody_.style.visibility = "hidden";
		objDOM = newEl("div", "style.position", "absolute", "style.left", "0", "style.right", "0", "style.width", "100%", "style.height", "100%", "style.backgroundColor", "#FFFFFF", "style.zIndex", "999999", "style.filter", "alpha(opacity=0)", "style.opacity", "0.00");
		objBody_.insertBefore(objDOM, objBody_.firstChild);
		objBody_.style.cursor = "wait";
		}
	else
		{
		//objBody_.style.visibility = "visible";
		objBody_.removeChild(objBody_.firstChild);
		objBody_.style.cursor = "default";
		}
	}
