/**
 * The SensorFactory is a singleton for creating and retrieving sensors. The getSensor method
 * is the primary method. It takes the URI of the sensor, and either retrieves it from the
 * cache of known methods or creates a new sensor and puts it into the cache.
 */
function SensorFactory(sensorScheme) {
	this.sensorScheme = sensorScheme;
}

SensorFactory.prototype = {
		/**
		 * Creates a new sensor for the given topic.
		 * @param uri the uri identifying this sensor.
		 *   Sensors are identified by URIs. Here is an example of a topic:
		 *     
		 *     record://analytics.reloadnyc.com/com/worldevolved/pageviews
		 *     
		 *   The uri is deconstructed as follows:
		 *     protocol : "record" specifies the route the sensor Observation takes.
		 *                The "record" protocol records the Observation to a log for
		 *                  batch analysis later.
		 *                The "publish" protocol routes the Observation to subscribers
		 *                  in real-time. The "publish" protocol is not yet supported.
		 *     host : "analytics.reloadnyc.com" specifies the server that will route
		 *       		  the Observation. The server must implement the required
		 *      		  protocol.
		 *     sensor_id : "com/worldevolved/pageviews" specifies the subject of the
		 *     		  observation. The Observation's subject can be considered its
		 *              type and determines who recieves the Observation. 
		 * @return a Sensor object for the given topic.
		 */
	getSensor : function SensorFactory_getSensor(uri) {
		if (this.cache == null)
			this.cache = new Object();
		if (this.cache[uri] == undefined) {
			this.cache[uri] = new Sensor(this.sensorScheme, uri);
		}
		return this.cache[uri];
	}
}

if (typeof(sensorScheme) == "undefined") {
    var sensorScheme = "http";
}

var sensorFactory = new SensorFactory(sensorScheme);

/**
 * Creates a Sensor used to record Observations.
 * 
 * @param uri
 *            the uri identifying this sensor.
 */
function Sensor(sensorScheme, uri) {
	this.uri = uri;
	this.obsEncoder = new URLObservationEncoder(sensorScheme);
	this.pinger = new URLPinger();
}

Sensor.prototype = {

	/** the sensor's uri */
	uri : null,

	/** 
	 * Records an Observation based on the given data.
	 * @param data an object containing key value pairs of data. Each value should
	 *   be in the form of a String. 
	 */
	record : function Sensor_record(data) {
		var o = new Observation(this.uri, data);
		var url = this.obsEncoder.encode(o);
		if(CANOPY_MOUSE_DEBUG=="true"){
			console.info(url)
		}else{
			this.pinger.ping(url);
		}
	}
}

/**
 * Observations are produced when sensors record a map of data. Observations
 * capture the information related to the event along w/ the data.
 */
function Observation(uri, data) {
	this.uri = uri;
	this.data = data;
}

Observation.prototype = {

	getUri : function() {
		return this.uri;
	},

	/**
	 * @return a String representation of the Observation for debugging.
	 */
	toString : function Observation_toString() {
		var str = "Observation: \n";
		str += "\ttopic : " + this.uri + "\n";
		str += "\tdate : \n";
		for ( var x in this.data) {
			str += "\t\t" + x + " : " + this.data[x] + "\n";
		}
		return str;
	}
}

function URLObservationEncoder(sensorScheme) {
    this.sensorScheme = (sensorScheme == null) ? "null" : sensorScheme;
}

URLObservationEncoder.prototype = {
	encode : function URLObservationEncoder_observation(observation) {
		return this.sensorScheme + "://" + this._getHostname(observation.getUri())
				+ "/record.png?" + this._encodeParams(observation);
	},

	_getHostname : function URLObservationEncoder__Hostname(url) {
		var re = new RegExp('^(?:record|publish)?\://([^/]+)', 'im');
		return url.match(re)[1].toString();
	},

	_encodeParams : function URLObservationEncoder__encodeParams(observation) {
		var str = "";
		var data = observation.data;
		for ( var param in data) {
			str += "&" /*+ escape(param) + "="*/ + escape(data[param]);
		}
		return str.substr(1);
	}
}

function URLPinger() {
	this.tracker = document.createElement("img");
	document.body.appendChild(this.tracker);
}

URLPinger.prototype = {
	ping : function URLPinger__ping(url) {
		this.tracker.src = url;
	}
}
