jQuery.fn.extend({
	carouselSQLI: function(options) {
		return this.each(function() {
			new carouselSQLI(this, options);
			return this;
		});
	}
});

/**
 * Carousel SQLI 
 * @constructor
 */
carouselSQLI = function(element, options){
	options = options || {};
	this.$object = jQuery(element);
	this.params = this.merge(options, this.Default);
	this.$object.data('carouselSQLI', this.clone(this));
	this.formatting();
	this.initialization();
};

carouselSQLI.$object = null;
carouselSQLI.params = {};
carouselSQLI.prototype.Default = {
	vertical 		: false,
	itemClass		: 'item',
	windowClass		: 'carouselWindow',
	verticalClass	: 'vertical',
	horizontalClass	: 'horizontal',
	listClass		: 'list',
	buttonNext		: '<div class="next"></div>',
	buttonPrev 		: '<div class="prev"></div>',
	animated		: false,
	position		: 0,
	elementToScroll : 3
};

carouselSQLI.prototype.clone = function(obj){
	var newObj = {};
	for(key in obj)
		if (jQuery.isPlainObject(obj[key]))newObj[key] = this.clone(obj[key]);
		else newObj[key] = obj[key];
	return newObj;
};

carouselSQLI.prototype.merge = function(Current, Default){
	var paramsToReturn = '';
	CurDefault = this.clone(Default);
	if(jQuery.isPlainObject(Current)){
		if(jQuery.isPlainObject(Default)){
			paramsToReturn =  CurDefault;
			for(Key in Current)	paramsToReturn[Key] = Current[Key];
		}else{
			paramsToReturn = Current;
			paramsToReturn.Default = CurDefault;
		}
	}else if(jQuery.isArray(Current)){
		if(jQuery.isPlainObject(Default)){
			paramsToReturn =  CurDefault;
			paramsToReturn.Current = Current;
		}else paramsToReturn = Current;	
	}else{
		if(jQuery.isPlainObject(Default)){
			paramsToReturn =  CurDefault;
			paramsToReturn.Current = Current;
		}else if(jQuery.isArray(Default)) paramsToReturn =  CurDefault;
		else paramsToReturn = Current;
	}
	return paramsToReturn;
};

carouselSQLI.prototype.formatting = function(){
	var engine = this;
	if(this.$object.children()[0].nodeName == 'SELECT'){
		var $element = jQuery(this.$object.children()[0]);
		var $newElement = jQuery('<ul/>');
		$element.children('option').each(function(){
			$newElement.append(jQuery('<li/>').append( jQuery('<a/>').attr( 'href', $(this).val() ).attr( 'target', $(this).attr('alt') ).html($(this).html()) ));
		});
		this.$object.children().remove();
		this.$object.append($newElement);
	}else if(this.$object.children()[0].nodeName != 'UL'){
		//if(window.console)console.error('carousel SQLI : ', 'Carousel DOM element n\'a pas la bonne structure.')
		return false;
	}
	var window	= '<div class="'+this.params.windowClass+' '+((this.params.vertical)?this.params.verticalClass:this.params.horizontalClass)+' '+this.params.windowClass+'-'+((this.params.vertical)?this.params.verticalClass:this.params.horizontalClass)+'" />';
	var list	= '<div class="'+this.params.listClass+'" />';
	this.$object.children().wrap(window);
	this.$object
		.prepend(jQuery(this.params.buttonPrev).addClass('prev-'+((this.params.vertical)?this.params.verticalClass:this.params.horizontalClass)).addClass((this.params.vertical)?this.params.verticalClass:this.params.horizontalClass))
		.append(jQuery(this.params.buttonNext).addClass('next-'+((this.params.vertical)?this.params.verticalClass:this.params.horizontalClass)).addClass((this.params.vertical)?this.params.verticalClass:this.params.horizontalClass));
	this.$object.find('ul').wrap(list);
	this.$object.find('.'+this.params.listClass)
		.css({position:'absolute'})
		.find('li').each(function(){
			if(!jQuery(this).hasClass(engine.params.itemClass))jQuery(this).toggleClass(engine.params.itemClass);
		});
	if(!this.params.vertical)this.$object.append(jQuery('<div style="clear:both;" />'));
};

