(function($){
	$.fn.slideshow = function(options) {
		
		/**
		
		requires cms-slideshows.css and CMSSlideshows.php
		
		*/
		
		this.version = 1.20100721
		
		// multiple
		if (this.length > 1) {
			this.each(function(){ $(this).slideshow(options); });
			return this;
		}
		
		this.defaults = {
			path: '', // path to pictures
			spinner: '/assets/spinner-white.png', // path to spinner
			loop: true, // loop slideshow
			transition: 700, // fade in-out time
			rate: 3700, // slide change rate
			current: 0, // current slide
			captions: true, // caption display
			counters: true, // counter display
			joiners: ' of ', // counter display
			opacity: .7, // caption opacity
		};
		
		this.options = $.extend({}, this.defaults, options);
		
		
		/* standards */
		this.spinnerHeight = 48, // spinner height
		this.spinnerWidth = 48, // spinner width
		this.spinnerSpeed = 48, // spinner speed
		
		
		/* slides */
		this.slides = this.find(".slides");
		
		
		
		// configure
		this.configure = function(){
			
			var viewer = this;
			
			// borders
			var borders = viewer.outerWidth() - viewer.innerWidth();
			
			if (viewer.hasClass("slideshows-player")) {
				viewer.width(640 - borders);
				viewer.height(400 - borders);
			}
			else {
				viewer.width(300 - borders);
				viewer.height(200 - borders);
			}
			
			// spinner
			var spinner = new Image();
			spinner.src = viewer.options.spinner;
			spinner.onload = function(){
				viewer.frames = spinner.width / viewer.spinnerWidth;
			};
			
			// counters
			viewer.counters(viewer);
			
			// slides
			this.slides.each(function(index, slide){
			
				$(slide).append('<span class="spinners"></span>');
									  
				viewer.spinners(slide);
				
				$(slide).prepend('<div class="slideshows-pictures"></div>');
				var picture = $(slide).find(".slideshows-pictures");
				$(picture).css("background-position", "center center");
				$(picture).css("background-repeat", "no-repeat");
				$(picture).css("height", viewer.height()+"px");
				$(picture).css("overflow", "hidden");
				$(picture).css("width", viewer.width()+"px");
				
				viewer.captions(slide);
				
				$(slide).data('slideshow', viewer);
				
				$(slide).fadeOut(0);
				$(slide).css("visibility", "visible");
				
			});
			
		};
		
		// counters
		this.counters = function(){
			if (this.options.counters) {
				
				this.append('<div class="slideshows-counters"></div>');
				var counter = this.find(".slideshows-counters");
				$(counter).css("position", "absolute");
				
				var html = '1' + this.options.joiners + this.slides.length;
				$(counter).text(html);
				
			}
		};
		
		// updates
		this.updates = function(index){
			if (this.options.counters) {
				var counter = this.find(".slideshows-counters");
				var html = (index + 1) + this.options.joiners + this.slides.length;
				$(counter).text(html);
			}
		};
		
		// captions
		this.captions = function(slide){
			if ($(slide).find(".slideshows-captions").length > 0) {
				
				var caption = $(".slideshows-captions", $(slide));
				
				if (this.options.captions && caption.html().length > 0) {
					
					var width = $(slide).width();
					
					caption.css("display", "block");
					caption.css("position", "absolute");
					caption.css("bottom", 0);
					
					var left = caption.css("padding-left");
					var right = caption.css("padding-right");
					
					left = left.replace(/px/, '')
					right = right.replace(/px/, '')
					
					caption.width(width - left - right);
					caption.css("opacity", this.options.opacity);
					
				}
				else caption.remove();
			}
		};
		
		// spinners
		this.spinners = function(slide){
			
			var spinner = $(slide).find(".spinners");
			spinner.css("display", "block");
			spinner.css("position", "absolute");
			
			var top = ($(slide).height() - this.spinnerHeight) / 2;
			spinner.css("height", this.spinnerHeight+"px");
			spinner.css("top", top);
			
			var left = ($(slide).width() - this.spinnerWidth) / 2;
			spinner.css("width", this.spinnerWidth+"px");
			spinner.css("left", left);
			
			spinner.css("background-image", "url("+this.options.spinner+")");
			spinner.css("background-repeat", "no-repeat");
			spinner.css("background-position", "0px");
			
		};
		
		// following
		this.following = function(toggle){
			var slide = this.options.current + 1;
			if (slide > this.slides.length - 1) {
				if (!this.options.loop) return false;
				slide = 0;
			}
			this.show(slide, toggle);
		};
		
		// preceding
		this.preceding = function(toggle){
			var slide = this.options.current - 1;
			if (slide < 0) {
				if (!this.options.loop) return false;
				slide = this.slides.length - 1;
			}
			this.show(slide, toggle);
		};
		
		// show
		this.show = function(index, toggle){
			
			this.pause();
			
			var fade = this.options.transition;
			
			if (index != this.options.current) {
				this.slides.eq(this.options.current).fadeOut(fade);
			}
			
			
			this.slides.eq(index).fadeIn(fade);
			
			var picture = this.slides.eq(index).find(".slideshows-pictures");
			var background = picture.css("background-image");
			if (background == 'none') {
				this.backgrounds(index, toggle);
				picture.fadeOut(0);
			}
			else if (!toggle) {
				this.play();
			}
			
			this.updates(index);
			this.options.current = index;
			
		};
		
		// backgrounds
		this.backgrounds = function(index, toggle){
			
			var viewer = this;
			var slide = this.slides.eq(index);
			
			var id = window.setInterval(viewer.spin, viewer.spinnerSpeed, slide);
			
			var uid = slide.attr("id");
			
			var extension = "png";
			if (slide.hasClass("jpg")) {
				extension = "jpg";
			}
			
			var background = new Image();
			background.src = this.options.path + uid + "." + extension;
			
			background.onload = function(){
				$(slide).find(".spinners").fadeOut(
					300, 
					function(){ 
						$(this).remove();
						window.clearInterval(id);
					}
				);
				$(slide).find(".slideshows-pictures")
				.css("background-image", "url("+this.src+")")
				.fadeIn(viewer.options.transition);
				if (!toggle) viewer.play();
			};
			
		};
		
		// pause
		this.pause = function(){
			if (this.interval) {
				window.clearInterval(this.interval);
				this.interval = false;
			}
		};
		
		// initiate
		this.initiate = function(){
			
			this.configure();
			this.show(this.options.current);
			
		};
		
		
		
		
		// mouse handlers
		this.slides.click(function(event) {
			if (!(slideshow = $(this).data('slideshow'))) {
				var slideshow = this;
			}
			
			var left = event.clientX - slideshow.offset().left;
			var center = $(this).width() / 2;
			
			if (left > center) slideshow.forward();
			else slideshow.reverse();
			
		}).mouseenter(function(){
			if (!(slideshow = $(this).data('slideshow'))) {
				var slideshow = this;
			}
			
			slideshow.pause();
			
		}).mouseleave(function(){
			if (!(slideshow = $(this).data('slideshow'))) {
				var slideshow = this;
			}
			
			slideshow.pause();
			slideshow.play();
			
		});
		
		// forward
		this.forward = function(){
			if (!(slideshow = $(this).data('slideshow'))) {
				var slideshow = this;
			}
			
			slideshow.pause();
			slideshow.following(true);
			
		};
		
		// reverse
		this.reverse = function(){
			if (!(slideshow = $(this).data('slideshow'))) {
				var slideshow = this;
			}
			
			slideshow.pause();
			slideshow.preceding(true);
			
		};
		
		// spin
		this.spin = function(slide){
			
			if (!(slideshow = $(slide).data('slideshow'))) {
				var slideshow = slide;
			}
			
			var spinner = $(".spinners", $(slide));
			var position = spinner.css("background-position");
			
			if (position) {
				
				position = position.replace(/px/g, "");
				var positions = position.split(" ");
				
				left = positions[0] - slideshow.spinnerWidth;
				if (Math.abs(left) >=  slideshow.spinnerWidth * slideshow.frames) {
					left = 0;	
				}
				spinner.css("background-position", left + "px");
			}
			
		};
		
		// play
		this.play = function(){
			if (!(slideshow = $(this).data('slideshow'))) {
				var slideshow = this;
			}
			
			if (!slideshow.interval && slideshow.options.rate > 1000) {
				slideshow.interval = window.setInterval(
					function(){ slideshow.following(); }, 
					slideshow.options.rate
				);
			}
			
			return this;
			
		}
		
		
		return this.initiate();
		
		
	};
})(jQuery);
