/* 
Author: Kevin O'Brien
Email: kevin@clockwork.net
Company: Clockwork Acive Media Systems
Version: 1.2
Last Modified: 11.25.11
*****************************
ref:	http://code.google.com/apis/analytics/docs/tracking/gaTrackingSite.html
		https://www.google.com/analytics/web/#report/visitors-overview/a5653468w50838518p51483429/%3F_.advseg%3Duser1563152878%2Cuser1692985168%26_.date00%3D20111010%26_.date01%3D20111011/
		http://www.google.com/support/forum/p/Google%20Analytics/thread?tid=5003ffffedf3ee6c&hl=en
Uses
****
== V1.0 ==
* one account (this.s.UA = '')
* multiple accounts (this.s.UA = [])
* cross domain (this.s.domains.length > 1)
* cross domain links that open in a new window
* cross domain across non combined root level domains (no objects in this.s.domains)
* cross domain across non combined sub domains (no objects in this.s.domains)
* cross domain across combined sub domains (objects in this.s.domains using {entity:'',subs:['']})
	* this resets to domain property to the entity level and doesn't need to pass longer url on links and forms
* cross domain on multiple accounts
* All cross domain and multiple accounts work in same or new window
* virtual page views for:
	* external links (this.s.track_external_links)
	* assets (this.s.asset_extentions)
	* assets track in AMM preview
* All virtual page views in same window or new or frame name
* All virtual page views work for multiple accounts
* ecommerce (also for multiple accounts)
* forms across multiple domains in same window
* forms across multiple domains in new window / iframe
* forms across multiple domains with multiple accounts same / new window / frame
* In all domain matching ://www. = :// (this.s.domains, links, forms)
* Track event to all active ua accounts through method
== V1.1 ==
* Only track specific domains
* Exclude sub domains from tracking
== V1.2 ==
* Track virtual page views for # links
* Disable cross domain tracking if this.o.domains is defined but does not contain the current domain
* Bug fix: links with nested html tags caused an error because of event bubbling

TODO
****

Examples
********
// REQUIRED in the <head> of the document
var cwGA = jQuery(document).analytics({
	'UA': ['5653468-4','XXXXX-X'] // required [] or ''
});
// Cross domain tracking example to add to init code:
	'domains': [{entity: 'clockwork.net', subs: ['dev1', 'dev2']}, 'dev3.clockwork.net', 'dev4.clockwork.net']
// Optionally call anywhere after code above
cwGA.track_virtual('asd');
cwGA.track_transaction(
	[
		// Item 1
		['001', '90', 'Product 1', 'Category 1', '32.95', '1'],
		// Item 2
		['001', '92', 'Product 2', 'Category 1', '17.04', '1']
	],
	// Transaction
	['001', 'Example Store', '49.99', '2.30', '5.00', 'Minneapolis', 'Minnesota', 'USA']
); //http://code.google.com/apis/analytics/docs/tracking/gaTrackingEcommerce.html
cwGA.track_event('category', 'action', 'label', 1); //http://code.google.com/apis/analytics/docs/tracking/eventTrackerGuide.html

*/