carouselSQLI.prototype.initialization = function(){
	if(this.params.vertical)this.$object.find('.'+this.params.listClass+' ul').height(this.realWindowHeight());
	else this.$object.find('.'+this.params.listClass+' ul').width(this.realWindowWidth());
	this.buttonGestion();
	this.accessibilityRules();
};

carouselSQLI.prototype.buttonGestion = function(){
	var $window = this.$object.find('.'+this.params.windowClass);
	var $list	= $window.find('.'+this.params.listClass);
	var $prev	= this.$object.children(':first');
	var $next	= (this.params.vertical)?this.$object.children(':last'):this.$object.children(':last').prev();
	var engine	= this;
	$next.unbind('click');
	$prev.unbind('click');
	
	if(this.params.vertical){
		var hW	= $window.height();
		var hL	= $list.height();
		var tL	= parseInt($list.css('top').split('px')[0]);
		var last= this.realHeight($list.children().children(':last'));
		var first= this.realHeight($list.children().children(':first'));
		if(tL == 0 || tL+first > 0){
			$prev.addClass('disabled');
			$prev.removeClass('prev-'+engine.params.verticalClass);
			$prev.addClass('prev-'+engine.params.verticalClass+'-disabled');
		}else{
			$prev.removeClass('disabled');
			$prev.removeClass('prev-'+engine.params.verticalClass+'-disabled');
			$prev.addClass('prev-'+engine.params.verticalClass);
			$prev.bind('click', engine.clickPrev);
		}
		if(tL == (hW-hL) || tL < (hW-hL)+last  ){
			$next.addClass('disabled');
			$next.removeClass('next-'+engine.params.verticalClass);
			$next.addClass('next-'+engine.params.verticalClass+'-disabled');
		}else{
			$next.removeClass('disabled');
			$next.removeClass('next-'+engine.params.verticalClass+'-disabled');
			$next.addClass('next-'+engine.params.verticalClass);
			$next.bind('click', engine.clickNext);
		}
	}else{
		var wW	= $window.width();
		var wL	= $list.width();
		var lL	= parseInt($list.css('left').split('px')[0]);
		var last= this.realWidth($list.children().children(':last'));
		var first= this.realWidth($list.children().children(':first'));
		if(lL == 0 || lL + first > 0 ){
			$prev.addClass('disabled');
			$prev.removeClass('prev-'+engine.params.horizontalClass);
			$prev.addClass('prev-'+engine.params.horizontalClass+'-disabled');
		}else{
			$prev.removeClass('disabled');
			$prev.removeClass('prev-'+engine.params.horizontalClass+'-disabled');
			$prev.addClass('prev-'+engine.params.horizontalClass);
			$prev.bind('click', engine.clickPrev);
		}
		if(lL == (wW-wL) || lL < (wW-wL)+last ){
			$next.addClass('disabled');
			$next.removeClass('next-'+engine.params.horizontalClass);
			$next.addClass('next-'+engine.params.horizontalClass+'-disabled');
		}else{
			$next.removeClass('disabled');
			$next.removeClass('next-'+engine.params.horizontalClass+'-disabled');
			$next.addClass('next-'+engine.params.horizontalClass);
			$next.bind('click', engine.clickNext);
		}
	}
};



