(function($) {

function MediaAsset(o, media) {
	MAX_HERO_WIDTH = 469;
	MAX_HERO_HEIGHT = 264;
	MAX_THUMBNAIL_WIDTH = 64;
	MAX_THUMBNAIL_HEIGHT = 48;
	MAX_AVATAR_WIDTH = 27;
	MAX_AVATAR_HEIGHT = 27;
	
	var self = this;
	
	this.id = function() { return this.visibleType() + '-' + media.reference };
	this.anchor = function() { return '#' + this.id() };
	this.reference = function() { return media.reference };
	this.adType = function() { return this.visibleType() };
	
	this.thumbnail = function() {
		return $('<div class="mediaThumb" />').append(this.thumbnailImage());
	};
	
	this.hero = function() {
		return "";
	};
	
	this.avatarImage = function() {
		if ((media.logo == null) || (media.logo == "") || (media.logo.toLowerCase() == "None".toLowerCase())) {
			return "";
		}
		else if (media.logo.toLowerCase() == "Lonely Planet".toLowerCase()) {
			return loadImage(this._placeholderImage('Lonely Planet media'),
				o.avatarBaseUrl + '/authorLp-27x27.gif', MAX_AVATAR_WIDTH, MAX_AVATAR_HEIGHT);
		}
		else if (media.logo.toLowerCase() == "BBC".toLowerCase()) {
			return loadImage(this._placeholderImage('BBC media'),
				o.avatarBaseUrl + '/authorBBC-27x27.gif', MAX_AVATAR_WIDTH, MAX_AVATAR_HEIGHT);
		}
	};
	
	this.credit = function() {
		var credit = $('<div class="mediaCredit" />');
		credit.append(this.avatarImage());
		var details = $('<ul />');
        details.append($('<li class="name" />').text(media.credit));
        details.append($('<li class="position" />').text(media.creditTitle));
        credit.append(details);
        return credit;
	};
	
	this.details = function() {
		var detail = $('<div class="mediaDetails" />');
		return detail;
	};
	
	var loaded = false;
	var loadCallbacks = null;
	this.load = function(callback) {
		callback = callback || function() { };
		if (loaded) {
			callback.call(self);
			return;
		}
		if (loadCallbacks != null) {
			loadCallbacks.push(callback);
			return;
		}
		loadCallbacks = [callback];
		this._load(function() {
			loaded = true;
			$.each(loadCallbacks, function(i,callback) { callback.call(self) });
			loadCallbacks = null;
		});
	};
	
	this.contentRendered = function(content, o, data) { };
		
	this._placeholderImage = function(alt) {
		return $(new Image()).attr('alt', alt);
	};
	
	this._loadHeroImage = function(image, src) {
		return loadImage(image, src, MAX_HERO_WIDTH, MAX_HERO_HEIGHT);
	};
	
	this._loadThumbnailImage = function(image, src) {
		return loadImage(image, src, MAX_THUMBNAIL_WIDTH, MAX_THUMBNAIL_HEIGHT);
	};
	
	function loadImage(image, src, maxWidth, maxHeight) {
		return image.backgroundLoadImage(src, function() {
			image.centerImageToBox(maxWidth, maxHeight);
		});
	};
}


function LPIImageAsset(o, media) {
	HERO_FILENAME = '469x264.jpg';
	THUMBNAIL_FILENAME = '64x48.jpg';
	IMAGE_FILENAME = '681x454.jpg';
	
	var self = this;

	var mediaCredit = "";
	
	if(!( (media.logo == null) || (media.logo == "")
			|| (media.logo.toLowerCase() == "None".toLowerCase())))
	{
		mediaCredit = media.logo + " ";
	}
	
	media = $.extend({
		creditTitle: mediaCredit + 'Photographer'
	}, media);
	
	MediaAsset.call(this, o, media);
	var refParts = media.reference.split('-', 2);
	var imageBaseUrl = o.lpiBaseUrl + '/' + refParts[0] + '/' + media.reference + '/';
	var imageGlobalBaseUrl = o.lpiGlobalBaseUrl + '/' + refParts[0] + '/' + media.reference + '/';
	var licenseUrl = o.lpiLicenseUrlTemplate.replace(/\[LPIAssetNumber\]/, refParts[0].leftPad(7, '0') + 'X' + refParts[1].leftPad(4, '0'));
	
	this.visibleType = function() { return 'photo' };
	
	var baseHero = this.hero;
	this.hero = function() {
		var infoIcon = $('<div class="infoIcon pngfix" />');
		var heroContent = $('<div class="mediaHero" />').append(this.heroImage()).append(infoIcon);
		var overlay = $('<div class="overlay" />');
		overlay.append($('<div class="mbGalleryOpen">View gallery</div>').openOnClick(this.anchor()));
		overlay.append(this.details());
		heroContent.append(overlay);
		overlay.infoHover({
			beforeShow: function() { infoIcon.stop(true, true).fadeOut('normal') },
			beforeHide: function() { infoIcon.stop(true, true).fadeIn('normal') }
		});
		return heroContent;
	};
	
	var baseDetails = this.details;
	this.details = function() {
		var detail = baseDetails.call(this).append($('<p class="caption" />').text(media.caption)).append(this.credit());
		return detail;
	};
	
	this.heroImage = function() {
		return this._loadHeroImage(this._placeholderImage(media.caption), imageBaseUrl + HERO_FILENAME);
	};
	
	this.thumbnailImage = function() {
		return this._loadThumbnailImage(this._placeholderImage(media.caption), imageBaseUrl + THUMBNAIL_FILENAME);
	};
	
	this.image = function(callback) {
		return this._placeholderImage(media.caption).backgroundLoadImage(imageBaseUrl + IMAGE_FILENAME, callback);
	};
	
	this.content = function(maxWidth, maxHeight, link) {
		var image = this.image(function() {
			$(this).centerImageToBox(maxWidth, maxHeight);
		});
		
		var content = $('<div class="imageAsset" />').css({width: maxWidth, height: maxHeight});
		content.append(image);
		var infoIcon = $('<div class="infoIcon pngfix" />');
		content.append(infoIcon)
		if (link)
			image.css({cursor: 'pointer'}).openOnClick(link);
		var overlay = buildContentOverlay();
		content.append(overlay);
		overlay.infoHover({
			beforeShow: function() { infoIcon.stop(true, true).fadeOut('normal') },
			beforeHide: function() { infoIcon.stop(true, true).fadeIn('normal') }
		});
		return content;
	};
	
	this.contentRendered = function(content, o, data) {
		if (data.imageAssetRendered === undefined) {
			data.imageAssetRendered = true;
			content.find('.overlay').infoHover('reveal', 3000);
		}
	};

	this.pictopiaUrl = function() {
		return o.pictopiaBaseUrl + '/lonelyplanet/e/?' 
			+ 'photo_name=' + escape(media.reference)
			+ '&caption=' + escape(media.caption)
			+ '&t_url=' + escape(imageGlobalBaseUrl + IMAGE_FILENAME)
			+ '&photographer=' + escape(media.credit);
	};
	
	this._load = function(callback) {
		this.image(callback);
	};
	
	function buildContentOverlay() {
		var copyright = $('<p class="copyright">&copy; Copyright Lonely Planet Images 2008</p>');
		var pictopiaLink = $('<a class="pictopia-link hoverfix pngfix" target="_blank">Buy a print of this photo</a>').attr('href', self.pictopiaUrl());
		var licenseLink = $('<a class="license-link linkChevron" target="_blank">License this image</a>').attr('href', licenseUrl);
		var relatedLinks = $('<ul />');
		relatedLinks.append($('<li />').append(licenseLink));
		
		pictopiaLink.click(function() {
			//notify omniture
			s.tl(this, 'o', s.pageName + ' : Buy Print');
		});

		var related = $('<div class="related" />').append(pictopiaLink).append(relatedLinks);
		return $('<div class="overlay" />').append(self.details().append(copyright)).append(related);
	};
	
	function omnitureNotifyPictopiaBuy() {
		void(s.tl(this, 'o', s.pageName + ' : Buy Print'));
	};
}
LPIImageAsset.prototype = new MediaAsset();
LPIImageAsset.prototype.constructor = LPIImageAsset;


function BCVideoAsset(o, media, resourceLoader) {
	var self = this;
	
	media = $.extend({
		creditTitle: 'Producer'
	}, media);
	if (media.related_links) {
		$.each(media.related_links, function(i, link) { media.related_links[i] = $.extend({external_link: 'true'}, link); });
	}
	
	MediaAsset.call(this, o, media);
	
	this.visibleType = function() { return 'video' };
	
	var baseThumbnail = this.thumbnail;
	this.thumbnail = function() {
		return baseThumbnail.call(this).append('<span class="video pngfix" />');
	};
	
	var baseHero = this.hero;
	this.hero = function() {
		var infoIcon = $('<div class="infoIcon pngfix" />');
		var heroContent = $('<div class="mediaHero videoAsHero" />').append(this.heroImage()).append(infoIcon);
		var overlay = $('<div class="overlay" />');
		overlay.append(this.details());
		heroContent.append(overlay);
		overlay.infoHover({
			beforeShow: function() { infoIcon.stop(true, true).fadeOut('normal') },
			beforeHide: function() { infoIcon.stop(true, true).fadeIn('normal') }
		});
		return heroContent.append('<span class="video pngfix" />');
	};
	
	var baseDetails = this.details;
	this.details = function() {
		var detail = baseDetails.call(this).append($('<p class="caption" />').text(media.title)).append(this.credit());
		return detail;
	};
	
	this.heroImage = function() {
		var image = this._placeholderImage(media.title);
		resourceLoader.loadByReference(media.reference, function(data) {
			self._loadHeroImage(image, data.videoStillURL);
		});
		return image;
	};
	
	this.thumbnailImage = function() {
		var image = this._placeholderImage(media.title);
		resourceLoader.loadByReference(media.reference, function(data) {
			self._loadThumbnailImage(image, data.thumbnailURL);
		});
		return image;
	};
	
	this.content = function(maxWidth, maxHeight) {
		var content = $('<div class="videoAsset" />');
		content.append($('<h2 />').text(media.title));
		content.append($('<p />').text(media.caption));
		content.append(this.credit());
		
		if (media.related_links != null) {
			var relatedLinksHtml = $('<ul class="related"/>');
			var external_links = this._externalRelatedLinks();
			$.each(external_links, function(i, related_link) {
				var relatedLinkHtml = $('<a class="linkChevron" />').html(related_link.title).attr('href', related_link.related_url).attr('target', '_blank');
				relatedLinksHtml.append($('<li />').append(relatedLinkHtml));
			});
			relatedLinksHtml.find('li:last').addClass('endListItem');
			
			var internal_links = this._internalRelatedLinks();
			$.each(internal_links, function(i, related_link) {
				var relatedLinkHtml = $('<a class="linkChevron" />').html(related_link.title).attr('href', related_link.related_url);
				relatedLinksHtml.append($('<li />').append(relatedLinkHtml));
			});
			content.append(relatedLinksHtml);
		}
		
		return content;
	};
	
	this.contentRendered = function(content, o) {
		o.videoPlayer.bcVideoPlayer('play', media.reference);
	};
	
	this._load = function(callback) {
		callback();
	};
	
    this._internalRelatedLinks = function() {
        return $.grep(media.related_links, function(link) { return !link.external_link });
    };

    this._externalRelatedLinks = function() {
        return $.grep(media.related_links, function(link) { return link.external_link });
    };
}
BCVideoAsset.prototype = new MediaAsset();
BCVideoAsset.prototype.constructor = BCVideoAsset;

$.widget('lp.mediaBlock', {
	_init: function() {
		var self = this, o = this.options;
		// create our own callback rather than using JQuery's jsonp generated one so that it's cacheable
		window['_lpmb'] = function(data) { self._setup(data) };
		$.ajax({
			type: 'GET',
			url: o.collectionUrl + ((o.collectionUrl.indexOf('?') < 0)? '?':'&') + 'callback=_lpmb',
			dataType: 'script',
			cache: true
		});
		
		$(document).ready(function() {
			$(window).hashchange(function() { self._notifyHashChange() });
			self._notifyHashChange();
		});
	},
	
	_setup: function(data) {
		var self = this, div = this.element, o = this.options;
		
		o = this.options = $.extend(this._calculateOptionDefaults(), o);
		
		if (data.collection == null) return;
		
		var assets = this._assets = self._constructAssets(data.collection.medias);
		if (assets.length == 0) return;
		
		self.element.addClass('mediaBlock').addClass(o.style);
		
		div.append(self._buildHero(assets[0]));
		var mbThumbs = self._buildThumbs(assets.slice(1, o.thumbnails+1));
		mbThumbs.append($('<div class="mbGalleryOpen">View gallery</div>').openOnClick(assets[0].anchor()));
		div.append(mbThumbs);
		
		div.find('.pngfix').ie6PNGFix();
		div.find('.hoverfix').ie6HoverFix();
		
		o.bcResourceLoader.process();
	},
	
	_calculateOptionDefaults: function() {
		var o = this.options;
		var defaults = {
			bcResourceLoader: new BrightcoveResourceLoaderCache(new BrightcoveBatchResourceLoader(o.bcServicesUrl, o.bcToken)),
			thumbnails: 6
		};
		switch (o.style) {
		case 'medium':
			defaults.thumbnails = 5;
			break;
		}
		return defaults;
	},
	
	assets: function() {
		return this._assets;
	},
	
	lightbox: function() {
		return this._initLightbox();
	},
	
	_notifyHashChange: function() {
		var self = this, assets = this._assets;
		if (!assets || assets.length == 0) return;
		var hash = location.hash.replace(/^#/, '');
		
		if (this._lightbox == null) {
			// initialize the lightbox iff the hash is for an asset
			var asset = $.first(assets, function(i,asset) { return asset.id() == hash });
			if (asset == null)
				return;
			this._initLightbox();
		}
	},
	
	_constructAssets: function(medias) {
		var self = this, o = this.options;
		return $.map(medias, function(media) {
			switch(media.media_type) {
			case 'LPI-IMAGE': return new LPIImageAsset(o, media);
			case 'BC-VIDEO': return new BCVideoAsset(o, media, o.bcResourceLoader);
			default: return null;
			}
		});
	},
	
	_buildHero: function(asset) {
		var self = this, o = this.options;
		return asset.hero().addClass('mbHero').openOnClick(asset.anchor());
	},
	
	_buildThumbs: function(assets) {
		var self = this, o = this.options;
		var list = $('<ul />');
		$.each(assets, function(i, asset) {
			var thumb = asset.thumbnail().openOnClick(asset.anchor());
			list.append($('<li />').append(thumb));
		});
		return $('<div class="mbThumbs" />').append(list);
	},
	
	_initLightbox: function() {
		var o = this.options;
		if (this._lightbox == null) {
			this._lightbox = $('<div />');
			$('body').append(this._lightbox);
			this._lightbox.mediaLightbox($.extend(o, {
				title: o.lightboxTitle,
				assets: this._assets
			}));
		}
		return this._lightbox;
	}
});
		
		
$.extend($.lp.mediaBlock, {
	defaults: {
		style: 'wide'
	}
});


$.widget('lp.mediaLightbox', {
	_init: function() {
		var self = this, div = this.element, o = this.options;
		this._isOpen = false;
		this._selectedAsset = null;
		
		if (o.assets.length == 0) return;
		
		div.addClass('mediaLightbox').hide();
		var container = $('<div class="mlContainer" />');
		container.append(this._buildHead());
		container.append(this._buildContent());
		container.append(this._buildFilmstrip());
		container.append(this._buildFoot());
		div.append(container);
		
		div.find('.arrow').ie6HoverFix();

		div.openOnClick('');
		// stop clicks within the lightbox itself propagating to the lightBoxDiv.click above
		container.click(function(event) { event.stopPropagation() });
		
		this._mediaFader.mediaFader(this.options);
		this._filmstrip.mediaFilmstrip($.extend(o, {assets: o.assets}));
		
		o.bcResourceLoader.process();
		
		$(document).ready(function() {
			$(window).hashchange(function() { self._notifyHashChange() });
			self._notifyHashChange();
		});
	},
	
	showAsset: function(asset, callback) {
		var o = this.options;
		callback = callback || function() { };
		if (asset == this._selectedAsset) return this._open(callback);
		this._selectedAsset = asset;
		var assetIdx = $.inArray(asset, o.assets);

		this._preloadAssets(assetIdx);
		this._updateControls(assetIdx);
		this._mediaFader.mediaFader('displayAsset', this._selectedAsset, (assetIdx < o.assets.length-1)? o.assets[assetIdx+1] : null);

		this._open(function() {
			this._filmstrip.mediaFilmstrip('selectAsset', this._selectedAsset, assetIdx);
			this._updateAds();
			this._omnitureNotifyView();
		});
	},
	
	_notifyHashChange: function() {
		var self = this, assets = this.options.assets;
		if (!assets || assets.length == 0) return;
		var hash = location.hash.replace(/^#/, '');
		
		var asset = $.first(assets, function(i,asset) { return asset.id() == hash });
		if (asset) {
			this.showAsset(asset);
		} else {
			this.close();
		}
	},
	
	_open: function(callback) {
		var self = this, div = this.element, o = this.options;
		callback = callback || function() { };
		
		if (this._isOpen) return callback.call(self);
		this._isOpen = true;
		
		o.beforeOpen.call(div);
		scroll(0,0);
		
		$('body').addOverlay({}, function() {
			div.fadeIn('normal', function () { callback.call(self) });
		});
	},
	
	close: function(callback) {
		var self = this, o = this.options;
		callback = callback || function() { };
		
		if (!this._isOpen) return callback.call(self.element);
		this._isOpen = false;
		
		this._selectedAsset = null;
		this._removeAds();
		this._mediaFader.mediaFader('notifyHide');
		
		self.element.fadeOut('normal', function() {
			$('body').removeOverlay();
			o.afterClose.call(self.element);
			return callback.call(self.element);
		});
	},
	
	_buildHead: function() {
		var o = this.options;
		var head = $('<div class="mlHead" />');
		head.append($('<p class="title" />').text(o.title));
		head.append($('<div class="close" />').openOnClick(''));
		if (o.adZone != undefined) {
			this._sponsorAd = $('<div class="sponsor" />');
			head.append(this._sponsorAd);
		}
		return head;
	},
	
	_buildContent: function() {
		var content = $('<div class="mlContent" />');
		this._lhsControl = $('<div class="arrow disabled" />');
		content.append($('<div class="control control-lhs" />').append(this._lhsControl));
		this._mediaFader = $('<div class="media" />');
		content.append(this._mediaFader);
		this._rhsControl = $('<div class="arrow" />');
		content.append($('<div class="control control-rhs" />').append(this._rhsControl));		
		return content;
	},
	
	_buildFilmstrip: function() {
		var o = this.options;
		this._filmstrip = $('<div class="mlFilmstrip" />');
		return this._filmstrip;
	},
	
	_buildFoot: function() {
		var o = this.options;
		var foot = $('<div class="mlFoot" />');
		if (o.adZone != undefined) {
			this._leaderboardAd = $('<div class="leaderboard" />');
			foot.append(this._leaderboardAd);
		}
        return foot;
	},
	
	_preloadAssets: function(assetIdx) {
		var self = this, o = this.options;
		var currentAsset = this._selectedAsset;
		
		var assetsToLoad = [assetIdx];
		for (var i = 1; i <= o.preloadNext || i <= o.preloadPrev; i++) {
			if (i <= o.preloadNext)
				assetsToLoad.push(assetIdx + i);
			if (i <= o.preloadPrev)
				assetsToLoad.push(assetIdx - i);
		}
		var preloadAssets = function() {
			if (currentAsset != self._selectedAsset || assetsToLoad.length == 0)
				return;
			var nextIdx = assetsToLoad.shift();
			if (nextIdx < 0 || nextIdx >= o.assets.length)
				return preloadAssets();
			o.assets[nextIdx].load(preloadAssets);
		}
		preloadAssets();
	},
	
	_updateControls: function(assetIdx) {
		var o = this.options;
		var nextAsset = null;
		
		if (assetIdx <= 0) {
			this._lhsControl.addClass('disabled');
		} else {
			this._lhsControl.removeClass('disabled');
			this._lhsControl.unbind('click').openOnClick(o.assets[assetIdx-1].anchor());
		}
		if (assetIdx >= o.assets.length-1) {
			this._rhsControl.addClass('disabled');
		} else {
			this._rhsControl.removeClass('disabled');
			this._rhsControl.unbind('click').openOnClick(o.assets[assetIdx+1].anchor());
		}
	},
	
	_updateAds: function() {
		var o = this.options;
		if (o.adZone === undefined)
			return;
		var ord = Math.floor(o.adOrdGenerator() * 10000000000);
		this._sponsorAd.empty().append(this._adIframe(this._sponsorAdUrl(ord, 1), 276, 32));
		this._leaderboardAd.empty().append(this._adIframe(this._leaderboardAdUrl(ord, 2), 728, 90));
	},
	
	_removeAds: function() {
		this._sponsorAd.empty();
		this._leaderboardAd.empty();
	},
	
	_adIframe: function(src, width, height) {
		return '<iframe src="' + src + '" width="' + width + '" height="' + height + '" marginwidth="0" marginheight="0" hspace="0" vspace="0" frameborder="0" scrolling="no" allowtransparency="true" />';
	},
	
	_sponsorAdUrl: function(ord, tile) {
		return this._generateAdUrl(ord, tile, '276x32,1x1');
	},

	_leaderboardAdUrl: function(ord, tile) {
		return this._generateAdUrl(ord, tile, '728x90');
	},
	
	_generateAdUrl: function(ord, tile, size) {
		var o = this.options;
		var dcopt = (tile == 1)? 'dcopt=ist;' : '';
		return 'http://ad.doubleclick.net/adi/' + o.adSite + '/' + o.adZone + ';!category=expand;' + dcopt + o.adKeywords + ';tnm=mediablock-'+ this._selectedAsset.adType() +';tile=' + tile + ';sz=' + size + ';ord=' + ord + '?';
	},
	
	_omnitureNotifyView: function() {
	    // Traffic Variables
	    s.prop4 = "";
	    s.prop7 = "media box";
	    if(this.options.omnitureContext.length == 0) {
	    	s.prop8 = this._selectedAsset.visibleType();
	    } else {
	    	s.prop8 = this.options.omnitureContext + " " + this._selectedAsset.visibleType();
	    }
	    s.prop9 = "";
	    s.prop10 = "";
	    s.prop11 = this._selectedAsset.reference();
	    
	    // E-commerce Variables
	    s.eVar6 = s.prop4;
	    s.eVar7 = s.prop11;
	    s.eVar12 = s.prop7;
	    s.eVar13 = s.prop8;
	    s.eVar14 = s.prop9;
	    s.eVar15 = s.prop10;
	    
	    // if country(prop2), or city(prop3) variables are undefined do not include in pageName
	    if (s.prop2 === undefined || s.prop2 === "") {
	        s.pageName = s.channel +" : "+ s.prop1 +" : "+ s.prop8;
	    } else if (s.prop3 === undefined || s.prop3 === "") {
	        s.pageName = s.channel +" : "+ s.prop1 +" : "+ s.prop2 +" : "+ s.prop8; 
	    } else {
	        s.pageName = s.channel +" : "+ s.prop1 +" : "+ s.prop2 +" : "+ s.prop3 +" : "+ s.prop8;
	    }
	    
	    void(s.t()); 
	}
});


$.extend($.lp.mediaLightbox, {
	defaults: {
		title: 'Gallery',
		assets: [],
		beforeOpen: function() { },
		afterClose: function() { },
		preloadNext: 2,
		preloadPrev: 1,
		adOrdGenerator: Math.random,
		adKeywords: '',
		omnitureContext: ''
	}
});


$.widget('lp.mediaFilmstrip', {
	_init: function() {
		var self = this, div = this.element, o = this.options;
		if (o.assets.length == 0) return;
		this._carouselLoaded = false;
		
		this._lhsControl = $('<div class="arrow disabled" />');
		this._rhsControl = $('<div class="arrow" />');
		
		if (o.assets.length <= o.visible)
			this._rhsControl.addClass('disabled');
		
		this._carouselDiv = $('<div class="carousel" />');
		div.append($('<div class="control control-lhs" />').append(this._lhsControl));
		div.append(this._carouselDiv);
		div.append($('<div class="control control-rhs" />').append(this._rhsControl));
		
		div.find('.arrow').ie6HoverFix();
		
		var carouselList = $('<ul></ul>');
		$.each(o.assets, function(i,asset) {
			var thumb = asset.thumbnail().openOnClick(asset.anchor());
			carouselList.append($('<li />').append(thumb));
		});
		this._thumbDivs = carouselList.find('> li > div');
		this._carouselDiv.append(carouselList);

		// FS LPOnline Release 12:
		// Disable ie6 png fix as the AlphaImageLoader filter used by IE6
		// will break event handling and event callback in the brightcove video.
		// This problem only occurs in thumbnail, and so the resolution is we
		// are using CSS hack to apply style selective to IE6.
		//this._thumbDivs.find('.pngfix').ie6PNGFix();
		this._thumbDivs.find('.hoverfix').ie6HoverFix();
	},
	
	selectAsset: function(asset, assetIdx) {
		assetIdx = assetIdx || $.inArray(asset, this.options.assets);
		if (assetIdx < 0) return;
		
		this._thumbDivs.removeClass('selected');
		this._thumbDivs.eq(assetIdx).addClass('selected');
		this._carousel().carousel('view', assetIdx);
	},
	
	_carousel: function() {
		var self = this, div = this._carouselDiv, o = this.options;
		// lazy load carousel as the carousel code requires the list to be visible (eg. the lightbox is open)
		if (!self._carouselLoaded) {
			self._carouselLoaded = true;
			div.carousel({
				visible: o.visible,
				scroll: o.visible-1,
				speed: 600,
				circular: false,
				easing: 'easeInOutQuart',
				beforeStart: function(before, after) {
					self._lhsControl.removeClass('disabled');
					self._rhsControl.removeClass('disabled');
					if (after.index(div.find('li:first')) >= 0)
						self._lhsControl.addClass('disabled');
					if (after.index(div.find('li:last')) >= 0)
						self._rhsControl.addClass('disabled');
				}
			});
			self._lhsControl.click(function() { div.carousel('prev') });
			self._rhsControl.click(function() { div.carousel('next') });
		}
		return self._carouselDiv;
	}
});


$.extend($.lp.mediaFilmstrip, {
	defaults: {
		assets: [],
		visible: 10
	}
});


$.widget('lp.mediaFader', {
	_init: function() {
		var self = this, div = this.element, o = this.options;
		
		this._assetDiv = $('<div class="asset" />');
		this._faderDiv = $('<div class="asset" />').hide();
		this._videoPlayer = $('<div class="videoPlayer" />');
		
		this._videoPlayer.bcVideoPlayer('hide');
		this._selectedAsset = null;
		this._displayedAsset = null;
		this._fadeOutRunning = false;
		this._assetData = {};
		
		div.append(this._assetDiv);
		div.append(this._faderDiv);
		div.append(this._videoPlayer);
		
		this._videoPlayer.bcVideoPlayer({
			playerId: o.brightcovePlayerId
		});
	},
	
	notifyHide: function() {
		this._faderDiv.stop(true, true).empty().hide();
		this._videoPlayer.bcVideoPlayer('reset');
		this._videoPlayer.bcVideoPlayer('hide');
		this._selectedAsset = null;
		this._displayedAsset = null;
		this._fadeOutRunning = false;
		this._assetData = {};
	},
	
	displayAsset: function(asset, nextAsset) {
		this._selectedAsset = asset;
		this._nextAsset = nextAsset;
		this._updateDisplay();
	},
	
	_updateDisplay: function() {
		var self = this, o = this.options, asset = this._selectedAsset;
		if (this._fadeOutRunning || asset == this._displayedAsset)
			return;
		
		var assetDiv = this._assetDiv, faderDiv = this._faderDiv;
		if (this._displayedAsset != null) {
			this._fadeOutRunning = true;
			this._videoPlayer.bcVideoPlayer('stop');
			faderDiv.empty().show();
			this._displayedAsset = null;
			assetDiv.contents().appendTo(faderDiv);
			faderDiv.fadeOut('normal', function() {
				faderDiv.empty();
				self._fadeOutRunning = false;
				self._updateDisplay();
			});
		}
		assetDiv.empty().hide();

		// background load the asset and then show when done
		asset.load(function() {
			if (asset == self._displayedAsset)
				return;
			if (asset != self._selectedAsset) {
				self._updateDisplay();
				return;
			}
			
			var content = asset.content(o.maxWidth, o.maxHeight, self._nextAsset? self._nextAsset.anchor() : null);
			assetDiv.append(content).show();
			self._videoPlayer.bcVideoPlayer('hide');
			asset.contentRendered(content, {videoPlayer: self._videoPlayer}, self._assetData);
			
			content.find('.pngfix').ie6PNGFix();
			content.find('.hoverfix').ie6HoverFix();

			self._displayedAsset = asset;
		});
	}
});


$.extend($.lp.mediaFader, {
	defaults: {
		maxWidth: 579,
		maxHeight: 386
	}
});


$.widget('lp.infoHover', {
	_init: function() {
		var o = this.options, elem = this.element;
		elem.addClass('infoHoverContent');
		elem.wrap('<div class="infoHover" />');
		var background = $('<div class="infoHoverBG" />');
		// use a nested background in IE to smooth animations
		if (!$.browser.msie)
			background.wrap('<div class="infoHoverBG" />');
		elem.before(background);
		
		background.css({background: 'black', opacity: o.bgOpacity});
		
		elem.parent().children().hide();
		this._bindMouse();
	},

	destroy: function() {
		var container = this.element.closest('.infoHover');
		container.replaceWith(this.element);
		this.element.removeClass('infoHoverContent');
		this.element.hide();
	},
	
	show: function() {
		var self = this, o = this.options, infoHover = this.element.closest('.infoHover'), elems = infoHover.children();
		elems.stop(true, true).animDelay(o.showDelay).afterAnim(function() {
			o.beforeShow.call(self, infoHover);
		}).fadeIn(o.showSpeed, function() {
			o.afterShow.call(self, infoHover);
		});
	},
	
	hide: function() {
		var self = this, o = this.options, infoHover = this.element.closest('.infoHover'), elems = infoHover.children();
		elems.stop(true, true).animDelay(o.hideDelay).afterAnim(function() {
			o.beforeHide.call(self, infoHover);
		}).fadeOut(o.hideSpeed, function() {
			o.afterHide.call(self, infoHover);
		});
	},
	
	reveal: function(time) {
		var self = this, o = this.options, infoHover = this.element.closest('.infoHover'), elems = infoHover.children();
		self._unbindMouse();
		o.beforeShow.call(self, infoHover);
		elems.stop(true, true).fadeIn(o.showSpeed).afterAnim(function() {
			o.afterShow.call(self, infoHover);
		}).animate({border: 0}, time).afterAnim(function() {
			o.beforeHide.call(self, infoHover);
		}).fadeOut(o.hideSpeed, function() {
			o.afterHide.call(self, infoHover);
			self._bindMouse();
		});
	},
	
	_bindMouse: function() {
		var self = this, infoHover = this.element.closest('.infoHover');
		infoHover.parent().bind('mouseover.infoHover', function() { self.show() });
		infoHover.parent().bind('mouseout.infoHover', function() { self.hide() });
	},
	
	_unbindMouse: function() {
		var infoHover = this.element.closest('.infoHover');
		infoHover.parent().unbind('mouseover.infoHover');
		infoHover.parent().unbind('mouseout.infoHover');
	}
});


$.extend($.lp.infoHover, {
	defaults: {
		showDelay: 400,
		hideDelay: 100,
		showSpeed: 'normal',
		hideSpeed: 'slow',
		bgOpacity: 0.55,
		beforeShow: function() { },
		afterShow: function() { },
		beforeHide: function() { },
		afterHide: function() { }
	}
});


function BrightcoveBatchResourceLoader(servicesUrl, token) {
	var self = this;
	var queue = {};
	var queued = 0;
	
	this.loadByReference = function(refId, callback) {
		queue[refId] = queue[refId] || [];
		queue[refId].push(callback);
		queued++;
	};
	
	this.process = function() {
		if (queued == 0) return;
		var refIds = [];
		for (var refId in queue) {
			refIds.push(refId);
		}
		var pending = queue;
		queue = {};
		queued = 0;
		
		// create our own callback rather than using JQuery's jsonp generated one so that it's cacheable
		window['_lpbc'] = function(response) {
			$.each(response.items, function (i,item) {
				if (item && item.referenceId) {
					// for image urls on lp.tv, remove pubId appended by brightcove - lp.tv doesn't like it there
					item.thumbnailURL = sanitizeUrl(item.thumbnailURL);
					$.each(pending[item.referenceId], function(j, callback) {
						callback.call(self, item);
					});
				}
			});
		};
		var parameters = { reference_ids: refIds.join(','), fields: 'id,referenceId,thumbnailURL,videoStillURL' };
		$.ajax({
			type: 'GET',
			url: servicesUrl + ((servicesUrl.indexOf('?') < 0)? '?':'&') + 'token=' + token + '&command=find_videos_by_reference_ids&callback=_lpbc',
			data: parameters,
			dataType: 'script',
			cache: true
		});
	};
	
	function sanitizeUrl(url) {
		// for image urls on lp.tv, remove pubId appended by brightcove - lp.tv doesn't like it there
		if (url && url.match(/^http:\/\/www.lonelyplanet.tv\/GetImage.aspx?/)) {
			url = url.replace(/&pubId=\d+/gi,'');
		}
		return url;
	}
}


function BrightcoveResourceLoaderCache(resourceLoader) {
	var self = this;
	var cache = {};
	
	this.loadByReference = function(refId, callback) {
		var cached = cache[refId];
		if (cached != null) {
			callback.call(self, cached);
			return;
		}
		resourceLoader.loadByReference(refId, function(data) {
			cache[refId] = data;
			callback.call(self, data);
		});
	};
	
	this.process = function() { resourceLoader.process() };
}


$.widget('lp.bcVideoPlayer', {
	_init: function() {
		var self = this, div = this.element, o = this.options;
		this._loaded = false;
		this._listeners = {};
		this._player = null;
		this._menu = null;
		this._content = null;
		this._volume = o.volume;
		this._loadedId = null;
		this._playingId = null;
		this._loadQueue = [];
		this._playing = false;
		this._adPlaying = false;
		this._adModule = null;
		
		div.addClass('bcVideoPlayer');

		var flashObject = $('<object class="BrightcoveExperience">'
				+ '<param name="bgcolor" value="#4c4c4c" />'
				+ '<param name="width" value="430" />'
				+ '<param name="height" value="370" />'
				+ '<param name="playerID" value="' + o.playerId + '" />'
				+ '<param name="isVid" value="true" /></object>');
		this._playerDiv = $('<div />');
		
		div.append(this._playerDiv);
		
		this.hide();
		
		this._noVideo = $('<div class="noVideo" />');
		this._noVideo.append($('<span />').text('Sorry, there was a problem finding that video - but there\'s plenty more to choose from.'));
		div.append(this._noVideo.hide());
		
		brightcove.createExperience(flashObject.get(0), this._playerDiv.get(0), true);
	},
	
	playerLoaded: function(bcExperience) {
		var self = this;
		var expModule = bcExperience.getModule(APIModules.EXPERIENCE);
		expModule.addEventListener(BCExperienceEvent.TEMPLATE_READY, function() {
			self._playerReady(bcExperience, expModule);
		});
	},
	
	_playerReady: function(bcExperience, expModule) {
		var self = this;
		expModule.removeEventListener(BCExperienceEvent.TEMPLATE_READY, arguments.callee);
		if (this._loaded) {
			this._content.removeEventListener(BCContentEvent.VIDEO_LOAD, this._videoLoadListener);
			this._player.removeEventListener(BCVideoEvent.VOLUME_CHANGE, this._volumeChangeListener);
		}
		this._player = bcExperience.getModule(APIModules.VIDEO_PLAYER);
		this._menu = bcExperience.getModule(APIModules.MENU);
		this._content = bcExperience.getModule(APIModules.CONTENT);
		this._adModule = bcExperience.getModule(APIModules.ADVERTISING);
		this._adStartListener = function(ev) {
			self._adPlaying = true;
		};
		this._adCompleteListener = function(ev) {
			self._adPlaying = false;
		};
		this._adModule.addEventListener(BCAdvertisingEvent.AD_START, this._adStartListener);
		this._adModule.addEventListener(BCAdvertisingEvent.AD_COMPLETE, this._adCompleteListener);
		this._videoLoadListener = function(ev) { return self._onAsynchVideoLoad(ev) };
		this._content.addEventListener(BCContentEvent.VIDEO_LOAD, this._videoLoadListener);
		this._player.setVolume(this._volume);
		this._volumeChangeListener = function() { return self._onVolumeChange() };
		this._player.addEventListener(BCVideoEvent.VOLUME_CHANGE, this._volumeChangeListener);
		this._loaded = true;
		if (this._loadQueue.length > 0) {
			this._processLoadQueue();
		}
	},
	
	show: function() {
		this.element.css('visibility', '');
		this._playerDiv.show();
		this._playerDiv.css('visibility', '');
		this._noVideo.hide();
	},
	
	hide: function() {
		// set visibility rather than use hide, as this doesn't cause flash to reload in FF
		this.element.css('visibility', 'hidden');
	},
	
	reset: function() {
		this.stop();
		this._loadedId = null;
		this._playingId = null;
		this._loadQueue = [];
	},

	playerPlay: function(bcPlayer) {
		if (this._adPlaying)
		{
			// There is a video ad paused in the video display, resume playing
			bcPlayer.pause(false);
		}
		else
		{
			// Resume or play video, there is not Ad in the video display
			
			bcPlayer.play();

		}
	},

	play: function(id) {
		this.show();
		this._playing = true;
		this._loadQueue.push(id);
		if (this._loaded && this._loadQueue.length == 1) {
			
			this._processLoadQueue();
		}
	},

    stop: function() {
		this._playing = false;
		if (this._loaded) {
			
			this._player.pause(true);
			
			this._player.stop();
		}
	},
	
	_processLoadQueue: function() {
		// splices the queue to hold just the last asset in the queue
		this._loadQueue.splice(0, this._loadQueue.length - 1);

		/*
		 *If we are processing an asset that is already loaded then
		 *shift the asset of the queue and just call play again. 
		 */	
		
		if (this._loadQueue[0] == this._loadedId) {
			this._loadQueue.shift();
			//this._player.play();
			this.playerPlay(this._player);
			return;
		}
		this._menu.closeMenuPage();
		/*
		 * We have an asset request and have not previously fetched it.
		 * So disable the player and go fetch it asynchronously.
		 */ 
		if (!this._content.getVideo(this._loadQueue[0], 'referenceId')) {
			this._player.setEnabled(false);
			this._content.getVideoAsynch(this._loadQueue[0], 'referenceId');
			return;
		}
		//Otherwise we have an asset that has been fetched so cue it up for playing 
		this._cueVideo(this._loadQueue.shift());
	},
	
    _onAsynchVideoLoad: function(event) {
    	var id = this._loadQueue.shift();
    	if (this._loadQueue.length != 0) {
    		
    		this._processLoadQueue();
    		return;
    	}
    	this._player.setEnabled(true);
        if (event.video == null) {
        	this._loadedId = id;
            this._noVideo.show();
            this._playerDiv.css('visibility', 'hidden');
            return;
        }
		
        this._cueVideo(id);
    },
	
	_cueVideo: function(id) {
    	this._loadedId = id;
		
		this._player.cueVideo(id, 'referenceId');
		
		if (this._playing) {
			//this._player.play();
			
			this.playerPlay(this._player);
		} else {
			
			this._player.stop();
		}
	},
	
	_onVolumeChange: function() {
		this._volume = this._player.getVolume();
	}
});

$.extend($.lp.bcVideoPlayer, {
	defaults: {
		volume: 0.7,
		playerId: 1815820737
	}
});

})(jQuery);

//BrightCove callback
brightcove.removeListeners();
function onTemplateLoaded(experienceID) {
	$('#'+experienceID).closest('.bcVideoPlayer').bcVideoPlayer('playerLoaded', brightcove.getExperience(experienceID));
};
