(function($) {
	$.fn.nextSlide = function() {
		// get slide index and count
		var ss = $(this);
		var slideIndex = parseInt(ss.data("SlideIndex"));
		var slideCount = parseInt(ss.data("SlideCount"));
		var slidePlaylist = ss.data("SlidePlaylist");
		var slideState = ss.data("ShowState");

		var newSlideIndex = (slideIndex + 1) % slideCount;
		return ss.goToSlide(newSlideIndex);
	};

	$.fn.prevSlide = function() {
		// get slide index and count
		var ss = $(this);
		var slideIndex = parseInt(ss.data("SlideIndex"));
		var slideCount = parseInt(ss.data("SlideCount"));
		var slidePlaylist = ss.data("SlidePlaylist");
		var slideState = ss.data("ShowState");

		var newSlideIndex = (slideIndex - 1);
		if (newSlideIndex < 0) newSlideIndex += slideCount;

		return ss.goToSlide(newSlideIndex);
	};

	$.cssNextBackPlayControls = function(options) {
		var defaultOptions = {
			playControlsCssClass: "SlideyPlayControls",
			nextCssClass: "SlideyNextImage",
			prevCssClass: "SlideyPrevImage",
			controlDimOpacity: 1.0,
			controlLitOpacity: 1.0,
			buttonDimOpacity: 0.75,
			buttonLitOpacity: 1.0,
			playControlsPosition: {
				position: "absolute",
				bottom: "4px",
				right: "4px"
			}
		};
		
		var newOpt = $.extend(true, defaultOptions, options);
		
		return {
			options: newOpt,
			ss: null,
			render: function() {
				var ss = this.ss;
				var options = this.options;
				var ssOptions = ss.data("Options");
				var slides = ss.children();

				var playControls = $(document.createElement("div"))
					.css(options.playControlsPosition)
					.css("zIndex", ssOptions.zIndexTop)
					.css("opacity", options.controlDimOpacity)
					.bind("mouseenter", function() { $(this).animate({opacity: options.controlLitOpacity}, 200); })
					.bind("mouseleave", function() { $(this).animate({opacity: options.controlDimOpacity}, 200); })
					.addClass(options.playControlsCssClass);					
				ss.append(playControls);
				
				// add previous button
				var prev = $("<div>")
					.addClass(options.prevCssClass)
					.css("opacity", options.buttonDimOpacity)
					.bind("mouseenter", function() { $(this).animate({opacity: options.buttonLitOpacity}, 200); })
					.bind("mouseleave", function() { $(this).animate({opacity: options.buttonDimOpacity}, 200); })					
					.click(function() { ss.prevSlide(); return false; });
				// add next button
				var next = $("<div>")
					.addClass(options.nextCssClass)
					.css("opacity", options.buttonDimOpacity)
					.bind("mouseenter", function() { $(this).animate({opacity: options.buttonLitOpacity}, 200); })
					.bind("mouseleave", function() { $(this).animate({opacity: options.buttonDimOpacity}, 200); })
					.click(function() { ss.nextSlide(); return false; });
					
				playControls.append(prev);
				playControls.append(next);
				playControls.append($("<br style='clear:both' />"));
			}
		};
	}
	
	$.textPlayControls = function(options) {
		var defaultOptions = {
			showPageSelect: true,
			showNextBack: true,
			pageButtonCss: {
				base: {
					cursor: "pointer",
					cssFloat: "left",
					padding: "2px",
					textAlign: "center",
					border: "1px solid #CCC",
					margin: "0px 0px 0px 0px",
					background: "none"
				},

				// whether or not the page is the current one
				inactive: { border: "1px solid #CCC" }, active: { border: "1px solid #888" },
				// whether or not the page is currently highlighted by the mouse
				dim: { background: "none" }, lit: { backgroundColor: "#FFF" }
			},
			
			playControlsCss: {
				base: {
					position: "absolute",
					bottom: "4px",
					right: "4px",
					fontFamily: "verdana, arial, sans-serif",
					fontSize: "9px",
					fontWeight: "bold",
					color: "black",
					padding: "2px",
					opacity: 0.45,
					backgroundColor: "#CCC",
					border: "1px solid #666"
				},

				// whether or not the controls are currently highlighted by the mouse
				dim: { opacity: 0.45 }, lit: { opacity: 0.7 }
			}
		};
		//var ss = slideShow;
		//var ssOptions = ss.data("Options");

		var newOpt = $.extend(true, defaultOptions, options);
		return {
			options: newOpt,
			
			ss: null,

			updateSelectedSlide: function(index) {
				if (this.options.showPageSelect) {
					this.ss.find(".SlidePage").css(this.options.pageButtonCss.inactive);
					this.ss.find(".SlidePage:eq(" + index + ")").css(this.options.pageButtonCss.active);
				}
			},

			render: function() {
				//alert(this.options.pageButtonCss.fontFamily);
				var ss = this.ss;
				var options = this.options;
				var ssOptions = ss.data("Options");
				var playControls = $(document.createElement("div"));
				var slides = ss.children();

				playControls.css(this.options.playControlsCss.base).css({ zIndex: ssOptions.zIndexTop });

				// fade in/fade out playcontrols on mouseover
				playControls
                        .bind("mouseenter", function() { $(this).stop(true, true).animate(this.options.playControlsCss.lit, 200); })
                        .bind("mouseleave", function() { $(this).stop(true, true).animate(this.options.playControlsCss.dim, 200); });

				var createPageButton = function(slideText, nextSlide) {
					var page = $(document.createElement("div"));
					page.appendTo(playControls).css(options.pageButtonCss.base);

					page.text(slideText);
					page.data("SlideIndex", nextSlide);

					page
                        .bind("mouseenter", function() { $(this).css(options.pageButtonCss.lit) })
                        .bind("mouseleave", function() { $(this).css(options.pageButtonCss.dim) });

					// highlight initial slide
					if (nextSlide == "0")
						page.css(options.pageButtonCss.active);
					else
						page.css(options.pageButtonCss.inactive);

					if (nextSlide == "n")
						page.click(function() { ss.nextSlide(); });
					else if (nextSlide == "p")
						page.click(function() { ss.prevSlide(); });
					else {
						page.addClass("SlidePage");
						page.click(function() {
							var index = parseInt($(this).data("SlideIndex"));
							ss.goToSlide(index);
						});
					}
				}

				if (options.showNextBack) createPageButton("<", "p");
				if (options.showPageSelect) {
					for (var i = 0; i < slides.length; i++) {
						createPageButton(i + 1, i);
					}
				}
				if (options.showNextBack) createPageButton(">", "n");

				playControls.append("<br style='clear:both;'/>");
				playControls.appendTo(ss);
			}
		};
	}

	$.fn.goToSlide = function(newSlideIndex) {
		return this.each(function() {
			// get slide index and count
			var ss = $(this);
			var slideIndex = parseInt(ss.data("SlideIndex"));
			var slideCount = parseInt(ss.data("SlideCount"));
			var slidePlaylist = ss.data("SlidePlaylist");
			var slideState = ss.data("ShowState");
			var animState = ss.data("AnimState")
			var options = ss.data("Options");
			
			ss.stopTime("slideanims");
			if ((slideState == "playing" || slideState == "paused") && slideIndex != newSlideIndex && !animState) {
				// pick our new slide
				var slides = ss.children();

				if (newSlideIndex >= 0 && newSlideIndex < slideCount) {
					// get the elements for old and new slides
					var oldSlide = slides.eq(slidePlaylist[slideIndex]);
					var newSlide = slides.eq(slidePlaylist[newSlideIndex]);

					// swap z-indexes around so new slide is always on top
					oldSlide.css("z-index", options.zIndexBottom);
					newSlide.css("z-index", options.zIndexTop);

					// set state to "animating"						
					// set state back to idle once done animating
					ss.data("AnimState", true).oneTime(options.fadeLength, function() { $(this).data("AnimState", false) });
						
					// do the fade
					newSlide.stop(true, true).fadeIn(options.fadeLength);
					// don't fade out old slide; hide it after the new slide fade is complete
					oldSlide.stop(true, true).oneTime(options.fadeLength, "hideold", function() { $(this).hide(); });

					/*
					if (options.showPageSelect) {
					ss.find(".SlidePage").css($.slideyStyles.pageButton.inactive);
					ss.find(".SlidePage:eq(" + newSlideIndex + ")").css($.slideyStyles.pageButton.active);
					}
					*/
					if (options.playControls && options.playControls.updateSelectedSlide)
						options.playControls.updateSelectedSlide(newSlideIndex);

					// save our current slide index
					ss.data("SlideIndex", newSlideIndex);
				}

				if (slideState == "playing") {
					ss.oneTime(options.slideLength, "slideanims", function() {
						$(this).nextSlide();
					});
				}
			}
		});
	};

	$.fn.slidey = function(options) {
		var defaults = {
			// how long a slide will display for
			slideLength: 10000,
			// length of the fade transition
			fadeLength: 500,
			// z-index of the "top" slide during the fade transition
			zIndexTop: 10,
			// z-index of the "bottom" slide during the fade transition
			zIndexBottom: 9,
			// ordering: "Sequential" / "Random" / "FirstThenRandom"
			ordering: "Sequential",
			// whether or not to show the play controls
			showPlayControls: true,
			// whether or not to show next/previous buttons
			showNextBack: true,
			// whether or not to show page number buttons
			showPageSelect: true,
			// playControls
			playControls: $.textPlayControls({})
		};
		
		var options = $.extend(defaults,options);
		// backwards compat
		if ( !options.showPlayControls ) options.playControls = null;
		
		return this.each(function() {
			var obj = $(this);
			var slides = obj.children();

			// give playcontrols reference to this slideshow
			if (options.playControls) options.playControls.ss = obj;

			// stack all slides on top of each other
			obj.css("position", "relative");
			slides.css("position", "absolute").css("top", "0px").css("left", "0px");

			// set our initial slide index and slide count for future reference
			obj.data("SlideIndex", 0).data("SlideCount", slides.length);

			// start out sorted
			var SlidePlaylist = new Array();
			for (var i = 0; i < slides.length; i++)
				SlidePlaylist[i] = i;

			// shuffle the playlist if random
			if (options.ordering.toLowerCase() == "random" || options.ordering.toLowerCase() == "firstthenrandom") {
				SlidePlaylist.sort(function(a, b) {
					if (options.ordering.toLowerCase() == "firstthenrandom") {
						if (a == 0) return -1;
						else if (b == 0) return 1;
					}
					if (Math.random() > 0.5)
						return -1;
					else
						return 1;
				});
			}
			obj.data("SlidePlaylist", SlidePlaylist);
			obj.data("ShowState", "playing");
			obj.data("Options", options);

			// hide all slides
			slides.css("display", "none").css("z-index", options.zIndexBottom);
			// show first slide
			slides.eq(SlidePlaylist[0]).css("display", "");

			// get the widest and tallest our slideshow should be
			var topWidth = 0;
			var topHeight = 0;
			slides.each(function() {
				if ($(this).width() > topWidth) topWidth = $(this).width();
				if ($(this).height() > topHeight) topHeight = $(this).height();
			});

			// set slide w/h
			obj.width(topWidth).height(topHeight);

			// only do the slideshow if we have more than one slide
			if (slides.length > 1) {
				if (options.playControls && options.playControls.render) options.playControls.render();

				// every [slideLength] seconds, fade in a new slide
				obj.oneTime(options.slideLength, "slideanims", function() {
					$(this).nextSlide();
				});
			}
		});
	};
})(jQuery); 
