Cultourist weather component

This is a testing ground and documentation page for the weather component of Cultourist. The purpose of the weather component is to fetch appropriate data from yr.no and create a decimal number suitable for suggestion scoring.

Kumpula weather specs

symbol
windSpeed
temperature
cloudiness
humidity
precipitation

Testing grounds

symbol
windSpeed
temperature
cloudiness
humidity
precipitation

Source code

/**
 * yr.js
 *  http://api.yr.no/weatherapi/locationforecast/1.6/?lat=xx.xxx;lon=yy.yyy
 * 
 * <weatherdata>
 *  <product class="pointData">
 *  -- many other forecasts and then the first with a symbol-tag --
 *   <time datatype="forecast" from="2009-10-19T18:00:00Z" to="2009-10-19T19:00:00Z">
 *    <location altitude="0" latitude="xx.xxxx" longitude="yy.yyyy">
 *     <symbol id="CLOUD" number="4"/>
 *    </location>
 *   </time>
 *   </product>
 *  </weatherdata>
 *  
 *  We'll rely on the getElementsByTagName -method of the DOM and assume that
 *  the tree is laid out in the DOM in the same order that it is in the XML file.
 *  
 *  @author Atte Hinkka <ahinkka@cs.helsinki...>
 *  @author Simon Kåll <skall@cs.helsinki...>
 */

////
//// Actual yrLib
////
/*
 * Usage:
 *  yrLib.getWeather(latitude, longitude, callbackFunction(weather));
 *  
 * callBackFunction gets one of the following as its argument:
 *  - null (request failed)
 *  - probability between 0 and 1
 */
var yrLib = {
	// This is a generic AJAX-callback function, should use some ready-made for this.
	uriToDOMObject: function(uri, callbackFunction){
		var xhttp = new window.XMLHttpRequest();
		
		function callbackFactory(request, callback){
			return function(event){
				if (xhttp.readyState === 4) {
					if (xhttp.status === 200) {
						callback(request.responseXML);
					}
					else {
						callback(null);
					}
				}
			}
		}
		xhttp.onreadystatechange = callbackFactory(xhttp, callbackFunction);
		
		xhttp.open("GET", uri, true);
		xhttp.send("");
	},
	
	getWeather: function(latitude, longitude, callbackFunction){
		var uriBase = "http://api.yr.no/weatherapi/locationforecast/1.6/?lat=latval;lon=lonval";
		var uri = uriBase.replace("latval", latitude);
		uri = uri.replace("lonval", longitude);
		
		function callbackFactory(callback){
			return function(xml) {
				var currentSymbolElem = xml.getElementsByTagName("symbol")[0];
				var symbol = currentSymbolElem.attributes[0].value;
				var windSpeed = (xml.getElementsByTagName("windSpeed")[0]).getAttribute("mps");
				var temperature = (xml.getElementsByTagName("temperature")[0]).getAttribute("value");
			        var cloudiness = (xml.getElementsByTagName("cloudiness")[0]).getAttribute("percent");
				var humidity = (xml.getElementsByTagName("humidity")[0]).getAttribute("value");
				var precipitation = (xml.getElementsByTagName("precipitation")[0]).getAttribute("value");
				//alert(symbolValue);
                                var context = {};
                                context.symbol = symbol;
                                context.windSpeed = windSpeed;
                                context.temperature = temperature;
                                context.cloudiness = cloudiness;
                                context.humidity = humidity;
                                context.precipitation = precipitation;
				callback(yrLib.interpretWeatherString(symbol, windSpeed, temperature, cloudiness,
								      humidity, precipitation), context);
			};
		}
		uri = "kumpula_forecast.xml";
		yrLib.uriToDOMObject(uri, callbackFactory(callbackFunction));
	},
	
	interpretWeatherString: function (symbol, windSpeed, temperature, cloudiness,
					  humidity, precipitation) {
                symbol = symbol.replace('\n', '');
	        //console.log(symbol + windSpeed + temperature + cloudiness + humidity + precipitation);
		var goodWeather = {
			SUN: true,
			LIGHTCLOUD: true,
			PARTLYCLOUD: true,
			CLOUD: true,
			SNOWSUN: true
		}
 		var mediocreWeather = {
			LIGHTRAINSUN: true,
			LIGHTRAINTHUNDERSUN: true,
			LIGHTRAIN: true,
			SNOW: true,
			FOG: true
		}
		var badWeather = {
			RAIN: true,
			RAINTHUNDER: true,
			SLEET: true,
			SNOWTHUNDER: true,
			SLEETSUN: true,
		}
		
		var symbolValue = 1.0;
		var symbolWeight = 1.0;
		
		if (symbol === 'CLOUD') {
		    symbolWeight = 0.25;
		}
 		if (goodWeather.hasOwnProperty(symbol)) {
			symbolValue = 1.0;
		}
 		if (mediocreWeather.hasOwnProperty(symbol)) {
			symbolValue = 0.5;
		}
		if (badWeather.hasOwnProperty(symbol)) {
			symbolValue = 0.0;
		}
		
		var windValue = 1.0;
		var windWeight = 0.3;
		if (windSpeed > 7.0) {
		    windValue = 0;
		    windWeight = 1;
		}
		
		
		var cloudinessValue = 1 - (cloudiness / 100);
		var cloudinessWeight = 0.2;
		
		var humidityValue = 1.0;
		if (humidity > 90.0) {
		    humidityValue = (100 - humidity) / 10;
		}
		var humidityWeight = 0.8;
		
		var precipitationW = 1;
		var precipitationV = 0;
		if (precipitation < 10) {
		    precipitationV = 1 - (precipitation / 10);
		}
		
		// When below zero, humidity is not considered at all
		if (temperature < 0.0) {
		    humidityValue = 1.0;
		}
		//console.log(precipitationV);
		
		return (symbolWeight*symbolValue + windWeight*windValue + cloudinessWeight*cloudinessValue + humidityWeight*humidityValue) / (symbolWeight + windWeight + cloudinessWeight + humidityWeight);
	}
}