

(function($) {

	// Attach event handlers to several elements as a single
	$.fn.hoverGroup = function(handlerIn, handerOut, o)
	{
		var group = this;

		// Set state on each member
		group.each(function() {
			$(this).data('hovered', false);
		});
		
		var elDebug = null; //$("<div></div>");
		if(elDebug) elDebug.css({position: 'absolute', left: 0, top: 0}).appendTo($("body"));
		function debug(str) {
			if(elDebug) elDebug.append("<p style='margin:0;'>" + str + "</p>");
		}
		
		function isGroupHovered(except) {
			var result = false;
			var str = "";
			group.each(function() {
				str += " " + ((this != except) ? $(this).data('hovered') : ("(" + $(this).data('hovered') + ")"));
				if(this != except && $(this).data('hovered')) result = true;
			});
			debug(str + " = " + result);
			return result;
		}
		
		var outTimeout = 0;
		
		// Only trigger 'in' if none in the group are hovered
		// Only trigger 'out' if none in the group are hovered
		group.hover(
			function(event) {
				debug("Over: " + this.className);
				$(this).data('hovered', true);
				if(!isGroupHovered(this) && !outTimeout) {
					debug("==&gt; Executing over");
					handlerIn(event);
				}
			},
			function(event) {
				debug("Out: " + this.className);
				$(this).data('hovered', false);
				if(!isGroupHovered()) {
					outTimeout = window.setTimeout(function() {
						outTimeout = 0;
						if(!isGroupHovered()) {
							debug("==&gt; Executing out");
							handerOut(event);
						}
					}, 100);
				}
			}
		);
		
		return this;
	};


	// Call on slideshow/viewport div
	$.fn.slideshow_spef = function(o) {
	
		// Slideshow
		// * Viewport
		// * Captions
		// * Controls
		// * Menu
		
		var hover_menu = o.perpetualMenu ? false : true;
		
		var slideshow = this;
		slideshow.wrapInner($("<div class='slideshow-viewport'></div>"));
		viewport = $(".slideshow-viewport", slideshow);
		//captions = $("<div class='slideshow-captions'></div>").appendTo(slideshow);
		//controls = $("<div class='slideshow-controls'></div>").appendTo(slideshow);
		//menu = $("<div class='slideshow-menu'></div>").appendTo(slideshow);

		defaultTimeout = 4000;
		
		var images;
		if(o.images) {
			images = o.images;
		}
		if(!images) {
			images = [];
			//$("img", viewport).each(function() {
			//	images.push({ uri: this.src, timeout: defaultTimeout });
			//});
			if(o.menu) {
				$("a", o.menu).each(function() {
					images.push({ uri: this.href, timeout: defaultTimeout });
				});
			}
		}
				
		var width = slideshow.width();
		var height = slideshow.height();
		
		var selected = 1;
		
		slideshow.css({ position: 'relative' });
		
		viewport.css({width: width+'px', height: height+'px' });
		viewport.slideshowViewport({ images: images });
		//viewport.bind('show', function(event) { menu.select(event.id); });

		var alpha_while_fading = $.support.opacity;
		
		/*
		//controls.css({width: width+'px', display: 'none', opacity: 0});
		controls.css({width: width+'px', height: height+"px"});
		controls.slideshowControls({});
		controls.bind('play', function() { viewport.play(); controls.disable('play'); controls.enable('pause'); });
		controls.bind('pause', function() { viewport.pause(); controls.enable('play'); controls.disable('pause'); });
		controls.bind('next', function() { viewport.prev(); return false; });
		controls.bind('prev', function() { viewport.next(); return false; });
		controlButtons = controls.children(".button");
		controlButtons.css({display: 'none'});
		if(alpha_while_fading) controlButtons.css('opacity', 0); 

		menu.css({width: width+'px', position: 'absolute', left: 0, top: height+'px'});
		if(hover_menu) menu.css({ visibility: 'hidden', opacity: 0 });
		//menu.css({width: width+'px' });
		menu.append(o.menu);
		menu.slideshowMenu({ images: o.menu ? null : images });
		menu.select(selected);
		menu.bind('select', function(event) { selected = event.id; viewport.show(event.id); });
		//menu.bind('mouseover', function(event) { viewport.show(event.id); });
		//menu.bind('mouseout', function(event) { if(event.id != selected) { viewport.show(selected); } });
		$('.jcarousel-item a', menu).css({ display: 'block', width: "48px", height: "36px", position: "relative", overflow: "hidden", textAlign: "center" });
    	$('.jcarousel-item a img').each(function() {
			var self = $(this);
			$("<img />").bind('load', function() {
    			//in this scope self refers to the image
				var img = $(this);
				var clip = self.parents('a');
				var w = img.width();
				var h = img.height();
				if(w===0){w = img.attr("width");}
				if(h===0){h = img.attr("height");}
				//grab a ratio for image to user defined settings
				var rw = parseInt(clip.css('width').slice(0,-2))/w;
				var rh = parseInt(clip.css('height').slice(0,-2))/h;
				//determine which has the smallest ratio (thus needing
				//to be the side we use to scale so our whole thumb is filled)
				var ratio;
				if(rw<rh){
					//we'll use ratio later to scale and not distort
					ratio = rh;
					var left = ((w*ratio- parseInt(clip.css('width').slice(0,-2)))/2)*-1;
					left = Math.round(left);
					self.css({right:left});
				}else{
					ratio = rw;
					self.css({top:0});
				}
				//use those ratios to calculate scale
				var width = Math.round(w*ratio);
				var height = Math.round(h*ratio);
				self.css("position","relative");
				var imgcss={
					width: width+"px",
					height: height+"px"
				};
				self.css(imgcss);
    		}).attr('src', $(this).attr('src'));
		});

		
		(slideshow.add(viewport).add(controls).add(menu)).hoverGroup(
			function() {
				controlButtons.stop().css({display: 'block'});
				if(alpha_while_fading) controlButtons.stop().animate({opacity: 1 }, 500); 
				if(hover_menu) menu.css({visibility: 'visible'}).stop().animate({opacity: 1 }, 500);
				viewport.pause();
				controls.enable('play'); controls.disable('pause');
			},
			function() {
				//if(alpha_while_fading) controlButtons.stop().animate({opacity: 0 }, 500, function() { $(this).css({display: 'none'}); } );
				//else controlButtons.css({display: 'none'});
				controlButtons.stop().animate(alpha_while_fading ? {opacity: 0 } : { margin: 0 }, 500, function() { $(this).css({display: 'none'}); } );
				if(hover_menu) menu.stop().animate({opacity: 0 }, 500, function() { $(this).css({visibility: 'hidden'}); } );
				viewport.play();
				controls.disable('play'); controls.enable('pause');
			}
		);
		 */
		
		viewport.play();
	};

})(jQuery);



