(function( $ ){
  $.fn.sickSlideshow = function(options) {
  	var settings = {
			'transition' : '',//wave, blank (fade)
			'height' : 200,
			'width' : 500,
			'cols' : 10,
			'rows' : 10,
			'autoPlay' : true,
			'autoDelay' : 7,
			'controls' : true,
			'arrows' : false
		}
    return this.each(function() {
			if(options) {
				$.extend( settings, options );
			}
			if(settings.transition == '') { //if we use a simple fade there is no reason to setup a grid
				settings.cols = settings.rows = 1;
			}
			//setup the width and height for each tile based on how many cols and rows we want
			settings.tileWidth = Math.ceil(settings.width/settings.cols);
			settings.tileHeight = Math.ceil(settings.height/settings.rows);
			var is_paused = false;
			var is_transitioning = 0;
			var $this = $(this);
			//grab the images/slides
			var slides = new Array();
			$this.children().each(function() {
				var tag = this.tagName.toLowerCase();
				var img = $(this);
				var slide = {};
		 		if(tag == 'a') {
					slide.href = img.attr('href');
					slide.src = img.find('img').attr('src');
					slides.push(slide);
				} else if(tag == 'img') {
					slide.src = img.attr('src');
					slides.push(slide);
				}
			});
			//preload images
			for(var i=0;i<slides.length;i++) {
				(new Image()).src=slides[i].src;
			}
			
			//set up timer
			if(settings.autoPlay) {
				var autoPlay;
				autoPlay=setInterval(function(){playNextSlide();},settings.autoDelay*1000);
			}
			function playNextSlide() {
				if(!is_paused) {
					next();
				}
			}
			//create a wrapper to hold all of the slides
			$this_wrapper = $('<div class="sick-slideshow">').css('visibility','visible');
			//ensure a few css properties are set correctly
			$this.css({'position':'relative','visibility':'visible','display':'block','width':settings.width,'height':settings.height});
			$this_wrapper.css({'width':settings.width,'height':settings.height,'overflow':'hidden'});
			$this.html("\n").append($this_wrapper);
			
			if(settings.arrows) {
				//add the arrows
				var arrows = $('<div class="sick-slide-arrows">');
				arrows.html('<div class="sick_arrow sick_arrow_left"><a class="sick_arrow_left">&lt;</a></div><div class="sick_arrow sick_arrow_right"><a class="sick_arrow_right">&gt;</a></div>');
				$this_wrapper.before(arrows);
				//left and right buttons
				$('.sick-slide-arrows div.sick_arrow a').click(function(){
					if(is_transitioning > 0) return false; //do not progress until transition is completed
					var nav_id = current.id;
					if($(this).hasClass('sick_arrow_right')) {
						nav_id++;
						if(nav_id > slides.length-1) {nav_id = 0;}
						doTransition(nav_id);
						if(settings.autoPlay) restartTimer();
					} else {
						nav_id--;
						if(nav_id < 0) {nav_id = slides.length-1;}
						doTransition(nav_id);
						if(settings.autoPlay) restartTimer();
					}
					return false;
				});
			}
			
			if(settings.controls) {
				//add the controls
				var controls = $('<div class="slide-controls">');
				var control_list = $('<ul>');
				control_list.append('<li class="play_pause"><a>Play/Pause</a></li>');
				for(var i = 0; i<slides.length; i++) {
					var nav = '<li><a id="nav_'+i+'" class="slide-nav" href="#">'+(i+1)+'</a></li>';
					control_list.append(nav);
				}
				controls.append(control_list);
				$this_wrapper.append(controls);
				//play/pause btn
				$('.slide-controls li.play_pause a').click(function(){
					if ($(this).hasClass('paused')) {
						$(this).removeClass('paused');
						restartTimer();
						is_paused = false;
					} else {
						$(this).addClass('paused');
						stopTimer();
						is_paused = true;
					}
				});
				//general nav items
				$('.slide-controls a.slide-nav').click(function(){
					if(is_transitioning > 0) return false; //do not progress until transition is completed
					var nav_id = $(this).attr('id').split('_');
					nav_id = nav_id[1];
					if(nav_id != current.id) {
						doTransition(nav_id);
						if(settings.autoPlay) restartTimer();
					}
					return false;
				});
			}
			//empty object to hold the current slide info
			var current = {};
			//function used to create the grid used for animations
			function createGrid(params) {
				var el = $([]),tmp;
				for(var i = 0; i < settings.rows; i++) {
					var row = $('<div>');
					for(var j = 0; j < settings.cols; j++) {
						tmp = $('<div>');
						tmp.attr({'class':'tile', 'id':'tile_'+i+'_'+j});
						tmp.css({'background':"url('"+params.img.src+"') "+(-j*settings.tileWidth)+'px '+(-i*settings.tileHeight)+'px','width':settings.tileWidth, 'height':settings.tileHeight, 'opacity':0});
						if(params.img.href) {
							var a = $('<a>');
							a.attr("href",params.img.href);
							a.css({'width':settings.tileWidth, 'height':settings.tileHeight, 'display':'block'});
							tmp = tmp.append(a);
						}
						row = row.append(tmp);
					}
					el = el.add(row);
				}
				return el;
			}
			//primary function that handles the transition from 1 slide to another
			function doTransition(id) {
				if(!slides[id]) return false;
				if(current.id) {
					if(current.id == id) return false;
					$('.sick-slide').css('z-index',1);
					$('.sick-slide').not(current.slide).remove();
				}
				var params = {'cols':settings.cols, 'rows':settings.rows, 'img':slides[id]};
				var newSlide = $('<div class="sick-slide">').html(createGrid(params)).prepend("\n\n").append("\n\n");
				var slide_width = settings.cols*settings.tileWidth+5;
				newSlide.css({'width':slide_width,'z-index':10});
				$this_wrapper.append(newSlide);
				switch(settings.transition) {
					case 'wave':
						//wave transition
						transitionStarted();
						var total_delay = 0;
						var loop = settings.cols+(settings.rows-1);
						for(var i = 0; i < loop; i++) {
							for(var j = 0; j < settings.rows; j++) {
								var temp_id = i-j;
								//var c_row = $('.sl-slide').find('div:eq('+j+')');
								if(temp_id >= 0 && temp_id <= settings.cols) {
									var tile = newSlide.find('div#tile_'+j+'_'+temp_id);
									total_delay = 100*i;
									tile.delay(total_delay).animate({'opacity':1},500);
								}
							}	
						}
						complex_transition = setTimeout(function(){transitionFinished();}, total_delay)
					break;
					
					default:
						transitionStarted();
						newSlide.find('div').find('div').animate({'opacity':1},500,transitionFinished);
					break;
				}
				//remove active from all nav items
				$('.slide-controls a').removeClass('active');
				$('.slide-controls a#nav_'+id).addClass('active');
				current.id = id;
				current.slide = newSlide;
			}
			//simple functions when an animation is going on
			function transitionStarted() {
				is_transitioning = parseFloat(is_transitioning)+1;
			}
			//simple function when an animation is completed
			function transitionFinished() {
				is_transitioning = parseFloat(is_transitioning)-1;
			}
			//easy function to access previous slide
			function prev() {
				if(is_transitioning > 0) return false; //do not progress until transition is completed
				var id = parseFloat(current.id)-1;
				if(id < 0) id = slides.length-1;
				doTransition(id);
				if(settings.autoPlay) restartTimer();
			}
			//easy function to access next slide
			function next() {
				if(is_transitioning > 0) return false; //do not progress until transition is completed
				var id = parseFloat(current.id)+1;
				if(id >= slides.length) id = 0;
				doTransition(id);
				if(settings.autoPlay) restartTimer();
			}
			function startTimer() {
				autoPlay=setInterval(function(){playNextSlide();},settings.autoDelay*1000);
			}
			function stopTimer() {
				clearInterval(autoPlay);
			}
			function restartTimer() {
				clearInterval(autoPlay); 
				autoPlay=setInterval(function(){playNextSlide();},settings.autoDelay*1000);
			}
			//public methods
			$.fn.sickSlideshow.loadSlide = function(slide_id) {
				if(is_transitioning > 0) return false; //do not progress until transition is completed
				var id = parseFloat(slide_id);
				if(id >= 0 && id < slides.length) {
			 		doTransition(id);
					if(settings.autoPlay) restartTimer();
				}
			};
			//load the first slide
			doTransition(0);
    });
  };
})( jQuery );
