/* 

Author: Kevin O'Brien
Email: kevin@clockwork.net
Company: Clockwork Acive Media Systems
Last Modified: 06.07.10
Version: 1.34

*/

(function($) {

	$.fn.tentcarousel = function(params) {
		return new $.tentcarousel(jQuery(this), params);
	};

	$.tentcarousel = function(e, params) {
	
		//Config variables
		this.target = $tc = jQuery(e);
		this.current = 0;
		this.last_current = 0
		this.doubleClicks = 0;
		this.doubleClicksp = 0;
		if(params.width) { this.carousel_width = params.width }else { alert("Carousel: 'height' & 'width' are required"); return false; }
		if(params.height) { this.carousel_height = params.height }else { alert("Carousel: 'height' & 'width' are required"); return false; }
		this.carousel_height = params.height || this.fail();
		this.continuous = params.continuous === undefined ? false : params.continuous;
		this.loop = params.loop === undefined ? true : params.loop;
		this.speed = params.speed === undefined ? 700 : params.speed;
		this.interval = params.interval === undefined ? 4000 : params.interval;
		this.indicator = params.indicator === undefined ? true : params.indicator;
		this.indicator_numbered = params.indicator_numbered === undefined ? false : params.indicator_numbered;
		this.transition = params.transition || 'slide';
		this.start_at = params.start_at === undefined ? 0 : params.start_at;
		this.pages_per_slide = params.pages_per_slide === undefined ? 1 : params.pages_per_slide;
		this.page_padding = params.page_padding ? params.page_padding : [0,0,0,0];
		this.page_width = params.page_width === undefined ? (this.carousel_width - ((this.page_padding[1] + this.page_padding[3]) * this.pages_per_slide)) / this.pages_per_slide : params.page_width;
		this.easing = params.transition || 'swing';
		//Class Names
		this.carousel_clip_class = params.carousel_clip_class || 'carousel_page_clip';
		this.carousel_contain_class = params.carousel_contain_class || 'carousel_page_contain';
		this.carousel_page_class = params.carousel_page_class || 'carousel_page';
		this.previous_class = params.previous_class || 'carousel_prev';
		this.next_class = params.next_class || 'carousel_next';
		this.page_count = this.target.find('.'+this.carousel_page_class).length;
		//Callbacks
		this.previous_callback_done = params.previous_callback_done || null;
		this.next_callback_done = params.next_callback_done || null;
		this.previous_callback_start = params.previous_callback_start || null;
		this.next_callback_start = params.next_callback_start || null;
		this.carousel_active = params.carousel_active || null;
		
		//Setup Carousel
		if(!this.config_carousel()) return;
		this.apply_css();
		this.apply_listeners();
		this.update_indicator();
		
		this.active = true;
		try { this.carousel_active(this.target); }catch(e) {}
		
		this.target.carousel = this;
		return this;
		
	}

	$.tentcarousel.prototype = {
	
		config_carousel: function() {
		
			var o = this;
		
   			this.target.addClass('carousel_activated');
			this.target.wrapInner('<div class="'+this.carousel_contain_class+'"></div>');
			this.target.wrapInner('<div class="'+this.carousel_clip_class+'"></div>');
			this.page_contain = this.target.find('.'+this.carousel_contain_class);
			this.clip = this.target.find('.'+this.carousel_clip_class);
			this.pages = this.target.find('.'+this.carousel_page_class);
			this.slide_count = Math.ceil(this.page_count / this.pages_per_slide);
			if(this.slide_count <= 1) return false;
			this.pages.each(function(i, val){
				jQuery(this).addClass('carousel_page_'+i);
			})
			this.target.append('<a href="#" class="'+this.previous_class+'" title="Previous">&lt</a><a href="#" class="'+this.next_class+'" title="Next">&gt</a>');
			this.prev = this.target.find('.'+this.previous_class);
			this.next = this.target.find('.'+this.next_class);
			if(this.indicator || this.indicator_numbered) this.make_indicator();
			if((this.transition == 'fade') || (this.loop == 'false')) this.continuous = false;
			return true;
				
		},
		
		apply_css: function(page) {
			
			if(!page) {
				this.target.css({ 'width': this.carousel_width+'px', 'height': this.carousel_height+'px' })
				this.clip.css({'width':this.carousel_width+'px', 'height':this.carousel_height+'px', 'overflow':'hidden', 'position':'relative'});
				this.page_contain.css({'width':(this.page_count*this.carousel_width)+'px', 'position':'absolute' });
				this.pages.css({'width':this.page_width+'px', 'height':this.carousel_height+'px', 'overflow':'hidden', 'position':'relative', 'float':'left', 'padding':this.page_padding[0]+'px '+this.page_padding[1]+'px '+this.page_padding[2]+'px '+this.page_padding[3]+'px'});
				if(this.continuous) this.make_continuous();
				if(!this.loop) this.prev.addClass('disabled');
				if(this.slide_count == 1) this.next.addClass('disabled');
				if(this.transition == 'fade') {
					this.pages.css({'position': 'absolute', 'left': 0, 'top': 0, 'z-index': 1, 'opacity': 0});
					this.target.find('.'+this.carousel_page_class+':first').css('opacity',1)
					this.target.find('.'+this.carousel_page_class+':first').css({'z-index': 2});
				}
				if(this.start_at != 0) this.jump_to(this.start_at, true);
			}else {
				if(this.transition == 'fade') {
					jQuery(page).css({'position': 'absolute', 'left': 0, 'top': 0, 'z-index': 1, 'opacity': 0});
				}else {
					jQuery(page).css({'width':this.page_width+'px', 'height':this.carousel_height+'px', 'overflow':'hidden', 'position':'relative', 'float':'left', 'padding':this.page_padding[0]+'px '+this.page_padding[1]+'px '+this.page_padding[2]+'px '+this.page_padding[3]+'px'});
				}
			}
		
		},
		
		apply_listeners: function() {

			var target = this;

			//Listeners
			this.prev.click(function(){ target.go_prev(); return false; });
			this.next.click(function(){ target.go_next(); return false; });
			if(this.interval) {
				this.timer = setInterval(function(){ target.go_next(); return false; }, this.interval);
				this.prev.click(function(){ target.stop_auto_slide(); });
				this.next.click(function(){ target.stop_auto_slide(); });
			}
		
		},
		
		go_next: function(jumped_from, instant) {
		
			var o = this;
		
			//Calculating current page
			this.last_current = jumped_from === undefined ? this.current : jumped_from;
			this.current++;
			this.jumpped_by = this.current - this.last_current;
			this.jumpped_by = this.pages_per_slide > 1 ? this.jumpped_by * this.pages_per_slide : this.jumpped_by;
			var hit_end = false;
			if(this.current >= this.slide_count) {
				if(this.loop) {
					if(!this.continuous) this.current = 0;
				}else {
					if(this.current > (this.slide_count)-1) {
						hit_end = true;
					}
					this.current--;
				}
			}
		
			try { this.next_callback_start(this); }catch(e) {}
			
			if( !this.loop && ((this.current + 1) >= this.slide_count)) {
				this.next.addClass('disabled');
			}
			if(!this.loop && (this.current > 0)) this.prev.removeClass('disabled');
			
			if(!hit_end) {
				//Animate
				switch(this.transition) {
				
					case 'fade':
						this.target.find('.'+this.carousel_page_class+':eq('+this.last_current+')').stop();
						this.target.find('.'+this.carousel_page_class+':eq('+this.actual_page()+')').stop();
						if(!instant) {
							this.target.find('.'+this.carousel_page_class+':eq('+this.last_current+')').css('z-index','3').animate({'opacity': 0}, { "duration": this.speed, 'complete': function(){ jQuery(this).css('z-index', '1'); } });
							this.target.find('.'+this.carousel_page_class+':eq('+this.actual_page()+')').css('z-index','2').animate({'opacity':1}, { "duration": this.speed });
						}else {
							this.target.find('.'+this.carousel_page_class+':eq('+this.last_current+')').css('z-index','3').css('opacity', 0);
							this.target.find('.'+this.carousel_page_class+':eq('+this.actual_page()+')').css('z-index','2').css('opacity',1);
						}
						break;

					default:
						this.page_contain.stop();
						if(!instant) {
							this.page_contain.animate({left:-(this.current * this.carousel_width) +"px"}, { "duration": this.speed, "easing": this.easing, 'complete': function(){ o.callback_next(); } });
						}else {
							this.page_contain.css('left', -(this.current * this.carousel_width) +"px");
						}

				}

				if(this.continuous && this.loop) {
					for(var i=0; i<this.jumpped_by; i++ ) {
						var farthestRight = parseInt(this.target.find('.'+this.carousel_page_class+':last').css('left').replace('px','')) + this.page_width;
						this.target.find('.'+this.carousel_page_class+':eq('+(this.doubleClicks + i + this.doubleClicksp)+')').clone().appendTo(this.page_contain);
						this.target.find('.'+this.carousel_page_class+':last').css('left',farthestRight);
					}
					this.doubleClicks += this.jumpped_by - 1;
				}
				
				this.update_indicator();
				this.doubleClicks++;
			}
		},
		
		go_prev: function(jumped_from, instant) {
		
			var o = this;
		
			//Calculating current page
			this.last_current = jumped_from === undefined ? this.current : jumped_from;
			this.current--;
			this.jumpped_by = this.last_current - this.current;
			this.jumpped_by = this.pages_per_slide > 1 ? this.jumpped_by * this.pages_per_slide : this.jumpped_by;
			var hit_end = false;
			if(this.current < 0) {
				if(this.loop) {
					if(!this.continuous) this.current = (this.slide_count) - 1;
				}else {
					if(this.current < 0) {
						hit_end = true;
					}
					this.current++;
				}
			}
		
			try { this.previous_callback_start(this); }catch(e) {}
			
			if(!this.loop && (this.current == 0)) this.prev.addClass('disabled');
			if(!this.loop && (this.current < (this.slide_count-1))) this.next.removeClass('disabled');
			
			if(!hit_end) {
				//Animate
				switch(this.transition) {
				
					case 'fade':
						this.target.find('.'+this.carousel_page_class+':eq('+this.last_current+')').stop();
						this.target.find('.'+this.carousel_page_class+':eq('+this.actual_page()+')').stop()
						if(!instant) {
							this.target.find('.'+this.carousel_page_class+':eq('+this.last_current+')').css('z-index','3').animate({'opacity': 0}, { "duration": this.speed, 'complete': function(){ jQuery(this).css('z-index', '1'); } });
							this.target.find('.'+this.carousel_page_class+':eq('+this.actual_page()+')').css('z-index','2').animate({'opacity': 1}, { "duration": this.speed });
						}else {
							this.target.find('.'+this.carousel_page_class+':eq('+this.last_current+')').css('z-index','3').css('opacity', 0);
							this.target.find('.'+this.carousel_page_class+':eq('+this.actual_page()+')').css('z-index','2').css('opacity',1);
						}
						break;

					default:
						this.page_contain.stop();
						if(!instant) {
							this.page_contain.animate({left:-(this.current * this.carousel_width) +"px"}, { "duration": this.speed, "easing": this.easing, 'complete': function(){ o.callback_prev(); } });
						}else {
							this.page_contain.css('left', -(this.current * this.carousel_width) +"px");
						}

				}
				
				if(this.continuous && this.loop) {
					for(var i=0; i<this.jumpped_by; i++ ) {
						var farthestLeft = parseInt(this.target.find('.'+this.carousel_page_class+':first').css('left').replace('px','')) - this.page_width;
						this.target.find('.'+this.carousel_page_class+':eq('+(this.target.find('.'+this.carousel_page_class).length - 1 - this.doubleClicksp - i - this.doubleClicks)+')').clone().prependTo(this.page_contain);
						this.target.find('.'+this.carousel_page_class+':first').css('left',farthestLeft);
					}
					this.doubleClicksp += this.jumpped_by - 1;
				}
				
				this.update_indicator();
				this.doubleClicksp++;
			}
		
		},
		
		jump_to: function(index, instant) {
		
			this.stop_auto_slide();
			
			if(index < this.actual_page()) {
			
				var jumped_from = this.current;
				this.current = this.current - (this.actual_page() - index) + 1;
				this.go_prev(jumped_from, instant);
				
			}else {
				
				if(index == this.actual_page()) return;
				var jumped_from = this.current;
				this.current = this.current + (index - this.actual_page()) - 1;
				this.go_next(jumped_from, instant);
				
			}
			
		},
		
		callback_next: function() {
			this.clear_continuous();
			
			try { this.next_callback_done(this); }catch(e) {}
		},
		
		callback_prev: function() {
			this.clear_continuous();
			
			try { this.previous_callback_done(this); }catch(e) {}
		},
		
		clear_continuous: function() {
			if(this.continuous && this.loop) {
				for(var i=0; i<this.doubleClicks; i++) {
					this.target.find('.'+this.carousel_page_class+':first').remove();
				}
				this.doubleClicks = 0;
				for(var i=0; i<this.doubleClicksp; i++) {
					this.target.find('.'+this.carousel_page_class+':last').remove();
				}
				this.doubleClicksp = 0;
			}
		},
		
		stop_auto_slide: function() {
			clearInterval(this.timer);
		},
		
		make_continuous: function() {
		
			var o = this;
		
			this.pages.each(function(i, val) {
				jQuery(this).css({'position':'absolute', 'left': (o.page_width * i) + 'px'});
			});
			if( this.loop ) this.target.find('.'+this.carousel_page_class+':last').prependTo(this.page_contain).css('left',-this.page_width + 'px');
		
		},
		
		make_indicator: function() {
		
			var o = this;
		
			this.target.append('<div class="carousel_indicator"></div>');
			var indicator = this.target.find('.carousel_indicator');
			
			for(var i=0; i<this.slide_count; i++) {
				o.content = o.indicator_numbered ? i + 1 : '&middot;';
				indicator.append('<div class="carousel_inicator_page carousel_inicator_page_'+i+'"><a href="#page_'+i+'">'+o.content+'</a></div>');
			}
			
			jQuery(indicator).find('.carousel_inicator_page').each(function(i, val) {
				jQuery(this).click(function(){ o.jump_to(i); return false; })
			});
			
			indicator.find('.carousel_inicator_page:eq('+this.start_at+')').addClass('current')
		},
		
		update_indicator: function() {	

			if(this.slide_count > this.target.find('.carousel_inicator_page').length) {
				this.target.find('.carousel_indicator').append('<div class="carousel_inicator_page carousel_inicator_page_'+this.pages.length+'"><a href="#page_'+this.pages.length+'">'+this.content+'</a></div>');
			}

			this.target.find('.carousel_indicator .carousel_inicator_page').removeClass('current');
			this.target.find('.carousel_indicator .carousel_inicator_page:eq('+this.actual_page()+')').addClass('current');
			
		},
		
		actual_page: function(last) {
		
			var o = this;
			var actual_page = last ? last : this.current;
			
			if(this.slide_count > 0) {
				while((actual_page < 0) || (actual_page > this.slide_count-1)){
					actual_page = (actual_page < 0) ? actual_page + o.slide_count : actual_page - o.slide_count;
				}
			}else {
				actual_page = 0;
			}
			
			return actual_page;
		
		},
	
		add_slide: function(new_content) {
			// TODO: Needs testing for unlooped continuous setting
			this.page_contain.append('<div class="'+this.carousel_page_class+'">'+new_content+'</div>');//jQuery('<div class="'+this.carousel_page_class+'">'+html+'</div>').insertAfter(this.target.find('.carousel_page_'+(this.pages.length - 1)+':last'));
			var new_page = this.target.find('.'+this.carousel_page_class+':last');
			this.pages.push(new_page);
			this.page_count = this.pages.length;
			this.slide_count = Math.ceil(this.page_count / this.pages_per_slide);
			this.page_contain.css({'width':(this.page_count*this.carousel_width)+'px', 'position':'absolute' });
			this.update_indicator();
			this.apply_css(new_page);
			if(this.continuous) {
				var position = this.page_count = 1 ? 0 : parseInt(this.target.find('.carousel_page_'+(this.pages.length - 2)+':last').css('left').replace('px','')) + this.page_width + 'px';
				jQuery(new_page).css({'position': 'absolute', 'left': position});
			}
			this.next.removeClass('disabled');
		}
		
		
	}
})(jQuery);