// Viewport (Slideshow)
// ==================================================================
// * Container div, either empty or one image there
// * Initially stopped
// * options
//   * images: [ { uri, timeout}, ... ]
// * show(id)
// * play()
// * pause()
// * next()
// * prev()
// * first()
// * last()
(function($) {

	$.fn.slideshowViewport = function(o) {
		this.data('images', o.images);
		this.data('listeners', { show: [] });
		this.data('tmpimg', null);
		this.css({ position: 'relative', overflow: 'hidden' });
		this.each(function() {
			var img = $("img", this);
			if(img.length == 0) {
				img = new Image();
				img.src = $(this).data('images')[0].uri;
				img = $(img);
				$(this).append(img);
			}
			img.addClass('current');
			$(this).data('state', { current: 0, playing: false, timeout: 0 });
		});
		
		this.play = function() { play(this); };
		this.pause = function() { pause(this); };
		this.show = function(id) { show(this, id); };
		this.next = function() { next(this); };
		this.prev = function() { prev(this); };
		this.bind = function(eventType, handler) {
			this.data('listeners')[eventType].push(handler);
		}
		
		return this;
	};

	function swapImage(container, id) {
		container.data('state').current = id;
		if(container.data('state').timeout) {
			window.clearTimeout(container.data('state').timeout);
			container.data('state').timeout = 0;
			$('img.tmpimg', container).stop();
		}
		var img = $("img.current", container)[0];

		var tmpimg = container.data('tmpimg');
		if(tmpimg) {
			$(tmpimg).remove();
		}			
		tmpimg = new Image();
		container.data('tmpimg', tmpimg);
		
		$(tmpimg).css({ position: 'absolute', top: 0, left: 0, opacity: 0 });
		$(tmpimg).addClass('tmpimg');
		$(tmpimg).appendTo(container);
		var loaded = false;
		var animLength = 1000;
		$(tmpimg).bind('load', function() {
			if(loaded) return;
			loaded = true;
			$(tmpimg).css({ width: $(img).width() + "px", height: $(img).height() + "px"});
			$(tmpimg).animate({opacity: 1.0}, animLength, function() {
				img.src = tmpimg.src;
				$('a', container).attr('href', container.data('images')[id].link ? container.data('images')[id].link : '');
				//$(this).remove();
				//window.setTimeout(function() { $(tmpimg).remove(); }, 100);
				if(container.data('state').playing && container.data('state').current == id) {
					var dur = container.data('images')[id].timeout;
					container.data('state').timeout = window.setTimeout(function() { container.data('state').timeout = 0; next(container); }, dur);
				}
			});
		});
		tmpimg.src = container.data('images')[id].uri;
		
		var event = { id: id + 1};
		for(var i in container.data('listeners').show) {
			container.data('listeners').show[i](event);
		}
	}
	
	function play(c)
	{
		var state = c.data('state');
		if(!state.playing) {
			state.timeout = window.setTimeout(function() { c.data('state').timeout = 0; next(c); }, c.data('images')[state.current].timeout);
			state.playing = true;
			// dispatchEvent
		}
	}

	function pause(c)
	{
		var state = c.data('state');
		if(state.playing) {
			window.clearTimeout(state.timeout);
			state.timeout = 0;
			state.playing = false;
			// dispatchEvent
		}
	}
	
	function show(c, id)
	{
		swapImage(c, Math.max(1, Math.min(id, c.data('images').length)) - 1);
	}

	function next(c)
	{
		var id_next = (c.data('state').current + 1) < c.data('images').length ? (c.data('state').current + 1) : 0;
		swapImage(c, id_next);
	}
	
	function prev(c)
	{
		var id_next = (c.data('state').current - 1) >= 0 ? (c.data('state').current - 1) : (c.data('images').length - 1);
		swapImage(c, id_next);
	}

})(jQuery);