(function ($) {

	$.fn.analytics = function (s) {
		return new $.analytics(this, s);
	};

	$.analytics = function (el, s) {

		// Settings
		this.s = $.extend({
			UA:						'XXXXX-X',
			d:						window.document.domain,
			domains:				[],
			track_external_links:	true,
			asset_extentions:		['pdf', 'txt', 'csv', 'doc', 'docx', 'xls', 'ppt', 'jpg', 'jpeg', 'png', 'gif', 'psd', 'ai', 'eps', 'zip', 'xml', 'json', 'avi', 'mp4', 'mp3', 'mov', 'mpeg', 'wmv', 'rtf', 'swf', 'flv'],
			external_prefix:		'/external/',
			debug:					false,
			include_only:			null,
			track:					true,
			exclude_subdomains:		['preview', 'dev', 'test', 'stage', 'review', 'demo', 'train']
		}, s);

		if(!this.s.track) return;

		// Variables
		var o						= this;
		this.$t						= null;
		window._gaq					= window._gaq || [];
		this.current_domain_state	= null;
		this.track_multi			= this.s.UA.constructor === Array ? true : false;
		this.cross_domain_disabled	= false;

		// Process Variables
		this.s.UA = this.track_multi ? this.s.UA : [this.s.UA];

		// Init
		this.setup();
		$(document).ready(function () { o.$t = $(el); o.init(); });

		return this;
	};

	$.analytics.prototype = {

		setup: function () {

			if(!this.s.track) return;

			// Include Specific Domains Only
			if(this.s.include_only) {
				var inlcude_domain = this.match_domain(this.s.d, this.s.include_only);
				if(!inlcude_domain[0]) {
					this.s.track = false;
					if(this.s.debug) console.info('Current Domain not part of this.s.include_only');
					return;
				}
			}

			// Exclude Sub Domains
			if(this.s.exclude_subdomains) {
				var domain_parts = this.s.d.split('.');
				var domain_i;
				for(var ex_i = 0; ex_i < this.s.exclude_subdomains.length; ex_i++) {
					for(domain_i = 0; domain_i < domain_parts.length; domain_i++) {
						if(domain_parts[domain_i] == this.s.exclude_subdomains[ex_i]) {
							if(this.s.debug) console.info('Tracking off: current domain contains an excluded sub domain in this.s.exclude_subdomains: '+this.s.exclude_subdomains[ex_i]);
							this.s.track = false;
							return;
						}
					}
				}
			}

			// Activate Each Tracking Code
			for (var i = 0; i < this.s.UA.length; i++) {
				var pre = i == 0 ? '' : 't'+(i+1)+'.';

				// Set profile
				window._gaq.push([pre+'_setAccount', 'UA-'+this.s.UA[i]]);

				// Cross domain tracking
				if(this.s.domains.length > 0) {
					this.current_domain_state = this.match_domain(this.s.d);
					if(this.current_domain_state[1]) {
						window._gaq.push([pre+'_setDomainName', this.current_domain_state[1]]);
						window._gaq.push([pre+'_setAllowLinker', true]);
						if(this.s.debug) console.info('Cross domain active');
					}else if(this.s.debug) {
						this.cross_domain_disabled = true;
						console.info('Error: Cross domain defined but current domain not included, deactivating cross domain');
					}
				}

				// Track page view for current page
				window._gaq.push([pre+'_trackPageview']);
				if(this.s.debug) console.info('UA-'+this.s.UA[i]+' active!');
			}

			// Default async embed code
			(function() {
				var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
				ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
				var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
			})();
		},

		init: function() {
			
			if(!this.s.track) return;
			var self = this;
			$(document).ready(function(){

				// Convert all links
				$(self.$t).find('a').each(function(){
					self.convert_link(this);
				});

				// Forms only need attention for cross domain
				if(self.s.domains.length < 1) return;
				// Convert all forms
				$(self.$t).find('form[method="post"]').each(function(){
					self.convert_form(this);
				});
			});

		},

		convert_link: function(target) {
			
			if(!this.s.track) return;
			target = $(target);
			var href = target.attr('href');
			if(!href) return;
			var parts = href.split('/');
			if(parts[0] == 'http:' || parts[0] == 'https:') {
				// External link found
				var a_status = this.cross_domain_disabled ? [null] : this.match_domain(parts[2]);
				if(!a_status[0]) {
					// Link domain is NOT part of cross domain definition
					if(!this.s.track_external_links) return;
					parts.splice (0,2);
					parts = this.s.external_prefix+parts.join('/');
					this.link_virtual(target, href, parts)
				}else {
					// Link IS part of cross domain definition
					if(a_status[2] == this.current_domain_state[2]) return;
					if(target.attr('target') && (target.attr('target') != '_self')) target.click(function(e){ e.preventDefault(); window.open(window._gat._getTrackerByName()._getLinkerUrl($(target).attr('href')),$(target).attr('target')); });
						else target.click(function(e){ e.preventDefault(); window._gaq.push(['_link', target.attr('href')]); });
				}
			}else {
				// Virtual page views for assets with extensions in this.s.asset_extentions
				path = href.split('?')[0].split('#')[0];
				// AMM specific preview links
				if(path == '/amm/author/lookup_page.php') path = href.split('&url=')[1].split('&')[0].split('#')[0];
				parts = path.split('.');
				extension = parts[parts.length-1];
				// Set asset links for virtual page views
				for( var i = 0; i < this.s.asset_extentions.length; i++ ) {
					if(extension == this.s.asset_extentions[i]) this.link_virtual(target, href);
				}
				// Set hash links for virtual page views
				if(href[0] == '#') {
					href = document.location.pathname + document.location.search + href;
					this.link_virtual(target, href);
				}
			}
		},

		convert_form: function(target) {
			
			if(!this.s.track) return;
			try {
				target = $(target);
				var action = target.attr('action');
				var parts = action.split('/');
				if(parts[0] == 'http:' || parts[0] == 'https:') {
					var f_status = this.cross_domain_disabled ? [null] : this.match_domain(parts[2]);
					if(f_status[0]) {
						// form IS part of cross domain definition
						if(f_status[2] == this.current_domain_state[2]) return;
						target.submit(function(e){ _gaq.push(['_linkByPost', e.target]); });
					}
				}
			}catch(err){}
		},

		match_domain: function(url, against) {
			/* returns:
				[0]:
					1: url matches a parent entity
					2: url matches a sub of a parent entity
					3: url matches a unique domain string
					null: not part of cross domain tracking defined in this.s.domains
				[1]: domain value to set in GA init code (entity domain)
				[2]: matched index in this.s.domains[]
				[3]: matched sub index of entity
			*/
			if(!this.s.track) return;
			var against = against ? against : this.s.domains;

			var url_parts = url.split('.')
			if(url_parts[0] == 'www') {
				url_parts.splice(0,1)
				url = url_parts.join('.');
			}

			for( var i = 0; i < against.length; i++ ) {
			
				if(against[i].entity == url) {
					// Matches a parent domain with sub domains tracked as part of it
					return [1, against[i].entity, i, false];
					break
				}else if(against[i].entity){
					var matches_sub = false;
					for( var i2 = 0; i2 < against[i].subs.length; i2++ ) {
						if((against[i].subs[i2]+'.'+against[i].entity) == url) {
							// Matches a sub domain that tracks as part of it's parent
							return [2, against[i].entity, i, i2];
							break
						}
					}
					if(matches_sub) break;
				}
				if(against[i] == url) {
					// Matches a domain with no grouped subdomains
					return [3, 'none', i, false];
					break;
				}
			}
			return [];

		},

		link_virtual: function(target, destination, view) {
			if(!this.s.track) return;
			target = $(target);
			view = view ? view : destination;
			var track_view = '';
			for( var i = 0; i < this.s.UA.length; i++ ) {
				var pre = i == 0 ? '' : 't'+(i+1)+'.';
				track_view += "_gaq.push(['"+pre+"_trackPageview', '/vpv/"+view+"']); ";
			}
			// First: link in new tab; Second: link in same tab
			if(target.attr('target') && (target.attr('target') != '_self')) target.click(function(e){ e.preventDefault(); eval(track_view+"window.open('"+destination+"', '"+target.attr('target')+"');"); });
				else target.click(function(e){ e.preventDefault(); eval(track_view+"setTimeout(function(){ document.location = '"+destination+"'; }, 100);"); });
		},

		/******
		Here On:
			Available for anyone to track to all active UA codes easily.
		********************/
		
		track_virtual: function(view) {
			if(!this.s.track) return;
			view = view ? view : destination;
			for( var i = 0; i < this.s.UA.length; i++ ) {
				var pre = i == 0 ? '' : 't'+(i+1)+'.';
				window._gaq.push([pre+"_trackPageview", "/vpv/"+view]);
			}
		},

		track_event: function(category, action, label, value) {
			/* 
				category (required) String The name you supply for the group of objects you want to track. ex. 'Videos'
				action (required) String A string that is uniquely paired with each category, and commonly used to define the type of user interaction for the web object. ex. 'Play'
				label (optional) String An optional string to provide additional dimensions to the event data. ex. 'Baby\'s First Birthday'
				value (optional) Int An integer that you can use to provide numerical data about the user event. ex. 1 (added into a total in reporting)
			*/
			if(!this.s.track) return;
			for( var i = 0; i < this.s.UA.length; i++ ) {
				var pre = i == 0 ? '' : 't'+(i+1)+'.';
				window._gaq.push([pre+"_trackEvent", category, action, label, value]);
			}
		},

		track_transaction: function(items, transaction) {
			if(!this.s.track) return;
			for( var i = 0; i < this.s.UA.length; i++ ) {
				var pre = i == 0 ? '' : 't'+(i+1)+'.';
				
				for( var item_i = 0; item_i < items.length; item_i++ ) {
					this.add_item(items[item_i], pre);
				}
				_gaq.push([pre+'_addTrans',
					transaction[0],	// order ID - required
					transaction[1],	// affiliation or store name
					transaction[2],	// total - required
					transaction[3],	// tax
					transaction[4],	// shipping
					transaction[5],	// city
					transaction[6],	// state or province
					transaction[7]	// country
				]);
				
				_gaq.push([pre+'_trackTrans']);
			}
		},

		add_item: function(item, pre) {
			if(!this.s.track) return;
			_gaq.push([pre+'_addItem',
				item[0],	// order ID - required
				item[1],	// SKU/code - required
				item[2],	// product name
				item[3],	// category or variation
				item[4],	// unit price - required
				item[5]		// quantity - required
			  ]);
		}

	}

})(jQuery);
