// ----------------------------------------------------------------------------------
// -  A set of functions handling AJAX requests sent to the Yahoo! Weather service  -
// ----------------------------------------------------------------------------------

//Master function that attempts to create an XML HTTP request object, depending
//on the browser being used. If the object cannot be created, FALSE is returned.
function createRequestObject() {
	var reqObj = false;
	if (window.XMLHttpRequest) {
		//Non-MS browser
		reqObj = new XMLHttpRequest();
	} else if (window.ActiveXObject) {
		//Use MS ActiveX
		try {
			//Try object supported by later versions of IE
			reqObj = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (error1) {
			try {
				//Try object supported by older versions of IE
				reqObj = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (error2) {
				//Browser doesn't support XML HTTP requests
			}
		}
	}
	return reqObj;
}

//Submit a request for a weather forecast
//Parameters: locName  - name of the location for which to return the weather
//            locID    - ID of the location for which to return the weather (see http://developer.yahoo.com/weather/index.html for details on how to obtain location IDs)
//            tempUnit - unit in which to display the temperatue ("c" for Centigrade/Celsius, "f" for Fahrenheit)
function getWeather(relPath, locName, locID, tempUnit) {
	//There's no point retrieving the weather unless there is somewhere for us to display it
	if (document.getElementById("weather")) {
		//If either the location name or ID is blank, we cannot retrieve the weather
		if (locName=='' || locID=='') {
			//Display a message to the effect that the weather is unavailable
			document.getElementById("weather").innerHTML = "<div class='body_dark' style='padding:3px;font-size:70%;'>Unable&nbsp;to&nbsp;retrieve weather&nbsp;forecast.</div>";
		} else {
			//Set the global variables to the values passed as parameters. Global variables are used
			//because it is not possible to pass parameters to the AJAX callback function (processRequest)
			relativePath = relPath;
			locationName = locName;
			locationID = locID;
			temperatureUnit = tempUnit

			//Create the XMLHTMLRequest object
			httpRequest = createRequestObject();
			httpRequest.onreadystatechange = processRequest;
			//Generate the URL from the passed parameters
			url = relativePath+'ajax/weather_proxy.php?locationID='+locID+'&temperatureUnit='+temperatureUnit;
			//Send the request
			httpRequest.open('GET', url, true);
			httpRequest.send(null);
		}
	}
}

//This is the function that actually does something with the returned request
function processRequest() {
	if (httpRequest.readyState==4) {
		if (httpRequest.status==200) {
			//Grab a reference to the element that will hold the results
			var divObj = document.getElementById('weather_xml_source');
			//Populate the element with the raw text of the request results
			divObj.innerHTML = escape(httpRequest.responseText);

			//These variables will contain the HTML built up from the relevant data in the
			//XML document
			imageHTML = '';
			currentHTML = '';
			astronomyHTML = '';
			forecastHTML = '<strong>Forecast:</strong>';

			//Parse the XML elements into an array
			xmlDoc = new Array();
			xmlDoc = Xparse(unescape(document.getElementById('weather_xml_source').value));
			//Process each XML tag in turn, depending on its type. In doing so, we populate
			//the imageHTML, currentHTML and forecastHTML variables
			processTag(xmlDoc);

			//Construct the final output
			outputHTML = "<table border='0' cellpadding='0' cellspacing='0' style='padding:2px;'>\n";
			outputHTML += "<tr>\n";
			outputHTML += imageHTML;
			outputHTML += currentHTML;
			outputHTML += astronomyHTML;
			outputHTML += forecastHTML;
			//We didn't know at the time how many forecasts we would find, so we couldn't close
			//the containing <td>. Instead, we do so now.
			outputHTML += "</td>\n";
			outputHTML += "</tr>\n";
			outputHTML += "</table>\n";

			//Display the output
			document.getElementById("weather").innerHTML = outputHTML;

		} else {
			//There was a problem with the request
		}
	}
}

//Recursive function that processes each XML tag in turn, following the tree down until each
//childless node is reached
function processTag(xmlTag) {
	var result = new String();
	result += xmlTag.name + '\n';
	for (var i=0;i<xmlTag.contents.length;i++) {
		if (xmlTag.contents[i].type=='element') {
			//Have we found the current weather conditions?
			if (xmlTag.contents[i].name=='yweather:condition') {
				//Construct the image HTML
				imageHTML = "<td style='font-size:50%;text-align:center;'><img width='52' height='52' src='http://us.i1.yimg.com/us.yimg.com/i/us/we/52/" + xmlTag.contents[i].attributes["code"] + ".gif' alt='current weather conditions' title='current weather conditions' /><br /><strong>Yahoo!&nbsp;Weather</strong></td>\n";
				//Construct the HTML to display the current conditions
				currentHTML = "<td class='body_dark' style='font-size:60%;white-space:nowrap;'><strong>Current conditions in "+locationName+"</strong>";
				//If the conditions have come back as "Unknown", add a link to let the user requery
				if (xmlTag.contents[i].attributes["text"]=='Unknown') {
					forecastHTML += " (<a href='javascript:getWeather(\""+relativePath+"\", \""+locationName+"\", \""+locationID+"\", \"" + temperatureUnit + "\");'>try retrieving weather details again</a>)<br />\n";
				} else {
					forecastHTML += "<br />\n";
				}
				currentHTML += " (<a href='javascript:getWeather(\""+relativePath+"\", \""+locationName+"\", \""+locationID+"\", \"" + (temperatureUnit=="c" ? "f" : "c") + "\");'>show in " + (temperatureUnit=="c" ? "Fahrenheit" : "Centigrade") + "</a>)<br />\n";
				currentHTML += xmlTag.contents[i].attributes["text"];
				currentHTML += ", " + xmlTag.contents[i].attributes["temp"] + "&deg;" + temperatureUnit.toUpperCase() + "\n";
			}
			//Have we found the sunrise/sunset times?
			if (xmlTag.contents[i].name=='yweather:astronomy') {
				//Construct the HTML to display the sunrise/sunset times
				astronomyHTML += " (sunrise " + stripWhiteSpace(xmlTag.contents[i].attributes["sunrise"]);
				astronomyHTML += ", sunset " + stripWhiteSpace(xmlTag.contents[i].attributes["sunset"]) + ")<br />\n";
			}
			//Have we found a forecast?
			if (xmlTag.contents[i].name=='yweather:forecast') {
				//Construct the HTML to display the forecast
				forecastHTML += xmlTag.contents[i].attributes["day"] + ": ";
				forecastHTML += xmlTag.contents[i].attributes["text"];
				forecastHTML += " (low " + xmlTag.contents[i].attributes["low"] + "&deg;" + temperatureUnit.toUpperCase();
				forecastHTML += ", high " + xmlTag.contents[i].attributes["high"] + "&deg;" + temperatureUnit.toUpperCase() + ")<br />\n";
			}
			//Carry on processing
			result += processTag(xmlTag.contents[i]);
		}
		if (xmlTag.contents[i].type=='chardata' && stripWhiteSpace(xmlTag.contents[i].value).length>0) {
			result += replaceEntity(xmlTag.contents[i].value) + '\n<br />';
		}
		if (xmlTag.contents[i].type=='pi') {
			result += replaceEntity(xmlTag.contents[i].value) + '\n<br />';
		}
		if (xmlTag.contents[i].type=='comment') {
			result += replaceEntity(xmlTag.contents[i].value) + '\n<br />';
		}
	}
	return result;
}

//Strips white space characters (carriage returns, spaces and tabs) from a string
function stripWhiteSpace(elementString) {
	var tempArray = new Array();
	tempArray = elementString.split('\n');
	elementString = tempArray.join('');
	tempArray = elementString.split(' ');
	elementString = tempArray.join('');
	tempArray = elementString.split('\t');
	elementString = tempArray.join('');
	return elementString;
}

//Replaces &, < and > with their respective HTML character entities
function replaceEntity(elementString) {
	var tempArray = new Array();
	tempArray = elementString.split('&');
	elementString = tempArray.join('&amp;');
	tempArray = elementString.split('<');
	elementString = tempArray.join('&lt;');
	tempArray = elementString.split('>');
	elementString = tempArray.join('&gt;');
	return elementString;
}


//Initialise the HTTP multiple request object
//var httpRequest = createRequestObject();

//Global variables that hold the units for the temperature and the name of the location for which
//we are attempting to retrieve the weather. Globals are used because the AJAX callback function
//cannot be passed parameters.
var relativePath = '';
var locationName = '';
var locationID = '';
var temperatureUnit = '';

