

// Variables for custom settings. (More options available below line.)
lb_js = "JavaScripts/lightbox.js";
lb_color_js = "JavaScripts/lightbox-color.js";
lb_css = "CSS/lightbox.css";
previous_image = "Images/Lightbox/prev.gif";
next_image = "Images/Lightbox/next.gif";
blank_image = "Images/Lightbox/blank.gif";
loading_image = "Images/Lightbox/loading.gif";
rel_tag = 'lightbox';
/*
// Create all the needed html for lightbox automatically from the image information.
$(document).ready(function(){
	// For every element with the lightbox class find add the link directly to it.
	for (im = 0; im < $(".lightbox").length; im++) {
		if ($(".lightbox").eq(im).attr('src') != '') {
			$(".lightbox").eq(im).wrap('<a rel="lightbox-test" href="' + $(".lightbox").eq(im).attr('src').replace('small', 'large')  +'" title="' + $(".lightbox").eq(im).attr('alt') + '"></a>');
		}
	}
});*/

// Start of jQuery Plugin.
(function($) {
	
	// Debug
	if ( !$.browser.safari && typeof window.console !== 'undefined' && typeof window.console.log === 'function' ) {	
		// Use window.console.
		$.log = window.console.log;
	}
	else {
		// Don't use anything.
		$.log = function ( ) { };
	}
	
	// Pre-Req. Turn a params string or url into an array of params.
	$.params_to_json = $.params_to_json || function ( params ) {
		// Adjust.
		params = String(params);
		// Remove url if need be.
		params = params.substring(params.indexOf('?')+1);
		// params = params.substring(params.indexOf('#')+1);
		// Change + to %20, the %20 is fixed up later with the decode
		params = params.replace(/\+/g, '%20');
		// Is JSON loaded.
		if ( params.substring(0,1) === '{' && params.substring(params.length-1) === '}' ) {
			// If so use the JSON string.
			return eval(decodeURIComponent(params));
		}
		// Split the params string.
		params = params.split(/\&|\&amp\;/);
		var json = {};
		// Params.
		for ( var i = 0, n = params.length; i < n; ++i ) {
			// Adjust
			var param = params[i] || null;
			if ( param === null ) { continue; }
			param = param.split('=');
			// Change "var=blah" into ["var","blah"].
			if ( param === null ) { continue; }
			// Get.
			var key = param[0] || null;
			if ( key === null ) { continue; }
			if ( typeof param[1] === 'undefined' ) { continue; }
			// Gather all the parts.
			var value = param[1];
			// Fix.
			key = decodeURIComponent(key);
			value = decodeURIComponent(value);
			try {
			    // Value can be converted.
			    value = eval(value);
			}
			catch ( e ) {
			    // Value is a normal string.
			}
			// Set and add all the parts to JSON object.
			// console.log({'key':key,'value':value}, split);
			var keys = key.split('.');
			if ( keys.length === 1 ) {
				// Simple
				json[key] = value;
			}
			else {
				// Advanced
				var path = '';
				for ( ii in keys ) {
					key = keys[ii];
					path += '.'+key;
					eval('json'+path+' = json'+path+' || {}');
				}
				eval('json'+path+' = value');
			}
		}
		// Return the parts to JSON.
		return json;
	};
	
	// Declare the lightbox class.
	$.LightboxClass = function ( )	{
		// This is the handler for our constructor
		this.construct();
	};

	// Extend jQuery elements for Lightbox
	$.fn.lightbox = function ( options )	{
		// Init a el for Lightbox.
		// Eg. $('#gallery a').lightbox();
		// If need be: Instantiate $.LightboxClass to $.Lightbox
		$.Lightbox = $.Lightbox || new $.LightboxClass();
		// Handle IE6 appropriatly.
		if ( $.Lightbox.ie6 && !$.Lightbox.ie6_support ) {
			// Return the chain in IE6.
			return this;
		}
		// Establish the default options.
		options = $.extend({start:false,events:true}, options);
		// Get group.
		var group = $(this);
		// Check for events.
		if ( options.events ) {
			// Add events.
			$(group).unbind().click(function(){
				// Get obj.
				var obj = $(this);
				// Get rel.
				// var rel = $(obj).attr('rel');
				// Init group.
				if (!$.Lightbox.init($(obj)[0], group)) {
					return false;
				}
				// Display lightbox.
				if (!$.Lightbox.start()) {
					return false;	
				}
				// Cancel href.
				return false;
			});
			// Add style.
			$(group).addClass('lightbox-enabled');
		}
		
		// Check to see if it is started.
		if ( options.start ) {
			// Get obj.
			var obj = $(this);
			// Get rel.
			// var rel = $(obj).attr('rel');
			// Init group.
			if (!$.Lightbox.init($(obj)[0], group)) {
				return this;
			}
			// Display lightbox
			if ( !$.Lightbox.start() ) {
				return this;
			}
		}
		// Return the chain.
		return this;
	};
	
	// Define the lightbox class.
	$.extend($.LightboxClass.prototype, {
		// Everyting to do with the images.
		images: {
			// Write the variables into an array.
			list:[], 
			/* [ {
				src: 'url to image',
				link: 'a link to a page',
				title: 'title of the image',
				name: 'name of the image',
				description: 'description of the image'
			} ], */
			// The current active image
			image: false,
			// Functions.
			prev: function (image) {
				// Get previous image from the current one.
				if ( typeof image === 'undefined') {
					image = this.active();
					if (!image) {
						return image;
					}
				}
				// Check to see if there is a previous image.
				if (this.first(image)) {
					return false;
				}
				// Get the previous.
				return this.get(image.index-1);
			},
			next: function (image) {
				// Get next image from the current one.
				if (typeof image === 'undefined') {
					image = this.active();
					if (!image) {
						return image;
					}
				}
				// Check to see if there is an image after this one.
				if (this.last(image)) {
					return false;
				}
				// Get the next.
				return this.get(image.index+1);
			},
			first: function (image) {
				// Get the first image.
				if ( typeof image === 'undefined') {
					return this.get(0);
				}
				// Check to see if this is the first image.
				return image.index === 0;
			},
			last: function (image) {
				// Get the last image.
				if ( typeof image === 'undefined') {
					return this.get(this.size()-1);
				}
				// Check to see if this is the last image.
				return image.index === this.size()-1;
			},
			single: function ( ) {
				// See if this is the only image.
				return this.size() === 1;
			},
			size: function ( )	{
				// Find the number of images.
				return this.list.length;
			},
			
			empty: function ( ) {
				// Check to see if it is empty.
				return this.size() === 0;
			},
			clear: function ( ) {
				// Clear the image arrray.
				this.list = [];
				this.image = false;
			},
			active: function (image) {
				// Set or get the active image and use false to reset it.
				if ( typeof image === 'undefined') {
					return this.image;
				}				
				// Set the active image.
				if (image !== false) {
					// Make sure the image exists.
					image = this.get(image);
					if (!image)	{
						// Error.
						return image;
					}
				}
				this.image = image;
				return true;
			},
			add: function (obj) {
				// Is it necessary to recurse the file.
				if (obj[0])	{
					// Check to see if there are a lot of images.
					for (var i = 0; i < obj.length; i++)	{
						this.add(obj[i]);
					}
					return true;
				}
				// Try and create a default image.
				var image = this.create(obj);
				if (!image) {
					return image;
				}
				// Set the image index.
				image.index = this.size();
				// Push the image.
				this.list.push(image);
				// Success.
				return true;
			},
			create: function ( obj ) {
				// Create image.
				var image = {
					// Default.
					src:	'',
					title:	'Untitled',
					description:	'',
					name:	'',
					index:	-1,
					color:	null,
					width:	null,
					height:	null,
					image:	true
				};
				// Create.
				if (obj.image) {
					// There is already an image, so copy over values.
					image.src = obj.src || image.src;
					image.title = obj.title || image.title;
					image.description = obj.description || image.description;
					image.name = obj.name || image.name;
					image.color = obj.color || image.color;
					image.width = obj.width || image.width;
					image.height = obj.height || image.height;
					image.index = obj.index || image.index;
				}
				else if (obj.tagName) {
					// If the object is an element.
					obj = $(obj);
					if (obj.attr('src') || obj.attr('href')) {
						image.src = obj.attr('src') || obj.attr('href');
						image.title = obj.attr('title') || obj.attr('alt') || image.title;
						image.name = obj.attr('name') || '';
						image.color = obj.css('backgroundColor');
						// Extract description from title.
						var s = image.title.indexOf(': ');
						if ( s > 0 ) {
							// If description exists.
							image.description = image.title.substring(s+2) || image.description;
							image.title = image.title.substring(0,s) || image.title;
						}
					}
					else {
						// Unsupported element.
						image = false;
					}
				}
				else {
					// Unknown.
					image = false;
				}
				if (!image)	{
					// Error.
					$.log('ERROR', 'We dont know what we have:', obj);
					return false;
				}
				// Success.
				return image;
			},
			get: function (image) {
				// Get the active, or specified image.
				if (typeof image === 'undefined' || image === null) {
					// Get the active image.
					return this.active();
				}
				else if (typeof image === 'number') {
					// If there is an index, get the image.
					image = this.list[image] || false;
				}
				else {
					// Create.
					image = this.create(image);
					if (!image) {
						return false;
					}
					// Find.
					var f = false;
					for (var i = 0; i < this.size(); i++) {
						var c = this.list[i];
						if (c.src === image.src && c.title === image.title && c.description === image.description) {
							f = c;
						}
					}
					// Check to see if the image is found.
					image = f;
				}
				// Determine the image.
				if (!image) {
					// If the image doesn't exist...
					$.log('ERROR', 'The desired image doesn\'t exist: ', image, this.list);
					return false;
				}
				// Return image.
				return image;
			},
			debug: function ( ) {
				return $.Lightbox.debug(arguments);
			}
		},
		// User Options.
		constructed:		false,
		// The source location of our js file.
		src:				null,
		baseurl:			null,
		files: {
			// If you are doing a repack with packer (http://dean.edwards.name/packer/) then append ".packed" onto the js and css files before you pack it.
			js: {
				lightbox:	lb_js,
				colorBlend:	lb_color_js
			},
			css: {
				lightbox:	lb_css
			},
			images: {
				prev:		previous_image,
				next:		next_image,
				blank:		blank_image,
				loading:	loading_image
			}
		},
		text: {
			// For translating.
			image:		'Image',
			of:			'of',
			close:		'Close X',
			closeInfo:	'Click here or anywhere outside the image to close.',
			download:	'Direct link to download the image.',
			help: {
				close:		'',
				interact:	''
			},
			about: {
				text: 	'jQuery Lightbox Plugin (balupton edition)',
				title:	'Licenced under the GNU Affero General Public License.',
				link:	'http://jquery.com/plugins/project/jquerylightbox_bal'
			}
		},
		keys: {
			close: 'c',
			prev: 'p',
			next: 'n'
		},
		handlers: {
			// For custom actions.
			show:	null
		},
		opacity:  0.9,
		// If null - autodetect.
		padding: null,
		// Duration of effect, milliseconds.
		speed: 400,		
		// What to look for in the rels.
		rel: rel_tag,
		// Automatically do the rels?
		auto_relify: true,
		// Allow lightbox scroll with the page... (follow, disabled, ignore)		
		auto_scroll: 'follow',
		// True or False.
		auto_resize: true,
		// Is it IE6.
		ie6: null,
		ie6_support: true, 
		ie6_upgrade: true,
		// Color Blend (null - Auto-detect, true - Force, false - No).		
		colorBlend: null,
		// Display the download link.
		download_link: true,
		show_linkback: false,
		// Show info (auto - Automaticly Handle, true - force)
		show_info: 'auto',
		// Show extended info (auto - Automaticly Handle, true - force)
		show_extended_info: 'auto',		
		// Names of the options that can be modified.
		options:	['auto_scroll', 'auto_resize', 'download_link', 'show_info', 'show_extended_info', 'ie6_support', 'ie6_upgrade', 'colorBlend', 'baseurl', 'files', 'text', 'show_linkback', 'keys', 'opacity', 'padding', 'speed', 'rel', 'auto_relify'],
		// Functions
		construct: function (options) {
			// Construct Lightbox.
			// Initial construction.
			var initial = typeof this.constructed === 'undefined' || this.constructed === false;
			this.constructed = true;
			// Perform domReady.
			var domReady = initial;
			// Prepare options
			options = $.extend({}, options);
			// Handle files.
			// Add baseurl
			if (initial && (typeof options.files === 'undefined')) {
				// Load the files like default.
				// Get the src of the first script tag that includes our js file (with or without an appendix).
				this.src = $('script[src*='+this.files.js.lightbox+']:first').attr('src');
				// Make sure the js file exists.
				if (!this.src) {
					// Error.
					// $.log('WARNING', 'Lightbox was not able to find it\'s javascript script tag necessary for auto-inclusion.');
					// We don't work with files anymore, so don't care for domReady
					domReady = false;
				}
				else {
					// The baseurl is the src up until the start of the js file.
					this.baseurl = this.src.substring(0, this.src.indexOf(this.files.js.lightbox));
					// Apply baseurl to files.
					var me = this;
					$.each(this.files, function(group, val){
						$.each(this, function(file, val){
							me.files[group][file] = me.baseurl+val;
						});
					});
					delete me;
					// Add more params if they exist.
					options = $.extend(options, $.params_to_json(this.src));
				}	
			}
			else if (typeof options.files === 'object') {
				// Custom files.
				var me = this;
				$.each(options.files, function(group, val){
					$.each(this, function(file, val){
						this[file] = me.baseurl+val;
					});
				});
				delete me;
			}
			else {
				// If no files then perform domReady.
				domReady = false;
			}
			// Apply options
			for ( i in this.options ) {
				// Cycle through the options.
				var name = this.options[i];
				if ((typeof options[name] === 'object') && (typeof this[name] === 'object')) {
					// There is a group like text or files.
					this[name] = $.extend(this[name], options[name]);
				}
				else if (typeof options[name] !== 'undefined') 	{
					// Apply the option.
					this[name] = options[name];
				}
			}
			// Handle IE6.
			if (initial && navigator.userAgent.indexOf('MSIE 6') >= 0) {
				this.ie6 = true;
			}
			else {
				this.ie6 = false;
			}
			// Handle the DOM.
			if (domReady || typeof options.download_link !== 'undefined' ||  typeof options.colorBlend !== 'undefined' || typeof options.files === 'object' || typeof options.text === 'object' || typeof options.show_linkback !== 'undefined' || typeof options.scroll_with !== 'undefined')	{
				$(function() {
					// Fire the DOM handler.
					$.Lightbox.domReady();
				});
			}
			return true;
		},
		domReady: function ( ) {
			// Grab resources
			var bodyEl = document.getElementsByTagName($.browser.safari ? 'head' : 'body')[0];
			var stylesheets = this.files.css;
			var scripts = this.files.js;
			// Handle IE6 appropriatly
			if ( this.ie6 && this.ie6_upgrade ) {
				// Add the upgrade message.
				scripts.ie6 = 'http://www.savethedevelopers.org/say.no.to.ie.6.js';
			}
			// Color blend.
			if ( this.colorBlend === true && typeof $.colorBlend === 'undefined' ) {
				// Force colorBlend. Leave file in place to be loaded.
				this.colorBlend = true;
			}
			else {
				// Check whether colorblend is on or off.
				this.colorBlend = typeof $.colorBlend !== 'undefined';
				// Remove colorBlend file.
				delete scripts.colorBlend;
			}
			// Include stylesheets.
			for (stylesheet in stylesheets ) {
				var linkEl = document.createElement('link');
				linkEl.type = 'text/css';
				linkEl.rel = 'stylesheet';
				linkEl.media = 'screen';
				linkEl.href = stylesheets[stylesheet];
				linkEl.id = 'lightbox-stylesheet-'+stylesheet.replace(/[^a-zA-Z0-9]/g, '');
				$('#'+linkEl.id).remove();
				bodyEl.appendChild(linkEl);
			}
			// Include javascripts.
			for (script in scripts) 	{
				var scriptEl = document.createElement('script');
				scriptEl.type = 'text/javascript';
				scriptEl.src = scripts[script];
				scriptEl.id = 'lightbox-script-'+script.replace(/[^a-zA-Z0-9]/g, '');
				$('#'+scriptEl.id).remove();
				bodyEl.appendChild(scriptEl);
			}
			// Cleanup.
			delete scripts;
			delete stylesheets;
			delete bodyEl;
			// Append markup
			$('#lightbox,#lightbox-overlay').remove();
			$('body').append('<div id="lightbox-overlay"><div id="lightbox-overlay-text">'+(this.show_linkback?'<p><span id="lightbox-overlay-text-about"><a href="#" title="'+this.text.about.title+'">'+this.text.about.text+'</a></span></p><p>&nbsp;</p>':'')+'<p><span id="lightbox-overlay-text-close">'+this.text.help.close+'</span><br/>&nbsp;<span id="lightbox-overlay-text-interact">'+this.text.help.interact+'</span></p></div></div><div id="lightbox"><div id="lightbox-imageBox"><div id="lightbox-imageContainer"><img id="lightbox-image" /><div id="lightbox-nav"><a href="#" id="lightbox-nav-btnPrev"></a><a href="#" id="lightbox-nav-btnNext"></a></div><div id="lightbox-loading"><a href="#" id="lightbox-loading-link"><img src="' + this.files.images.loading + '" /></a></div></div></div><div id="lightbox-infoBox"><div id="lightbox-infoContainer"><div id="lightbox-infoHeader"><span id="lightbox-caption">'+(this.download_link ? '<a href="#" title="' + this.text.download + '" id="lightbox-caption-title"></a>' : '<span id="lightbox-caption-title"></span>')+'<span id="lightbox-caption-seperator"></span><span id="lightbox-caption-description"></span></span></div><div id="lightbox-infoFooter"><span id="lightbox-currentNumber"></span><span id="lightbox-close"><a href="#" id="lightbox-close-button" title="'+this.text.closeInfo+'">' + this.text.close + '</a></span></div><div id="lightbox-infoContainer-clear"></div></div></div></div>');
			// Update Boxes - for some crazy reason this has to be before the hide in safari and konqueror
			this.resizeBoxes();
			this.repositionBoxes();
			// Hide
			$('#lightbox,#lightbox-overlay,#lightbox-overlay-text-interact').hide();
			// Browser specifics IE6.
			if ( this.ie6 && this.ie6_support ) {
				// Support IE6 (IE6 does not support fixed positioning so absolute it - This is okay as we disable scrolling).
				$('#lightbox-overlay').css({
					position:	'absolute',
					top:		'0px',
					left:		'0px'
				});
			}
			// Cycle and preload images.
			$.each(this.files.images, function() {
				// Proload the image.
				var preloader = new Image();
				preloader.onload = function() {
					preloader.onload = null;
					preloader = null;
				};
				preloader.src = this;
			});
			// Apply events. 
			// If the window resizes, act appropriatly
			$(window).unbind().resize(function () {
				// The window has been resized.
				$.Lightbox.resizeBoxes('resized');
			});
			// If the window scrolls, act appropriatly.
			if ( this.scroll === 'follow' ) {
				$(window).scroll(function () {
					// The window scrolled.
					$.Lightbox.repositionBoxes();
				});
			}
			// Prev.
			$('#lightbox-nav-btnPrev').unbind().hover(function() {
				// Hover.
				$(this).css({ 'background' : 'url(' + $.Lightbox.files.images.prev + ') left 45% no-repeat' });
			}, function() {
				// Out.
				$(this).css({'background' : 'transparent url(' + $.Lightbox.files.images.blank + ') no-repeat' });
			}).click(function() {
				$.Lightbox.showImage($.Lightbox.images.prev());
				return false;
			});	
			// Next.
			$('#lightbox-nav-btnNext').unbind().hover(function() {
				// Hover.
				$(this).css({ 'background' : 'url(' + $.Lightbox.files.images.next + ') right 45% no-repeat' });
			}, function() { // out
				$(this).css({ 'background' : 'transparent url(' + $.Lightbox.files.images.blank + ') no-repeat' });
			}).click(function() {
				$.Lightbox.showImage($.Lightbox.images.next());
				return false;
			});
			// Help.
			if (this.show_linkback) {
				// Linkback exists so add handler.
				$('#lightbox-overlay-text-about a').click(function(){window.open($.Lightbox.text.about.link); return false;});
			}
			$('#lightbox-overlay-text-close').unbind().hover(
				function(){
					$('#lightbox-overlay-text-interact').fadeIn();
				}, function(){
					$('#lightbox-overlay-text-interact').fadeOut();
				}
			);
			// Image link.
			$('#lightbox-caption-title').click(function(){window.open($(this).attr('href')); return false;});
			// Assign close clicks.
			$('#lightbox-overlay, #lightbox, #lightbox-loading-link, #lightbox-btnClose').unbind().click(function() {
				$.Lightbox.finish();
				return false;	
			});
			// Relify.
			if ( this.auto_relify ) {
				this.relify();
			}
			return true;
		},
		// Create event.
		relify: function () {
			var groups = {};
			var groups_n = 0;
			var orig_rel = this.rel;
			// Create the groups.
			$.each($('[@rel*='+orig_rel+']'), function(index, obj) {
				// Get the group
				var rel = $(obj).attr('rel');
				// Check to make sure it is really a group.
				if ( rel === orig_rel ) {
					// No group.
					rel = groups_n;
				}
				// Make sure the group exists.
				if (typeof groups[rel] === 'undefined') {
					// Make the group.
					groups[rel] = [];
					groups_n++;
				}
				// Append the image.
				groups[rel].push(obj);
			});
			// Lightbox groups.
			$.each(groups, function (index, group) {
				$(group).lightbox();
			});
			// Done
			return true;
		},
		// Init a batch of lightboxes.
		init: function (image, images) {
			// Establish images.
			if ( typeof images === 'undefined' ) {
				images = image;
				image = 0;
			}
			// Clear.
			this.images.clear();
			// Add images.
			if (!this.images.add(images)) {
				return false;
			}
			// Check for images.
			if (this.images.empty())	{
				// No images.
				$.log('WARNING', 'Lightbox started, but no images: ', image, images);
				return false;
			}
			// Set active.
			if (!this.images.active(image)) {
				return false;
			}
			// Done.
			return true;
		},
		// Display the lightbox
		start: function ( ) {
			this.visible = true;
			// Adjust scrolling.
			if (this.scroll === 'disable') {
				$(document.body).css('overflow', 'hidden');
			}
			// Fix attention seekers.
			$('embed, object, select').css('visibility', 'hidden');//.hide(); - don't use this, give it a go, find out why!
			// Resize the boxes appropriatly.
			this.resizeBoxes('general');
			// Reposition the boxes.
			this.repositionBoxes({'speed':0});
			// Hide elements here to make the display smoother.
			$('#lightbox-infoFooter').hide();
			$('#lightbox-image,#lightbox-nav,#lightbox-nav-btnPrev,#lightbox-nav-btnNext,#lightbox-infoBox').hide();
			// Display the boxes.
			$('#lightbox-overlay').css('opacity',this.opacity).fadeIn(400, function() {
				// Show the lightbox.
				$('#lightbox').fadeIn(300);
				// Display first image.
				if (!$.Lightbox.showImage($.Lightbox.images.active())) {
					$.Lightbox.finish();	return false;
				}
			});
			// Done.
			return true;
		},
		// Close lightbox.
		finish: function ( ) {		
			// Hide lightbox.
			$('#lightbox').hide();
			$('#lightbox-overlay').fadeOut(function() {
				$('#lightbox-overlay').hide();
			});
			// Fix attention seekers (Other possible ending - .show();)
			$('embed, object, select').css({ 'visibility' : 'visible' });
			// End active image.
			this.images.active(false);
			// Adjust scrolling.
			if (this.scroll === 'disable') {
				$(document.body).css('overflow', 'visible');
			}
			// Finish.
			this.visible = false;
		},
		// Resize the boxes used on transition or window resize.
		resizeBoxes: function ( type ) {	
			// Resize overlay.
			if (type !== 'transition') {
				// Don't use the transition.
				var $body = $(this.ie6 ? document.body : document);
				$('#lightbox-overlay').css({
					width:		$body.width(),
					height:		$body.height()
				});
				delete $body;
			}
			// Handle cases.
			switch (type) {
				// General resize (start of lightbox).
				case 'general':
					return true;
				break;
				// Window was resized.	
				case 'resized':
					if (this.auto_resize === false){
						// Stop and reposition.
						this.repositionBoxes({'nHeight':nHeight, 'speed':this.speed});
						return true;
					}
				// Transition between images.
				case 'transition':
				// Unknown.
				default:
				break;
			}
			// Get image.
			var image = this.images.active();
			if (!image || !image.width || !this.visible) {
				// No image or no visible lightbox.
				$.log('WARNING', 'A resize occured while no image or no lightbox...');
				return false;
			}
			// Resize image box. (i:image, w:window, b:box, c:current, n:new, d:difference)
			// Get image dimensions.
			var iWidth  = image.width;
			var iHeight = image.height;
			// Get window dimensions.
			var wWidth  = $(window).width();
			var wHeight = $(window).height();
			// Check if we are in size. (Lightbox can take up 4/5 of size.)
			if (this.auto_resize !== false) {
			// Auto resize is on.
				var maxWidth  = Math.floor(wWidth*(4/5));
				var maxHeight = Math.floor(wHeight*(4/5));
				var resizeRatio;
				while (iWidth > maxWidth || iHeight > maxHeight) {
					// Resize if necessary.
					if (iWidth > maxWidth) {
						// Resize width, then height proportionally.
						resizeRatio = maxWidth/iWidth;
						iWidth = maxWidth;
						iHeight = Math.floor(iHeight*resizeRatio);
					}
					// Resize height, then width proportionally.
					if ( iHeight > maxHeight ) {
						resizeRatio = maxHeight/iHeight;
						iHeight = maxHeight;
						iWidth = Math.floor(iWidth*resizeRatio);
					}
				}
			}
			// Get current width and height.
			var cWidth  = $('#lightbox-imageBox').width();
			var cHeight = $('#lightbox-imageBox').height();
			// Get the width and height of the selected image plus the padding (padding*2 for both sides (left+right || top+bottom)).
			var nWidth	= (iWidth  + (this.padding * 2));
			var nHeight	= (iHeight + (this.padding * 2));
			// Diferences.
			var dWidth  = cWidth  - nWidth;
			var dHeight = cHeight - nHeight;
			// Set the overlay buttons height and the infobox width. (Other dimensions specified by CSS.)
			$('#lightbox-nav-btnPrev,#lightbox-nav-btnNext').css('height', nHeight); 
			$('#lightbox-infoBox').css('width', nWidth);
			// Handle final action.
			if (type === 'transition') {
				// Check to see if it is necessary to wait in transition.
				if (dWidth === 0 && dHeight === 0) {
					// If the same size.
					this.pause(this.speed/3);
					this.showImage(null, 3);
				}
				else {
					// If not the same size animate.
					$('#lightbox-image').width(iWidth).height(iHeight);
					$('#lightbox-imageBox').animate({width: nWidth, height: nHeight}, this.speed, function ( ) { $.Lightbox.showImage(null, 3); } );
				}
			}
			else {
				// If resized animate Lightbox.
				$('#lightbox-image').animate({width:iWidth, height:iHeight}, this.speed);
				$('#lightbox-imageBox').animate({width: nWidth, height: nHeight}, this.speed);
			}
			// Reposition.
			this.repositionBoxes({'nHeight':nHeight, 'speed':this.speed});
			// Done.
			return true;
		},
		// Current repositioning.
		repositioning:			false,
		reposition_failsafe:	false,
		repositionBoxes: function (options) {
			// Prepare.
			if (this.repositioning) {
				// Already in correct location.
				this.reposition_failsafe = true;
				return null;
			}
			this.repositioning = true;
			// Options.
			options = $.extend({}, options);
			options.callback = options.callback || null;
			options.speed = options.speed || 'slow';
			// Get page scroll.
			var pageScroll = this.getPageScroll();
			// Figure the position out.
			// alert($(window).height()+"\n"+$(document.body).height()+"\n"+$(document).height());
			// var nHeight = options.nHeight || parseInt($('#lightbox').height(),10) || $(document).height()/3;
			var nHeight = options.nHeight || parseInt($('#lightbox').height(),10);
			// Display lightbox in center.
			// var nTop = pageScroll.yScroll + ($(document.body).height() /*frame height*/ - nHeight) / 2.5;
			var nTop = pageScroll.yScroll + ($(window).height() /*frame height*/ - nHeight) / 2.5;
			var nLeft = pageScroll.xScroll;
			// Animate.
			var css = {
				left: nLeft,
				top: nTop
			};
			if (options.speed) {
				$('#lightbox').animate(css, 'slow', function(){
					if ( $.Lightbox.reposition_failsafe )	{
						// Fire again.
						$.Lightbox.repositioning = $.Lightbox.reposition_failsafe = false;
						$.Lightbox.repositionBoxes(options);
					}
					else {
						// Done.
						$.Lightbox.repositioning = false;
						if ( options.callback )
						{	// Call the user callback
							options.callback();
						}
					}
				});
			}
			else {
				$('#lightbox').css(css);
				if (this.reposition_failsafe) {
					// Fire again.
					this.repositioning = this.reposition_failsafe = false;
					this.repositionBoxes(options);
				}
				else {
					// Done.
					this.repositioning = false;
				}
			}
			// Done.
			return true;
		},
		visible: false,
		showImage: function (image, step) {
			// Establish image.
			image = this.images.get(image);
			if (!image) {
				return image;
			}
			// Default step.
			step = step || 1;
			// Split up below for jsLint compliance.
			var skipped_step_1 = step > 1 && this.images.active().src !== image.src;
			var skipped_step_2 = step > 2 && $('#lightbox-image').attr('src') !== image.src;
			if ( skipped_step_1 || skipped_step_2 )	{
				// Force step 1.
				$.log('We wanted to skip a few steps: ', image, step, skipped_step_1, skipped_step_2);
				step = 1;
			}
			// Decide what needs to be done.
			switch (step) {
				// Preload
				case 1:				
					// Disable keyboard nav.
					this.KeyboardNav_Disable();
					// Show the loading image.
					$('#lightbox-loading').show();
					// Hide elements.
					$('#lightbox-image,#lightbox-nav,#lightbox-nav-btnPrev,#lightbox-nav-btnNext,#lightbox-infoBox').hide();
					// Remove show info events to prevent the info from showing when the image is changing.
					$('#lightbox-imageBox').unbind();
					// Make the image the active image.
					if (!this.images.active(image)) {
						return false;
					}
					// Check if preload is needed.
					if (image.width && image.height) {
						// Preload is not needed so continue to next step.
						this.showImage(null, 2);
					}
					else {
						// A preloader is needed so create it.
						var preloader = new Image();
						// Set callback.
						preloader.onload = function() {
							// Update image with our new info and the preloaded image.
							image.width  = preloader.width;
							image.height = preloader.height;
							// Continue to next step
							$.Lightbox.showImage(null, 2);
							// Kill preloader
							preloader.onload = null;
							preloader = null;
						};
						// Start preload.
						preloader.src = image.src;
					}
					// Done.
				break;
				// Resize the container.
				case 2:
					// Apply image changes.
					$('#lightbox-image').attr('src', image.src);
					// Set container border. (Moved here for Konqueror fix - Credits to Blueyed.)
					if (typeof this.padding === 'undefined' || this.padding === null || isNaN(this.padding)) {
						// Autodetect.
						this.padding = parseInt($('#lightbox-imageContainer').css('padding-left'), 10) || parseInt($('#lightbox-imageContainer').css('padding'), 10) || 0;
					}
					// Determine whether or not to use colorBlend.
					if (this.colorBlend) {
						// Background.
						$('#lightbox-overlay').animate({'backgroundColor':image.color}, this.speed*2);
						// Border.
						$('#lightbox-imageBox').css('borderColor', image.color);
					}
					// Resize boxes. (Contains callback to next step.)
					this.resizeBoxes('transition');
					// Done.
				break;
				// Display the image.
				case 3:
					// Hide loading.
					$('#lightbox-loading').hide();
					// Animate image.
					$('#lightbox-image').fadeIn(this.speed*1.5, function() {
						$.Lightbox.showImage(null, 4);
					});
					// Start the proloading of other images.
					this.preloadNeighbours();
					// Show custom handlers.
					if (this.handlers.show !== null) {
						this.handlers.show(image);
					}
					// Done
				break;
				// Set image info/navigation
				case 4:
					// Hide and set image info
					var $title = $('#lightbox-caption-title').html(image.title || 'Untitled');
					if (this.download_link) {
						$title.attr('href', this.download_link ? image.src : '');
					}
					delete $title;
					$('#lightbox-caption-seperator').html(image.description ? ': ' : '');
					$('#lightbox-caption-description').html(image.description || '&nbsp;');
					// If part of a group display image number.
					if (this.images.size() > 1 ) {
						// Display
						$('#lightbox-currentNumber').html(this.text.image + '&nbsp;' + (image.index + 1) + '&nbsp;' + this.text.of + '&nbsp;' + this.images.size());
					}
					else {
						// Empty
						$('#lightbox-currentNumber').html('&nbsp;');
					}
					// Apply info events.
					$('#lightbox-imageBox').unbind('mouseover').mouseover(function(){
						$('#lightbox-infoBox').slideDown('fast');
					});
					$('#lightbox-infoBox').unbind('mouseover').mouseover(function(){
						$('#lightbox-infoFooter').slideDown('fast');
					});
					// Check if it is forced to show.
					if (this.show_extended_info === true) {
						// Force show.
						$('#lightbox-imageBox').trigger('mouseover');
						$('#lightbox-infoBox').trigger('mouseover');
					}
					else if (this.show_info === true) {
						// Force show.
						$('#lightbox-imageBox').trigger('mouseover');
					}
	
					// Define navigation configuration here and not in CSS file, because IE.
					$('#lightbox-nav-btnPrev, #lightbox-nav-btnNext').css({ 'background' : 'transparent url(' + this.files.images.blank + ') no-repeat' });
					// If not the first image, show the previous button.
					if ( !this.images.first(image) ) {
						$('#lightbox-nav-btnPrev').show();
					}
					// If not the last image, show the next button.
					if ( !this.images.last(image) ) {
						$('#lightbox-nav-btnNext').show();
					}
					// Make navigation active.
					$('#lightbox-nav').show();
					// Enable keyboard navigation.
					this.KeyboardNav_Enable();
					// Done.
				break;
				// Error handling.
				default:
					$.log('ERROR', 'Don\'t know what to do: ', image, step);
					return this.showImage(image, 1);
				// break;
			}
			// Done.
			return true;
		},
		// Preload neighboring images.
		preloadNeighbours: function () {			
			// Make sure it is not a single image.
			if (this.images.single() || this.images.empty())	{
				return true;
			}
			// Get the active image.
			var image = this.images.active();
			if (!image) {
			 return image;
			}
			// Load the previous image.
			var prev = this.images.prev(image);
			var objNext;
			if (prev) {
				objNext = new Image();
				objNext.src = prev.src;
			}
			// Load the next image.
			var next = this.images.next(image);
			if (next) {
				objNext = new Image();
				objNext.src = next.src;
			}
		},
		// Keyboard navigation.
		KeyboardNav_Enable: function () {
			$(document).keydown(function (objEvent) {
				$.Lightbox.KeyboardNav_Action(objEvent);
			});
		},
		KeyboardNav_Disable: function () {
			$(document).unbind();
		},
		KeyboardNav_Action: function (objEvent) {
			// Prepare.
			objEvent = objEvent || window.event;
			// Get the keycode.
			var keycode = objEvent.keyCode;
			var escapeKey = objEvent.DOM_VK_ESCAPE /* moz */ || 27;
			// Get key.
			var key = String.fromCharCode(keycode).toLowerCase();
			// Check whether to close.
			if (key === this.keys.close || keycode === escapeKey) {
				return $.Lightbox.finish();
			}
			// Check whether to get the previous image.
			if (key === this.keys.prev || keycode === 37) {
				return $.Lightbox.showImage($.Lightbox.images.prev());
			}
			// Check whether to get the next image.
			if (key === this.keys.next || keycode === 39) {
				return $.Lightbox.showImage($.Lightbox.images.next());
			}
			// Unknown.
			return true;
		},
		getPageScroll: function ( ) {
			var xScroll, yScroll;
			// Some browser.
			if (self.pageYOffset) {
				yScroll = self.pageYOffset;
				xScroll = self.pageXOffset;
			}
			// Explorer 6 Strict.
			else if (document.documentElement && document.documentElement.scrollTop) {
				yScroll = document.documentElement.scrollTop;
				xScroll = document.documentElement.scrollLeft;
			}
			// All other browsers.
			else if (document.body) {
				yScroll = document.body.scrollTop;
				xScroll = document.body.scrollLeft;	
			}
			var arrayPageScroll = {'xScroll':xScroll,'yScroll':yScroll};
			return arrayPageScroll;
		},
		pause: function ( ms ) {
			var date = new Date();
			var curDate = null;
			do { curDate = new Date(); }
			while ( curDate - date < ms);
		}	
	});
	
	// Instantiate
	if (typeof $.Lightbox === 'undefined')	{ 
		$.Lightbox = new $.LightboxClass();
	}
})(jQuery);