// Controls (Slideshow)
// ==================================================================
(function($) {
	$.fn.slideshowControls = function(options) {
		this.each(function() {
			var btn = {};
			if(0) {
				btn.play = $("<button class='button button-play'>Play<\/button>");
				btn.pause = $("<button class='button button-pause disabled' disabled='disabled'>Pause<\/button>");
				//btn.first = $("<button class='button button-first'>First<\/button>");
				//btn.last = $("<button class='button button-last'>Last<\/button>");
				btn.next = $("<button class='button button-next'>Next<\/button>");
				btn.prev = $("<button class='button button-prev'>Prev<\/button>");
			}
			else {
				btn.play = $("<a class='button button-play'>Play<\/a>");
				btn.pause = $("<a class='button button-pause disabled' disabled='disabled'>Pause<\/a>");
				//btn.first = $("<a class='button button-first'>First<\/a>");
				//btn.last = $("<a class='button button-last'>Last<\/a>");
				btn.next = $("<a class='button button-next'>Next<\/a>");
				btn.prev = $("<a class='button button-prev'>Prev<\/a>");
			}
			
			//$(this).append(btn.first);
			$(this).append(btn.prev);
			//$(this).append(btn.play);
			//$(this).append(btn.pause);
			$(this).append(btn.next);
			//$(this).append(btn.last);
			$(this).data('buttons', btn);
		});
		this.bind = function(eventType, handler) {
			switch(eventType) {
			case 'play':	$(this).data('buttons').play.bind('click', handler);	break;
			case 'pause':	$(this).data('buttons').pause.bind('click', handler);	break;
			case 'next':	$(this).data('buttons').next.bind('click', handler);	break;
			case 'prev':	$(this).data('buttons').prev.bind('click', handler);	break;
			}
		};
		this.enable = function(button, state) {
			var btn = $(this).data('buttons')[button];
			state = state === undefined ? true : state;
			if(btn) {
				if(state && btn.attr('disabled')) {
					btn.removeClass('disabled');
					btn.attr('disabled', null);
					// dispatchEvent ???
				}
				if(!state && !btn.attr('disabled')) {
					btn.addClass('disabled');
					btn.attr('disabled','disabled');
					// dispatchEvent ???
				}
			}
		}
		this.disable = function(button) {
			this.enable(button, false);
		}
		return this;
	};
})(jQuery);


