/* 
works well with the interface 

- troubles with multiple clicks 
- pr/nx clicks during autoplay 

- autoplay builds up long queue / 
? possibly a difference in timings ?
? block next while animation's on?

-animation blocked, removes the bug with multiple click on prev/next

- should autoplay be going through prev and nextSlide methods? YES
 
- next iteration implements data store to hold index information and eliminate dependency on 



*/



(function($) {

    $.fn.carousel = function(options) {
	
		var defaults = {  
		            animation: 'fade',
					shift_by:300,
					speed:400,
					holdfor:2000,
					layout:'horizontal',
					direction:-1,
					autoplay:false,
					previous_btn:null,
					next_btn:null,
					listener:null,
					id:null,
					target:null
					
				
		}
		
		
		
		
		var options = $.extend(defaults, options); 
		
		
		
		var carousel = '';
		var source = '';
		var currentIndex = 0;
		var totalItems;
		
		var d = 0;
		var direction = options.direction;
		var timeout;
			
			// delay animation if autoplay
			if(options.autoplay){
				d = options.holdfor;
				
			}
		var is_in_motion = false;
		var methods = {
			
			
			init : function(){
				
					
					//source and renaming lists
					
					
					if(options.id == null){
						
					var id = $(this).attr('id');
					$(this).attr('id',id+'-datasrc').hide();	
					$(this).parent().append('<ul id="'+id+'" />');
					source = $(this).find('> li');
					}
					
					else{
						var id = options.id;
						$(this).hide();	
						$(options.target).append('<ul id="'+id+'" />');
						source = $(this);
					
						
					}
					
					totalItems = source.length;
					carousel  = $('#'+id);
					carousel.css({overflow:'hidden'});				




					methods.appendSlide.call(this,0);

					carousel.bind('nextSlide',function(){
//						methods.clearAutoPlay.call(this);
						methods.nextSlide.call(this);
						
					});
					
					carousel.bind('previousSlide',function(){
//						methods.clearAutoPlay.call(this);
						methods.previousSlide.call(this);	
					});
					
					carousel.bind('updateIndex',function(e,ind){
						methods.updateIndex.call(this,ind);	
					});
					
					carousel.bind('displaySlide',function(e,ind){
						e.stopPropagation();
						methods.displaySlide.call(this,ind);	
					});
					
					carousel.bind('ajaxSlide',function(e,markup){
						e.stopPropagation();
						methods.addAjaxSlide.call(this,markup);
					});
					
					carousel.bind('stopAutoPlay',function(e){
						e.stopPropagation();
						methods.clearAutoPlay.call(this);
					});
					carousel.bind('restartAutoPlay',function(e){
						e.stopPropagation();
						methods.startAutoPlay.call(this);
					});
					
					if(typeof(options.listener) != undefined){}
					
					if(typeof(options.previous_btn) != undefined){
						$(options.previous_btn).click(function(){
							carousel.trigger('previousSlide');
						});
					}
					
					if(typeof(options.next_btn) != undefined){
						$(options.next_btn).click(function(){
							carousel.trigger('nextSlide');
						});
					}
					
					if(options.autoplay){
						timeout = setTimeout(function(){
							methods.nextSlide.call(this);							
							},options.holdfor+options.speed)
						
					}
			},
			updateIndex:function(ind){
				
				currentIndex=ind;
				
				
			},
			startAutoPlay:function(){
				options.autoplay = true;
				timeout = setTimeout(function(){
					methods.nextSlide.call(this);							
					},options.holdfor+options.speed);
			},
			clearAutoPlay:function(){
				
				options.autoplay = false;
				clearTimeout(timeout);
				
			},
			addAjaxSlide: function(markup){
				
				// find a slide to be cloned from source and attached to the output
			
				
				var i = carousel.children('li').length;				
				$(carousel).append('<li></li>');
				var slideLI = $(carousel).children('li:last-child');
				
				if(options.layout == 'vertical')
					$(slideLI).append(markup).css({top:direction*i*options.shift_by}).show().data('index',i);
				else
					$(slideLI).append(markup).css({left:direction*i*options.shift_by}).show().data('index',i);
			
					
				methods.dispatch.call(this,'onSlideReady');
				
				
			},
			appendSlide : function(index){
				
				// find a slide to be cloned from source and attached to the output
				var slide = source.get(index);
				var i = carousel.children('li').length;	
				var alpha = 0;
				if(i==0){alpha=1}

				$(carousel).append('<li></li>');
				var slideLI = $(carousel).children('li:last-child');
				
				if(options.layout == 'vertical')
					$(slideLI).append($(slide).clone().show()).css({top:direction*i*options.shift_by}).show().data('index',i);
				else if(options.layout == 'horizontal')
					$(slideLI).append($(slide).clone().show()).css({left:direction*i*options.shift_by}).show().data('index',i);
				else if(options.layout == 'alpha' && i!=0)
					$(slideLI).append($(slide).clone().show()).css({opacity:alpha}).show().data('index',i);
				else if(options.layout == 'alpha' && i==0)
						$(slideLI).append($(slide).clone().show()).css({opacity:alpha}).fadeIn().data('index',i);	
					
				methods.dispatch.call(this,'onSlideReady');
			},
			
			// gets Slide from actual carousel
			getSlide : function(index){
				return $(carousel).children('li').get(index);
			},
			
			updateSlides : function(){
				
				$(carousel).find('li:first-child').remove();
			
				
			},
			
			nextSlide: function(){
				
				if(is_in_motion)
					return;
					
					currentIndex++;
					direction = options.direction;
					
				
					
					if(currentIndex>totalItems-1){
							currentIndex = 0;
							//methods.appendSlide.call(this,0);
					}

					
					methods.moveSlides.call(this);
					
					if(options.autoplay){

					timeout = setTimeout(function(){
						
						methods.nextSlide.call(this);
						//clearTimeout(timeout);	
						
					},options.holdfor+options.speed)
						
						
					}
					
			},
			previousSlide:function(){
				
				if(is_in_motion)
					return;
					
				currentIndex--;	
				direction = (-1)*options.direction;
				
							
				if(currentIndex<0){
					currentIndex = totalItems-1;
						//methods.appendSlide.call(this,0);
				}
				//methods.appendSlide.call(this,currentIndex);
				methods.moveSlides.call(this);
				
			},
			
			displaySlide:function(ind){
				
				
				if(is_in_motion)
					return;
				
				/*
					if(ind > currentIndex)
									direction = (-1)*options.direction;
									else
									direction = options.direction;*/
				


					currentIndex=ind;	

					methods.moveSlides.call(this);	
				
			},
			
			moveSlides	: function(){
				
			is_in_motion = true;
			methods.appendSlide.call(this,currentIndex);
				
				
				
				$(carousel).children('li').each(function(){
						var i = $(this).index();
					
											
							
						if(options.layout == 'vertical'){
							$(this).animate({
				    		// works for direction positive 1	'top':(i*options.shift_by)-(options.direction*options.shift_by) +'px'
								'top':(direction*i*options.shift_by) - (direction*options.shift_by) +'px'},
								 	options.speed, function() {
										// do it only once:
										if(i==0){
											$(this).remove();
											is_in_motion = false;
											methods.dispatch.call(this,'onTransitionComplete');
										}
								})
						}
						
						else if(options.layout == 'horizontal'){
							$(this).animate({
				    			'left':(direction*i*options.shift_by) - (direction*options.shift_by) +'px'}, 
								options.speed, 
								function() {
										// do it only once:
										if(i==0){
											$(this).remove();
											is_in_motion = false;
											methods.dispatch.call(this,'onTransitionComplete');
											
										}
								})
						}
						
						else if(options.layout == 'alpha'){
							if(i==0){
								$(this).animate({
									'opacity': 0}, 
									options.speed,
									function() {
										$(this).remove();
										is_in_motion = false;
										methods.dispatch.call(this,'onTransitionComplete');
									});
							}
							else{
								$(this).animate({
					    			'opacity': 1}, 
									options.speed)
							}
						}
				});
			},
			
			dispatch	: function(ev){
				
				$(options.listener).trigger(ev,currentIndex);
			}
						
			
		}; // end of methods
				
		methods.init.call(this);
		
			
				
		
	
}
})(jQuery);







