/*
*
*	Project: 		Loader
*
*	Version: 		1.0.0 (20th October 2010)
*
*	Author: 		Rolled by Losource (losource.net)
*
*	Description: 	Advanced gallery that preloads and caches images
*
*	License: 		GNU General Public License
*
*	Copyright:		2010 Andrew Flannery
*
*	This program is free software: you can redistribute it and/or modify
*	it under the terms of the GNU General Public License as published by
*	the Free Software Foundation, either version 3 of the License, or
*	(at your option) any later version.
*
*	This program is distributed in the hope that it will be useful,
*	but WITHOUT ANY WARRANTY; without even the implied warranty of
*	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*	GNU General Public License for more details.
*
*	You should have received a copy of the GNU General Public License
*	along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

(function($) {
	var imageCache = new Array();
	var slideShowOn = false;
	var slideShowTimer;
	
	$.fn.loader = function(options) {
		if (!($.browser.msie && $.browser.version.substr(0,1) < 7)) {
			var opts = $.extend({}, $.fn.loader.defaults, options);
		
			this.each(function(i) {
				var elContainer = $(this).addClass('loader-container');

				var localOpts = {
					usingThumbs: $(opts.thumbList).length > 0,
					usingSlideshowControls: $(opts.slideShowControlsAppendee).length > 0,
					slideShowLink: null,
					usingPrevNextControls: $(opts.prevNextControlsAppendee).length > 0,
					usingScanControls: $(opts.scanControlsAppendee).length > 0,
					scanControls: null
				}
			
				localOpts = $.extend({}, localOpts, opts);
			
				//if there's an image already there disable it then send it to load
				if ($(elContainer).children('img').length > 0) {
					var src = $(elContainer).children('img').attr('src');
				
					$(elContainer).children('img').attr('src', '');
				
					if (src != '') {
						loadImage(elContainer, src, $(elContainer).children('img').attr('alt'), localOpts);
					}
				}
			
				//if we have some thumbs
				if (localOpts.usingThumbs) {
					$(localOpts.thumbList).find('a').click(function() {
						var elLink = $(this);
					
						$(localOpts.thumbList).find('li.active').removeClass('active');
					
						$(elLink).parent().addClass('active');

						loadImage(elContainer, $(elLink).attr('rel'), $(elLink).attr('title'), localOpts);
					
						return false;
					}).mousedown(function() {
						stopSlideShow(localOpts);	
					});
				
					//click the first thumb
					if ($(localOpts.thumbList).find('li.active').length > 0) {
						var startThumb = $(localOpts.thumbList).find('li.active').find('a');
					} else {
						var startThumb = $(localOpts.thumbList).find('a').first();
						$(startThumb).parent().addClass('active');
					}
				
					loadImage(elContainer, $(startThumb).attr('rel'), $(startThumb).attr('title'), localOpts, function() {
						//if we're preloading do it here, after loading the first image
						if (localOpts.slidesPreLoad) {
							var pathArray = [];
					
							$(localOpts.thumbList).find('a').each(function() {
								pathArray.push($(this).attr('rel')) 
							});
					
							if (localOpts.additionalPreLoadsFirst) {
								pathArray = localOpts.additionalPreLoads.concat(pathArray);
							} else {
								pathArray = pathArray.concat(localOpts.additionalPreLoads);
							}
						
							populateCache(pathArray);
						}
					});
				
				
					//if we're using prev next controls 
					if (localOpts.usingPrevNextControls) {
						elPrevious = $('<a href="#" class="loader-nav prev" rel="prev">&lt;</a>').click(function() {
							move($(this).attr('rel'), localOpts);
							return false;
						});
					
						elNext = $('<a href="#" class="loader-nav next" rel="next">&gt;</a>').click(function() {
							move($(this).attr('rel'), localOpts);
							return false;
						});
					
						$(opts.prevNextControlsAppendee).append(elPrevious).append(elNext).find('a.nav');		
					}
				
					//if we're using slideshow
					if (localOpts.usingSlideshowControls) {
						localOpts.slideShowLink = $('<a href="" class="loader-slideshow-link">' + localOpts.slideShowStartText + '</a>');
					
						$(localOpts.slideShowLink).click(function() {
							if (slideShowOn) { stopSlideShow(localOpts); } else { startSlideShow(localOpts); }
							return false;
						}).prependTo(opts.slideShowControlsAppendee);
					}
				}
			
				//if we're scan enabled
				if (localOpts.usingScanControls) {
					var elScanUpLink = $('<span href="" class="loader-scan-up-link up">Scan up</span>');
					var elScanDownLink = $('<span href="" class="loader-scan-down-link down">Scan down</span>');
					var scrollTimer;
				
					localOpts.scanControls = $('<ul class="loader-scan-controls disabled"><li></li><li></li></ul>');
				
					$(elScanUpLink).appendTo($(localOpts.scanControls).find('li').eq(0));
					$(elScanDownLink).appendTo($(localOpts.scanControls).find('li').eq(1));
				
					$(localOpts.scanControls).prependTo(opts.scanControlsAppendee);
				
					$(localOpts.scanControls).find('span').mousedown(function() {
						var ctrl = $(this);
					
						stopSlideShow(localOpts);
					
						if ($(ctrl).hasClass('up'))  {
							var dir = 'up';
							var max = 0;
						} else if ($(ctrl).hasClass('down')) {
							var dir = 'down';
							var imgH = $(elContainer).find('img').height();
							var contH = $(elContainer).height();
							var max = contH - imgH;
						}
					
						scrollTimer = setInterval(function() { scroller(dir, max, elContainer, localOpts); }, 1);
					}).mouseup(function() {
						clearInterval(scrollTimer);
					});
				
					$(window).resize(function() { checkScanControls(elContainer, localOpts); });
				}
			});
		}
	};
	
	function populateCache(pathArray) {
		var count = 0;
	    var totalImages = pathArray.length;
    	
    	var loadNext = function() {
    		var path = pathArray[count];
    		
    		
    		if (!inCache(path)) {
				var img = new Image;
			
				$(img).load(function() {
					count++;
					if (count <= totalImages) loadNext();
					addCache(path, img);
        		}).attr({
        			src: path
	        	});
			} else {
				count++;
				loadNext();
			}
		}
		
		loadNext();
	}
	
	function addCache(path, img) {
		imageCache[path] = img;
	}
	
	function inCache(path) {
		if (path in imageCache) {
			return imageCache[path];
		}
		
		return false;
	}
	
	function addImage(elContainer, img, caption, opts, callback) {
		//hide the image so we have something to fade in
		$(img).hide();
				
		//add it the image to the dom
		$(img).appendTo(elContainer);
				
		//sort out v centring
		if (opts.verticalCentreImage) {
			vertCentreImage(elContainer, opts);
			$(opts.verticalCentreContainer).resize(function() { vertCentreImage(elContainer, opts); });
		}
		
		checkScanControls(elContainer, opts)
				
		//fade in the image
		$(img).attr('alt', caption).fadeIn(function() {
			$(opts.captionContainer).html(caption);
			
			//if the slideshow is on then get ready for the next image
			if (slideShowOn) {
				slideShowTimer = setTimeout(function() { move('next', opts); }, 3000);	
			}
			
			if (callback) {
				callback();
			}
		});
	}
	
	function loadImage(elContainer, src, caption, opts, callback) {
		caption = caption || '';
		
		//get the old content
		var oldContent = $(elContainer).children('img');
		
		//add loading class
		$(elContainer).addClass('loading');
		
		//fade out old stuff and start working with new
		$(oldContent).fadeOut('normal', function() {
			$(oldContent).remove();
			
			if (inCache(src)) {
				//get the image from the cache
				var img = inCache(src);	
				
				addImage(elContainer, img, caption, opts, callback);
			} else {
				//its not cached so we load it
				var img = new Image;
				
				$(img).load(function() {
					addImage(elContainer, img, caption, opts, callback);
					
					//push the image into the cache
					addCache(src, img);
				}).attr({
					src: src,
					alt: caption,
					title: caption
				});
			}
		});
	}
	
	function vertCentreImage(elContainer) {
		var img = $(elContainer).find('img');

		if ($(img).length > 0) {
			var imgH = $(img).height();
			var contH = $(elContainer).height();
				
			$(img).css({ 'top': (contH-imgH)/2 });
		}
	}
	
	function move(i, opts) {
		var len = $(opts.thumbList).find('li').length;
		var iActive = $(opts.thumbList).find('li').index($(opts.thumbList).find('li.active'));
		
		switch (i) {
			case 'first':
				i = 1;
				break;
				
			case 'prev':
				i = iActive - 1;
				break;
			
			case 'next':
				i = iActive + 1;
				break;
				
			case 'last':
				i = len - 1;
				break;
		}
		
		if (i < 0) i = len - 1;
		
		if (i > (len - 1)) i = 0;
		
		$(opts.thumbList).find('li').eq(i).find('a').click();
	}
		
	function startSlideShow(opts) {
		move('next', opts);
		slideShowOn = true;
		$(opts.slideShowLink).text(opts.slideShowStopText)
	}
	
	function stopSlideShow(opts) {
		clearTimeout(slideShowTimer);
		slideShowOn = false;
		$(opts.slideShowLink).text(opts.slideShowStartText)
	}
	
	function imageIsOversize(elContainer) {
		var img = $(elContainer).find('img');
		
		if ($(img).length > 0) {
			var imgH = $(img).height();
			var contH = $(elContainer).height();
		
			return (imgH > contH);
		}
		
		return false;
	}
	
	function enableScanControls(opts) {
		$(opts.scanControls).removeClass('disabled');
	}
	
	function disableScanControls(opts) {
		$(opts.scanControls).addClass('disabled');
	}
	
	function checkScanControls(elContainer, opts) {
		if (imageIsOversize(elContainer)) { 
			enableScanControls(opts);
		} else { 
			disableScanControls(opts);
		}
	}
	
	function scroller(dir, max, elContainer, localOpts) {
		var currentPosition = parseInt($(elContainer).find('img').css('top'));
		
		var img = $(elContainer).find('img');
		
		if (dir == 'up') {
			if ((currentPosition + 5) < max) {
				$(img).css('top', currentPosition + 5);
			}
		} else if (dir == 'down') {			
			if ((currentPosition - 5) > max) {
				$(img).css('top', currentPosition - 5);
			}
		}
	}
	
	$.fn.loader.defaults = {
		verticalCentreImage: false,
		verticalCentreContainer: null,
		thumbList: null,
		slidesPreLoad: true,
		additionalPreLoads: null,
		additionalPreLoadsFirst: false,
		prevNextControlsAppendee: null,
		slideShowControlsAppendee: null,
		slideShowStartText: 'Start slide show',
		slideShowStopText: 'Stop slide show',
		scanControlsAppendee: null
	};
	
})(jQuery);

