(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).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('longdesc')
					,'position': i
					,'parentID': instanceID
				};
				// 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();
		var trigger		= $(this);
		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;
		var viewportHeight = $(document).height() - viewportOffset;
		// popup = the image/caption area
		popup.css({background: blackoutOptions.imgBGColor, 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()
			,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 Image</a>');
		navigation.append('<a class="previous">Previous Image</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: 0
				,marginLeft: '-125px'
			});
			var animationSpeed = blackoutOptions.animationSpeed;
		}
		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 () {
				// 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);}
				var closeButton = $('#blackoutCloseButton');
				// expand the popup to correct size and position
				popup.animate(
					 {
						  marginTop: -((image.height + 40) / 2)
						 ,height: image.height + 80
					 }
					,animationSpeed
					,blackoutOptions.easing
					,function () {
						popup.animate(
							 {
							 	 marginLeft: -(image.width / 2)
							 	,width: image.width
							 }
							,animationSpeed
							,blackoutOptions.easing
							,function () {
								// NOW opera can correctly add the image
								if ($.browser.opera){popup.prepend(image);}
								// create the navigation items
								$.fn.blackout.createNavigation(image, imageInstance);
								closeButton.show();
								$('#blackoutNavigation').show();
								// fade the image in
								$(image).fadeIn(
									blackoutOptions.fadeSpeed,
									function () {
										var caption = $('#blackoutCaption').empty();
										//caption.html('<h1>'+imageInstance.title+'</h1>'+'<div id="blackoutImageDescription">'+imageInstance.description+'</div>');
										caption.html(imageInstance.description);
										//if ($.browser.msie && $.browser.version == '6.0') {caption.css({height: (image.height - 15)});}
									}
								);
							}
						);
					}
				);
			}
		);
	}
	// 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: '#000'
		,sheetOpacity: '0.75'
		,imgBGColor: '#fff'
		,captionColor: '#000'
		,uniqueID: 'blackoutObject'
		,showCloseButton: true
		,closeButton: 'images/blackoutCloseButton.png'
		,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();}
	};
})(jQuery);
