(function($) {
	// the main blackout function
	$.fn.blackout = function (options) {
		return this.each(
			function (i) {
				// create our lightbox options by extending (or overriding, as necessary) the defaults
				blackoutOptions = $.extend({}, $.fn.blackout.defaults, options);
				// set a shorthand for the current list we're working with
				var blackoutList = $(this);
				// give each list a unique ID, enabling multiple blackout instances per page
				blackoutList.attr({'id': blackoutOptions.uniqueID + i});
				// add blackout objects to container
				$.fn.blackout.updateBlackoutObjects(blackoutList);
				// bind clicks from blackout anchors to the show function
				$('a', this).not('.controls').click($.fn.blackout.launchShow);
			}
		);
	};
	/* the object that will contain all of the instances of blackout objects
	   FORMAT:
	   { instanceID: [{imageID, imageURL, title, description, position, parentID}, ...], ... }
	   WHERE instanceID = the ID of the individual list
	*/
	$.fn.blackout.blackoutObject = {};
	// function to add image URL's and captions to each blackout object
	$.fn.blackout.updateBlackoutObjects = function (list) {
		var listItem	= $('li', list);
		var instanceID	= list.attr('id');
		var imageID		= instanceID + '_image_';
		if (typeof $.fn.blackout.blackoutObject[instanceID] == 'undefined') {$.fn.blackout.blackoutObject[instanceID] = [];}
		listItem.each(			
			function (i) {
				var $this = this;
				// add each image item to the object
				$.fn.blackout.blackoutObject[instanceID][i] = {
					 'imageID': imageID + i
					,'imageURL': $('a', this).attr(blackoutOptions.fullsizeTargetAttr)
					,'title': $('img', this).attr('alt')
					,'description': $('a', this).attr(blackoutOptions.captionAtrribute)
					,'position': i
					,'parentID': instanceID
					,'type': $('a', this).attr(blackoutOptions.typeAttr)
					,'movieHeight': parseInt($('a', this).attr(blackoutOptions.movieHeightAttr))
					,'movieWidth': parseInt($('a', this).attr(blackoutOptions.movieWidthAttr))
				};
				// give each anchor the image ID, so we know where in the stream to start the show
				$('a', this).not('.controls').attr({'id': imageID + i});
			}
		);
	}
	// the function that will handle setting up the show, creating the necessary DOM elements, etc.
	$.fn.blackout.launchShow = function (e) {
		e.preventDefault();
		if (this.tagName == 'A') {
			var trigger	= $(this);
		}
		else {
			var trigger = $($(this).siblings('a.trigger'));
		}
		var imageID		= trigger.attr('id');
		var instanceID	= imageID.substr(0, imageID.indexOf('_image_'));
		var imageList	= $.fn.blackout.blackoutObject[instanceID];
		var position	= 0;
		for (key in imageList){
			if (imageList[key].imageID == imageID) {
				position = key;
				break;
			}
		}
		var popup	= $('<div id="blackoutPopup" class="clearfix">').css(blackoutOptions.popupCSS);
		var viewportOffset = window.pageYOffset || document.documentElement && document.documentElement.scrollTop || document.body.scrollTop;
		if ($.browser.msie) {var viewportHeight =  document.documentElement.offsetHeight;}
		else {var viewportHeight = window.innerHeight;}

		// popup = the image/caption area
		popup.css({'top' : viewportOffset + (viewportHeight / 2)});
		// sheet = the colored background/blocking thing
		sheet	= $('<div id="blackoutSheet">');
		sheet.css({
			 background: blackoutOptions.sheetColor
			,height: $(document).height()
			,opacity: blackoutOptions.sheetOpacity
			,width: $(document).width()
		});
		if (blackoutOptions.showCloseButton) {
			var closeButton = $('<div id="blackoutCloseButton">Close &times;</div>');
			//closeButton.css({background: '#000 url('+blackoutOptions.closeButton+') right top no-repeat'});
			popup.append(closeButton);
		}
		
		// caption
		if (blackoutOptions.showCaption) {
			var $caption = $('<div id="blackoutCaption">');
			$caption.css(blackoutOptions.captionCSS);
			popup.append($caption);
			$caption.hide();
		}
		// navigation items
		if (blackoutOptions.showNavigationBar) {
			var navigation = $('<div id="blackoutNavigation">');
			navigation.append('<a class="next">Next</a>');
			navigation.append('<a class="previous">Previous</a>');
			popup.append(navigation);
		}
		if (blackoutOptions.alternateView) {
			switch (blackoutOptions.alternateView) {
				case 'filmstrip':
					var $filmstrip = $('<div id="blackoutFilmstrip">');
					var $filmstripUL = $('#' + instanceID).clone().attr({'id': ''});
					$filmstrip.append($filmstripUL);
					popup.append($filmstrip);
					$('a', $filmstripUL).bind('click', function (e) {
						e.preventDefault();
						var $me = $(e.currentTarget);
						var parentInstance = $.fn.blackout.blackoutObject[instanceID];
						var newPosition = 0;
						for (key in parentInstance){
							if (parentInstance[key].imageID == $me.attr('id')) {
								newPosition = key;
								break;
							}
						}
						$.fn.blackout.loadImage(parentInstance[newPosition]);
					});
					break;
			}
		}
		$('body').append(sheet);
		$('body').append(popup);
		sheet.fadeIn('100', function() {popup.fadeIn('250');});
		closeButton.bind('click', $.fn.blackout.killShow);
		sheet.bind('click', $.fn.blackout.killShow);
		$.fn.blackout.loadImage(imageList[position]);
	}
	// function to change the image out
	$.fn.blackout.loadImage = function (imageInstance) {
		if (blackoutOptions.alternateView) {
			switch (blackoutOptions.alternateView) {
				case 'filmstrip':
					var $filmstrip = $('#blackoutFilmstrip').hide();
					$('a', $filmstrip).removeClass('current');
					$('#' + imageInstance.imageID, $filmstrip).addClass('current');
					break;
			}
		}
		// select the popup
		var popup = $('#blackoutPopup');
		// if there is already an image (ie: we are shifting), fade it out, remove it, and drop the caption
		if ($('#blackoutMainMedia', popup).length) {
			$('#blackoutMainMedia', popup).fadeOut(blackoutOptions.fadeSpeed, function () {$(this).remove();});
			$('#blackoutNavigation > a', popup).unbind();
			// since the show is already open, we don't need the long opening animation, so switch to the quicker fadeSpeed
			var animationSpeed = blackoutOptions.fadeSpeed;
		}
		// otherwise, it's the first time we've opened the new show, so reset all dimensions/positioning
		else {
			$('#blackoutCloseButton').hide();
			$('#blackoutNavigation').hide();
			popup.css({
				 width: '250px'
				,height: 0
				,marginTop: '-50px'
				,marginLeft: '-140px'
			});
			var animationSpeed = blackoutOptions.animationSpeed;
		}
		var closeButton = $('#blackoutCloseButton');
		if (imageInstance.type == 'movie') {
			popup.animate(
				 {
					 marginLeft: -((imageInstance.movieWidth + 30) / 2)
					,width: imageInstance.movieWidth
				 }
				,animationSpeed
				,blackoutOptions.easing
				,function () {
					var caption = $('#blackoutCaption').empty().hide();
					//caption.html(imageInstance.description);
					var popupHeight = (imageInstance.movieHeight) + caption.height();
					var popupPadding = popup.outerHeight();
					popup.animate(
						 {
							 marginTop: -(popupHeight / 2) + 'px'
							,height: popupHeight + 'px'
						 }
						,animationSpeed
						,blackoutOptions.easing
						,function () {
							// NOW opera can correctly add the image
							if (blackoutOptions.showNavigationBar) {
								// create the navigation items
								$.fn.blackout.createNavigation(image, imageInstance);
								$('#blackoutNavigation').show();
							}
							var movie = $('<div>');
							var movieStr = '<embed width="' + imageInstance.movieWidth +'" height="' + imageInstance.movieHeight +'" wmode="transparent" flashvars="" id="FIR_1" quality="high" src="' + imageInstance.imageURL +'" type="application/x-shockwave-flash" />';
							movie.html(movieStr);
							popup.append(movie);
							closeButton.show();
						}
					);
				}
			);
		}
		else {
			var image = new Image();
			// set the correct src of the image, but make sure it is hidden
			$(image)
				.attr({
					 'id' : 'blackoutMainMedia'
					,'src': imageInstance.imageURL + '?rand=' + Math.floor(Math.random() * 999999999)
				}).hide();
			$(image).load(
				function () {
					var viewportOffset = window.pageYOffset || document.documentElement && document.documentElement.scrollTop || document.body.scrollTop;
					if ($.browser.msie) {var viewportHeight =  document.documentElement.offsetHeight;}
					else {var viewportHeight = window.innerHeight;}
					// add the image to the popup, as long as it's not opera. opera needs the image added later because... well, because opera is weird like that.
					if (!$.browser.opera){popup.prepend(image);}
					// expand the popup to correct size and position
					popup.animate(
						 {
							 marginLeft: -((image.width + 30) / 2)
							,top: viewportOffset + (viewportHeight / 2)
							,width: image.width
						 }
						,animationSpeed
						,blackoutOptions.easing
						,function () {
							var caption = $('#blackoutCaption').empty().hide();
							caption.html(imageInstance.description);
							var popupHeight = image.height;
							if (blackoutOptions.alternateView) {
								switch (blackoutOptions.alternateView) {
									case 'filmstrip':
										$filmstrip.show();
										popupHeight += $('ul', $filmstrip).height();
										break;
								}
							}
							var popupPadding = 70;
							popup.animate(
								 {
									 marginTop: -(popupHeight / 2) + 'px'
									,height: popupHeight + 'px'
								 }
								,animationSpeed
								,blackoutOptions.easing
								,function () {
									// make sure the sheet covers all
									sheet.css({
										 height: $(document).height()
										,width: $(document).width()
									})
									;
									// NOW opera can correctly add the image
									if ($.browser.opera){popup.prepend(image);}
									if (blackoutOptions.showNavigationBar) {
										// create the navigation items
										$.fn.blackout.createNavigation(image, imageInstance);
										$('#blackoutNavigation').show();
									}
									closeButton.show();
									// fade the image in
									$(image).fadeIn(
										blackoutOptions.fadeSpeed,
										function () {
											caption.show();
										}
									);
								}
							);
						}
					);
				}
			);
		}
	}
	// function for creating/binding navigation arrows
	$.fn.blackout.createNavigation = function(image, imageInstance) {
		var navigation = $('#blackoutNavigation');
		var previousButton = $('a.previous', navigation);
		var nextButton = $('a.next', navigation);
		var activate = $.fn.blackout.defaults.navigationButtonFunctions.activate;
		var deactivate = $.fn.blackout.defaults.navigationButtonFunctions.deactivate;
		var parentInstance = $.fn.blackout.blackoutObject[imageInstance.parentID];
		var position = parseInt(imageInstance.position);
		// if we are not at the last image, we need to show and bind the "next image" button
		if (position < (parentInstance.length - 1))
		{
			activate(nextButton);
			nextButton.one('click', function () {$.fn.blackout.loadImage(parentInstance[position + 1]);});
		}
		// if we ARE at the last image, we need to make sure we deactivate that link
		else {deactivate(nextButton);}
		//if we are not at the first image, we need to show and bind the "previous image" button
		if (position > 0)
		{
			activate(previousButton);
			previousButton.one('click', function () {$.fn.blackout.loadImage(parentInstance[position - 1]);});
		}
		// if we ARE at the first image, though, we need to make sure we deactivate that link
		else {deactivate(previousButton);}
	}
	// function to end the show
	$.fn.blackout.killShow = function () {
		$('#blackoutPopup').animate({height: 0, width: 0, margin: 0}, blackoutOptions.animationSpeed);
		$('#blackoutPopup').remove();
		$('#blackoutSheet').fadeOut('100', function() {$('#blackoutSheet').remove();});
	}
	// default options
	$.fn.blackout.defaults = {
		 alternateView: false
		,animationSpeed: 500
		,captionAtrribute: 'title'
		,captionCSS: {}
		,closeButton: 'images/blackoutCloseButton.png'
		,easing: 'swing'
		,fadeSpeed: 250
		,fullsizeTargetAttr: 'href'
		,movieWidthAttr: 'width'
		,movieHeightAttr: 'height'
		,navigationButtonFunctions : {
			 activate: function (e) {e.css({opacity: 1,cursor: 'pointer'});}
			,deactivate: function (e) {e.css({opacity: 0.25,cursor: 'default'});e.unbind();}
		 }
		,popupCSS : {}
		,sheetColor: '#333'
		,sheetOpacity: '0.667'
		,showCaption: true
		,showCloseButton: true
		,showNavigationBar: true
		,typeAttr: 'type'
		,uniqueID: 'blackoutObject'		
	};
})(jQuery);