(function($) {
	var _count=0;
	var debug=false;
	$.fn.slideshow = function(options) {	
		// Extend options with defaults. 
		options = $.extend({}, $.fn.slideshow.defaults, options);
		var selector = this.selector;

		return this.each(function() {
			var container = $(this);
			var instance = container.data('slideshow');
			if (instance) {
				instance.destroy();
				delete instance;
			}
			instance = new Slideshow(container, options);
			container.data('slideshow', instance);
		});
	};
	
	var Slideshow = function(container, options) {
			var slideshowId = ++_count;
			var placeholders = container.children('a'),
				imgs=[],
				busy = false,
				currentIdx = -1,
				nextIdx = -1, 
				currentImg = 0;
				
			var eventScope = 'slideshow_'+slideshowId;


			this.destroy = function() {
				container.unbind('.slideshow');
				pauseSlideshow();
				if (options.toggle) {
					$(options.toggle).unbind('click', onToggleClick);
				}
			};	


			// Loop thru the placeholders. 
			placeholders.each(function(i) {
				var img,src,
					placeholder=$(this);
				
				if (this.tagName != 'A') {
					var newPlaceholder = $('<a rel="image" href="'+this.src+'"></a>');
					placeholder.replaceWith(newPlaceholder);
					placeholders[i] = placeholder = newPlaceholder;
				};
				
				switch(placeholder.attr('rel')) {
					default:
					case 'image':
						var img = document.createElement('img');
						img.original = this.href;
						img.__type = 'image';
						$(img).css({display: 'none', visibility: 'hidden'});
						img.id = placeholder.attr('id');
						placeholder.replaceWith(img).attr('id', null);
						img.className = placeholder.attr('className');
						img.title = placeholder.attr('title');
						imgs[i] = img;
						break;
						
					case 'movie':
						// Quicktime movie
						var id = placeholder.attr('id');		
						var tmpId = 'slideshow-tmp-'+(+new Date());
						var object = '';
						/*
						object+= '<object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"';
						object+= ' id="'+tmpId+'" title="'+placeholder.attr('title')+'" ';
						object+= ' class="'+placeholder.attr('className')+'" ';
						object+= '	codebase="http://www.apple.com/qtactivex/qtplugin.cab" ';
						object+= '	height="200" width="400" style="display:none; visibility:hidden;">';
						object+= '		<param name="src" value=""/>';
						object+= '		<param name="controller" value="true" />';
						object+= '		<param name="kioskmode" value="true" />';
						object+= '		<param name="scale" value="aspect" />';
				//		object+= '		<param name="href" value="'+this.href+'" />';
				*/
						object+= '		<embed  type="video/quicktime" pluginspage="http://www.apple.com/quicktime/download/" ';
						object+= '	id="'+tmpId+'" class="'+placeholder.attr('className')+'" style="display:none; visibility:hidden;"	';
						object+= '			height="200" width="400" scale="aspect" ';
						object+= '			controller="true"  kioskmode="true" ';
						if (placeholder.hasClass('noplay'))
							object+= '			autoplay="false" ';
//						object+= '			href="'+this.href+'" ';
						object+= '			/>';
//						object+= '</object>';
					
						var style = placeholder.attr('style');
						placeholder.replaceWith(object);
						try {
						imgs[i] = $('#'+tmpId).get(0);
						imgs[i].id = id;
						imgs[i].original = this.href;
						imgs[i].style.cssText = style; 
						imgs[i].__type = 'movie';
						} catch(e) {
						debugger;
						}
						break;
				}
			});
			
			container.bind('slideshow:next.slideshow', next);
			container.bind('slideshow:prev.slideshow', prev);
			container.bind('slideshow:goto.slideshow', goto);
			container.bind('slideshow:refresh.slideshow', refresh);
			container.bind('slideshow:play.slideshow', continueSlideshow);
			container.bind('slideshow:stop.slideshow', pauseSlideshow);
			container.bind('slideshow:delete.slideshow', deleteItem);
			
			function deleteItem(ev) {
				var c = currentIdx;
				nextIdx = -1;
				currentIdx = -1;
				imgs = imgs.splice(c, 1);
				showImage(c);
			}
			if (options.toggle) {
				$(options.toggle).click(onToggleClick);
			}
			function onToggleClick(ev) {
				if (running) 
					pauseSlideshow();
				else
					continueSlideshow();
			}
			
			var theTimeout=null;
			var running = options.startSlideshow;
		
			function clearSlideshowTimeout() {
				if (theTimeout) {
					clearTimeout(theTimeout);
					theTimeout = null;
				}
			}
			function pauseSlideshow() {
				clearSlideshowTimeout();			
				if (running) {
					running=false;
					if (options.toggleCallback)
						options.toggleCallback(running);
				}
			}
			function continueSlideshow(delay) {
				delay = delay ? delay : options.slideshowStartupDelay
				setSlideshowTimeout(delay);
				if (!running) {
					running=true;
					if (options.toggleCallback)
						options.toggleCallback(running);
				}
			}
			function setSlideshowTimeout(delay) {
				clearSlideshowTimeout();
				function onTimeout() {
					next();
					theTimeout=null;
				}
				theTimeout = setTimeout(onTimeout, delay);
			}
		
			if (options.showFirst) {
				showImage(0);
			}
			
			
			
			container.addClass('slideshow');
			
			function next(ev) {
				showImage(currentIdx+1);
			}
			function prev(ev) {
				showImage(currentIdx-1);
			}
			function goto(ev, imgNr) {
				showImage(imgNr);
			}

			function showImage(idx) {
				var imgs = container.children('img, embed, object');
				if (!imgs.length) {
					return;
				}
				if (busy) {
					// @todo..
					// For controls, it is satisfying enough, to just be stopped, 
					// but for other purposes, this is not enough as it might halt image-preloading. 
					// Should really consider putting that logic in the application. 
				}
/*				if (debug)
					debugger;
	*/			
				if (idx !== false) {
					if (idx >= imgs.length) {idx = 0;}
					if (idx < 0) idx = imgs.length -1;
					
					if (nextIdx === idx) 
						return;
					
					var img = imgs[idx],
						$img = $(img),
						src = img.original;
												
					nextIdx = idx;
					
					try {
						if (options.beforeLoad)
							src = options.beforeLoad.call(container, src);
					}catch(e) {
						debugger;
					}
						
					function onLoaded() {
						try {
							img.onload=null;
						} catch(e) {
							img.onLoad = null;
						}
						$('#slideshow-queue').dequeue();
					
						size = {width: container.width(), height: container.height()};
					
						$img.css({display: 'block', visibility: 'hidden'});

						if (options.positionImage && img.__type == 'image') {						
							var top = options.valign * (size.height - img.height);
							var left = options.halign * (size.width - img.width);
							left = left<0 ? 0 : left;
							top = top< 0 ? 0 : top;
							$img.css({
								top: top + 'px', 
								left: left + 'px'
							});
							if (img.height == 0 && img.__type=='image') {
								$('#debug').prepend('image height is zero');
							}
						}
						if (img.__type == 'movie') {
							running = false;
						}
						$img.css({display: 'none', visibility: 'visible'});
						
						if (options.transition) {
							busy = true;
							try {							
							container.trigger('slideshow:beginTransition');
							}catch(e) {
								// sometimes in IE the trigger method seems to fail
							}
							options.transition.apply(container, [currentImg, img, function(ignore) {
								try {							
								container.trigger('slideshow:endTransition');
								}catch(e) {
									// sometimes in IE the trigger method seems to fail
								}
								if (!ignore) {
									if (running)
										continueSlideshow(options.slideshowInterval);
									busy = false;
									if (currentImg && currentImg.__type == 'movie') {
										$(currentImg).hide().css({height: 0}).get(0).height=0;
										$(currentImg).attr('src', '').find('embed').attr('src', '');
										$(currentImg).find('param[name=src]').attr('value', '');
										$(currentImg).replaceWith('<span id="safaribugfix"></span>');
										$('#safaribugfix').replaceWith(currentImg);
									}
									currentIdx = idx;
									currentImg = img;
								} 
							}]);
						} else {
							if (currentImg)
								currentImg.hide();
							$img.show();
							currentIdx = idx;
							currentImg = $img;
						}
						
					}
					function loader() {
						if (img.__type == 'movie') {
							$(img).attr('src', src).find('embed').attr('src', src);
							$(img).find('param[name=src]').attr('value', src);
							onLoaded();
						} else {
							try {
								img.onload = onLoaded;
							} catch(e) {
								img.onLoad = onLoaded;
							}
							img.src = src;
							if (img.complete) {
								onLoaded();
							}
						}
					}
					if (running) {
						// SKip the queue if the slideshow is running 
						loader();
					} else {
						$('#slideshow-queue').queue(loader);
					}
					
				} else {
					nextIdx = idx;
					if (options.transition) {
						busy=true;
						options.transition.apply(container, [currentImg, null, function(ignore) {
							if (!ignore) {
								if (running)
									continueSlideshow();
							
								busy = false;
								currentIdx = -1;
								currentImg = null;
							}
						}]);
					} else {
						if (currentImg) 
							currentImg.hide();
						currentIdx = -1;
						currentImg = null;
					}
				}
			}
			function refresh(ev) {
				nextIdx = -1;
				showImage(currentIdx);
			}
	}
	$(function() {
		$(document.body).append('<div id="slideshow-queue" style="display:none;"></div>');
	});
	
	$.fn.slideshow.defaults = {
		showFirst: true, 
		startSlideshow: false,
		slideshowInterval: 3000, 
		slideshowStartupDelay: 5000,
		positionImage: true,
		slideshowQueue: 'slideshow-queue',
		valign: 0.5, 
		halign: 0.5,
		toggle: '', 
		toggleCallback: '',
		transition: null,		// callback function (fromImg, toImg, callback);
		beforeLoad: null		// callback function (src), returns src
	}
})(jQuery);
