/*

Phototacious version 0.9.1

Added the debug variable

*/


(function($) {

	var settings;

	
	$.fn.phototacious = function(customSettings) {

		settings = $.extend({

					debug: false,
		
					//The image that should be display when the photo is not loaded yet
					loadingImage: 'loadingAnimation.gif',

					//Should the photos by loop on the end of the collection
					photoLoop: true,

					//Should the photos by loop on the end of the collection when in a slideshow
					slideShowLoop: true,

					//The timeout of the slideshow
					slideshowTimeout: 3000,

					//Do we want photos being preloaded
					preLoad: true,
					
					//Margin of the outer box to the window
					messageMargin: 10,

					//The minimum dimensions of a photo
					minPhotoWidth: 200,
					minPhotoHeight: 200,

					//The current photo
					currentPhoto: 1,	

					//Fade out timeout
					photoFadeOut: 900,

					//Fade in timeout
					photoFadeIn: 900,

					//The prefix text for the photo
					statusPrefix: 'photo ',

					//The seperator betwen the numbers: 1 =>of<= 10
					statusNumberSeperator: ' of ',					

					//Css for the overlay
					overlayCSS:  { 
						cursor: 'default',
						backgroundColor: '#000',
						opacity: 0.8
					},

					//Css for the photos
					photoCSS: { border: 'none' },

					//Css for the message
					messageCSS: { 
						top:  '4px', 
					    cursor: 'default',
						border: '1px solid #FFF',
					    backgroundColor: '#000'
					},

					//The fade in for the overlay
					overlayFadeIn:  200,
					
					//The fade out for the overlay
					overlayFadeOut:  400,
						
					//Should we show an overlay
					showOverlay: true
				
				}, customSettings || {});


		//Anitialize the settings.photos when not done yet	
		//'filename'	contains the photo filename
		//'width'		the width of the photo
		//'height'		the heigth of the photo
		// 
		// other syntax is only a photo url as value
		if(settings.photos==undefined)		settings.photos = new Array();

		if(settings.boxAnimation==undefined)		settings.boxAnimation = true;
		if(settings.boxAnimationDuration==undefined || isNaN(settings.boxAnimationDuration))		
			settings.boxAnimationDuration = 1000;

		
		//Retrieve dimension when handle dimension script is set
		var count = 1;
		customPhotos = settings.photos;
		settings.photos = {};
		for(var key in customPhotos) {

			if(settings.getDimensionsUrl!=undefined) {
				if((typeof customPhotos[key])=='string') {
					count++;	settings.photos[count] = customPhotos[key];
				} else if(customPhotos[key].filename!=undefined) {
					count++;	settings.photos[count] = customPhotos[key].filename;
				}				
			}

			if(settings.getDimensionsUrl==undefined
			&& (customPhotos[key] instanceof Array)!==false
			&& (vars=checkPhotoVars(customPhotos[key]))) {
				count++;	settings.photos[count] = vars;
			}
		}

		$(this).each(function() {

			//Getting the photos
			if(settings.getDimensionsUrl!=undefined) {

				var filename = $(this).attr('href').match(/^.+\.(gif|png|jpg|jpeg)/gi);
				if(filename!==null) {
					count++;
					settings.photos[count] = filename[0];
				}

			} else {

				//Getting the variables
				var vars = {};
				var parts = $(this).attr('href').replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
					vars[key] = value;
				});
			
				//Getting the photos
				var filename = $(this).attr('href').match(/^.+\.(gif|png|jpg|jpeg)/gi);
				if(filename!==null)		vars.filename = filename[0];

				//Store the photo if all details are found		
				if((vars=checkPhotoVars(vars))) {
					count++;
					settings.photos[count] = new Array();
					settings.photos[count]['width'] = vars['width'];
					settings.photos[count]['height'] = vars['height'];
					settings.photos[count]['filename'] = vars['filename'];		
				} 
			}


			//Assign onlick to link, when href isn't set correct show current photo
			$(this).click(function() {
				var filename = $(this).attr('href').match(/^.+\.(gif|png|jpg|jpeg)/gi);
				if(filename!==null) {		photoDisplay(filename[0]); }
				else		photoDisplay(settings.currentPhoto);
				return false;
			});


		});


		//Getting the dimensions of the photos when requested
		if(settings.getDimensionsUrl!=undefined)	getDimensions();


		//Finall check, make sure settings.photos has the right syntax, remove items which haven't 
		var count = 0;	
		customPhotos = settings.photos;
		settings.photos = new Array();
		for(var key in customPhotos) {
			if(vars=checkPhotoVars(customPhotos[key])) {
				count++;
				settings.photos[count] = vars;
			}
		}


		//Restore the function of the links as there isn't any valid photo
		if(count==0) {
			$(this).each(function() {
				$(this).unbind('click');
			});
		}

		//Set auto fit photo to true when undefined
		if(settings.autoFitPhoto==undefined)
			settings.autoFitPhoto = true;

		//Make sure the settings.photos are hidden
		settings.photoCSS.display = 'none';

		settings.photoBorderWidth = 0;		
		if(settings.photoCSS.border!=undefined
		&& (border=settings.photoCSS.border.match(/^[0-9]+/))!==null)		
			settings.photoBorderWidth = (parseInt(border[0])*2);


		//Global defined timeout, false when there isnt a current timeout
		settings.timeoutPhotoLoad = false;			

		//Global defined timeout, false when there isnt a current timeout
		settings.slideshowTimer = false;

		//True when the script is running the slideShow
		settings.slideShow = false;

		//Total settings.settings.photos that should be displayed
		settings.totalPhotos = count;

		//The sequence in which the settings.photos should be loaded
		settings.loadedPhotosSequence = new Array();

		//Array containing all the settings.photos that are currently loading
		settings.loadingPhotos = new Array();					

		//Array containing all the settings.photos that are loaded
		settings.loadedPhotos = new Array();
		
		//Maximum width and height
		settings.photoDisplayWidth = $(window).width();
		settings.photoDisplayHeight = $(window).height();

		//Margins between the photos and the message box
		if(settings.photoDisplayMarginTop==undefined)
			settings.photoDisplayMarginTop = 0;
		if(settings.photoDisplayMarginBottom==undefined)
			settings.photoDisplayMarginBottom = 0;
		if(settings.photoDisplayMarginLeft==undefined)
			settings.photoDisplayMarginLeft = 0;
		if(settings.photoDisplayMarginRight==undefined)
			settings.photoDisplayMarginRight = 0;

		$('body').append("<div id=\"phototaciousDisplayBox\" style=\"display:none;\">"
						 + "<div id=\"phototaciousDisplay\"></div></div>");

		//Enable the #phototaciousDisplayBox
		if(settings.displayStatus!=undefined && settings.displayStatus==true)
			$("#phototaciousDisplayBox").append("<div id=\"phototaciousDisplayStatus\"></div>");

		//Set html for #phototaciousClose link when given
		if(settings.htmlSaveAs!=undefined && settings.saveAsUrl!=undefined) {
			$("#phototaciousDisplayBox").append("<a href=\"#\" id=\"phototaciousSaveAs\"></a>");
			$("#phototaciousSaveAs").html(settings.htmlSaveAs);
			$("#phototaciousSaveAs").click(function() {
				settings.hideControlsMovement = (new Date()).getTime();
				if($(("#photo"+settings.currentPhoto)).length>0) {
					var currentPhotoUrl = $(("#photo"+settings.currentPhoto)).attr('src');
					if(currentPhotoUrl!=undefined) {
						currentPhotoUrl = currentPhotoUrl.match(/^[^\?]+/i)
						currentPhotoUrl = currentPhotoUrl[0];
						window.location = settings.saveAsUrl+currentPhotoUrl;
					}
				}
				return false;
			});
		}
		
		//Set html for #phototaciousClose link when given
		if(settings.htmlClose!=undefined) {
			$("#phototaciousDisplayBox").append("<a href=\"#\" id=\"phototaciousClose\"></a>");
			$("#phototaciousClose").html(settings.htmlClose);
		}

		//Set html for backward link when given
		if(settings.htmlBackward!=undefined) {

			$("#phototaciousDisplayBox").append("<a href=\"#\" id=\"phototaciousBackward\"></a>");
			$("#phototaciousBackward").html(settings.htmlBackward);

			//Assign click event to backward button
			$("#phototaciousBackward").click(function () {	
				settings.hideControlsMovement = (new Date()).getTime();
				photoSwitch('backward');
				return false;
		    });

		}

		//Set html for forward link when given
		if(settings.htmlForward!=undefined) {

			$("#phototaciousDisplayBox").append("<a href=\"#\" id=\"phototaciousForward\"></a>");
			$("#phototaciousForward").html(settings.htmlForward);

			//Assign click event to forward button
		    $("#phototaciousForward").click(function () {
				settings.hideControlsMovement = (new Date()).getTime();
				photoSwitch('forward');
				return false;
		    });

		}

		//Set html slide show
		if(settings.htmlSlideShowStart!=undefined && settings.htmlSlideShowStop!=undefined) {

			$("#phototaciousDisplayBox").append("<a href=\"#\" id=\"phototaciousSlideShow\"></a>");
			$("#phototaciousSlideShow").html(settings.htmlSlideShowStart);

			//When the slideshow link is clicked
			$("#phototaciousSlideShow").click(function () {

				if(settings.slideShow===true)	stopSlideShow();
				else	startSlideShow();
				
				settings.hideControlsMovement = (new Date()).getTime();
				settings.slideshowTimer = setTimeout(function() {	controlSlideShow();	}, settings.slideshowTimeout); 
				return false;  

		    });
		}

						 

		//Setting the navigation for the between steps
		if(settings.steps!=undefined) {
			
			count = 1;
			customSteps = settings.steps;
			settings.steps = new Array();
			settings.steps[0] = 1;
			for(key in customSteps) {
				settings.steps[count] = customSteps[key];
				count++;
			}
			settings.steps[count] = settings.totalPhotos;

			if(settings.htmlForwardStep!=undefined) {

				$("#phototaciousDisplayBox").append("<a href=\"#\" id=\"phototaciousForwardStep\"></a>");
				$("#phototaciousForwardStep").html(settings.htmlForwardStep);

				//Assign click event to forward button
				$("#phototaciousForwardStep").click(function () {
					settings.hideControlsMovement = (new Date()).getTime();
					photoSwitch('forwardStep');
					return false;
			    });

			}

			if(settings.htmlBackwardStep!=undefined) {

				$("#phototaciousDisplayBox").append("<a href=\"#\" id=\"phototaciousBackwardStep\"></a>");
				$("#phototaciousBackwardStep").html(settings.htmlBackwardStep);

				//Assign click event to forward button
				$("#phototaciousBackwardStep").click(function () {
					settings.hideControlsMovement = (new Date()).getTime();
					photoSwitch('backwardStep');
					return false;
			    });

			}
		}


		if(settings.htmlBackwardEnd!=undefined) {

			$("#phototaciousDisplayBox").append("<a href=\"#\" id=\"phototaciousBackwardEnd\"></a>");
			$("#phototaciousBackwardEnd").html(settings.htmlBackwardEnd);

			//Assign click event to forward button
			$("#phototaciousBackwardEnd").click(function () {
				settings.hideControlsMovement = (new Date()).getTime();
				photoSwitch('backwardEnd');
				return false;
		    });

		}


		if(settings.htmlForwardEnd!=undefined) {

			$("#phototaciousDisplayBox").append("<a href=\"#\" id=\"phototaciousForwardEnd\"></a>");
			$("#phototaciousForwardEnd").html(settings.htmlForwardEnd);

			//Assign click event to forward button
			$("#phototaciousForwardEnd").click(function () {
				settings.hideControlsMovement = (new Date()).getTime();
				photoSwitch('forwardEnd');
				return false;
		    });
		}


		//When the window gets resize it will use this
		$(window).bind("resize", function(){
			setDisplayDimensions();
			setCurrentPhotoDimensions();
			boxDisplay('box');
		});  

		
		//Auto start slideshow
		if(settings.slideShowStart==true) {
			settings.slideShow = true;
			if(settings.htmlSlideShowStop!=undefined)
				$("#phototaciousSlideShow").html(settings.htmlSlideShowStop);
			photoDisplay(settings.currentPhoto);
			controlSlideShow();
		}


		settings.hideControlsMovement = false;
		if(settings.hideControlsElements!==undefined) {
			
			settings.hideControlsFading = false;
			settings.hideControlsTimer = false;			
			settings.hideControlsStatus = 'shown';

			if(settings.hideControlsSeconds===undefined || !isNaN(settings.hideControlsSeconds))
				settings.hideControlsSeconds = 4;
			if(settings.hideControlsFadeOut===undefined || !isNaN(settings.hideControlsFadeOut))
				settings.hideControlsFadeOut = 400;
			if(settings.hideControlsFadeIn===undefined || !isNaN(settings.hideControlsFadeIn))
				settings.hideControlsFadeIn = 200;
			
			customControlsElements = settings.hideControlsElements;
			settings.hideControlsElements = new Array();
			for(key in customControlsElements) {
				switch(customControlsElements[key]) {
					
					case 'close':
						element = '#phototaciousClose';
						break;
					case 'forwardStep':
						element = '#phototaciousForwardStep';
						break;
					case 'forwardEnd':
						element = '#phototaciousForwardEnd';
						break;
					case 'backward':
						element = '#phototaciousBackward';
						break;
					case 'forward':
						element = '#phototaciousForward';
						break;
					case 'slideShow':
						element = '#phototaciousSlideShow';
						break;
					case 'saveAs':
						element = '#phototaciousSaveAs';
						break;
					case 'displayStatus':
						element = '#phototaciousDisplayStatus';
						break;
					case 'backwardStep':
						element = '#phototaciousBackwardStep';
						break;
					case 'backwardEnd':
						element = '#phototaciousBackwardEnd';
						break;
				}
				settings.hideControlsElements[settings.hideControlsElements.length] = element;
			}

			if(settings.hideControlsElements.length>0) {

				$('#phototaciousDisplayBox').hover(function() {
					if(settings.hideControlsFading===false) {
						settings.hideControlsFading = true;
						settings.hideControlsStatus = 'shown';
						settings.hideControlsMovement = (new Date()).getTime();
						$(settings.hideControlsElements.join(", ")).fadeIn(settings.hideControlsFadeIn
																	  , function() {	settings.hideControlsFading = false;	});
					}
				}, function() {
					if(settings.hideControlsFading===false) {
						settings.hideControlsFading = true;
						settings.hideControlsStatus = 'hidden';
						settings.hideControlsMovement = false;
						$(settings.hideControlsElements.join(", ")).fadeOut(settings.hideControlsFadeOut
																		, function() {	settings.hideControlsFading = false;	});
					}
				});
				

				if(settings.hideControlsSeconds>0) {
					$('#phototaciousDisplayBox').mousemove(function() {
						settings.hideControlsMovement = (new Date()).getTime();
					});
					hideControls();
				}
			}
		}

		
		//Start preloading the images
		if(settings.preLoad==true)		loadPhotos();

		if(settings.callBackInit!=undefined)
			settings.callBackInit();

		return this;

	};


	function stopSlideShow() {
		settings.slideShow = false;
		if(settings.htmlSlideShowStart!=undefined) {
			$("#phototaciousSlideShow").html(settings.htmlSlideShowStart);
			if(settings.callBackSlideShow!=undefined)
				settings.callBackSlideShow();
		}
	}


	function startSlideShow() {
		settings.slideShow = true;
		if(settings.htmlSlideShowStop!=undefined) {
			$("#phototaciousSlideShow").html(settings.htmlSlideShowStop);	
			if(settings.callBackSlideShow!=undefined)
				settings.callBackSlideShow();						
		}
	}


	/**
	* Getting the dimensions of the photos using an external script
	*/
	function getDimensions() {

		var callBack = false;
		
		data = '';
		for(var key in settings.photos) 
			data += 'photos[]='+settings.photos[key]+'&';
		data = data.substring(0, data.length-1);
		settings.photos = {};

		$.ajax({
		  url: settings.getDimensionsUrl,
		  dataType: 'json',
		  data: data,
		  async: false,
		  success: function(data) {  settings.photos = data;	  	 },
		  error: function() {  
			  if(settings.debug===true)
				alert('Invalid json format returned by '+settings.getDimensionsUrl);	  	 
			}
		});
		return;

	};

	
	/**
	* check if the variables are all set to be used in settings.photos
	* @param vars			an array or object which is checked on the keys: 'width', 'height' and 'filename'
	* @return				on success it returns the vars, on failure it returns false
	*/
	function checkPhotoVars(vars) {
		
		count = 0;
		varsChecked = new Array();
		for(var key in vars) {

			switch(key) {				
				case 'width':
				case 'height':
					if(!isNaN(vars[key])) {
						varsChecked[key] = vars[key];
						count++;
					}
					break;

				case 'filename':
					varsChecked[key] = vars[key];
					count++;
					break;

			}
		}
		if(count==3)	return varsChecked;
		return false;
	};


	/**
	@description				displays a photo in the overlay. Uses the function waitLoadingPhoto to 
								handle a photo that are not loaded yet
	@param integer photo		the key of the photo in the settings.photos array
	@return boolean				true when the photo could be displayed, false when the photo is not loaded
								yet. If so it will continue with the function waitLoadingPhoto to load the photo
	*/
	function photoDisplay(photo) {

		//When photo is a filename
		if(isNaN(photo)) {			
			for(var key in settings.photos) {
				if(settings.photos[key]['filename']==photo) {
					photo = key;
					break;
				}
			}
		}
		if(isNaN(photo))		return false;

		if(settings.hideControlsElements!=undefined
		&& settings.hideControlsElements.length>0)
			$(settings.hideControlsElements.join(", ")).hide();

		//Reset any current photo settings
		settings.currentPhotoDimensions = undefined;

		//Sets the settings.currentPhoto pointer to this photo
		settings.currentPhoto = photo;

		//Check if the settings.currentPhoto is inside the photo array
		if(settings.currentPhoto>settings.totalPhotos) 	settings.currentPhoto = 1;
		if(settings.currentPhoto<1) 				settings.currentPhoto = settings.totalPhotos;	

		//Set the photo status tekst
		photoDisplayStatus();

		//Make sure all the photo displays are set to none
		hideAll();

		//Build the user interface
		boxDisplay('buildUI');
		
		//Checks if the photo is loaded als the function checkPhotoLoad takes care of from this point on
		if(checkPhotoLoaded(settings.currentPhoto)===false) {
			prioritiesLoadingPhotos(settings.currentPhoto);
			waitLoadingPhoto();
			return false;
		}
		boxDisplay('boxAuto');	
		return true;

	};


	/**
	* Puts the diplay on none for all settings.photos
	*/
	function hideAll() {

		//Make sure all the displays are set to none
		for(var i=1; i<=settings.totalPhotos; i++)
			$(("#photo"+i)).css('display', 'none');

	};


	/**
	* Switch the photo from one to the other
	*
	*@param action						'backward' one photo back
	*									'forward' one photo forward
	*									integer the key of the photo in the settings.photos array
	*@return							true when the photo could be displayed, false when the photo is not loaded
	*									yet. If so it will continue with the function waitLoadingPhoto to load the photo
	*/
	function photoSwitch(action) {

		//Determine which action needs to be taken
		var currentPhotoSet = settings.currentPhoto;
		switch(action) {

			//Forwards to the nearest point in settings.steps
			case 'forwardStep':

				for(var i=0; i<settings.steps.length; i++) {
					if(settings.steps[i]>settings.currentPhoto) {
						settings.currentPhoto = settings.steps[i];
						break;
					}
				}
				break;

			//Backwards to the nearest point in settings.steps
			case 'backwardStep':
				for(var i=(settings.steps.length-1); i>=0; i--) {
					if(settings.steps[i]<settings.currentPhoto) {
						settings.currentPhoto = settings.steps[i];
						break;
					}
				}
				break;

			//One rewind show first photo
			case 'backwardEnd':
				settings.currentPhoto = 1;
				break;

			//One rewind show first photo
			case 'forwardEnd':
				settings.currentPhoto = settings.totalPhotos;
				break;
			
			//One backward
			case 'backward':
				settings.currentPhoto--;
				break;
			
			//One forward
			case 'forward':
				settings.currentPhoto++;
				break;
			
			//Keep the photo specified in action
			default:				
				settings.currentPhoto = action;
				break;

		}


		//Check if the settings.currentPhoto is inside the photo array
		if(settings.currentPhoto>settings.totalPhotos || settings.currentPhoto<1) {
				
			
			if(settings.slideShow===true && settings.slideShowLoop===false) {
				settings.currentPhoto = currentPhotoSet;
				stopSlideShow();
				return false;
			} else if(settings.slideShow===false && settings.photoLoop===false) {
				settings.currentPhoto = currentPhotoSet;
				return false;
			}
				
			if(settings.currentPhoto>settings.totalPhotos) 		settings.currentPhoto = 1;
			if(settings.currentPhoto<1) 		settings.currentPhoto = settings.totalPhotos;	

		}


		//Fadeout the old photo
		$(("#photo"+currentPhotoSet)).fadeOut(settings.photoFadeOut, function() {
		
			//Make sure all the displays are set to none
			hideAll();	

			//Set the photo status tekst
			photoDisplayStatus();

			setCurrentPhotoDimensions();
		
			//Checks if the photo is loaded else the function checkPhotoLoad takes care of from this point on
			if(checkPhotoLoaded(settings.currentPhoto)===false) {	
				prioritiesLoadingPhotos(settings.currentPhoto, action);			
				waitLoadingPhoto();
				return false;
			}
		
			//Load the settings.currentPhoto
			boxDisplay('boxAuto');
			return true;

		});
	};


	/**
	*	Waits for the current photo to be loaded into the users cache and then displays it
	*	shows a loading image while waiting
	*/
	function waitLoadingPhoto() {
	
		if(checkPhotoLoaded(settings.currentPhoto)===false) {

			if(settings.timeoutPhotoLoad===false) {
				settings.loadingImageSet = true;
				$('#phototaciousDisplay').css('background', 'url('+settings.loadingImage+') no-repeat center');
			} else	
				clearTimeout(settings.timeoutPhotoLoad);		
			settings.timeoutPhotoLoad = setTimeout(function() {	waitLoadingPhoto();	}, 500);		
			return false;

		}	
		settings.timeoutPhotoLoad = false;

		//Fade in photo and remove the loading background
		boxDisplay('boxAuto');
	
	};


	/**
	* Loads all the settings.photos into the  settings.loadedPhotosSequence array when the photo
	* is not yet in the loadedPhotos array
	*
	* @note					after filling the array it will start loading the 
	*						settings.photos with the function loadPhoto
	*/
	function loadPhotos() {

		for(var i=0; i<settings.totalPhotos; i++) { 
			if(searchArray(settings.loadedPhotos, (i+1))===false
			&& searchArray(settings.loadedPhotosSequence, (i+1))===false)
				settings.loadedPhotosSequence[i] = (i+1);
		}
		loadPhoto('system');

	};


	/**
	* Search in the array for the value and will return the key of the first match
	*
	*@param array					the array that should be searched for the value
	*@param value					the value that needs to be found
	*@return boolean, integer		false when the value was not found, the key when it was
	*/
	function searchArray(array, value) {
	
		for(var i in array) {
			if(array[i]==value)		return i;
		}
		return false;
	};


	/**
	* priorities a photo in the loadedPhotos array, which will be loaded then as
	* the first one in the line. 
	*@param photo			the key of the photo in the settings.photos array
	*@param direction		'backward' / 'forward' , when navigation with the back button also priorities backward
	*@note					replace the global array settings.loadedPhotosSequence with the new created sequence
	*/
	function prioritiesLoadingPhotos(photo, direction) {

		if(direction==undefined)	direction = 'forward';
		photo = parseInt(photo);  //Make sure its an integer for calculation

		var photos = 0;
		var counter = 0;
		var sortedArray = new Array();
		while(photos<settings.totalPhotos) {
			
			switch(direction) {	
				default:
				case 'forward':
					if(photo>settings.totalPhotos)		photo = 1;
					value = 1;
					break;
				case 'backward':
					 if(photo==0)	photo = settings.totalPhotos;
					value = -1;
					break;
			}
			
			if(checkPhotoLoaded(photo)===false
			&& checkPhotoLoad(photo)===false
			&& searchArray(sortedArray, photo)===false) {
				sortedArray[counter] = photo;
				counter++;
			}
			photo += value;
			photos++;

		}
		settings.loadedPhotosSequence = sortedArray;

	};


	/**
	* Loads the next photo in the settings.loadedPhotosSequence array
	*@param reference		'system'		will reload this function till all the settings.photos are loaded
	*						'userDefined'	will load the first photo in line and stops then
	*/
	function loadPhoto(reference) {
		
		if(settings.loadedPhotosSequence.length>0) {

			if(settings.loadedFilenames==undefined)
				settings.loadedFilenames = new Array();


			var photo = settings.loadedPhotosSequence[0];

			//Make sure the photo isn't loaded yet, otherwise remove it
			//and get the following one
			while(checkPhotoLoaded(photo)===true || checkPhotoLoad(photo)===true) {

				//Removed the photo from the settings.loadedPhotosSequence
				settings.loadedPhotosSequence.splice(0, 1);
				if(settings.loadedPhotosSequence.length==0) {
					alert('skipped out');
					return;
				}
				var photo = settings.loadedPhotosSequence[0];

			}
		
			//Removed the photo from the settings.loadedPhotosSequence
			settings.loadedPhotosSequence.splice(0, 1);
		
			//Add the photo to the loadPhoto array
			settings.loadingPhotos[settings.loadingPhotos.length] = photo;

			//Add the img element with the photo to the layer #phototaciousDisplay
			$('#phototaciousDisplay').append('<img src="' + settings.photos[photo].filename + '"'
									  + ' id="photo'+ photo +'" alt="" border="0" style="display: none;">');
			$('#photo'+ photo).css(settings.photoCSS);
			
			//Only add the load event handler when photo really needs to be loaded, otherwise IE 7.0 gives problems.
			if($.inArray(settings.photos[photo].filename, settings.loadedFilenames)==-1) {

				settings.loadedFilenames[settings.loadedFilenames.length] = settings.photos[photo].filename;

				$('#photo'+ photo).attr('src', settings.photos[photo].filename).load(function() {

					//Remove from loadPhoto array
					var key = searchArray(settings.loadingPhotos, photo);
					if(key!==false)		settings.loadingPhotos.splice(key, 1);
				
					//Add to loaded photo to the loadedPhotos array
					settings.loadedPhotos[settings.loadedPhotos.length] = photo;
			
					//photo is loaded and the system made the call, load an other photo
					if(reference=='system')		loadPhoto('system'); 	
			
				});

			} else {

				//Remove from loadPhoto array
				var key = searchArray(settings.loadingPhotos, photo);
				if(key!==false)		settings.loadingPhotos.splice(key, 1);
				
				//Add to loaded photo to the loadedPhotos array
				settings.loadedPhotos[settings.loadedPhotos.length] = photo;
			
				//photo is loaded and the system made the call, load an other photo
				if(reference=='system')		loadPhoto('system'); 	

			}
		} 
	};


	/**
	* Sets the maximum width and height of the available space to show a photo
	*/
	function setDisplayDimensions() {

		var maxWidthPhotos = 0;
		var maxHeightPhotos = 0;
		var minWidthPhotos = 0;
		var minHeightPhotos = 0;
		for(var i=1; i<=settings.totalPhotos; i++) {
			
			//Getting the max width and height of the photos
			if(maxWidthPhotos<settings.photos[i].width)
				maxWidthPhotos = settings.photos[i].width;
			if(maxHeightPhotos<settings.photos[i].height)
				maxHeightPhotos = settings.photos[i].height;
			
			/* Get the highest minimum height and width of the photos 
			   when scalled down to minimum for fixing the box */
			if(settings.autoFitPhoto===false) {

				var heightForEachPixel = settings.photos[i].height/settings.photos[i].width;
				var minHeightPhoto = Math.floor(settings.minPhotoWidth * heightForEachPixel);
				var minWidthPhoto = settings.minPhotoWidth;

				if(minHeightPhoto>minHeightPhotos)		minHeightPhotos = minHeightPhoto;
				if(minWidthPhoto>minWidthPhotos)		minWidthPhotos = minWidthPhoto;

				var widthForEachPixel = settings.photos[i].width/settings.photos[i].height;
				var minWidthPhoto = Math.floor(settings.minPhotoHeight * widthForEachPixel);
				var minHeightPhoto = settings.minPhotoHeight;

				if(minHeightPhoto>minHeightPhotos)		minHeightPhotos = minHeightPhoto;
				if(minWidthPhoto>minWidthPhotos)		minWidthPhotos = minWidthPhoto;

			}
		}

		var marginWidth = settings.photoDisplayMarginLeft 
						+ settings.photoDisplayMarginRight
						+ (settings.photoBorderWidth*2)
						+ (settings.messageMargin*2);
		var maxWidth = $(window).width() - marginWidth;
		if(maxWidth<(settings.minPhotoWidth + marginWidth))
			maxWidth = settings.minPhotoWidth + marginWidth;

		if(maxWidthPhotos<maxWidth)
			settings.photoDisplayWidth = maxWidthPhotos;
		else	settings.photoDisplayWidth = maxWidth;
		

		var marginHeight = settings.photoDisplayMarginTop 
						+ settings.photoDisplayMarginBottom
						+ (settings.photoBorderWidth*2)
						+ (settings.messageMargin*2);
		var maxHeight = $(window).height() - marginHeight;
		if(maxHeight<(settings.minPhotoHeight + marginHeight))
			maxHeight = settings.minPhotoHeight + marginHeight;

		if(maxHeightPhotos<maxHeight)
			settings.photoDisplayHeight = maxHeightPhotos;
		else	settings.photoDisplayHeight = maxHeight;

		if(settings.autoFitPhoto===false) {
			settings.minHeightPhotos = minHeightPhotos;
			settings.minWidthPhotos = minWidthPhotos;
		}

	};


	/**
	* Removes the blockUI overlays and return the website in normal mode
	*/
	function removeBlockUI() {

		settings.slideShow = false;
		if(settings.htmlSlideShowStart!=undefined) {
			$("#phototaciousSlideShow").html(settings.htmlSlideShowStart);
			if(settings.callBackSlideShow!=undefined)
				settings.callBackSlideShow();	
		}
		$.unblockUI();
	
	}


	/**
	* Show which photo the current one is out of the settings.totalPhotos
	*/
	function photoDisplayStatus() {
	
		if($('#phototaciousDisplayStatus').length>0) {
			$('#phototaciousDisplayStatus').html(settings.statusPrefix 
										 + settings.currentPhoto 
										 + settings.statusNumberSeperator 
										 + settings.totalPhotos);
		if(settings.callBackDisplayStatus!=undefined)
			settings.callBackDisplayStatus();
		}

	};


	/**
	@description			check if a photo is already loaded or not
	@param integer photo	the key of the photo in the settings.photos array
	@return boolean			true when the photo is loaded, false on not
	*/
	function checkPhotoLoaded(photo) {

		if(searchArray(settings.loadedPhotos, photo)===false)
			return false;
		return true;

	};


	/**
	@description			check if a photo is already loaded or not
	@param integer photo	the key of the photo in the settings.photos array
	@return boolean			true when the photo is loaded, false on not
	*/
	function checkPhotoLoad(photo) {

		if(searchArray(settings.loadingPhotos, photo)===false)
			return false;
		return true;

	};


	/**
	* controls the slideshow if it should stop or play. 
	* determines the action based on the current status
	* when it's stop it plays and visa versa
	*
	*@param loading			only set to true when the photo is still loading
	*/
	function controlSlideShow(loading) {
	
		if(settings.slideshowTimer!==false)
			clearTimeout(settings.slideshowTimer);
		
		if(settings.slideShow===true && checkPhotoLoaded(settings.currentPhoto)!==false) {

			//Only show new photo when the slideshowTimout wasn't skipped
			if(loading===undefined)		photoSwitch('forward');

			settings.slideshowTimer = setTimeout(function() {		controlSlideShow();	}, settings.slideshowTimeout); 

		//When the photo isn't loaded back return in 500 milliseconds
		} else if(settings.slideShow===true && checkPhotoLoaded(settings.currentPhoto)===false) 
			settings.slideshowTimer = setTimeout(function() {		controlSlideShow(true);	}, 500); 

	};


	/**
	* Check if the controls need to be hidden or show and take action
	*/
	function hideControls() {

		if(settings.hideControlsTimer!==false)
			clearTimeout(settings.hideControlsTimer);

		if(settings.hideControlsFading===false && settings.hideControlsMovement!==false) {
		
			if(settings.hideControlsMovement<((new Date()).getTime()-(settings.hideControlsSeconds * 1000))) { 
				if(settings.hideControlsStatus=='shown') {
					settings.hideControlsFading = true;
					$(settings.hideControlsElements.join(", ")).fadeOut(settings.hideControlsFadeOut
																, function() {	settings.hideControlsFading = false;	});
					settings.hideControlsStatus = 'hidden';
				}
			} else if(settings.hideControlsStatus=='hidden') {
				settings.hideControlsFading = true;
				$(settings.hideControlsElements.join(", ")).fadeIn(settings.hideControlsFadeIn
																, function() {	settings.hideControlsFading = false;	});
				settings.hideControlsStatus = 'shown';
			}
		}
		settings.hideControlsTimer = setTimeout(function() {	hideControls();	}, 500);

	}


	/**
	@description			calculates the new photo size so it fits the screen mainting the ratio and
							resize the current image with the width and height attributes of the img tags
	@param integer photo	the key of the photo in the settings.photos array
	*/
	function setCurrentPhotoDimensions(photo) {

		var photoWidth = parseInt(settings.photos[settings.currentPhoto].width);
		var photoHeight = parseInt(settings.photos[settings.currentPhoto].height);   
		
		var maxWidth = (settings.photoDisplayWidth-settings.photoBorderWidth);
	    if(maxWidth<photoWidth) {	 
			var heightForEachPixel = photoHeight/photoWidth;
			var photoHeight = maxWidth * heightForEachPixel;
			var photoWidth = maxWidth;	 	
		}	

		var maxHeight = (settings.photoDisplayHeight-settings.photoBorderWidth);
		if(maxHeight<photoHeight) {		 
			var widthForEachPixel = photoWidth/photoHeight;
			var photoWidth = maxHeight * widthForEachPixel;
			var photoHeight = maxHeight;	 	
	    }

	
		if(photoWidth<settings.minPhotoWidth || photoHeight<settings.minPhotoHeight) {			
			var photoWidth = parseInt(settings.photos[settings.currentPhoto].width);
			var photoHeight = parseInt(settings.photos[settings.currentPhoto].height);   
			if(settings.photos[settings.currentPhoto].width<settings.photos[settings.currentPhoto].height) {
				var heightForEachPixel = photoHeight/photoWidth;
				var photoHeight = settings.minPhotoWidth * heightForEachPixel;
				var photoWidth = settings.minPhotoWidth;	
			} else {
				var widthForEachPixel = photoWidth/photoHeight;
				var photoWidth = settings.minPhotoHeight * widthForEachPixel;
				var photoHeight = settings.minPhotoHeight;	 
			}
		}
		
		
		//Setting the right width of canvas
		if(settings.autoFitPhoto) {
			height = photoHeight+settings.photoBorderWidth;
			width = photoWidth+settings.photoBorderWidth;
		} else  {	

			if((settings.photoDisplayHeight+settings.photoBorderWidth)<settings.minHeightPhotos) 
				height = settings.minHeightPhotos + settings.photoBorderWidth;
			else	height = settings.photoDisplayHeight+settings.photoBorderWidth;

			if((settings.photoDisplayWidth+settings.photoBorderWidth)<settings.minWidthPhotos)
				width = settings.minWidthPhotos + settings.photoBorderWidth;
			else	width = settings.photoDisplayWidth+settings.photoBorderWidth;

		} 


		var blockMsgLeft = ($(window).width() 
							- width 
							- settings.photoDisplayMarginLeft 
							- settings.photoDisplayMarginRight)/2;		
		var blockMsgTop = ($(window).height() 
							- height 
							- settings.photoDisplayMarginTop 
							- settings.photoDisplayMarginBottom)/2;
		var blockMsgWidth = width
							+ settings.photoDisplayMarginLeft
							+ settings.photoDisplayMarginRight;
		var blockMsgHeight = height
							+ settings.photoDisplayMarginTop
							+ settings.photoDisplayMarginBottom;

		
		var displayBoxWidth = width;
		var displayBoxHeight = height;

		var left = settings.photoDisplayMarginLeft;
		if(left<0)	left = 0;
		var top = settings.photoDisplayMarginTop;
		if(top<0)	top = 0;

		if(settings.autoFitPhoto===false && settings.photoCenter!==false) {
			left = ((width - photoWidth)/2) + settings.photoDisplayMarginLeft;
			top = ((height - photoHeight)/2) + settings.photoDisplayMarginTop;
			width = photoWidth;
			height = photoHeight;
		}
		var displayLeft = left;
		var displayTop = top;
		var displayWidth = width;
		var displayHeight = height;
		
		settings.currentPhotoDimensions = {'photo': {'height':Math.floor(photoHeight)
													, 'width':Math.floor(photoWidth)}
											, 'blockMsg': {'height': Math.floor(blockMsgHeight)
															, 'width':Math.floor(blockMsgWidth)
															, 'left': Math.floor(blockMsgLeft)
															, 'top': Math.floor(blockMsgTop)}
											, 'display': {'height': Math.floor(displayHeight)
															, 'width':Math.floor(displayWidth)
															, 'left': Math.floor(displayLeft)
															, 'top': Math.floor(displayTop)}
											, 'displayBox': {'height': Math.floor(displayBoxHeight)
															, 'width':Math.floor(displayBoxWidth)}};

	};


	function photoFadeIn() {

		if($('#photo'+settings.currentPhoto).length>0) {
			$('#photo'+settings.currentPhoto).css("height", settings.currentPhotoDimensions.photo.height + 'px');   		
			$('#photo'+settings.currentPhoto).css("width", settings.currentPhotoDimensions.photo.width + 'px');	
		}

		$(("#photo"+settings.currentPhoto)).fadeIn(settings.photoFadeIn, function() {
			if(settings.loadingImageSet===true) {
				$('#phototaciousDisplay').css('background-image', 'none');
				settings.loadingImageSet = false;
			}
			return true;
		});

	}


	function boxDisplay(action) {

		//Needed for 'buildUI' or when not set because what kid of reason
		if(settings.currentPhotoDimensions===undefined) {
			setDisplayDimensions();
			setCurrentPhotoDimensions();
		}
				
		switch(action) {

			case 'boxAuto':
				if(settings.boxAnimation===true) 		boxDisplay('boxAnimation');
				else	boxDisplay('boxPhoto');
				break;

			case 'boxAnimation':

				if(parseInt($("div.blockMsg").css('top'))==settings.currentPhotoDimensions.blockMsg.top
				&& parseInt($("div.blockMsg").css('left'))==settings.currentPhotoDimensions.blockMsg.left
				&& parseInt($("div.blockMsg").css('width'))==settings.currentPhotoDimensions.blockMsg.width
				&& parseInt($("div.blockMsg").css('height'))==settings.currentPhotoDimensions.blockMsg.height
				&& parseInt($("#phototaciousDisplay").css('top'))==settings.currentPhotoDimensions.display.top
				&& parseInt($("#phototaciousDisplay").css('left'))==settings.currentPhotoDimensions.display.left
				&& parseInt($("#phototaciousDisplay").css('width'))==settings.currentPhotoDimensions.display.width
				&& parseInt($("#phototaciousDisplay").css('height'))==settings.currentPhotoDimensions.display.height
				&& parseInt($("#phototaciousDisplayBox").css('width'))==settings.currentPhotoDimensions.blockMsg.width
				&& parseInt($("#phototaciousDisplayBox").css('height'))==settings.currentPhotoDimensions.blockMsg.height) {
					photoFadeIn();
					return false;
				}

				$("div.blockMsg").animate({top: settings.currentPhotoDimensions.blockMsg.top+'px'
										, left: settings.currentPhotoDimensions.blockMsg.left + 'px'
										, width: settings.currentPhotoDimensions.blockMsg.width+'px'
										, height: settings.currentPhotoDimensions.blockMsg.height+'px'}
										, settings.boxAnimationDurarion);
				$("#phototaciousDisplay").animate({top: settings.currentPhotoDimensions.display.top+'px'
										, left: settings.currentPhotoDimensions.display.left + 'px'
										, width: settings.currentPhotoDimensions.display.width+'px'
										, height: settings.currentPhotoDimensions.display.height+'px'}
										, settings.boxAnimationDurarion
										, function() {		
											$("#phototaciousDisplayBox").width(settings.currentPhotoDimensions.blockMsg.width);
											$("#phototaciousDisplayBox").height(settings.currentPhotoDimensions.blockMsg.height);												
											photoFadeIn();												
										});
				break;

			case 'buildUI':
		
				$.blockUI({
					message: $('div#phototaciousDisplayBox'), 
					css: settings.messageCSS,
					overlayCSS: settings.overlayCSS,
					fadeIn: settings.overlayFadeIn,
					fadeOut: settings.overlayFadeOut,
					showOverlay: settings.showOverlay
				}); 

	
				//Setting the removeBlockUI() function when clicked on the overlay
				$('.blockOverlay').click(removeBlockUI); 
				if($('#phototaciousClose').length>0)
					$('#phototaciousClose').click(function() { removeBlockUI(); return false;	}); 
				boxDisplay('box');
				break;
			
			case 'boxPhoto':
			case 'box':
				$("div.blockMsg").css("left", settings.currentPhotoDimensions.blockMsg.left + 'px');
				$("div.blockMsg").css("top", settings.currentPhotoDimensions.blockMsg.top + 'px');		
				$("div.blockMsg").width(settings.currentPhotoDimensions.blockMsg.width);
				$("div.blockMsg").height(settings.currentPhotoDimensions.blockMsg.height);
				$("#phototaciousDisplayBox").width(settings.currentPhotoDimensions.blockMsg.width);
				$("#phototaciousDisplayBox").height(settings.currentPhotoDimensions.blockMsg.height);
				$("#phototaciousDisplay").css("left", settings.currentPhotoDimensions.display.left + 'px');
				$("#phototaciousDisplay").css("top", settings.currentPhotoDimensions.display.top + 'px');
				$("#phototaciousDisplay").width(settings.currentPhotoDimensions.display.width);
				$("#phototaciousDisplay").height(settings.currentPhotoDimensions.display.height);

				if($('#photo'+settings.currentPhoto).length>0 && action=='box') {
					$('#photo'+settings.currentPhoto).css("height", settings.currentPhotoDimensions.photo.height + 'px');   		
					$('#photo'+settings.currentPhoto).css("width", settings.currentPhotoDimensions.photo.width + 'px');	
				}
				if(action=='boxPhoto')		photoFadeIn();	
				break;

		}
		return false;
		
	}


})(jQuery);

