var ArticleSlider = function(opts) {
	opts = opts || {};

	var config = {

		$moduleTable: jQuery(opts.moduleTable),
		$container: jQuery(opts.container, opts.moduleTable),

		hasNavThumbs: opts.hasNavThumbs || false,
		hasNavButtons: opts.hasNavButtons || false,
		navActiveClass: opts.navActiveClass || 'active',

		isAutoScroll: opts.isAutoScroll || false,
		isInfiniteScroll: (this.isAutoScroll === true) ? true : (opts.isInfiniteScroll || false),

		interval: opts.interval || 3000,

		speed: opts.speed || 200,

		wait: opts.wait || 1000
	};
	config.childType = config.$container.children(':first-child').get(0).nodeName.toLowerCase();
	config.children = config.$container.children(config.childType);
	config.totalPages = config.children.length;

	var instance;

	if(opts.effect == 'slide') {

		config.maskWidth = opts.maskWidth;

		instance = new ArticleSlider.Slider(config);

	} else if(opts.effect == 'fade') {

		instance = new ArticleSlider.Fader(config);

	} else if(opts.effect == 'fade-slide') {

		instance = new ArticleSlider.Fader(config);

		var currentTop,
			maskHeight = config.$container.find('.article').height();

		jQuery(instance).bind('articlewillchange', function(event, index) {

			// hide current description
			var currentDesc = jQuery(".desc:visible", config.$moduleTable);

			if(currentDesc.length > 0) {
				var top = parseInt(currentDesc.position().top, 10);
	
				currentDesc.css({
					top: top
				});
				currentDesc.animate({
					'top': maskHeight
				}, (config.speed / 2), function() {
					jQuery(this).css({
						top: top,
						visibility: 'hidden'
					});
				});
			}

			// hide new description until article is shown
			var desc = jQuery(".article:eq(" + index + ") .desc", config.$moduleTable);

			desc.css({
				visibility: 'hidden'
			});

		});

		jQuery(instance).bind('articledidchange', function(event, index) {
			var desc = $(".article:eq(" + index + ") .desc", config.$moduleTable),
				goTo = maskHeight - parseInt(desc.outerHeight(), 10);
	
			desc.css({
				top: maskHeight,
				visibility: 'visible'
			});

			desc.animate({
				'top': goTo
			}, (config.speed / 2));

		});
	}

	if(config.hasNavThumbs) {
		jQuery(opts.navThumbs, config.$moduleTable).bind('click', function(e) {
			instance.goTo.call(instance, jQuery(e.target).index());
			if(config.isAutoScroll) {
				instance.pauseAutoScrollFor(config.wait);
			}
		});

		jQuery(instance).bind('articledidchange', function(event, index) {

			jQuery(opts.navThumbs, config.$moduleTable).find('.' + config.navActiveClass).removeClass(config.navActiveClass);
			jQuery(opts.navThumbs, config.$moduleTable).children(":eq(" + index + ")").addClass(config.navActiveClass);
		});
	}

	if(config.hasNavButtons) {	
		jQuery(opts.buttonPrev, config.$moduleTable).bind('click', jQuery.proxy(instance, 'prev'));
		jQuery(opts.buttonNext, config.$moduleTable).bind('click', jQuery.proxy(instance, 'next'));
	}
};

// COMMON METHODS
var _proto = {
    
   	prev: function() {
		var goTo = this.currentArticle - 1;

		if(goTo < 0) {
			if(this.config.isInfiniteScroll) {
				goTo = this.config.totalPages - 1;
			} else {
				goTo = this.currentArticle;
			}
		}
		this.goTo(goTo, 'prev');

	},
	next: function() {
		var goTo = this.currentArticle + 1;

		if(goTo >= this.config.totalPages) {
			if(this.config.isInfiniteScroll) {
				goTo = 0;
			} else {
				goTo = this.currentArticle;
			}
		}
		this.goTo(goTo, 'next');

	},
	launchAutoScroll: function() {
        this.autoScrollTimer = setInterval(jQuery.proxy(this, 'next'), this.config.interval);
	},
	pauseAutoScrollFor: function(pauseTime) {
	    clearInterval(this.autoScrollTimer);
	    clearTimeout(this.wait);
	    this.wait = setTimeout(jQuery.proxy(this, 'launchAutoScroll'), pauseTime);
	}
	
};


// SLIDER CLASS
ArticleSlider.Slider = function(config) {

    	this.config = config;

    	this.config.$container.width(this.config.maskWidth * this.config.totalPages);

    	this.isAnimated = false;
    	this.autoScrollTimer = null;
    	this.wait = null;
    	this.currentArticle = 0;

    	this.left = 0;

    	if(this.config.isAutoScroll) {
    		this.launchAutoScroll();
    	}
};

(function() {
	for(var method in _proto) {
		ArticleSlider.Slider.prototype[method] = _proto[method];
	}
}());
ArticleSlider.Slider.prototype.goTo = function(index, direction) {
	// direction is facultative
	// it's only used when we have an infinite scroll and we click the arrows


	if(!this.isAnimated && index != this.currentArticle) {

		this.isAnimated	= true;

		var _this = this,
		$container = this.config.$container;

		jQuery(this).trigger('articlewillchange', [index]);


		var goTo = -(index * this.config.maskWidth);

		if(this.config.isInfiniteScroll) {

			if(direction == 'prev' && this.left === 0) {
	
                $container.children(this.config.childType + ":last").prependTo($container);
                $container.css('left', this.left - this.config.maskWidth);
				goTo = this.left;
	
			} else if(direction == 'next'){
				goTo = -this.config.maskWidth;
			}

		}

		this.left = goTo;

		$container.animate({
			'left': goTo
		}, function() {

			if(direction == 'next') {
				$container.children(_this.config.childType + ":first").appendTo($container);
	
                $container.css('left', 0);
				_this.left = 0;
			}

			jQuery(_this).trigger('articledidchange', [index]);
			_this.currentArticle = index;
			_this.isAnimated = false;
		});

		if(this.config.isAutoScroll) {
			this.pauseAutoScrollFor(this.config.wait);
		}
	}
};


// FADER CLASS
ArticleSlider.Fader = function(config) {
    (function($){
	    this.config = config;

    	$(this.config.children[0]).css('display', 'block');

    	this.isAnimated = false;
    	this.autoScrollTimer = null;
    	this.wait = null;
    	this.currentArticle = 0;

    	if(this.config.isAutoScroll) {
    		this.launchAutoScroll();
    	}
    })(jQuery);
};

(function() {
	for(var method in _proto) {
		ArticleSlider.Fader.prototype[method] = _proto[method];
	}
}());
ArticleSlider.Fader.prototype.goTo = function(index) {
    (function($){
	    if(!this.isAnimated && index != this.currentArticle) {

    		this.isAnimated = true;

    		var _this = this;

    		$(this).trigger('articlewillchange', [index]);

    		$(this.config.children[this.currentArticle]).fadeOut(this.config.speed);
    		$(this.config.children[index]).fadeIn(this.config.speed, function() {
    			$(_this).trigger('articledidchange', [index]);
    			_this.currentArticle = index;
    			_this.isAnimated = false;
    		});
    	}
	})(jQuery);
};
