(function($) {

	/**
	* @param options
	*/
	$.fn.carousel = function(options) {

		var settings = {
			count: 0,
			index: 0,
			selector: ".carousel",
			itemsArray: [],
			itemsSelector: ".items",
			itemSelector: "li",
			next: "next",
			timer: "8s",
			prev: "prev",
			speed: 750
		};

		var options = $.extend(settings, options);

		return this.each(function(i, e) {
			return new Carousel(e, options);
		});
	};

	/**
	* 
	*/
	function Carousel(ele, settings) {
		this.e = ele;
		this.$e = $(ele);
		this.settings = settings;

		init.call(this);

		if (this.settings.count > 1) {
			registerEvents.call(this);
		}
	}

	/**
	* 
	*/
	function init() {
		var obj = this;

		var iContainer = $(obj.$e.find(obj.settings.itemsSelector));
		obj.settings.itemsArray = iContainer.children(obj.settings.itemSelector);

		obj.settings.count = obj.settings.itemsArray.length;

		if (obj.settings.count > 1) {
			obj.settings.prevClass = "." + obj.settings.prev;
			obj.settings.nextClass = "." + obj.settings.next;

			obj.$e.append("<div class='" + obj.settings.prev + "'></div><div class='" + obj.settings.next + "'></div>")

			startLoop.call(obj);
		}
	}

	/**
	* 
	*/
	function registerEvents() {
		var obj = this;

		// Add firing events
		$(document).delegate(obj.settings.selector + " " + obj.settings.nextClass, "click", function() {
			stopLoop.call(obj);

			var data = getIndexes.call(obj, obj.settings.index + 1);
			data.direction = "next";

			$(this).trigger("carousel:slide", data);
		});
		$(document).delegate(obj.settings.selector + " " + obj.settings.prevClass, "click", function() {
			stopLoop.call(obj);

			var data = getIndexes.call(obj, obj.settings.index - 1);
			data.direction = "prev";

			$(this).trigger("carousel:slide", data);
		});

		// Hover events
		$(document).delegate(obj.settings.selector + " " + obj.settings.prevClass, "mouseover", function() {
			$(this).addClass("prev-hover");
		});
		$(document).delegate(obj.settings.selector + " " + obj.settings.prevClass, "mouseout", function() {
			$(this).removeClass("prev-hover");
		});
		$(document).delegate(obj.settings.selector + " " + obj.settings.nextClass, "mouseover", function() {
			$(this).addClass("next-hover");
		});
		$(document).delegate(obj.settings.selector + " " + obj.settings.nextClass, "mouseout", function() {
			$(this).removeClass("next-hover");
		});

		// Bind events
		$(document).bind("carousel:slide", function(event, data) {
			slide.call(obj, event, data);
		});
		$(document).bind("mainnav:slide", function(event, data) {
			stopLoop.call(obj);

			slide.call(obj, event, data);
		});
	}

	/**
	* 
	*/
	function startLoop() {
		var obj = this;
		obj.$e.everyTime(obj.settings.timer, "carousel:loop", function() {

			var data = getIndexes.call(obj, obj.settings.index + 1);
			data.direction = "next";

			obj.$e.find(obj.settings.nextClass).trigger("carousel:slide", data);
		});
	}

	/**
	* 
	*/
	function stopLoop() {
		var obj = this;
		obj.$e.stopTime("carousel:loop");
	}

	/**
	* 
	*/
	function getIndexes(newIndex) {
		var obj = this;

		var data = {
			newIndex: newIndex
		};

		// implement wrap-around looping
		if (data.newIndex >= obj.settings.count) {
			data.newIndex = 0;
		} else if (data.newIndex < 0) {
			data.newIndex = obj.settings.count - 1;
		}

		return data;
	}

	/**
	* 
	*/
	function slide(event, data) {
		var obj = this;

		obj.settings.index = data.newIndex;

		obj.settings.itemsArray.each(function(i, e) {
			$(e).hide();
		});

		$(obj.settings.itemsArray[obj.settings.index]).fadeIn(obj.settings.speed);
	}
})(jQuery);
