(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, img', this).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': $('img', 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).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">');
		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({
			 background: blackoutOptions.imgBGColor
			,top: viewportOffset + (viewportHeight / 2)
			,zIndex: 9999999
		});
		// sheet = the colored background/blocking thing
		var sheet	= $('<div id="blackoutSheet">');
		sheet.css({
			 background: blackoutOptions.sheetColor
			,height: $(document).height()
			,opacity: blackoutOptions.sheetOpacity
			,width: $(document).width()
			,zIndex: 999999
		});
		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
		popup.append($('<div id="blackoutCaption">'));
		// navigation items
		var navigation = $('<div id="blackoutNavigation">');
		navigation.append('<a class="next">Next</a>');
		navigation.append('<a class="previous">Previous</a>');
		popup.append(navigation);
		$('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) {
		// 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 ($('img', popup).length) {
			$('img', 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 + popupPadding) / 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();
							//caption.show();
						}
					);
				}
			);
		}
		else {
			var image = new Image();
			// set the correct src of the image, but make sure it is hidden
			$(image).attr({'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) + caption.height();
							var popupPadding = 70;
							popup.animate(
								 {
									 marginTop: -((popupHeight + popupPadding) / 2) + 'px'
									,height: popupHeight + 'px'
								 }
								,animationSpeed
								,blackoutOptions.easing
								,function () {
									// 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.activateNavigationButton;
		var deactivate = $.fn.blackout.defaults.deactivateNavigationButton;
		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 = {
		 sheetColor: '#333'
		,sheetOpacity: '0.667'
		,imgBGColor: '#fff'
		,captionColor: '#000'
		,uniqueID: 'blackoutObject'
		,showCloseButton: true
		,showNavigationBar: true
		,closeButton: 'images/blackoutCloseButton.png'
		,captionAtrribute: 'longdesc'
		,fullsizeTargetAttr: 'href' // some people like to have a fallback URL (other than a blank page with an image)
									// for users without javascript, which means the href attribute of the anchor tag
									// will not be the actual location of the fullsize image, so we need to allow
									// for the direct fullsize link to be placed on any other attribute of the anchor.
									// alternatives include name, title, and target (though target is deprecated in XHTML)
		,animationSpeed: 500
		,easing: 'swing'
		,fadeSpeed: 250
		,activateNavigationButton: function (e) {e.css({opacity: 1,cursor: 'pointer'});}
		,deactivateNavigationButton: function (e) {e.css({opacity: 0.25,cursor: 'default'});e.unbind();}
		// None of the following three attrributes are valid on their trigger elements, mais c'est la vie. Just make it work for now.
		,typeAttr: 'type'
		,movieWidthAttr: 'width'
		,movieHeightAttr: 'height'
	};
})(jQuery);