if (typeof(Patron) == "undefined") {
	Patron = {
		_adDefinitionArray: new Array(),

		// do an explicit init so that the tests can
		// zap everything and start over.
		init: function() {
			// config
			this.displayAds = true;
			this.inQA       = 'false' == 'true';

			// targting vars
			this.zone  = null; // MUST be set or ads won't work.
			this.ord   = this.generateOrd();
			this.ag    = "0";
			this.gnd   = "0";
            this.zip   = "";
            this.site  = "default";
			this.genre = null;
			this.tile  = 0;
			
			if( document.cookie != null && document.cookie.match(/v3ad=(\d+):(\d+):(\d+):(\d*)/) ) {
				this.displayAds = RegExp.$1 != '0';
				this.ag  = RegExp.$2;
				this.gnd = RegExp.$3;
                this.zip = RegExp.$4;
            }
	
			if( document.cookie != null && document.cookie.match(/v2pub=(\w+)/) ) {
				this.site = RegExp.$1;
			}
		},
	
		setZone: function(zone) {
			this.zone = zone;
		},
		
		setSite: function(site) {
			this.site = site;
		},

		setProfile: function(cookieValue) {
			var date = new Date();
			date.setTime(date.getTime()+(30*24*60*60*1000));	// 30 days
			var cookieStr = "v3ad=" + cookieValue + "; ";
			cookieStr += "expires=" + date.toGMTString() + "; ";
			cookieStr += "path=/; ";
			if (document.domain != null && document.domain.match(/pandora.com$/) ) {
				cookieStr += "domain=.pandora.com;";
			}
			document.cookie = cookieStr;

			// reset vars for future embeds
			var args = cookieValue.split(":");
			this.displayAds = String(args[0]) != '0';
			this.ag         = args[1];
			this.gnd        = args[2];
            this.zip        = args[3];
        },
		
		setQA: function(bool) {
			this.inQA = bool;
		},
		
		getDisplayAds: function() {
			return this.displayAds;
		},
		
		cacheGenre: function(genre) {
			this.genre = genre;
		},

		generateOrd: function() {
			return new Date().getTime() + "" + Math.floor(Math.random()*1000000);
		},
		
		generateEmbedUrl: function(path, options) {
			if (options == null)
				options = {};

			if (options.ord == null)
				options.ord = this.ord;

			if (options.genre != null) {
				// a new genre is specified.  We need to cache it.  (RADIO-4126)
				this.cacheGenre(options.genre);
			} else if (this.genre != null) {
				// see if we have a cached genre around
				options.genre = this.genre;
			}

			if (window.location.search != null && window.location.search.match(/patron=([^&]+)/)) {
				options.patron = RegExp.$1;
			}

			var pairs = [];
			for (var n in options) {
				pairs[pairs.length] = n + "=" + options[n];
			}
			
			return path + "?" + pairs.join('&');
		},

		insertIFrame: function(id, width, height, options, embedPrefix) {

			if (!this.displayAds)
				return;

			// if zone isn't set, it's an error.  The zone must be set.
			if (this.zone == null)
				return;
			
			document.write(this.generateIFrame(id, width, height, options, embedPrefix));
		},

		generateIFrame: function(id, width, height, options, embedPrefix) {
			if (!options)
				options = {};

			options.sz = width + "x" + height;
			if (options.tile == null)
				options.tile = ++this.tile;

			if (embedPrefix == null)
				embedPrefix = this.zone;

			var url = this.generateEmbedUrl("/include/" + embedPrefix + "AdEmbed.html", options);

			if (options.sz == "2000x8") {
				// not the real size...
				width = 728;
				height = 90;
			}

			if (options.sz == "2000x9" || options.sz == "2000x10") {
				// promotional gallery links - actual iframe dimensions
				width = 300;
			    height = 32;
			}

			// unique ids are necessary to prevent Safari caching bugs
			var unique = id + (new Date().getTime());
			var iframe = '<div id="' + id + '">'
			               + '<iframe id="' + unique +'" '
			               + 'src="' + url + '" '
			               + 'frameborder=0 marginheight=0 marginwidth=0 '
			               + 'scrolling="no" allowTransparency="true" '
			               + 'width="' + width + '" '
			               + 'height="' + height + '"></iframe></div>';

			this._adDefinitionArray.push(
			{
				unique: unique,
				options: options
			});

			return iframe;
		},

		// fetch and paint new ads for the backstage page
		refreshAds: function(){
			//regenerate the ord
			this.ord   = this.generateOrd();

			for (var i = 0; i < this._adDefinitionArray.length; i++){
				var adDefinition = this._adDefinitionArray[i];

				if (adDefinition.options == null){
					adDefinition.options = {};
				}

				// use the new ord
				adDefinition.options.ord = this.ord;

				var url = this.generateEmbedUrl("/include/" + this.zone + "AdEmbed.html", adDefinition.options);
				
				this.setIFrameURL(adDefinition.unique, url);
			}
		},

		setIFrameURL: function(iframeID, url){
			$("#" + iframeID).attr("src", url);
		},

		updateTargetingOptions: function(options) {
			if (!this.displayAds)
				return null;

			// if zone isn't set, it's an error.  The zone must be set.
			if (this.zone == null)
				return null;

			if (!options)
				options = {};

			options.ord   = this.ord;
			options.ag    = this.ag;
			options.gnd   = this.gnd;
            options.zip   = this.zip;

			return options;
		},

		// used for customization of stationa and advertiser pages
		insertScript: function(width, height, options) {
			options = this.updateTargetingOptions(options);
			if (options == null) return;

			options.sz = width + "x" + height;
			if (options.tile == null)
				options.tile = ++this.tile;
			
			if (options.ord == null)
				options.ord = this.ord;

			var url = this.generateDCUrl(options, "adj");

			document.write('<script src="' + url + '"><\/script>');
		},
		
		// Used for blog leaderboards.
		// Not capable of supporting expandables.
		insertDCFrame: function(id, width, height, options) {
			options = this.updateTargetingOptions(options);
			if (options == null) return;
			
			options.sz = width + "x" + height;
			if (options.tile == null)
				options.tile = ++this.tile;
			
			if (options.ord == null)
				options.ord = this.ord;

			var url = this.generateDCUrl(options, "adi");
			
			// need a unique ID on the IFrame for Safari
			var adId = "ad" + (new Date().getTime());
			html = '<iframe src="' + url + '" id="' + adId + '" ' +
				   'frameborder="0" scrolling="no" marginheight="0" marginwidth="0" ' +
				   'topmargin="0" leftmargin="0" allowtransparency="true" width="' + width + '" ' +
				   'height="' + height + '"></iframe>';

			document.write('<div id="' + id + '">' + html + '</div>');
		},
		
		generateDCUrl: function(options, embedType) {

			// split things up to dete blockers
			var url = 'http://a'+'d.doublecl'+'ick.net/' + embedType + '/pand.';
		
			url += this.site;
			url += "/";
			url += this.inQA ? "test" : "prod";
			url += ".";
			url += this.zone;

			for (var n in options) {
				if (n != "sz" && n != "ord" && n != "tile" && options[n] != null && options[n] !== "") {
					url += ";" + n + "=" + options[n];
				}
			}

			// sz, tile, and ord need to be last on the URL according
			// Dart docs.  ord must be very last!  RADIO-4408
			url += ";sz=" + options.sz;
			if (options.tile != null)
				url += ";tile=" + options.tile;
			url += ";ord=" + options.ord;

			return url;
		},

		// for use within an embedded IFrame.  "private" -- do not call directly.
		insertAd: function(options) {
			options = this.updateTargetingOptions(options);
			if (options == null) return;

			// sz is determined from the URL
            if(window.location.search != null && window.location.search.length > 1) {
				var query = window.location.search.substr(1);
				var pairs = query.split("&");
				for (var i = 0; i < pairs.length; i++) {
					var tuple = pairs[i].split("=");
					
					// skip vars that begin with _ so you can optionally avoid
					// inclusion in the options hash.
					if (tuple[0].charAt(0) != '_') {
						options[tuple[0]] = tuple[1];
					}
				}
			}			

			var url = this.generateDCUrl(options, "adj");
			
			document.write('<script src="' + url + '"><\/script>');
		}
	};
	
	Patron.init();
}