// Menu (Slideshow)
// ==================================================================
(function($) {
	$.fn.slideshowMenu = function(o) {
		this.each(function() {
			var self = $(this);
			self.data('listeners', { select: [], mouseover: [], mouseout: [] });
			self.data('state', { selected: 0, mouseover: 0 });
			var ul = $("ul", this);
			if(o.images) {
				ul = $("<ul></ul>");
				for(var i = 0; i < o.images.length; ++i) {
					var a = $("<a href=''><img src='" + o.images[i].uri + "' alt='' /></a>");
					ul.append($("<li></li>").append(a));
				}
			}
			$(this).append(ul);
			$("a", ul).each(function() {
				$(this)
					.bind('click', function() {
						var event = { id: $(this).closest('li').attr('jcarouselindex') };
						if(self.data('state').selected && self.data('state').selected != event.id) {
							$("li[jcarouselindex=" + self.data('state').selected + "] a img", self).fadeTo(500, 0.4);
						}
						self.data('state').selected = event.id;
						for(var i in self.data('listeners').select) {
							self.data('listeners').select[i](event);
						}
						return false;
					})
					.bind('mouseover', function() {
						var event = { id: $(this).closest('li').attr('jcarouselindex') };
						if(self.data('state').selected != event.id) $("img", this).stop(true,true).fadeTo(250,1);
						self.data('state').mouseover = event.id;
						for(var i in self.data('listeners').mouseover) {
							self.data('listeners').mouseover[i](event);
						}
						return false;
					})
					.bind('mouseout', function() {
						var event = { id: $(this).closest('li').attr('jcarouselindex') };
						if(self.data('state').selected != event.id) $("img", this).stop(true,true).fadeTo(500,0.4);
						if(self.data('state').mouseover == event.id) self.data('state').mouseover = 0;
						for(var i in self.data('listeners').mouseout) {
							self.data('listeners').mouseout[i](event);
						}
						return false;
					})
					.children("img").css('opacity', 0.4);
			});
			var carousel = ul.jcarousel({ rtl: true });
			self.data('carousel', carousel.data('jcarousel'));
		});
		this.bind = function(eventType, handler) {
			this.data('listeners')[eventType].push(handler);
		}
		this.select = function(id) {
			if(this.data('state').selected != id && this.data('state').mouseover != id) {
				this.data('carousel').scroll($.jcarousel.intval(id));
				if(this.data('state').selected && this.data('state').selected != id) {
					$("li[jcarouselindex=" + this.data('state').selected + "] a img", this).fadeTo(500, 0.4);
				}
				this.data('state').selected = id;
				$("li[jcarouselindex=" + id + "] a img", this).fadeTo(250, 1);				
			}
		}
		return this;
	};
})(jQuery);