carouselSQLI.prototype.goTo = function(newPosition){
	if(!this.params.animated){
		this.params.animated = true;
		var $lis = this.$object.find('li');
		if(this.params.vertical){
			var nH = 0;
			if(newPosition > this.params.position){
				for(var i=(this.params.position*this.params.elementToScroll); i<(newPosition)*this.params.elementToScroll; i++)
					if(jQuery($lis[i]).length!=0)nH += this.realHeight(jQuery($lis[i]));
				this.$object.find('.'+this.params.listClass).animate({top : '-='+nH}, 500, this.animationStop);
				engine.params.position = newPosition;
			}else if(newPosition < this.params.position){
				for(var i=(this.params.position*this.params.elementToScroll)-1; i>=(newPosition)*this.params.elementToScroll; i--)
					if(jQuery($lis[i]).length!=0)nH += this.realHeight(jQuery($lis[i]));
				this.$object.find('.'+this.params.listClass).animate({top : '+='+nH}, 500, this.animationStop);
				engine.params.position = newPosition;
			}else{this.params.animated = false;}
		}else{
			var nW = 0;
			if(newPosition > this.params.position){
				for(var i=(engine.params.position*engine.params.elementToScroll); i<((newPosition)*engine.params.elementToScroll); i++)
					if(jQuery($lis[i]).length!=0)nW += engine.realWidth(jQuery($lis[i]));
				engine.$object.find('.'+engine.params.listClass).animate({left : '-='+nW}, 500, engine.animationStop);
				engine.params.position = newPosition;
			}else if(newPosition < this.params.position){
				for(var i=(engine.params.position*engine.params.elementToScroll)-1; i>=((newPosition)*engine.params.elementToScroll); i--)
					if(jQuery($lis[i]).length!=0) nW += engine.realWidth(jQuery($lis[i]));
				engine.$object.find('.'+engine.params.listClass).animate({left : '+='+nW}, 500, engine.animationStop);
				engine.params.position = newPosition;
			}else{this.params.animated = false;}
		}
	}
};

carouselSQLI.prototype.clickNext = function(event){
	$parent = jQuery(this).parent()
	while($parent.data('carouselSQLI')==null)$parent= $parent.parent();
	engine = $parent.data('carouselSQLI');
	engine.goTo(engine.params.position+1);
};

carouselSQLI.prototype.clickPrev = function(event){
	$parent = jQuery(this).parent()
	while($parent.data('carouselSQLI')==null)$parent= $parent.parent();
	engine = $parent.data('carouselSQLI');
	engine.goTo(engine.params.position-1);
};

carouselSQLI.prototype.animationStop = function(event){
	$parent = jQuery(this).parent()
	while($parent.data('carouselSQLI')==null)$parent= $parent.parent();
	engine = $parent.data('carouselSQLI');
	engine.buttonGestion();
	engine.params.animated = false;
	
};

carouselSQLI.prototype.realWidth = function($element){
	return $element.innerWidth();
};

carouselSQLI.prototype.realHeight = function($element){
	return $element.innerHeight();
};

carouselSQLI.prototype.realWindowWidth = function(){
	var nW = 0;
	$lis =this.$object.find('.'+this.params.listClass+' ul').children();
	for(var i=0; i<$lis.length; i++)
		nW += this.realWidth(jQuery($lis[i]));
	return nW+(30*$lis.length);
};

carouselSQLI.prototype.realWindowHeight = function(){
	var nH = 0;
	$lis =this.$object.find('.'+this.params.listClass+' ul').children(); 
	for(var i=0; i<$lis.length; i++)
		nH += this.realHeight(jQuery($lis[i]));
	return nH;
};

carouselSQLI.prototype.accessibilityRules = function(){
	this.$object.find('.'+this.params.listClass+' ul').children().each(function(){
		jQuery(this).focusin(function(event){
			$parent = jQuery(this).parent()
			while($parent.data('carouselSQLI')==null)$parent= $parent.parent();
			engine = $parent.data('carouselSQLI');
			$lis = engine.$object.find('.'+engine.params.listClass+' ul').children();
			for (var i=0 ; i<$lis.length; i++){
				if ($lis[i] == this){
					var nPos = Math.floor(i/engine.params.elementToScroll);
					engine.goTo(nPos);
				} 
			}
		});
	});
};
