/************************************************************************************
  Adds affiliate tracking info to Amazon and iTunes URLs and Google Analytic params
  to all other URLs
 
  Can also be used to add tracking info to  all absolute URLs on a page.
 
  Sample usage:
  <script src="http://static.sonybmgstore.com/tools/affiliatelinks.js"></script>
  <script>
    AffiliateLinks.setLabel("columbia");
    AffiliateLinks.setMedium("artistsite");    
    // set source to the domain of this web page
  </script>
  
  Sample usage 2: 
  <script src="http://static.sonybmgstore.com/tools/affiliatelinks.js"></script>
  <script>
    AffiliateLinks.setLabel("epic");
    // explicitly set medium, source, and campaign
    AffiliateLinks.setMediumSourceCampaign("website", "epicrecords.com", "grammys");    
  </script>
  
  If you add that javascript code to a page, an onload event loops through all the 
  links on the page and adds the tracking information. It skips relative URLs
  and "links" that call javascript functions. It also skips any URL that contains
  a parameter "skipaffiliate"
  
  You can register additional exclusion rules by calling AffiliateLinks.registerExclusion
  The exclusion can be one of:
  1. A RegExp 
  2. A string which should be converted into a RegExp
  3. A function
  
  Examples:
  AffiliateLinks.registerExclusion(new RegExp("^http://yahoo\\.com", "i")); // exclude Yahoo links
  AffiliateLinks.registerExclusion("aol\\.com"); // exclude any link that contains the string aol.com
  AffiliateLinks.registerExclusion( 
  	function(url) {   		
  		if( CUSTOM CONDITIONAL LOGIC ) {
  			// url should be excluded
  			return true;
  		}
  	}
  );
  
  
  Implementation notes:
  1. To add additional record labels, modify the Affiliate.accounts array
  2. The rewriting of URLs is handled by the REFORMATTERS array. 

  Author: Avery Gross
 
************************************************************************************/

String.prototype.trim = function () {
  return this.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1");
};

