﻿var Void=function(){};if(!window.console){window.console={warn:Void,log:Void,error:Void,info:Void}};
if(!window.console.group){window.console=$.extend(window.console,{group:Void,groupEnd:Void,groupCollapsed:Void,dir:Void});}
window.cloneObj=function(o){var c={};for(p in o){if(o[p]!==undefined){if(typeof o[p]=="object"){c[p]=cloneObj(o[p]);}else{c[p]=o[p];}}}return c;};
/*************************************************************************
 * jquery.TrackIt.js - Version 1.2
 *************************************************************************
 * @author Aaron Lisman (Aaron.Lisman@ogilvy.com)
 * @author Adam S. Kirschner (AdamS.Kirschner@ogilvy.com)
 * $Revision: 159 $
 * $Date: 2009-07-28 14:20:40 -0400 (Tue, 28 Jul 2009) $
 *************************************************************************
 */
(function($) {
	/**
	* Create a new instance of the tracker, "this" should be the data grid itself
	* 
	* @param {string} trackerModule the Tracking Module to use, either ga or omniture (other aliases exist)
	* @param {object} options a set of options that can be used to override $.TrackIt.defaults
	*/
	$.initTrackIt = function(trackerModule, options) {
		return new $.TrackIt(trackerModule, options);
	};

	/**
	* Main Constructor. Initializes the main Tracker object, merges in the correct tracking module and returns
	* an instance of the tracker itself. This function will also attach a click event using jQuery.live
	* 
	* @param {object} data the tracking data itself
	* @param {string} trackerModule the Tracking Module to use, either ga or omniture (other aliases exist)
	* @param {object} options a set of options that can be used to override $.TrackIt.defaults
	*/
	$.TrackIt = function(trackerModule, options) {
		// jQuery sucks sometimes, keep "this"
		var that = this;

		// allow options to override default settings
		this.settings = $.extend({}, this.defaults, options.Settings);
				
		if (this.settings.ShowDebugInfo) { console.group("$.TrackIt() - Init"); }

		// some debug info
		if (this.settings.TestMode && this.settings.ShowDebugInfo) {
			console.groupCollapsed("$.TrackIt() - Test Mode is Enabled, Tracking Disabled!");
		} else if (this.settings.ShowDebugInfo) {
			console.info("$.TrackIt() - Tracking Enabled. Debug Mode On.");
		}

		// omniture does suck with flash, needs a "fake link"
		this.InitDudLink();

		// merge the tracking Module object settings into this object
		this.loadTrackingModule(trackerModule);

		// reset all track events
		this.__CALLBACK_EVENTS = {};
		$.each(this.__GLOBAL_EVENTS, function() { that.__CALLBACK_EVENTS[this + ''] = []; });

		// extend global placeholders
		if (options.GlobalHolders) { $.extend(this.BuiltInHolders, options.GlobalHolders); }

		// use live to set global click listener
		$("*").live('click', function() { that.HandleGenericClick(this); });

		if (options.Plugins) {
			$.each(options.Plugins, function() {
				if (this["Init"] && typeof this["Init"] == "function") { this.Init.apply(that); }
			});
		}

		if (this.settings.ShowDebugInfo) { console.groupEnd(); }

		// if there was an xml file specified, load it	
		if (options.XmlUrl) {
			// load the track data from an Xml File, send in an extra data that is set (if any)
			this.loadXml(options.XmlUrl, options.TrackData);
		} else {
			// set the track data
			this.TrackData = options.TrackData;

			// callback functions should run when this module has done its basic initialization
			this.fireEvent('ready');
		}
	};

	/**
	* $.TrackIt Methods
	*/
	$.extend($.TrackIt.prototype, {
		__GLOBAL_EVENTS: ['ready', 'afterProcessHolders', 'beforeProcessHolders', 'beforeTrack', 'afterTrack'],
		__INDIVIDUAL_EVENTS: ['afterProcessHolders', 'beforeProcessHolders', 'beforeTrack', 'afterTrack'],
		/**
		* These are the basic options that can be overridden by $.TrackIt to help debugging
		* and other customizations that may be necessary. Every option is set to false by default.
		*
		* @param TestMode {bool} whether or not reporting is actually sent to service.
		* @param TrackKeyAttribute {string} the html attribute that is checked for a track key when an item is clicked on
		* @param EnableUrlMappingWithDeepLink {bool} whether or not the tracker should be disabled if a "#" is present on pageload 
		* @param ShowMissingHolderWarnings {bool} a warning will show up in Firebug when a holder ([some holder]) is evaluated based on no specified input
		* @param ShowDebugInfo {bool} whether or not to show detailed tracker debug information to track stack trace and other useful information while testing
		* @param SanityCheckEnabled {bool} whether or not to show a detailed report that verifies the existance (or non existance) of all holders in all track keys	
		* @param SanityCheckMissingOnly {bool} whether or not to only show holders that are not defined during a data sanity check
		* @param ShowOnlyReportedData {bool} regardless of other variables that are set, this option will ensure that reported data will show in console
		*/
		defaults: {
			TestMode: false,
			TrackKeyAttribute: "trackKey",
			EnableUrlMappingWithDeepLink: false,
			ShowMissingHolderWarnings: false,
			ShowDebugInfo: false,
			SanityCheckEnabled: false,
			SanityCheckMissingOnly: false,
			SanityCheckFromFlash: false,
			ShowOnlyReportedData: false
		},

		HandleGenericClick: function(ele) {
			// if the tracking attribute has a valid value in it, then this element should be tracked
			if (typeof $(ele).attr(this.settings.TrackKeyAttribute) !== 'undefined') {
				// this key should corespond to the data
				var key = $(ele).attr(this.settings.TrackKeyAttribute);
				
				// track it and send the link ele as an option
				this.track(key, { ele: ele });
			}
		},
		InitDudLink: function() {
			// create a dud link, hide it. this is used for links from flash
			this.DudHtmlLink = $("<a></a>")
				.css("display", "none")
				.attr("href", "javascript:Void()");

			$(document.body).append(this.DudHtmlLink);
		},

		/**
		* This function will merge in the proper tracking module, whether it is Omniture or Google Analytics
		*
		* @param {string} module a string representation of what module to load
		*/
		loadTrackingModule: function(module) {
			switch (module.toLowerCase()) {
				case "googleanalytics":
				case "google":
				case "ga":
					$.extend(this, window.TrackingModules.GoogleAnalytics);
					break;
				case "omniture":
				case "omni":
					$.extend(this, window.TrackingModules.Omniture);
					break;
				default:
					console.error("WARNING: No valid tracking module was specified!");
			}
		},

		/**
		* This function is useful when loading an external XML file as the basis for the tracking spec. 
		* A xml file path is passed and is processed via an XmlHttpRequest. An optional object can be passed
		* that will be merged with the XML document that is loaded. The option object can be typically used
		* for passing extra keys that will be holders within a variables value. 
		* 
		* @param xmlUrl {string} the URL of where the trackData XML file lives. 
		* @param extraTrackData {obj} an object that will be merged into the XML file once it is loaded, useful for custom functions as holders
		*/
		loadXml: function(xmlUrl, extraTrackData) {
			// again jquery sucks
			var that = this;

			// lets go, ajax time
			$.ajax({
				'url': xmlUrl,
				'complete': function(xml) {
					// if no data comes back, do nothing
					if (xml.responseText.length > 0) {
						// set processed data 
						that.TrackData = that.parseXml(xml.responseText, extraTrackData);
					}

					// since we're ready now, go, this should change to a custom event
					that.fireEvent('ready');
				}
			});
		},
		/**
		* This function will take an xml as a string an call "getXmlObject" which will give a XML DOM object that 
		* can be used to parse. It does not use any of the jquery find methods to parsing the XML since jquery will
		* make all of the tag names uppercase which is not desired. 
		*/
		parseXml: function(xml, extraTrackData) {
			var trackEvents = {};

			// get all of the trackEvent nodes.
			xml = this.getXmlObject(xml).getElementsByTagName("trackEvent");

			$(xml).each(function() {
				if (this.tagName) {
					var trackEvent = $(this);
					var newTrackEvent = {
						urlMap: trackEvent.attr('urlMap'),
						event: trackEvent.attr('event')
					};

					$(this.childNodes).each(function() {
						if (this.tagName) {
							newTrackEvent[this.tagName] = $(this).text();
						}
					});

					trackEvents[trackEvent.attr('eventName')] = newTrackEvent;
				}
			});

			return trackEvents;
		},
		/**
		* Since we cannot use jquery to parse the XML, we will need to create either an ActiveXObject for IE or use a 
		* standardized method to retrieve a valid XML dom.
		*/
		getXmlObject: function(str) {
			var out;
			// create ActiveXObject for IE
			try {
				var xml = ($.browser.msie) ? new ActiveXObject("Microsoft.XMLDOM") : new DOMParser();
				xml.async = false;
			} catch (e) {
				throw new Error("XML Parser could not be instantiated");
			};

			// get the XML DOM object itself and return it.
			try {
				if ($.browser.msie)
					out = (xml.loadXML(str)) ? xml : false;
				else
					out = xml.parseFromString(str, "text/xml");
			} catch (e) {
				throw new Error("Error parsing XML string");
			};

			return out;
		},
		/**
		* TrackIt has the ability to attach events to several call back methods, 
		*/
		addCallback: function(eventType, callback) {
			if (this.settings.ShowDebugInfo) { console.info("$.TrackIt.addCallback() - Adding Callback to '" + eventType + "'", callback); }

			if ($.inArray(eventType, this.__GLOBAL_EVENTS > -1)) {
				this.__CALLBACK_EVENTS[eventType].push(callback);
			} else {
				if (this.settings.ShowDebugInfo) {
					console.warn("$.TrackIt.addCallback() - Failed to add callback to '" + eventType + "'! ", callback);
				}
			}
		},

		/**
		* This function is simply a list of callback functions that should be run when the tracker object
		* has been fully initialized and is ready to begin tracking. This function will eventually be an 
		* event that will be listened upon so that plugins may extend this function.
		*/
		fireEvent: function(eventType, params) {
			var retVal = true;

			var that = this;

			if (typeof eventType == "string") {
				if (this.__CALLBACK_EVENTS[eventType] && this.__CALLBACK_EVENTS[eventType].length > 0) {
					if (this.settings.ShowDebugInfo) { console.group("$.TrackIt.fireEvent() - Firing Global Event '" + eventType + "'"); }

					$.each(this.__CALLBACK_EVENTS[eventType], function() {
						// if false is explicitly sent back, return false
						if (this.apply(that, [params]) === false) {
							retVal = false;
						}
					});

					if (this.settings.ShowDebugInfo) { console.groupEnd(); }
				}

				// check that params has a key, and check to see if that key has an eventType to throw and is a function
				if (params && params.key && this.TrackData[params.key] &&
					this.TrackData[params.key][eventType] && typeof this.TrackData[params.key][eventType] == "function"
					) {
					// it much be called from track data
					if (this.settings.ShowDebugInfo) { console.info("$.TrackIt.fireEvent() - Firing Local Event '" + eventType + "'"); }

					// if false is explicitly sent back, return false
					if (this.TrackData[params.key][eventType].apply(that, [params]) === false) {
						retVal = false;
					}
				}
			}

			return retVal;
		},

		/**
		* Function that will track an event. A key is used to map to the proper parameters that will
		* be passed to the tracker itself. The options is an object where each key is a holder. This is
		* when it is necesary to pass dynamic values into a tracking string.
		* 
		* @param {string} key the name of the event to get the data from
		* @param {object} options an object where each key will be processed as a holder, options.ele can also be a HtmlLinkElement
		*/
		track: function(key, options) {
			// if a string comes back as options, this is most likely flash, so eval it
			if (typeof options == "string") {
				// this was in the jquery library, line 3725
				options = window["eval"]("(" + options + ")");
			} else if (options == null) {
				options = {};
			}

			// log that a track event has occured, show options and key that was caught
			if (this.settings.ShowDebugInfo) { console.groupCollapsed("$.TrackIt.track() - key='", key, "' options=", options); }

			// if the key is a valid track key
			if (this.TrackData[key]) {

				// get the parsed version of the data (if there are placeholders) 
				var parsedData = this.GetParsedData(key, options);

				if (this.fireEvent('beforeTrack', { key: key, options: options, parsedData: parsedData })) {
					// detect what kind of an event that occured and use the loaded module to track the event
					if (parsedData.event && parsedData.event.toLowerCase() == "pageview") {
						if (this.settings.ShowDebugInfo) { console.info('$.TrackIt.track()-->DoTrackPageView("' + key + '")'); }
						this.DoTrackPageView(parsedData, options)
					} else {
						if (this.settings.ShowDebugInfo) { console.info('$.TrackIt.track()-->DoTrackEvent("' + key + '")'); }
						this.DoTrackEvent(parsedData, options);
					}

					this.fireEvent('afterTrack', { key: key, options: options, parsedData: parsedData });
				} else {
					if (this.settings.ShowDebugInfo) { console.info("$.TrackIt.track() - beforeTrack returned false. Skipping track."); }
				}
			}

			if (this.settings.ShowDebugInfo) { console.groupEnd(); }
		},

		/**
		* This will return parsed data from the TrackData object. Key and eventType are used to retrieve the 
		* raw data. ele is passed in so that we can retrieve data from the element itself and use it in the reporting.
		* 
		* @param {string} key the name of the event to get the data from
		* @param {object} options contains extra information that will help with integrating the holders
		*/
		GetParsedData: function(key, options) {
			var retVal = null;

			// find out if the key exists in TrackData
			if (this.TrackData[key]) {

				// retrieve it and replace all the holders in each data element
				retVal = cloneObj(this.TrackData[key]);

				for (var varName in retVal) {
					if (typeof retVal[varName] != 'function') {
						retVal[varName] = unescape(this.ReplaceHolders(retVal[varName], key, options));
					}
				}
			}

			return retVal;
		},

		/**
		* Return an array of all the Holders that exist in this string. A holder is the part of the string that has {}.
		* 
		* @param {string} str a string with or without a Holder
		*/
		GetPlaceHolderArray: function(str) {
			return str.match(/\[[^\]]+\]/g);
		},

		/**
		* This plugin comes with a variety of pre-existing holders that may come convenient to the implementer. 
		*	- [TEXT] - "ele.text()" of a HtmlElement
		*  - [TITLE] - title tag of the page
		*  - [H1] - the "ele.text()" of the first HtmlHeadingElement
		*  - [ALT] - the "ele.alt" attribute of a HtmlElement
		*  - [HREF] - the desintation url of a HtmlLinkElement
		*  - [ATTR:value] - returns the value of what the HtmlAttribute "value" is for the current HtmlElement
		*  - [ATTR+:value] - similar to ATTR however, will check parent elements and returns the first occurance
		*/
		BuiltInHolders: {
			'TEXT': function() { return $(this).text(); },
			'TITLE': function() { return $('title').text(); },
			'H1': function() { return $("H1").text(); },
			'ALT': function() { return $(this).attr('alt'); },
			'HREF': function() { return $(this).attr('href'); },
			'ATTR': function() { return $(this).attr(value); },
			'ATTR+': function() {
				var pars = $(this).parents('*[' + value + ']');
				if (pars.length > 0) {
					return $(pars[0]).attr(value); // get the attribute		
				}
			},
			'PAGENAME': function() {
				var fn = window.location.toString().split('/');
				return fn[fn.length - 1];
			},
			'DOWNLOADFILENAME': function() {
				var fn = $(this).attr('href').toString().split('/');
				return fn[fn.length - 1];
			},
			'URL': function() { return document.location.toString(); }
		},

		/**
		* This function will get all of the holders within a string and replace it based on the holder. The set of options
		* that was passed will be processed here
		* 
		* @param str {string} a preparsed string that main contain holders
		* @param key {string} the track key event that is being tracked
		* @param options {object} an object where each key will coorespond to a holder
		*/
		ReplaceHolders: function(str, key, options) {
			var skipHolders = true;

			// throw beforeReplaceHolders event
			if (this.TrackData[key]["beforeReplaceHolders"] && typeof this.TrackData[key]["beforeReplaceHolders"] == "function") {
				skipHolders = this.TrackData[key]["beforeReplaceHolders"].apply(this, [{ key: key, str: str, options: options}]);
			}

			// get all Holders that exist in this string
			var holders = this.GetPlaceHolderArray(str);

			if (holders && skipHolders !== false) {
				// go through each holder
				for (var index = 0; index < holders.length; index++) {

					// get the holder
					var holder = holders[index];

					// reset the parsed holder
					var parsedHolder = "";

					// get rid of the curly braces and split at colon
					var splitArr = holder.toString().substring(1, (holder.length - 1)).toString().split(":");
					var command = splitArr[0]; var value = splitArr[1];

					// process the existing track key properties first, recognizes functions and string values
					if (typeof this.TrackData[key][command] == "function") {
						parsedHolder = this.TrackData[key][command].apply(options.ele || null, [{ instance: this, key: key, value: value}]);
					} else if (typeof this.TrackData[key][command] == "string") {
						parsedHolder = this.TrackData[key][command];
					}
					// rerun same rules on the passed options
					else if (options && typeof options[command] == "function") {
						parsedHolder = options[command].apply(options.ele || null, [{ instance: this, key: key, value: value}]);
					} else if (options && typeof options[command] == "string") {
						parsedHolder = options[command];

						// built in holders
					} else if (this.BuiltInHolders[command]) {
						parsedHolder = this.BuiltInHolders[command].apply(options.ele || null, [{ instance: this, key: key, value: value}]);
					} else {
						if (this.settings.ShowMissingHolderWarnings && this.settings.ShowDebugInfo) {
							console.warn("$.TrackIt.HandleBuiltInHolder() - Missing Holder Detected - '" + command + "' in key '" + key + "'");
						}
					}

					// throw afterReplaceHolders event
					if (this.TrackData[key]["afterReplaceHolders"] && typeof this.TrackData[key]["afterReplaceHolders"] == "function") {
						retVal = this.TrackData[key]["afterReplaceHolders"].apply(this, [{ key: key, str: str, options: options}]);
						if (retVal) { str = retVal; }
					}

					// replace the parsed value of the holder with the holder itself
					str = str.replace(holder, parsedHolder);
				}
			}

			return str;
		}
	});
	/**
	*
	*/
	window.TrackItPlugins = {
		/**
		* @class
		 		
		* The data sanity checker will iterate through each track key and process all the holders within 
		* each variable. It will detect whether or not a valid holder replacement was found or not. An
		* extra option "SanityCheckMissingOnly" can be used to only report on those holders that are missing.
		* This will show up in the console regardless of the other options that are set.
		*/
		DataSanityCheck: {
			Init: function() { this.addCallback('ready', window.TrackItPlugins.DataSanityCheck.Go); },
			Go: function(flashValidHolders, flashInvalidHolders) {
				holderStatus = {};
				if (!flashValidHolders) { flashValidHolders = {}; }
				if (!flashInvalidHolders) { flashInvalidHolders = {}; }
				for (var key in this.TrackData) {
					if (!this.settings.SanityCheckMissingOnly) { holderStatus[key] = {}; }
					keyData = cloneObj(this.TrackData[key]);
					for (var varName in keyData) {
						var str = keyData[varName];
						if (typeof str == 'string') {
							var holders = this.GetPlaceHolderArray(str);
							if (holders) {
								for (var i = 0; i < holders.length; i++) {
									var holder = holders[i];
									var splitArr = holder.toString().substring(1, (holder.length - 1)).toString().split(":");
									var command = splitArr[0]; var value = splitArr[1];
									if (!(this.BuiltInHolders[command]) &&
										!(keyData[command]) &&
										!(flashValidHolders[command])) {
										if (!holderStatus[key]) { holderStatus[key] = {}; }
										holderStatus[key][command] = false;
									} else {
										if (!this.settings.SanityCheckMissingOnly) {
											holderStatus[key][command] = true;
										} else if (holderStatus[key] && holderStatus[key][command]) {
											delete holderStatus[key][command];
										}
									}
								}
							}

						}
					}
				}
				if (this.settings.ShowDebugInfo) {
					console.groupCollapsed("TrackItPlugins.DataSanityCheck() - Results");
					console.dir(holderStatus);
					console.groupEnd();
				}
			}
		},
		/**
		* This plugin will copy all prop's from each track key and copy its value into a coresponding eVar.
		*/
		CopyPropToEVar: {
			Init: function() { this.addCallback('ready', TrackItPlugins.CopyPropToEVar.Go); },
			Go: function() {
				if (this.settings.ShowDebugInfo) { console.groupCollapsed("TrackItPlugins.CopyPropToEVar.Go() - Results"); }

				var regex = new RegExp("(\\d+)", "g");
				var newEVars = {};
				for (var key in this.TrackData) {
					keyData = this.TrackData[key];
					for (var varName in keyData) {
						if (varName.indexOf("prop") > -1) {
							var i = varName.match(regex)[0];
							keyData["eVar" + i] = keyData["prop" + i];
							if (!newEVars[key]) { newEVars[key] = {}; }
							newEVars[key]["eVar" + i] = keyData[varName];
						}
					}
				}

				if (this.settings.ShowDebugInfo) {
					console.dir(newEVars);
					console.groupEnd();
				}
			}
		},
		/**
		* Once the tracker has been loaded, it begins by checking the URL and the XML to see if any
		* pageview event should fire. This function has a recognized options "EnableUrlMappingWithDeepLink"
		* in the event that you want the deep linking controler to control what should be reported. This is 
		* useful when using deep linking with JavaScript or Flash.
		*/
		CheckUrlMapping: {
			Init: function() { this.addCallback('ready', window.TrackItPlugins.CheckUrlMapping.Go); },
			Go: function() {
				var that = this;

				// if the option "EnableUrlMappingWithDeepLink" is set and there's a match URL map, then skip UrlMapping for this load
				if (document.location.hash.length > 0 && !this.settings.EnableUrlMappingWithDeepLink) {
					if (this.settings.ShowDebugInfo) { console.info("TrackItPlugins.CheckUrlMapping.Go() - Deep Link Detected, Disabling Url Mapping"); }
				} else {
					// the feature is enabled, so show info that it's going to process
					if (this.settings.ShowDebugInfo) { console.group("TrackItPlugins.CheckUrlMapping.Go() - Enabled"); }
					if (this.settings.ShowDebugInfo) { console.info("TrackItPlugins.CheckUrlMapping.Go() - Check against URL: ", document.location.pathname); }
					var found = false;
					// go through each track key
					for (var trackKey in this.TrackData) {
						var trackObj = this.TrackData[trackKey];

						// ensure that a url mapping exists
						if (trackObj.urlMap) {
							var urlMappings = trackObj.urlMap.split("|");

							$.each(urlMappings, function() {
								// check the URL and the url mapping as a regex, do some regex non-friendly manipulation first
								var mapping = this.replace("[", "\\["); mapping = mapping.replace("]", "\\]");
								var mapping = mapping.replace("*", ".*");

								if (!found && (new RegExp("^" + mapping + "$", "i")).test(unescape(document.location.pathname))) {
									// if the test pasts as a regex match, then track this event
									if (that.settings.ShowDebugInfo) { console.info("TrackItPlugins.CheckUrlMapping.Go() - Found Key: '" + trackKey + "'"); }
									that.track(trackKey, {});
									found = true;
								}
							});
						}
					}

					if (this.settings.ShowDebugInfo && !found) { console.info("TrackItPlugins.CheckUrlMapping.Go() - Key Not Found!"); }
				}

				if (this.settings.ShowDebugInfo) { console.groupEnd(); }
			}
		},

		RecordLastTrack: {
			Init: function() {
				window.TrackItPlugins.RecordLastTrack.__LAST_REPORT = {};

				this.addCallback('afterTrack', function(options) {
					window.TrackItPlugins.RecordLastTrack.__LAST_REPORT = $.extend(window.TrackItPlugins.RecordLastTrack.__LAST_REPORT, options.parsedData);
					if (this.settings.ShowDebugInfo) { console.info("TrackItPlugins.RecordLastTrack() - Last data set saved!"); }
				});

				this.BuiltInHolders["LAST"] = window.TrackItPlugins.RecordLastTrack.LastHolder;
			},
			LastHolder: function(options) {
				if (window.TrackItPlugins.RecordLastTrack.__LAST_REPORT && window.TrackItPlugins.RecordLastTrack.__LAST_REPORT[options.value]) {
					return window.TrackItPlugins.RecordLastTrack.__LAST_REPORT[options.value];
				} else {
					if (options.instance.settings.ShowDebugInfo) { console.warn("TrackItPlugins.RecordLastTrack() - LAST value request not found '" + options.value + "'") }
				}
			}
		}
	}

	/**
	* A tracking module needs to declare at least 2 kinds of tracking methods, "TrackEvent" and "TrackPageView". The outter 
	* shell of $.TrackIt is essentially a wrapper for both of these functions. Each function will receieve the data node
	* of the correct event that was passed. The TrackEvent function will also receive the element that the event fired from.
	*/
	window.TrackingModules = {
		/*
		* !!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!
		* THIS IMPLEMENTATION WAS NOT TESTED WITH VERSION 1.0 
		* THESE CALLBACKS SHOULD BE CHECKED AND CONFIRMED WITH 
		* GOOGLE ANALYTICS!
		* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		*/
		GoogleAnalytics: {
			Type: "Google Analytics",
			DoTrackEvent: function(data, ele) {
				if (this.settings.ShowDebugInfo) {
					console.info(data);
				} else {
					pageTracker._trackEvent(data.category, data.action, data.opt_label, data.opt_value);
				}
			},
			DoTrackPageView: function(data) {
				if (this.settings.ShowDebugInfo) {
					console.info(data);
				} else {
					pageTracker._trackPageview(data.pageName);
				}
			}
		},
		Omniture: {
			Type: "Omniture",
			/**
			* This is the omniture implementation of the TrackEvent. This handles all special cases in terms of being able
			* to track the proper variables.
			* 
			* @param {Object} data the parsed data that should be reported.
			* @param {HtmlElement} ele the HtmlElement that the event fired from
			*/
			DoTrackEvent: function(data, options) {
				// create new omniture instance
				var s = s_gi(s_account);

				// merge all the data into "s"
				$.extend(s, data);

				// these are TrackIt specific attributes used, we don't want this to merge with the tracker at all.
				var excludeVars = ["type", "event", "urlMap", "customLinkName"];
				$.each(excludeVars, function() { delete s[this] });

				// omniture needs to know all the variables we are settings asside
				// from just setting it, add all the variable names to an array
				var linkTrackVars = [];
				for (var varName in data) {
					if (!(excludeVars[varName])) { linkTrackVars.push(varName); }
				}

				// join the array with and tell omniture these are the variables
				s.linkTrackVars = linkTrackVars.join(',');

				// not only do we need set the s.events variable, but also s.linkTrackEvents
				// if an event does get thrown
				if (s.events && s.events.length > 0) {
					s.linkTrackEvents = s.events;
				}

				// if in test mode just show what would get reported
				if (this.settings.TestMode && (this.settings.ShowOnlyReportedData || this.settings.ShowDebugInfo)) {
					console.groupCollapsed("TrackItModules.Omniture.DoTrackEvent() - Track Event Skipped:");
					console.dir({ "s": s, "data": data });
					console.groupEnd();
				} else {
					// use a dud link and set the link url and link text if they exist
					if (options['link url'] && options['link text']) {
						this.DudHtmlLink
							.attr('href', options['link url'])
							.text(options['link text']);
					}

					var dudLink = null;
					if (this.DudHtmlLink && this.DudHtmlLink.length > 0) {
						dudLink = this.DudHtmlLink.get(0);
					}

					// either send in the HtmlLinkElement that was passed or the dud link
					// customLinkName allows for a custom value 
					s.tl(options.ele || dudLink, data.customLinkType || 'o', data.customLinkName || null);

					if (this.settings.ShowDebugInfo || this.settings.ShowOnlyReportedData) {
						console.groupCollapsed("TrackItModules.Omniture.DoTrackEvent() - Event tracked successfully.");
						console.dir({ "s": s, "data": data });
						console.groupEnd();
					}

					// clear the dud link
					this.DudHtmlLink
							.attr('href', '')
							.text('');

					// clean up, clear out all the values that were set
					for (var key in data) { delete s[key] };
				}
			},
			DoTrackPageView: function(data) {

				// use existing s object from current page
				$.extend(s, data);

				// if in test mode AND we're showing some sort of information, we show the data
				if (this.settings.TestMode && (this.settings.ShowOnlyReportedData || this.settings.ShowDebugInfo)) {
					console.groupCollapsed("TrackItModules.Omniture.DoTrackPageView() - Page View tracking is being skipped.")
					console.dir({ "s": s, "data": data });
					console.groupEnd();
				}

				// if not in test mode, then actually track it
				if (!this.settings.TestMode) {
					s.t();

					// decipher whether or not the tracked information should show
					if (this.settings.ShowDebugInfo || this.settings.ShowOnlyReportedData) {
						console.groupCollapsed("TrackItModules.Omniture.DoTrackPageView() - Page View tracked successfully.");
						console.dir({ "s": s, "data": data });
						console.groupEnd();
					}
				}

				// clean up, clear out all the values that were set
				for (var key in data) { delete s[key] };
			}
		}
	}
})(jQuery);
