ADCENTRIC.lang.namespace("ADCENTRIC.tracking");

ADCENTRIC.tracking.EventPixelDispatcher = function() {
	var witness_event_queue = new Array();
	var queue_processing = false;
	var pixel = new Image();

	function process_queue() {
		queue_processing = true;
		pixel.onload = function() {
			pixel = new Image();
			if (witness_event_queue.length > 0) {
				process_queue();
			} else {
				queue_processing = false;
			}
		};
		pixel.src = witness_event_queue.shift();
	}

	function maybe_process_queue() {
		if (!queue_processing) {
			process_queue();
			return true;
		}
		return false;
	}

	function cache_bust(url) {
		var qindex = url.indexOf("?");
		var random = "r=" + Math.random();

		if (qindex < 0) {
			random = "?" + random;
		} else if (qindex != (url.length - 1)) {
			random = "&" + random;
		}
		return(url + random);
	}

	return {
		dispatch: function(event_pixel_url, dont_cache_bust) {
			var url = event_pixel_url;

			if (!dont_cache_bust) {
				url = cache_bust(url);
			}
			witness_event_queue.push(url);
			return maybe_process_queue();
		}
	};
};

/*
 * ADCENTRIC.tracking.SiteStatsPage is an object allowing for tracking of arbitrary
 * events/actions within a page of a site using an AdCentric event pixel, the URL of
 * which is passed in via the SiteStatsPage constructor defined here.
 *
 * Arbitrary events/interactions are tacked onto the specified event pixel via
 * the querystring.  The name of the event being logged is passed into the
 * action method of the returned SiteStatsPage object and is tacked onto the
 * query string as the value of the adc_action event parameter.  Additional
 * arguments can be logged via the action method via the optional param_keyvals
 * argument hash.  If the second argument is { "foo": "bar", "baz": "blah" },
 * then the additional foo=bar&baz=blah parameters will be appended to the querystring.
 * See example below for how this is done.
 *
 * Note that the tag code this is used from is the tag code of a SiteStats
 * campaign creative in AdCentric specifically created for the purposes of
 * tracking a site.  The impressions on said tag are sufficient to generate
 * site statistics at the page-level.  For Ajax, Flash, and other in-page special
 * event tracking, ADCENTRIC.tracking.SiteStatsPage().action() is used.
 *
 * Note also that this is a very similar model to that used by Google Analytics'
 * urchinTracker - in fact, if urchinTracker is defined, SiteStatsPage will take
 * care of calling it as well, passing in at least the same name as that provided
 * to the action method.
 * 
 * EXAMPLE USAGE:
 *
 * In the site-stats tag code, at least ADCENTRIC core and tracking js must
 * be loaded:
 *
 * if ("undefined" === typeof adcAction) {
 *     var adcAction = function(name, params) {
 *         ADCENTRIC.tracking.SiteStatsPage('__ADC_EVENT[SITESTATS]').action(name, params);
 *     }
 * }
 *
 * Then later in the page that includes the tag, for instance:
 * document.getElementById("my_link").onclick = function(e) {
 *     adcAction("my_link_click", { "ageGroup": "18-25", "coolnessFactor": "100" });
 * };
 *
 */
ADCENTRIC.tracking.SiteStatsPage = function(siteevent_url) {
	var dispatcher = ADCENTRIC.tracking.EventPixelDispatcher();
	var global_param_keyvals = { };

	function compute_send_params(new_params) {
		var params = { };

		for (var key in global_param_keyvals)
			params[key] = global_param_keyvals[key];
		if ("undefined" !== typeof new_params) {
			for (var key in new_params)
				params[key] = new_params[key];
		}
		return params;
	}

	return {
		siteevent_url: siteevent_url,
		debug: false,

		set_global_params: function(param_keyvals) {
			global_param_keyvals = param_keyvals;
		},
		get_global_params: function() {
			return global_param_keyvals;
		},
		action: function(name, param_keyvals) {
			var n = String(name), params = "";
			var querystring;
			var send_params = compute_send_params(param_keyvals);

			for (var key in send_params)
				params += "&" + encodeURIComponent(String(key)) + "=" + encodeURIComponent(String(send_params[key]));

			// If Google Analytics' urchinTracker() is loaded, feed it the passed-in 'name' as well:
			if ("undefined" !== typeof urchinTracker)
				urchinTracker(n);

			// we use encodeURI not encodeURIComponent for the name/adc_action, as we would like to
			// allow for slashes ("/") to be included, unencoded, for convenience
			querystring = "adc_action=" + encodeURI(n) + params;
			if (this.debug) {
				alert("ADCENTRIC.tracking.SiteStatsPage: " + querystring);
			}
			return dispatcher.dispatch(this.siteevent_url + "?" + querystring);
		},
		view: function(name, param_keyvals) {
			return this.action("/views/" + String(name), param_keyvals);
		},
		click: function(name, param_keyvals) {
			return this.action("/clicks/" + String(name), param_keyvals);
		},
		hover: function(name, param_keyvals) {
			return this.action("/hovers/" + String(name), param_keyvals);
		}
	};
};

ADCENTRIC.tracking.WitnessProfile = function(profile_name, witness_node_url) {
	var dispatcher = ADCENTRIC.tracking.EventPixelDispatcher();

	return {
		witness_node_url: witness_node_url,
		profile_name: encodeURIComponent(profile_name),

		set: function(score) {
			return dispatcher.dispatch(this.witness_node_url + "?profile=" + this.profile_name + "&set_value=" + String(Integer(score)));
		},
		remove: function() {
			return dispatcher.dispatch(this.witness_node_url + "?profile=" + this.profile_name + "&remove=1");
		},
		increase_affinity: function(how_much_score) {
			return dispatcher.dispatch(this.witness_node_url + "?profile=" + this.profile_name + "&increment_value=" + String(Integer(how_much_score)));
		},
		decrease_affinity: function(how_much_score) {
			return this.increase_affinity(Integer(how_much_score) * -1);
		}
	};
};

ADCENTRIC.tracking.MultiWitnessProfile = function(profile_name, witness_node_urls) {
	var wps = new Array();
	var i;

	for (i = 0; i < witness_node_urls.length; i++)
		wps.push(ADCENTRIC.WitnessProfile(profile_name, witness_node_urls[i]));

	return {
		profile_name: encodeURIComponent(profile_name),
		witness_node_urls: witness_node_urls,

		set: function(score) {
			var i;
			for (i = 0; i < wps.length; i++) {
				wps[i].set(score);
			}
			return false;
		},
		remove: function() {
			var i;
			for (i = 0; i < wps.length; i++) {
				wps[i].remove();
			}
			return false;
		},
		increase_affinity: function(how_much_score) {
			var i;
			for (i = 0; i < wps.length; i++) {
				wps[i].increase_affinity(how_much_score);
			}
			return false;
		},
		decrease_affinity: function(how_much_score) {
			return this.increase_affinity(Integer(how_much_score) * -1);
		}
	};
};
