/******************************************************************************/ 
/******************************************************************************/
// Communication utilities                                                    //
// Copyright 2007-2008 Collaborative Bike Map Project
/******************************************************************************/
/******************************************************************************/


/*******************************************************************
// Submit asynchronous HTTP get or post request and define its state change handler 
// via the callback parameter.  Also define an optional error handler.  
// Paramters:
//   url - URL of handling server page
//   dopost - False for GET, True for POST  
//            (if we want to support header-only request, make this a 3-way int paramaeter
//             with values of GET, POST or HEAD -- TBD)
//   values - Object whose name/value pairs indicate named POST parameters 
//   callback - Routine to be called when response is received.  It will be passed
//              two parameters (in order)...
//                 1. The received XML string or Document object, depending on how the server sends it.  It is
//                    retrieved from the responseText or responseXML property of the 
//                    HTTP request object.
//                 2. A string of HTTP header info as returned by
//                    getAllResponseHeaders() of the HTTP request object.
//   errorHandler - (optional) Error handler to be invoked upon error response
*******************************************************************/
function callServer (url, dopost, values, callback, errorHandler) {
	
	var hreq;
	
	// Get HTTP request object
	if (!(hreq = getHttpReqObject())) {
		alert ("Your browser does not support this web site.");
		return false;
	}
	
	// Set and define closure function to handle response
	hreq.onreadystatechange = function() {
		if (hreq.readyState == 4) {
			if (hreq.status == 200)  
				callback (extractResponse(hreq), hreq.getAllResponseHeaders());      // invoke callback with HTTP response value			 
				     // p. 487 in O'Reilly JavaScript book has header parsing routine if we need one
			else if (errorHandler) 
				errorHandler (hreq.status, hreq.statusText);					
			else 
				alert ("Error in callServer response handler.  Url = " + url + ". Parameter list = " + values);
		}
	}
	
	// Send the request
	if (dopost) {
		hreq.open ("POST", url, true);
		hreq.setRequestHeader ("Content-Type", "application/x-www-form-urlencoded");
		hreq.send (buildUriParmString (values));		
	}
	else {
		var url2 = url + '?' + buildUriParmString (values);
		hreq.open ("GET", url2, true);
		hreq.send (null);
	}
}

/*******************************************************************
// Submit synchronous HTTP get or post request and return the result.  
// Paramters:
//   url - URL of handling server page
//   dopost - False for GET, True for POST  
//            (if we want to support header-only request, make this a 3-way int paramaeter
//             with values of GET, POST or HEAD -- TBD)
//   values - Object whose name/value pairs indicate named POST parameters 
// Return value: Anonymous object that has two elements: 'response' and 'headers'.
//   'response'is an XML string or Document object, depending on how the server sends it.  It is
//             retrieved from the responseText or responseXML property of the 
//             HTTP request object.
//   'headers' is a string of HTTP header info as returned by
//             getAllResponseHeaders() of the HTTP request object.
*******************************************************************/
function callServerSync (url, dopost, values) {
	
	var hreq;
	
	// Get HTTP request object
	if (!(hreq = getHttpReqObject())) {
		alert ("Your browser does not support this web site.");
		return false;
	}
	
	// Send the request
	if (dopost) {
		hreq.open ("POST", url, false);
		hreq.setRequestHeader ("Content-Type", "application/x-www-form-urlencoded");
		result = hreq.send (buildUriParmString (values));		
	}
	else {
		var url2 = url + '?' + buildUriParmString (values);
		hreq.open ("GET", url2, false);
		hreq.send (null);				
	}

	// Return anonymous object that has two elements: 'response' and 'headers'
	return ({response:extractResponse(hreq), headers:hreq.getAllResponseHeaders()});
	
}



/*******************************************************************
// Get new XMLHttpRequest object (or equivalent)
// Returns object if successful; otherwise returns zero
*******************************************************************/
function getHttpReqObject () {
	var hreq;

	try	{
	// Firefox, Opera 8.0+, Safari
		hreq = new XMLHttpRequest();
	} catch (e)	{
		// Internet Explorer
		try {
		  hreq = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			// Older IE?
			try {
				hreq = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {
				// error
				return 0;
			}
		}
	}		
	return hreq;
}


/*******************************************************************
// Return appropriate response property a given HTTP request object,
// based on the header' mime type
*******************************************************************/
function extractResponse (hreq) {
	
	switch (hreq.getResponseHeader ("Content-Type")) {
		
		// XML type...
		case "text/xml":
			return hreq.responseXML;      // this is an XML document object, not a string
			break;
			
		// Javascript type...
		case "text/json":
		case "text/javascript":
		case "application/javascript":
		case "application/x-javascript":
			return eval (hreq.responseText);
			break;
			
		// Text type (including XML via string)...
		default:
			return hreq.responseText;
			
	}
}

/*******************************************************************
// Convert values object to single URL type parameter string containing 
// names and values.  For example: {a:2;b:3} becomes "a=2&b=3".
*******************************************************************/
function buildUriParmString (values) {
	var pairs = [];
	var regexp = /%20/g; 
	var name, value, pair;
	  
	for (name in values) {
		value = values[name];
		pair = encodeURIComponent(name).replace(regexp,"+") + '=' + encodeURIComponent(value).replace(regexp,"+");
		pairs.push (pair);
	}
	
	return pairs.join('&');
}	
		


/*******************************************************************/
/*******************************************************************/
// TEST STUFF
/*******************************************************************/
/*******************************************************************/

/*******************************************************************
// FOR TESTING... Get XML from server -- just a test for now
*******************************************************************/
function getServerXML () {
	callServer ("server_functions.php", false, {}, handleServerXML);
}


/*******************************************************************
// FOR TESTING... Callback routine to handle XML from server -- just a test for now
*******************************************************************/
function handleServerXML (xml, headers) {

	// var elem = document.getElementById ("v_segdesc");

	var xmldoc = getXmlDoc (xml);
	var topnode = xmldoc.documentElement;
	s = formatXML (xml) + '<br/><br/>HEADERS:<br/>' + headers + '<br/><br/>' + describeXMLnode (topnode, 0);
	dumpTextToWindow (s, "Downloaded server data");
}