var AffiliateLinks = {
	setMediumSourceCampaign: function(medium, source, campaign) {
		AffiliateLinks.debug("setMediumSourceCampaign(" + medium + ", " + source + ", " + campaign + ")");
		if( medium != null ) AffiliateLinks.setMedium(medium);
		if( source != null ) AffiliateLinks.setSource(source);
		if( campaign != null ) AffiliateLinks.setCampaign(campaign);
	},
	setLabel: function(name) {
		if( AffiliateLinks.isBlank(name) ) return;
		name = name.toLowerCase().replace(/[^a-z0-9\-]/g, "");
		if( AffiliateLinks.accounts[name] != null ) {
			AffiliateLinks.label = name;
		}
		else {
			alert("No account found for: " + name);
		}
	},
	setMedium: function(medium) {
		AffiliateLinks.medium = AffiliateLinks.formatTrackingCode(medium);
	},
	setSource: function(source) {
		if( AffiliateLinks.RE_URL.test(source) ) {		
			source = AffiliateLinks.getDomain(source);	
		}
		AffiliateLinks.source = AffiliateLinks.formatTrackingCode(source);
		AffiliateLinks.debug("source set to " + AffiliateLinks.source);
	},	
	setCampaign: function(campaign) {
		AffiliateLinks.campaign = AffiliateLinks.formatTrackingCode(campaign);
	},
	setContentName: function(contentName) {
		AffiliateLinks.contentName = AffiliateLinks.formatTrackingCode(contentName);
	},
	setKeyword: function(keyword) {
		AffiliateLinks.keyword = AffiliateLinks.formatTrackingCode(keyword);
	},
	addTracking: function(url) {
		if( AffiliateLinks.isBlank(url) ) return url;
		url = url.trim();
		if ( !AffiliateLinks.RE_ABSOLUTE_URL.test(url) )	{
			return url;
		}
		else {
			var ioSlash = url.indexOf("/", 9);
			var ioQuestionMark = url.indexOf("?");
			var endDomain = ioSlash > 0 && (ioSlash<ioQuestionMark || ioQuestionMark < 0) ? ioSlash : ioQuestionMark;
			if( endDomain < 0 ) {
				url = url.toLowerCase();
			}
			else {
				url = url.substring(0, endDomain).toLowerCase() + url.substring(endDomain);
			}

		}
		return AffiliateLinks.applyFormatters(url);
	},
	isBlank: function(val) {
		if(val==null){return true;}
		for(var i=0;i<val.length;i++){
			if((val.charAt(i)!=' ')&&(val.charAt(i)!="\t")&&(val.charAt(i)!="\n")&&(val.charAt(i)!="\r")) {
				return false;
			}
		}
		return true;
	},
	getMedium: function() {
		if( AffiliateLinks.isBlank(AffiliateLinks.medium) ) return ""; 
		return AffiliateLinks.medium.indexOf("-") >= 0 ? AffiliateLinks.medium : AffiliateLinks.formatTrackingCode(AffiliateLinks.label) + "-" + AffiliateLinks.medium;
	},
	getSource: function() {
		return AffiliateLinks.source;
	},
	getTrackingCode: function() {
		var campaign = AffiliateLinks.campaign;
		if( campaign == null ) return "";
		if( campaign.indexOf("|") > 0 ) return campaign;
		var medium = AffiliateLinks.getMedium();
		var source = AffiliateLinks.getSource();	
		if( medium ==null && source == null ) return campaign;
		return medium + (source || campaign ? "|" + source + (campaign ? "|" + campaign : "") : "");
	},
	getLinkshareTrackingCode: function() {
		return this.getTrackingCode();
	},
	formatTrackingCode: function(s) {
		if( s == null ) return null;
		return s.toLowerCase().replace(AffiliateLinks.RE_FORMAT_TRACKING_CODE, "");
	},
	encode: function(s) {
		return escape(s);
	},
	decode: function(s) {
		return unescape(s.replace(/\+/g,  " "));
	},
	getAccount: function(name) {
		if( name == null ) return AffiliateLinks.accounts[AffiliateLinks.label];
		var account = AffiliateLinks.accounts[name];
		if( account == null ) {
			alert("No affiliate account information found for label " + name);
		}
		return account != null ? account : AffiliateLinks.account[AffiliateLinks.label];
	},
	addOrReplaceParam: function(url, paramName, paramValue) {
		if( new RegExp("[?&]"+ paramName + "=").test(url) ) {
			//AffiliateLinks.debug("URL already contains " + paramName + " url=" + url);
			return url.replace(new RegExp("([?&]"+ paramName + "=)[^&]*([&]?)"), "$1" + paramValue + "$2");
		}
		else {
			return url + (url.indexOf('?') > 0 ? "&" : "?") + paramName + "=" + paramValue;
		}
	},
	getParam: function(url, paramName) {
		var arr = new RegExp("[?&]" + paramName + "=" + "([^&]*)[&]?").exec(url);
		if( arr && arr.length > 1 ) {
			return arr[1];
		}
	},
	removeParam: function(url, paramName) {
		if( url == null ) return "";
		//AffiliateLinks.debug("Removing param " + paramName + " from url: " + url);
		return url.replace( new RegExp(paramName + "=" + "[^&]*&?", "g"), "").replace(/[?&\/]$/, "");
		//AffiliateLinks.debug("After removing param " + paramName + " from url: " + url);
	},
	debug: function(msg) {
		var debugDiv = document.getElementById("debug");
		if( debugDiv != null ) {
			debugDiv.innerHTML += msg + "<hr>";
		}
	},
	clearDebug: function() {
		var debugDiv = document.getElementById("debug");
		if( debugDiv != null ) {
			debugDiv.innerHTML = "";
		}
	},		
	addOnLoadEvent: function(func){
		var oldonload = window.onload;
		if (typeof window.onload != 'function') {
			window.onload = func;
		} else {
			window.onload = function() {
				oldonload();
				func();
			}
		}
	},
	applyFormatters: function(url) {
		//AffiliateLinks.debug("applyFormatters(url): url=" + url);
		for(var i=0; i< AffiliateLinks.REFORMATTERS.length; i++) {
			if( AffiliateLinks.REFORMATTERS[i].pattern.test(url) ) {
				//AffiliateLinks.debug("Applied reformatter #" + (i+1) + " pattern=" + AffiliateLinks.REFORMATTERS[i].pattern);
				return AffiliateLinks.REFORMATTERS[i].reformat(url);
			}
		}
		//AffiliateLinks.debug("Checked all " + AffiliateLinks.REFORMATTERS.length + " AffiliateLinks.REFORMATTERS. No match");
		return null;
	},	
	getDomain: function(url) {
		//AffiliateLinks.debug("Getting domaing from url: " + url);
		var arr = AffiliateLinks.RE_DOMAIN_FROM_URL.exec(url);
		if( arr == null || arr.length <= 0 ) {
			//AffiliateLinks.debug("No domain found for url: " + url);
			return null;
		}
		return arr[1].trim();
	},
	isLinkExcluded: function(link) {
		if( link == null || link.href == null ) return true;
		if( link.skipaffiliate ) return true; // note: only works on IE
		//AffiliateLinks.debug("Testing exclusions for link " + link.href);
		for(var i=0; i<AffiliateLinks.exclusions.length; i++) {
			//AffiliateLinks.debug("Testing exclusion index #" + i + ": " + AffiliateLinks.exclusions[i]);
			//alert("Testing exclusion index #" + i + ": " + AffiliateLinks.exclusions[i]);
			if( AffiliateLinks.exclusions[i].test(link.href) ) return true;
		}
		return false;
	},
	updateLinks: function() {
		AffiliateLinks.debug("<hr>**** Adding tracking to all links on the page ****");
		AffiliateLinks.debug(
			"label=" + AffiliateLinks.label
			+ " medium=" + AffiliateLinks.getMedium()
			+ " source=" + AffiliateLinks.getSource()
			+ " campaign=" + AffiliateLinks.getTrackingCode()
		);
		AffiliateLinks.debug("document.location.href=" + document.location.href + " domain=" + AffiliateLinks.getDomain(document.location.href));
		for(li in document.links) {
			if( !AffiliateLinks.isLinkExcluded(document.links[li] ) ) {			
				if( !document.links[li].oldhref ) {				
					document.links[li].oldhref = document.links[li].href;
				}			
				document.links[li].href = AffiliateLinks.addTracking(document.links[li].href);
				AffiliateLinks.debug("Link #" + (1+li*1) + ": old link=" + document.links[li].oldhref + " new link: " + document.links[li].href);
			}
		}
	},
	registerExclusion: function(rule) {
		AffiliateLinks.debug("Registering exclusion type=" + (typeof rule) + " rule=" + rule);
		//alert("Registering exclusion type=" + (typeof rule) + " rule=" + rule);
		var exclusion = null;
		if(typeof rule == "string") {
			exclusion = new RegExp(rule);		
		}
		else  {
			if( rule.test ) {
				exclusion = rule;
			}
			else {		
				exclusion = { test: function(url) { return rule(url)} };
			}
		}	
		AffiliateLinks.exclusions[AffiliateLinks.exclusions.length] = exclusion;
	},	
	registerDefaultExclusions: function() {
		// exclude URLs that contain a skipaffiliate parameter (case insensitive)
		AffiliateLinks.registerExclusion(new RegExp("[/?&]skipaffiliate", "i"));		
	},
	defaultOnLoad: function() {
		AffiliateLinks.updateLinks();		
	},	
	defaultOnLoadHook: function() {
		AffiliateLinks.defaultOnLoad();
	},
	init: function() {	
		AffiliateLinks.accounts["columbia"] = {amazon_account: 'columbia_records-20', linkshare_account: 'CTiugamq7cM'}
		AffiliateLinks.accounts["d2c"] = {amazon_account: 'gdbdirect-20', linkshare_account: 'VAfS58hgrRU'}
		AffiliateLinks.accounts["epic"] = {amazon_account: 'epicrecords-20', linkshare_account: 'x87i2Q2WuTk'}
		//AffiliateLinks.accounts["j-records"] = {amazon_account: 'j_records-20', linkshare_account: 'W3RlldWcIOU'}
		AffiliateLinks.accounts["jive"] = {amazon_account: 'jive-20', linkshare_account: 'KtsYJHHpUV8'}		
		AffiliateLinks.accounts["latin"] = {amazon_account: 'sbmglatin-20', linkshare_account: 'VAfS58hgrRU'}
		AffiliateLinks.accounts["legacy"] = {amazon_account: 'legacy_recordings-20', linkshare_account: 'LNxp/3YMBs0'}
		AffiliateLinks.accounts["masterworks"] = {amazon_account: 'masterworks-20', linkshare_account: 'LNxp/3YMBs0'}
		AffiliateLinks.accounts["nashville"] = {amazon_account: 'sonybmg_nashville-20', linkshare_account: 'BlerbFnmTXg'}
		AffiliateLinks.accounts["provident"] = {amazon_account: 'provident-20', linkshare_account: '4riB6Q8of1U'}		
		AffiliateLinks.accounts["rca"] = {amazon_account: 'rca-20', linkshare_account: 'RGwXLtiwlbk'}
		AffiliateLinks.accounts["victor"] = {amazon_account: 'cmg-20', linkshare_account: 'LNxp/3YMBs0'}
		//AffiliateLinks.accounts["red"] = {amazon_account: 'gdbdirect-20', linkshare_account: 'VAfS58hgrRU'}
		AffiliateLinks.REFORMATTERS[AffiliateLinks.REFORMATTERS.length] = {
			/*
			 * Linkshare link. Swap out the "id" parameter (the affiliate account)
			 * and add/replace the u1 [campaign tracking code] parameter
			 */
			pattern: new RegExp("^http://click.linksynergy\\.com/fs-bin/(click|stat)", "i"),
			reformat: function (url) {
				url = AffiliateLinks.addOrReplaceParam(url, "id", AffiliateLinks.getAccount().linkshare_account);
				url = AffiliateLinks.addOrReplaceParam(url, "u1", AffiliateLinks.getLinkshareTrackingCode());
				return url;
			}
		};
		AffiliateLinks.REFORMATTERS[AffiliateLinks.REFORMATTERS.length] = {
			/*
			 * iTunes new format e.g. http://itunes.apple.com/us/album/leave-this-town/id320054021
			 */
			pattern:
			new RegExp("^http://itunes\\.apple\\.com/([^/]*/)?album/([^/]*/)?id[0-9]+"),
			reformat: function (url) {
				var account = AffiliateLinks.getAccount();
				var trackingCode = AffiliateLinks.getLinkshareTrackingCode();
				var offerID = account.itunesOfferId ? account.itunesOfferId : AffiliateLinks.DEFAULT_ITUNES_OFFER_ID;
				//alert(url);
				var albumID = new RegExp("^http://itunes\\.apple\\.com/([^/]*/)?album/([^/]*/)?id([0-9]+)").exec(url)[3];
				var songID = AffiliateLinks.getParam(url, "i");
				var trackingURL = "http://click.linksynergy.com/fs-bin/stat?id="
					+ account.linkshare_account
					+ "&u1=" + trackingCode
					+ "&offerid=" + offerID
					+ "&type=3&subid=0&tmpid=1826&RD_PARM1=http%253A//itunes.apple.com/WebObjects/MZStore.woa/wa/viewAlbum%253Fid%253D"
					+ albumID;
				if( songID) {
					trackingURL += "%2526i%253D" + songID;
				}
				//alert("Tracking URL: " + trackingURL);
				return trackingURL;
			}
		};
		AffiliateLinks.REFORMATTERS[AffiliateLinks.REFORMATTERS.length] = {
			/*
			 * iTunes
			 */
			pattern:
			new RegExp("^http://((phobos|itunes)\\.apple\\.com|ax\\.(phobos|itunes)\\.apple\\.com\\.edgesuite\\.net)"),
			reformat: function (url) {
				var account = AffiliateLinks.getAccount();
				var trackingCode = AffiliateLinks.getLinkshareTrackingCode();
				var offerID = account.itunesOfferId ? account.itunesOfferId : AffiliateLinks.DEFAULT_ITUNES_OFFER_ID;
				return "http://click\.linksynergy\.com/fs-bin/stat?id="
					+ account.linkshare_account
					+ "&u1=" + trackingCode
					+ "&offerid=" + offerID
					+ "&type=3&subid=0&tmpid=1826&RD_PARM1="
					+ AffiliateLinks.encode(AffiliateLinks.encode(url));
			}
		};
		AffiliateLinks.REFORMATTERS[AffiliateLinks.REFORMATTERS.length] = {
			/*
			 * Amazon link that already has an affiliate tracking code
			 */
			pattern: new RegExp("^http[s]?://(www\\.)?amazon\\.com.*[?&/]tag="),
			reformat: function (url) {
				return url.replace(/([/&?]tag=)[^/&]*([/&]?)/, "$1" + AffiliateLinks.getAccount().amazon_account + "$2");
			}
		};
		AffiliateLinks.REFORMATTERS[AffiliateLinks.REFORMATTERS.length] = {
			/*
			 * Regular Amazon link (no existing tracking code)
			 * AffiliateLinks MUST be listed after the version with the tracking code!!!
			 */
			pattern: new RegExp('^https?://(www\\.)?amazon\\.com'),
			reformat: function (url) {
				return "http://www.amazon\.com/gp/redirect.html?ie=UTF8&location="
					+ AffiliateLinks.encode(url)
					+ "&tag=" + AffiliateLinks.getAccount().amazon_account
					+ "&linkCode=ur2&camp=1789&creative=9325";
			}
		};
		AffiliateLinks.REFORMATTERS[AffiliateLinks.REFORMATTERS.length] = {
			/*
			 * Add/replace the google analytic params on all other URLS.
			 *
			 * NOTE: AffiliateLinks entry must be listed after all others!!!
			 */
			pattern:
			new RegExp("^http"), // match any other absolute URL
			reformat: function (url) {
				if( !AffiliateLinks.isBlank(AffiliateLinks.medium) ) {
					//AffiliateLinks.debug("Adding utm_medium=" + AffiliateLinks.getMedium() + " to " + url);
					url = AffiliateLinks.addOrReplaceParam(url, "utm_medium", AffiliateLinks.getMedium());
				}
				else {
					url = AffiliateLinks.removeParam(url, "utm_medium");
				}
				if( !AffiliateLinks.isBlank(AffiliateLinks.source) ) {
					//AffiliateLinks.debug("Adding utm_source=" + AffiliateLinks.getSource() + " to " + url);
					url = AffiliateLinks.addOrReplaceParam(url, "utm_source", AffiliateLinks.getSource());
				}
				else {
					//AffiliateLinks.debug("Removing utm_source from " + url);
					url = AffiliateLinks.removeParam(url, "utm_source");
				}
				if( !AffiliateLinks.isBlank(AffiliateLinks.campaign) ) {
					url = AffiliateLinks.addOrReplaceParam(url, "utm_campaign", AffiliateLinks.getTrackingCode());
				}
				else {
					//AffiliateLinks.debug("Removing utm_campaign from " + url);
					url = AffiliateLinks.removeParam(url, "utm_campaign");
				}
				// if keyword or content set, add/replace values in URL. 
				// If not set, keep current value
				if( !AffiliateLinks.isBlank(AffiliateLinks.contentName) ) {
					url = AffiliateLinks.addOrReplaceParam(url, "utm_content", AffiliateLinks.contentName);
				}
				if( !AffiliateLinks.isBlank(AffiliateLinks.keyword) ) {
					url = AffiliateLinks.addOrReplaceParam(url, "utm_keyword", AffiliateLinks.keyword);
				}
				//AffiliateLinks.debug("Returning url: " + url);
				return url;
			}
		};		
		
		// set defaults
		AffiliateLinks.setLabel("d2c");
		AffiliateLinks.setMedium("website");
		AffiliateLinks.setSource(document.location.href);
		AffiliateLinks.registerDefaultExclusions();		
		AffiliateLinks.addOnLoadEvent(AffiliateLinks.defaultOnLoadHook);
		
	}, // end init function
	RE_URL:  new RegExp("://|^www\\.|\\.com$|\\.com[?/]", "i"),
	RE_ABSOLUTE_URL: new RegExp("^http[s]?://", "i"),
	RE_FORMAT_TRACKING_CODE: new RegExp("\\.com$|[^A-Za-z0-9\\.]", "g"),
	RE_DOMAIN_FROM_URL: new RegExp("^(?:[^:]*://)?(?:www\\.)?([^/?]*)(?:(?:\\.com)?[/?])?"),
	DEFAULT_ITUNES_OFFER_ID: 78941,	
	/*
	 * The affiliate account information for each label
	 */
	accounts: new Array(),
	/*
	 * The REFORMATTERS array handles the rewriting. 
	 * 
	 * Each element includes two properties:
	 * pattern: A regular expression of URLs that it handles
	 * reformat: The function that adds the tracking info to the URL
	 *
	 * It is initialized in the init() method
	 */
	REFORMATTERS: new Array(),
	exclusions: new Array()
} // end AffiliateLinks declaration

AffiliateLinks.init();