/**
 *
 * ex.carousel.js
 *
 * @version 1.0
 * @author Tatsuhisa Ishikawa
 *
 */
if(!window.ex){ var ex = {}; }
(function(jQuery){

ex.Carousel = ex.Class.create();
Object.extend(ex.Carousel.prototype, (function(){
	var getItems = function(a, f){
		if (typeof f != 'string') f = '';
		return $('> *' + f, a);
	}
	
	var getCurrentItems = function(c, o, n) {
		var oi = getItems(c, ':lt('+o.items.visible+')'),
			ni = getItems(c, ':lt('+(o.items.visible+n)+'):gt('+(n-1)+')');
		return [oi, ni];
	};
	
	var getItemIndex = function(num, dev, org, firstItem, totalItems, $cfs) {
		if (typeof num == 'string') {
			if (isNaN(num)) num = $(num);
			else 			num = parseInt(num);
		}
		if (typeof num == 'object') {
			if (typeof num.jquery == 'undefined') num = $(num);
			num = getItems($cfs).index(num);
			if (num == -1) num = 0;
			if (typeof org != 'boolean') org = false;
		} else {
			if (typeof org != 'boolean') org = true;
		}
		if (isNaN(num))	num = 0;
		else 			num = parseInt(num);
		if (isNaN(dev))	dev = 0;
		else 			dev = parseInt(dev);

		if (org) num += firstItem;
		num += dev;
		
		if (totalItems > 0) {
			while (num >= totalItems)	{	num -= totalItems; }
			while (num < 0)				{	num += totalItems; }
		}
		return num;
	};
	
	var getNaviObject = function(target, obj, page, auto) {
		if (typeof page != 'boolean') page = false;
		if (typeof auto != 'boolean') auto = false;
		
		if (typeof obj == 'undefined' || obj == null)	obj = {};
		if (typeof obj == 'string') obj = target.parent().find(obj);
		if (page) {
			if (typeof obj.jquery != 'undefined')	obj = { container: obj };
			if (typeof obj.container == 'string')	obj.container = $(obj.container);
		} else if (auto) {
			if (typeof obj == 'boolean')				obj = { play: obj };
			if (typeof obj == 'number')				obj = { pauseDuration: obj };
		} else {
			if (typeof obj.jquery	!= 'undefined')		obj = { button: obj };
			if (typeof obj.button	== 'string')		obj.button = $(obj.button);
		}
		return obj;
	}
	
	var linkAnchors = function ($c, se, $cfs) {
		if (typeof $c == 'undefined' || $c.length == 0) $c = $('body');
		else if (typeof $c == 'string') $c = $($c);
		if (typeof $c != 'object') return false;
		if (typeof se == 'undefined') se = '';
		$c.find('a'+se).each(function() {
			var h = this.hash || '';
			if (h.length > 0 && getItems($cfs).index($(h)) != -1) {
				$(this).unbind('click').click(function(e) {
					e.preventDefault();
					$cfs.trigger('slideTo', h);
				});
			}
		});
	}
	
	var getPadding = function(p) {
		if (typeof p == 'number')	p = [p];
		else if (typeof p == 'string') p = p.split('px').join('').split(' ');

		if (typeof p != 'object') {
			p = [0];
		}
		for (i in p) {
			p[i] = parseInt(p[i]);
		}
		switch (p.length) {
			case 0:
				return [0, 0, 0, 0];
			case 1:
				return [p[0], p[0], p[0], p[0]];
			case 2:
				return [p[0], p[1], p[0], p[1]];
			case 3:
				return [p[0], p[1], p[2], p[1]];
			default:
				return p;
		}
	};
	
	var setSizes = function($c, o) {
		var $w = $c.parent();
		var $i = getItems($c);
		var $l = $i.filter(':nth('+(o.items.visible-1)+')');
		var is = getSizes(o, $i);

		$w.css(mapWrapperSizes(getSizes(o, $i.filter(':lt('+o.items.visible+')'), true), o));
		if (o.usePadding) {
			$l.css(o.dimentions[6], $l.data('cfs_origCssMargin') + o.padding[1]);
			$c.css(o.dimentions[5], o.padding[0]);
			$c.css(o.dimentions[4], o.padding[3]);
		}
		$c.css(o.dimentions[0], is[0]*2);
		//$c.css(o.dimentions[2], is[1]);
	};
	
	var getSizes = function(o, $i, wrap) {
		if (typeof wrap != 'boolean') wrap = false;
		var di = o.dimentions;
		var s1 = 0;
		var s2 = 0;

		if (wrap && typeof o[di[0]] == 'number') 	s1 += o[di[0]];
		else if (typeof o.items[di[0]] == 'number') 	s1 += o.items[di[0]] * $i.length;
		else {
			$i.each(function() { 
				s1 += $(this)[di[1]](true);
			});
		}

		if (wrap && typeof o[di[2]] == 'number') s2 += o[di[2]];
		else if ( typeof o.items[di[2]] == 'number') 	s2 += o.items[di[2]];
		else {
			$i.each(function() {
				var m = $(this)[di[3]](true);
				if (s2 < m) s2 = m;
			});
		}
		return [s1, s2];
	};
	
	var mapWrapperSizes = function(ws, o) {
		var pad = (o.usePadding) ? o.padding : [0, 0, 0, 0];
		var wra = {};
			wra[o.dimentions[0]] = ws[0] + pad[1] + pad[3];
			//wra[o.dimentions[2]] = ws[1] + pad[0] + pad[2];
		return wra;
	};
	
	return {
		options		: {},
		carousel	: null,
		wrapper		: null,
		firstItem	: 0,
		totalItems	: 0,
		pauseTimePassed : 0,
		direction	: 'next',
		autoTimeout : null,
		autoInterval : null,
		pausedGlobal: false,
		usePadding	: false,
		varnumvisitem : false,
		isActive : true,
		
		initialize	: function(target, options){
			this.carousel = $(target);
			this.wrapper = $(target).wrap('<div class="carousel_wrapper" />').parent();
			
			
			this._init(options);
			
			var t = this;
			this.totalItems	= getItems(this.carousel).length;
			
			this.wrapper.css({
				position: 'relative',
				overflow: 'hidden'
			});
			this.carousel.data('cfs_origCss', {
				width	: this.carousel.css('width'),
				//height	: this.carousel.css('height'),
				position: this.carousel.css('position'),
				top		: this.carousel.css('top'),
				left	: this.carousel.css('left')
			})/*.css({
				position: 'absolute'
			});*/
				
			this.showNavigation(this.options, this.totalItems);
			this.bindEvents();
			this.bindButtons();
			
			this.linkAnchors('', '.caroufredsel', this.carousel);
				
			setSizes(this.carousel, this.options);
			
			if (this.options.items.start !== 0 && this.options.items.start !== false) {
				var s = this.options.items.start;
				if (this.options.items.start === true) {
					s = window.location.hash;
					if (!s.length) s = 0;
				}
				this.carousel.trigger('slideTo', [s, 0, true, { duration: 0 }]);
			}
			
			//this.carousel.isActive = false;
			//this.carousel.activate = this.activate;
			//this.carousel.deactivate = this.deactivate;
		},
		
		_init : function(options){
			var defaults = {
				infinite	: true,
				circular	: true,
				direction	: 'left',
				items		: {
					visible		: 5,
					start		: 0
				},
				scroll		: {
					easing		: 'easeOutCubic',
					duration	: 500,
					pauseOnHover : false
				},
				auto		: false,
				prev		: null,
				next		: null,
				pagination	: null
			}
			
			this.options = $.extend(defaults, options);
			
			this.options.padding = getPadding(this.options.padding);
			this.options.usePadding = (
				this.options.padding[0] == 0 && 
				this.options.padding[1] == 0 && 
				this.options.padding[2] == 0 && 
				this.options.padding[3] == 0
			) ? false : true;
			
			
			this.direction = (this.options.direction == 'up' || this.options.direction == 'left') ? 'next' : 'prev';
			if (this.options.direction == 'right' || this.options.direction == 'left') {
				this.options.dimentions = ['width', 'outerWidth', 'height', 'outerHeight', 'left', 'top', 'marginRight', 'innerWidth'];
			} else {
				this.options.dimentions = ['height', 'outerHeight', 'width', 'outerWidth', 'top', 'left', 'marginBottom', 'innerHeight'];
				this.options.padding = [this.options.padding[3], this.options.padding[2], this.options.padding[1], this.options.padding[0]];
			}
			
			if (!this.options.items.width)		this.options.items.width 	= getItems(this.carousel).outerWidth(true);
			//if (!this.options.items.height)	this.options.items.height	= getItems(this.carousel).outerHeight(true);
			
			if (this.options.items.visible == 'variable') {
				if (typeof this.options[this.options.dimentions[0]] == 'number') {
					this.options.maxDimention = this.options[this.options.dimentions[0]];
					this.options[this.options.dimentions[0]] = null;
				} else {
					this.options.maxDimention = this.wrapper.parent()[this.options.dimentions[7]]();
				}
				if (this.options.items[this.options.dimentions[0]] == 'variable') {
					this.varnumvisitem = true;
					this.options.items.visible = 0;
				} else {
					this.options.items.visible = Math.floor(this.options.maxDimention / this.options.items[this.options.dimentions[0]]);
				}
			}
			
			if (typeof this.options.items.minimum	!= 'number')		this.options.items.minimum		= this.options.items.visible;
			if (typeof this.options.scroll.items	!= 'number')		this.options.scroll.items		= this.options.items.visible;
			if (typeof this.options.scroll.duration	!= 'number')	this.options.scroll.duration	= 500;
			
			this.options.auto		= getNaviObject(this.wrapper, this.options.auto, false, true);
			this.options.prev		= getNaviObject(this.wrapper, this.options.prev);
			this.options.next		= getNaviObject(this.wrapper, this.options.next);
			this.options.pagination	= getNaviObject(this.wrapper, this.options.pagination, true);
			
			this.options.auto		= $.extend({}, this.options.scroll, this.options.auto);
			this.options.prev		= $.extend({}, this.options.scroll, this.options.prev);
			this.options.next		= $.extend({}, this.options.scroll, this.options.next);
			this.options.pagination	= $.extend({}, this.options.scroll, this.options.pagination);
			
			if (typeof this.options.pagination.anchorBuilder != 'function')	this.options.pagination.anchorBuilder	= jQuery.fn.exCarousel.pageAnchorBuilder;
			if (typeof this.options.auto.play != 'boolean')					this.options.auto.play					= true;
			if (typeof this.options.auto.nap != 'boolean')					this.options.auto.nap					= true;
			if (typeof this.options.auto.delay != 'number')					this.options.auto.delay					= 0;
			if (typeof this.options.auto.pauseDuration != 'number')			this.options.auto.pauseDuration			= (this.options.auto.duration < 10) ? 2500 : this.options.auto.duration * 5;
		},
		
		bindEvents : function(){
			var c = this.carousel;
			
			c.bind('pause', handlePause);
			c.bind('play', handlePlay);
			
			if (this.varnumvisitem) {
				c.bind('prev', handlePrev);
				c.bind('next', handleNext).trigger('next', { duration: 0 });
			}else{
				c.bind('prev', function(e, sO, nI) {
					c.trigger('scrollPrev', [sO, nI]);
				});
				c.bind('next', function(e, sO, nI) {
					c.trigger('scrollNext', [sO, nI]);
				});
			}
			
			c.bind('scrollPrev', handleScrollPrev);
			c.bind('scrollNext', handleScrollNext);
			
			c.bind('slideTo', handleSlideTo)
			 .bind('insertItem', handleInsertItem)
			 .bind('removeItem', handleRemoveItem)
			 .bind('updatePageStatus', handleUpdatePageStatus);
			
			var t = this;
			// Pause
			function handlePause(e, g){
				if (typeof g != 'boolean') g = false;
				if (g) t.pausedGlobal = true;
				if (t.autoTimeout != null) {
					clearTimeout(t.autoTimeout);
				}
				if (t.autoInterval != null) {
					clearInterval(t.autoInterval);
				}
			}
			// Play
			function handlePlay(e, d, f, g){
				c.trigger('pause');
				if (t.options.auto.play) {
					if (typeof g != 'boolean') {
						if (typeof f == 'boolean') 		g = f;
						else if (typeof d == 'boolean')	g = d;
						else 								g = false;
					}
					
					if (typeof f != 'number') {
						if (typeof d == 'number')		f = d;
						else							f = 0;
					}
					
					if (d != 'prev' && d != 'next')		d = t.direction;
					
					if (g) t.pausedGlobal = false;
					if (t.pausedGlobal) return;

					t.autoTimeout = setTimeout(function() {
						if (c.is(':animated')) {
							c.trigger('play', d);
						} else {
							t.pauseTimePassed = 0;
							c.trigger(d, t.options.auto);
						}
					}, t.options.auto.pauseDuration + f - t.pauseTimePassed);
					
					if (t.options.auto.pauseOnHover === 'resume') {
						t.autoInterval = setInterval(function() {
							t.pauseTimePassed += 100;
						}, 100);
					}
				}
			}
			
			function handlePrev(e, sO, nI){
				if (c.is(':animated')) return false;
				var items = getItems(c);
				var total = 0;
				var x = 0;
					
				if (typeof sO == 'number') nI = sO;
				if (typeof nI != 'number') {
					for (var a = items.length-1; a >= 0; a--) {
						current = items.filter(':eq('+ a +')')[t.options.dimentions[1]](true);
						if (total + current > t.options.maxDimention) break;
						total += current;
						x++;
					}
					nI = x;
				}
				for (var a = items.length-nI; a < items.length; a++) {
					current = items.filter(':eq('+ a +')')[t.options.dimentions[1]](true);
					if (total + current > t.options.maxDimention) break;
					total += current;
					if (a == items.length-1) a = 0;
					x++;
				};
				t.options.items.visible = x;
				t.carousel.trigger('scrollPrev', [sO, nI]);
			}
			
			function handleNext(e, sO, nI){
				if (t.carousel.is(':animated')) return false;
				var items = getItems(t.carousel);
				var total = 0;
				var x = 0;
				
				if (typeof sO == 'number') nI = sO;
				if (typeof nI != 'number') nI = t.options.items.visible;

				for (var a = nI; a < items.length; a++) {
					current = items.filter(':eq('+ a +')')[t.options.dimentions[1]](true);
					if (total + current > t.options.maxDimention) break;
					total += current;
					if (a == items.length-1) a = 0;
					x++;
				};
				t.options.items.visible = x;
				t.carousel.trigger('scrollNext', [sO, nI]);
			}
			
			function handleScrollPrev(e, sO, nI){
				if (t.carousel.is(':animated')) return false;
				if (t.options.items.minimum >= t.totalItems) return log('Not enough items: not scrolling');

				if (typeof sO == 'number') nI = sO;
				if (typeof sO != 'object') sO = t.options.prev;
				if (typeof nI != 'number') nI = sO.items;
				if (typeof nI != 'number') return log('Not a valid number: not scrolling');
				
				if (!t.options.circular) {
					var nulItem = t.totalItems - t.firstItem;
					if (nulItem - nI < 0) {
						nI = nulItem;
					}
					if (t.firstItem == 0) {
						nI = 0;
					}
				}
				
				t.firstItem += nI;
				if (t.firstItem >= t.totalItems) t.firstItem -= t.totalItems;

				if (!t.options.circular) {
					if (t.firstItem == 0 && nI != 0 && t.options.prev.onEnd) {
						t.options.prev.onEnd();
					}
					if (t.options.infinite) {
						if (nI == 0) {
							t.carousel.trigger('next', t.totalItems - t.options.items.visible);
							return false;
						}
					} else {
						if (t.firstItem == 0 && t.options.prev.button) t.options.prev.button.addClass('disabled');
						if (t.options.next.button) t.options.next.button.removeClass('disabled');
					}
				}
				
				if (nI == 0) {
					return false;
				}
				
				getItems(t.carousel, ':gt('+(t.totalItems-nI-1)+')').prependTo(t.carousel);
				if (t.totalItems < t.options.items.visible + nI) getItems(t.carousel, ':lt('+((t.options.items.visible+nI)-t.totalItems)+')').clone(true).appendTo(t.carousel);
				
				var c_itm = getCurrentItems(t.carousel, t.options, nI);
				var l_cur = getItems(t.carousel, ':nth('+(nI-1)+')');
				var l_old = c_itm[1].filter(':last');
				var l_new = c_itm[0].filter(':last');
				
				if (t.options.usePadding) l_old.css(t.options.dimentions[6], l_old.data('cfs_origCssMargin'));
				
				var i_siz = getSizes(t.options, getItems(t.carousel, ':lt('+nI+')'));
				var w_siz = mapWrapperSizes(getSizes(t.options, c_itm[0], true), t.options);

				if (t.options.usePadding) l_old.css(t.options.dimentions[6], l_old.data('cfs_origCssMargin') + t.options.padding[1]);
				
				var a_cfs = {};
				var a_new = {};
				var a_cur = {};
				var a_dur = sO.duration;

				if (a_dur == 'auto')	a_dur = t.options.scroll.duration / t.options.scroll.items * nI;
				else if (a_dur <= 0)	a_dur = 0;
				else if (a_dur < 10)	a_dur = i_siz[0] / a_dur;

				if (sO.onBefore) sO.onBefore(c_itm[1], c_itm[0], w_siz, a_dur);
				
				if (t.options.usePadding) {
					var new_m = t.options.padding[3];
					a_cur[t.options.dimentions[6]] = l_cur.data('cfs_origCssMargin');
					a_new[t.options.dimentions[6]] = l_new.data('cfs_origCssMargin') + t.options.padding[1];
					l_cur.css(t.options.dimentions[6], l_cur.data('cfs_origCssMargin') + t.options.padding[3]);
					l_cur.stop().animate(a_cur, {
						duration: a_dur,
						easing	: sO.easing
					});
					l_new.stop().animate(a_new, {
						duration: a_dur,
						easing	: sO.easing
					});
				} else {
					var new_m = 0;
				}
				a_cfs[t.options.dimentions[4]] = new_m;
				
				if ((typeof t.options[t.options.dimentions[0]] != 'number' && typeof t.options.items[t.options.dimentions[0]] != 'number') ||
					(typeof t.options[t.options.dimentions[2]] != 'number' && typeof t.options.items[t.options.dimentions[2]] != 'number')
				) {
					t.wrapper.stop().animate(w_siz, {
						duration: a_dur,
						easing	: sO.easing
					});
				}
				
				c.data('cfs_numItems', nI)
					.data('cfs_slideObj', sO)
					.data('cfs_oldItems', c_itm[1])
					.data('cfs_newItems', c_itm[0])
					.data('cfs_wrapSize', w_siz)
					.css(t.options.dimentions[4], -i_siz[0])
					.animate(a_cfs, {
						duration: a_dur,
						easing	: sO.easing,
						complete: function() {
							if (c.data('cfs_slideObj').onAfter) {
								c.data('cfs_slideObj').onAfter(c.data('cfs_oldItems'), c.data('cfs_newItems'), c.data('cfs_wrapSize'));
							}
							if (t.totalItems < t.options.items.visible + c.data('cfs_numItems')) {
								getItems(c, ':gt('+(t.totalItems-1)+')').remove();
							}
							var l_itm = getItems(c, ':nth('+(t.options.items.visible+c.data('cfs_numItems')-1)+')');
							if (t.options.usePadding) {
								l_itm.css(t.options.dimentions[6], l_itm.data('cfs_origCssMargin'));
							}
						}
					});
				t.carousel.trigger('updatePageStatus').trigger('play', a_dur);
			}
			
			function handleScrollNext(e, sO, nI){
				if (t.carousel.is(':animated')) return false;
				if (t.options.items.minimum >= t.totalItems) return ;
				if (typeof sO == 'number') nI = sO;
				if (typeof sO != 'object') sO = t.options.next;
				if (typeof nI != 'number') nI = sO.items;
				if (typeof nI != 'number') return  ;
				
				if (!t.options.circular) {
					if (t.firstItem == 0) {
						if (nI > t.totalItems - t.options.items.visible) {
							nI = t.totalItems - t.options.items.visible;
						}
					} else {
						if (t.firstItem - nI < t.options.items.visible) {
							nI = t.firstItem - t.options.items.visible;
						}
					}
				}

				t.firstItem -= nI;
				if (t.firstItem < 0) t.firstItem += t.totalItems;

				if (!t.options.circular) {
					if (t.firstItem == t.options.items.visible && nI != 0 && t.options.next.onEnd) {
						t.options.next.onEnd();
					}
					if (t.options.infinite) {
						if (nI == 0) {
							t.carousel.trigger('prev', t.totalItems-t.options.items.visible);
							return false;
						}
					} else {
						if (t.firstItem == t.options.items.visible && t.options.next.button) t.options.next.button.addClass('disabled');
						if (t.options.prev.button) t.options.prev.button.removeClass('disabled');
					}
				}

				if (nI == 0) {
					return false;					
				}

				if (t.totalItems < t.options.items.visible + nI) getItems(t.carousel, ':lt('+((t.options.items.visible+nI)-t.totalItems)+')').clone(true).appendTo(t.carousel);

				var c_itm = getCurrentItems(t.carousel, t.options, nI);
				var l_cur = getItems(t.carousel, ':nth('+(nI-1)+')');
				var l_old = c_itm[0].filter(':last');
				var l_new = c_itm[1].filter(':last');

				if (t.options.usePadding) {
					l_old.css(t.options.dimentions[6], l_old.data('cfs_origCssMargin'));
					l_new.css(t.options.dimentions[6], l_new.data('cfs_origCssMargin'));
				}

				var i_siz = getSizes(t.options, getItems(t.carousel, ':lt('+nI+')'));
				var w_siz = mapWrapperSizes(getSizes(t.options, c_itm[1], true), t.options);

				if (t.options.usePadding) {
					l_old.css(t.options.dimentions[6], l_old.data('cfs_origCssMargin') + t.options.padding[1]);
					l_new.css(t.options.dimentions[6], l_new.data('cfs_origCssMargin') + t.options.padding[1]);
				}

				var a_cfs = {};
				var a_old = {};
				var a_cur = {};
				var a_dur = sO.duration;

				if (a_dur == 'auto')	a_dur = t.options.scroll.duration / t.options.scroll.items * nI;
				else if (a_dur <= 0)	a_dur = 0;
				else if (a_dur < 10)	a_dur = i_siz[0] / a_dur;

				if (sO.onBefore) sO.onBefore(c_itm[0], c_itm[1], w_siz, a_dur);

				a_cfs[t.options.dimentions[4]] = -i_siz[0];

				if (t.options.usePadding) {
					a_old[t.options.dimentions[6]] = l_old.data('cfs_origCssMargin');
					a_cur[t.options.dimentions[6]] = l_cur.data('cfs_origCssMargin') + t.options.padding[3];
					l_new.css(t.options.dimentions[6], l_new.data('cfs_origCssMargin') + t.options.padding[1]);

					l_old.stop().animate(a_old, {
						duration: a_dur,
						easing	: sO.easing
					});
					l_cur.stop().animate(a_cur, {
						duration: a_dur,
						easing	: sO.easing
					});
				}

				if ((typeof t.options[t.options.dimentions[0]] != 'number' && typeof t.options.items[t.options.dimentions[0]] != 'number') ||
					(typeof t.options[t.options.dimentions[2]] != 'number' && typeof t.options.items[t.options.dimentions[2]] != 'number')
				){
					t.wrapper.stop().animate(w_siz, {
						duration: a_dur,
						easing	: sO.easing
					});
				}
				
				t.carousel.data('cfs_numItems', nI)
					.data('cfs_slideObj', sO)
					.data('cfs_oldItems', c_itm[0])
					.data('cfs_newItems', c_itm[1])
					.data('cfs_wrapSize', w_siz)
					.animate(a_cfs, {
						duration: a_dur,
						easing	: sO.easing,
						complete: function() {
							if (c.data('cfs_slideObj').onAfter) {
								c.data('cfs_slideObj').onAfter(c.data('cfs_oldItems'), c.data('cfs_newItems'), c.data('cfs_wrapSize'));
							}
							if (t.totalItems < t.options.items.visible+c.data('cfs_numItems')) {
								getItems(c, ':gt('+(t.totalItems-1)+')').remove();
							}
							var org_m = (t.options.usePadding) ? t.options.padding[3] : 0;
							c.css(t.options.dimentions[4], org_m);
							
							var l_itm = getItems(c, ':lt('+c.data('cfs_numItems')+')').appendTo(c).filter(':last');
							if (t.options.usePadding) {
								l_itm.css(t.options.dimentions[6], l_itm.data('cfs_origCssMargin'));
							}
						}
					});
				t.carousel.trigger('updatePageStatus').trigger('play', a_dur);
			}
			
			function handleSlideTo(e, num, dev, org, obj) {
				if (c.is(':animated')) return false;
				
				num = getItemIndex(num, dev, org, t.firstItem, t.totalItems, c);
				if (num == 0) return false;
				if (typeof obj != 'object') obj = false;
				if (t.options.circular) {
					if (num < t.totalItems / 2) 	c.trigger('next', [obj, num]);
					else 							c.trigger('prev', [obj, t.totalItems-num]);
				} else {
					if (t.firstItem == 0 || t.firstItem > num)	c.trigger('next', [obj, num]);
					else										c.trigger('prev', [obj, t.totalItems-num]);
				}
			}
			
			function handleInsertItem(e, itm, num, org, dev) {
				if (typeof itm == 'object' &&  typeof itm.jquery == 'undefined')	itm = $(itm);
				if (typeof itm == 'string') 			itm = $(itm);
				if (typeof itm != 'object' || typeof itm.jquery == 'undefined' || itm.length == 0) return log('Not a valid object.');
						
				if (typeof num == 'undefined' || num == 'end') {
					t.carousel.append(itm);
				} else {
						num = getItemIndex(num, dev, org, t.firstItem, t.totalItems, t.carousel);
					var $cit = getItems(t.carousel, ':nth('+num+')');
						
					if ($cit.length) {
						if (num <= t.firstItem) t.firstItem += itm.length;
						$cit.before(itm);
					} else {
						$cfs.append(itm);
					}
				}
				t.totalItems = getItems(t.carousel).length;
				linkAnchors('', '.caroufredsel', t.carousel);
				setSizes(t.carousel, t.options);
				showNavi(t.options, t.totalItems);
				t.carousel.trigger('updatePageStatus', true);
			}
			
			function handleRemoveItem(e, num, org, dev){
				if (typeof num == 'undefined' || num == 'end') {
					getItems(t.carousel, ':last').remove();
				} else {
						num = getItemIndex(num, dev, org, t.firstItem, t.totalItems, t.carousel);
					var $cit = getItems(t.carousel, ':nth('+num+')');
					if ($cit.length){
						if (num < t.firstItem) t.firstItem -= $cit.length;
						$cit.remove();
					}
				}
				t.totalItems = getItems(t.carousel).length;
				linkAnchors('', '.caroufredsel', t.carousel);
				setSizes(t.carousel, t.options);
				showNavi(t.options, t.totalItems);
				t.carousel.trigger('updatePageStatus', true);
			}
			
			function handleUpdatePageStatus(e, bpa){
				if (!t.options.pagination.container) return false;
				if (typeof bpa == 'boolean' && bpa) {
					getItems(t.options.pagination.container).remove();
					for (var a = 0; a < Math.ceil(t.totalItems/t.options.items.visible); a++) {
						t.options.pagination.container.append(t.options.pagination.anchorBuilder(a+1));
					}
					getItems(t.options.pagination.container).unbind('click').each(function(a) {
						$(this).click(function(e) {
							e.preventDefault();
							t.carousel.trigger('slideTo', [a * t.options.items.visible, 0, true, t.options.pagination]);
						});
					});
				}
				var nr = (t.firstItem == 0) ? 0 : Math.round((t.totalItems-t.firstItem)/t.options.items.visible);
				getItems(t.options.pagination.container).removeClass('selected').filter(':nth('+nr+')').addClass('selected');
			}
		},
		
		bindButtons : function(){
			var c = this.carousel;
			var t = this;
			if (this.options.auto.pauseOnHover && this.options.auto.play) {
				this.wrapper.hover(
					function() { c.trigger('pause'); },
					function() {
						if(!t.isActive) return;
						c.trigger('play');
					}
				);
			}
			
			// Prev
			if (this.options.prev.button) {
				this.options.prev.button.click(function(e) {
					c.trigger('prev');
					e.preventDefault();
				});
				if (this.options.prev.pauseOnHover && this.options.auto.play) {
					this.options.prev.button.hover(
						function() { c.trigger('pause');	},
						function() { c.trigger('play');	}
					);
				}
				if (!this.options.circular && !this.options.infinite) {
					this.options.prev.button.addClass('disabled');
				}
			}
			
			// Next
			if (this.options.next.button) {
				this.options.next.button.click(function(e) {
					e.preventDefault();
					c.trigger('next');
				});
				if (this.options.next.pauseOnHover && this.options.auto.play) {
					this.options.next.button.hover(
						function() { c.trigger('pause');	},
						function() { c.trigger('play');	}
					)
				}
			}
			
			if (this.options.pagination.container) {
				c.trigger('updatePageStatus', true);
				if (this.options.pagination.pauseOnHover && this.options.auto.play) {
					this.options.pagination.container.hover(
						function() { c.trigger('pause');	},
						function() { c.trigger('play');	}
					);
				}
			}
			
			if (this.options.auto.play) {
				c.trigger('play', this.options.auto.delay);
				if ($.fn.nap && this.options.auto.nap) {
					c.nap('pause', 'play');
				}
			}
		},
		
		showNavigation : function(o, t) {
			if (o.items.minimum >= t) {
				var f = 'hide';
			} else {
				var f = 'show';
			}
			if (o.prev.button) o.prev.button[f]();
			if (o.next.button) o.next.button[f]();
			if (o.pagination.container) o.pagination.container[f]();
		},
		
		linkAnchors : function($c, se) {
			linkAnchors($c, se, this.carousel);
		},
		
		destroy : function(){
			this.carousel.css(this.carousel.data('cfs_origCss'))
				.unbind('pause')
				.unbind('play')
				.unbind('prev')
				.unbind('next')
				.unbind('scrollTo')
				.unbind('slideTo')
				.unbind('insertItem')
				.unbind('removeItem')
				.unbind('updatePageStatus');
			this.wrapper.replaceWith(this.carousel);
			return this;
		},
		
		currentPosition : function(){
			if (this.firstItem == 0) return 0;
			return this.totalItems - this.firstItem;
		},
		
		deactivate : function(){
			var c = this.carousel;
			//alert(this.active);
			this.isActive = false;
			//alert("pause");
			c.trigger('pause');
		},
		
		activate : function(){
			var c = this.carousel;
			this.isActive = true;
			//alert("play");
			c.trigger('play');
		}
		
	}
})());

jQuery.fn.exCarousel = function(options){
	return this.each(function(){ 
		new ex.Carousel(this, options); 
	});
}
jQuery.fn.exCarousel.pageAnchorBuilder = function(nr) {
	return '<a href="#"><span>'+nr+'</span></a>';
};

})(jQuery);
