(function($){

    $.fn.slideshow = function(options) {

        var images = [];
        var currentIndex = 0;
        var hTimer;
        var queue = null;
        var inTransition = false;
        var self = this;
        var isGoing = false;
        
        options = $.extend({
            timer : 4000,
            imageClass : 'slideshow-image',
            selectedClass : 'selected',
            menuZIndex : 4,
            frontZIndex : 3,
            fadeLayerZIndex : 2,
            fadeLayerID : 'FadeLayer',
            startText : 'start',
            stopText : 'stop'
        }, options);
        
        init();
        
        /*
         * Initial setup
         */
        function init() {
	        
        	setupSlideshow();
	        
	        setupMenu();
	        
	        createFadeLayer();
        
	        start();
        }
        
        function stop() {
        	//stop the timer
    		clearTimeout(hTimer);
    		hTimer = null;
    		
    		//change class
    		//$('#' + options.stopLinkID).addClass('selected');
    		
    		$('#' + options.stopLinkID).html(options.startText);
    		
    		isGoing = false;
        }
        
        function start(immediately) {
        	//start slideshow
        	
        	if (immediately) {
        		isGoing = true;
	            changeImage();
	            $('#' + options.stopLinkID).html(options.stopText);
	            return;
        	}
        	
	        hTimer = setTimeout(function(){
	        	isGoing = true;
	            changeImage();
	            $('#' + options.stopLinkID).html(options.stopText);
	        }, options.timer);
        }
        
        function setupSlideshow() {
        	$(self).css('position', 'relative');
        	
	        var first = true;
	        
	        //hide all but first image
	        $(self).children().each(function(i, val){
	
	            if (!first){
	                $(this).hide();
	            } else {
	                
	                $(this).css({
	                    'z-index' : options.frontZIndex
	                });
	                first = false;
	            }
	
	            images.push(this);
	            $(this).attr('id', 'image' + i);
	
	            $(this).css('position', 'absolute');
	            
	        });
        }
        
        /*
         * Layer to fade in the background, workaround for anti-aliasing problems in ie
         * Solid layer sits over background layer and fades out, so it appears as if 
         * the background layer is fading in
         */
        function createFadeLayer() {
        	$(self).append('<li id="' + options.fadeLayerID + '"><!-- --></li>');
        	$('#' + options.fadeLayerID).css({
        			'display' : 'none',
        			'z-index' : options.fadeLayerZIndex,
        			'background-color' : '#FFF',
        			'width' : $(images[0]).css('width'),
        			'height' : $(images[0]).css('height')
        	});
        }

        function changeImage(){

            var nextIndex = currentIndex + 1;

            //wrap
            if (nextIndex > images.length - 1) {
                nextIndex = 0;
            }

            doTransition(nextIndex);
           
        }
        
        function doTransition(newIndex) {

        	if (hTimer) {
        		clearTimeout(hTimer);
        	}
        	
        	//if images already transitioning, queue this one until it is finished
        	if (inTransition) {
        		queue = function(){
        			doTransition(newIndex);
        		};
        		return;
        	}
        	
        	//transition started
        	inTransition = true;
            
        	//move the menu
        	if (options.menu) {
                setMenuSelected(newIndex);
            }
        	
        	/*setTimeout(function(){
        		
        	},options.timer/8);*/
        	
        	//show fade layer to simulate fade in
        	$('#' + options.fadeLayerID).show().fadeOut(options.timer/3);
        	$(images[newIndex]).show();
        	
            $(images[currentIndex]).fadeOut(options.timer/3, function(){
                $(images[newIndex]).css('z-index', options.frontZIndex);
                $(images[currentIndex]).css('z-index', 1);
                $(images[currentIndex]).hide();
                $('#' + options.fadeLayerID).hide();
                currentIndex = newIndex;
                
                inTransition = false;
                
                //if a move is queued, perform it and return, slideshow will
                //restart after the next move
                if (queue && typeof(queue) === 'function') {
                	queue.call();
                	queue = null;
                	return;
                }
                
                hTimer = setTimeout(function(){
                    changeImage();
                }, options.timer);
            });

        }
        
        function setImage(link) {
 
        	var nextIndex = 0;
        	
        	//find next index
        	var total = images.length;
        	for (var i = 0; i < total; i++) {
        		if ($(link).hasClass($(images[i]).attr('id'))) {
        			nextIndex = i;
        		}
        	}
        	
        	//if slideshow is stopped, show it has started again
            if (!isGoing) {
            	isGoing = true;
            	$('#' + options.stopLinkID).html(options.stopText);
            }
        	
        	doTransition(nextIndex);
        }
        
        function setupMenu() {
        	
        	$(options.menu).css('z-index', options.menuZIndex);
	        $(options.menu).find('a.panes').each(function(i, val){
	        	$(this).click(function(event){
	        			setImage(this);
	        			event.preventDefault();
	        		})
	        		.addClass('image' + i) 
	        		.css('cursor','pointer');
	        });
	        
	        if (options.stopLinkID) {
	        	$('#' + options.stopLinkID).click(function(event){
	        		
	        		if (isGoing) {
	        			
	        			if (inTransition) {
	        				queue = function(){stop();};
	        				return;
	        			}
	        			
	        			stop();
	        		}
	        		else {
	       
	        			start(true);
	        		}
	        		
	        		event.preventDefault();
	        	});
	        }
	        
	        setMenuSelected(0);
        }
        
        

        function setMenuSelected(index) {
            $(options.menu).find('a').removeClass(options.selectedClass);
            $(options.menu).find('.' + $(images[index]).attr('id')).addClass(options.selectedClass);
        }

        
    };
})(jQuery);
