(function($){
	//global object to hold all global variables
	var g = {
		slideWidth: 0,
		slideCount: 0,
		currentDot: 0,
		currentDotCache: null,
		lengths: 0,
		selectedDot: 0,
		
		//allows the user to click right or left a few times before the selected slide is final
		delay: {}, //timeout object
		autoScroll: {}, //interval object
		autoScrollDelay: {} //timeout object
	};
	
	$.fn.famigoSlider = function(options){
		//defaults for user defined settings
		var defaults = {
			slideContainer: "#content-container", //slide container selector
			dotContainer: "#content-nav-dots", //dot container selector
			leftArrow: "#content-nav-left", //left arrow selector
			rightArrow: "#content-nav-right", //right arrow selector
			
			//animation settings
			easing: "easeInOutExpo", //easing for animation
			duration: 500, //duration of animation
			interval: 10000, //time in milliseconds between auto-scrolls
			pause: 55000, //time in milliseconds to keep auto-scroll paused
			
			//background image positions for the two dot states
			dotSelectedPos: "-181px -225px",
			dotUnselectedPos: "-174px -225px"
		}
		options = $.extend(true, defaults, options);
		
		g.slideCount = $(options.slideContainer + " > div").size(); //number of slides
		g.slideWidth = $(options.slideContainer + " > div:eq(0)").width(); //individual width of slides
		g = $.extend(options, g);
		
		initalizeSlider();
		bindEvents();
		updateDots(1, 0);
	}
	//resets slide elements to initial position with slide 0 at the beginning
	function initalizeSlider() {
		var left = 0; //css left property
	
		//loop through each slide and position them one after the other. slide 0 is the beginning
		for (i = 0; i < g.slideCount; i++) {
			$(g.slideContainer + " > div:eq(" + i + ")").css({"left" : left + "px"});
			left += g.slideWidth;
		}
		$(g.slideContainer + " > div").css({"visibility":"visible"});
		enableAutoScroll();
	}
	
	//event handler for slider navigation. decides what to do when a nav element is clicked. the mother brain of this entire application
	function navEventHandler(element) {
		//element = element that user clicked on
		var direction = ""
		
		//assign selectedDot. if arrow is clicked, override direction
		switch (element) {
			case g.rightArrow:
				g.selectedDot = g.currentDot + 1;
				direction = "right";
				g.lengths++;
			break;
			case g.leftArrow:
				g.selectedDot = g.currentDot - 1;
				direction = "left"
				g.lengths--;
			break;
			default: 
				g.selectedDot = element;
				if (g.selectedDot > g.currentDot) direction = "right";
				else direction = "left";
				g.lengths = g.selectedDot - g.currentDot;
		}
		//slideCount - 1 because index starts at 0 whereas counting starts at 1
		if (g.selectedDot > g.slideCount - 1) {
			g.selectedDot = 0;
		} else if (g.selectedDot < 0) {
			g.selectedDot = g.slideCount - 1;
		}
	
		//step 1: update position of highlighted dot
		
		//if the current dot has not been cached yet, store so that we know what the current slide was
		if (g.currentDotCache == null) {
			g.currentDotCache = g.currentDot;
		}
		
		//update the highlighted dot
		updateDots(g.currentDot, g.selectedDot);
		
		//set distance. multiply by lengths to get real distance. if lengths is greater than slideCount, subtract slideCount
		if (g.lengths > g.slideCount) {
			g.lengths -= g.slideCount;
		} else if (g.lengths < -g.slideCount) {
			g.lengths += g.slideCount;
		}
		distance = g.lengths * g.slideWidth * -1;
		
		//step 2: arrange slides for smooth animation only if arrow is clicked
		extend(direction, g.currentDotCache, g.currentDot);
		
		//step 3: do animation. wait a bit though before executing
		clearTimeout(g.delay);
		g.delay = setTimeout(function(){
			//if the current slide is the selected slide, don't go anywhere
			if (g.currentDotCache != g.selectedDot) {
				moveToSlide(distance);
			}
		}, 200);
	}
	
	//when user selects a slide, the slides get repositioned to make a continuous animation to that slide
	function extend(direction, current, ending) {
		//direction = which way the animation is going to flow
		//current = the current slide
		//ending = the slide that the user wants to go to
		var left = 0;
		$(g.slideContainer).css({"left":"0px"});
		
		if (direction == "right") { //if direction is right
			//position slide (or container) at 0
			for (i = current; i < g.slideCount; i++) {
				$(g.slideContainer + " > div:eq(" + i + ")").css({"left" : left + "px"});
				left += g.slideWidth;
			}
			for (i = 0; i < current; i++) {
				$(g.slideContainer + " > div:eq(" + i + ")").css({"left" : left + "px"});
				left += g.slideWidth;
			}
		} else if (direction == "left") { //if direction is left
			//position slide (or container) at the far end
			for (i = current; i >= 0; i--) {
				$(g.slideContainer + " > div:eq(" + i + ")").css({"left" : left + "px"});
				left -= g.slideWidth;
			}
			for (i = g.slideCount - 1; i > current; i--) {
				$(g.slideContainer + " > div:eq(" + i + ")").css({"left" : left + "px"});
				left -= g.slideWidth;
			}
		}
	}
	
	//the actual animation
	function moveToSlide(distance){
		//distance = the pixels to the left or right of the current slide to animate to
		
		//step 1: unbind nav elements to prevent the user from messing up the animation
		$(g.leftArrow + ", " + g.rightArrow).unbind("click");
		$(g.dotContainer + " > *").unbind("click");
		
		//step 2: animation
		$(g.slideContainer).animate({
			"left": distance
		}, {
			duartion: g.duration,
			easing: g.easing,
			complete: function(){
				//step 3: rebind nav elements
				bindEvents();
				g.currentDotCache = null;
				g.lengths = 0;
			}
		});
	}
	
	//when the user selects a slide, update the highlighted dot so that the user knows which slide he selected
	function updateDots(oldDot, newDot) {
		$(g.dotContainer + " > *:eq(" + oldDot + ")").css({"background-position" : g.dotUnselectedPos});
		$(g.dotContainer + " > *:eq(" + newDot + ")").css({"background-position" : g.dotSelectedPos});
		g.currentDot = g.selectedDot;
	}
	
	//bind events to elements
	function bindEvents() {
		$(g.leftArrow + ", " + g.rightArrow).bind("click", function(){
			navEventHandler("#" + $(this).attr("id"));
			disableAutoScroll();
		});
		$(g.dotContainer + " > *").bind("click", function(){
			navEventHandler($(this).index());
			disableAutoScroll();
		});
	}
	
	//enables the slide to scroll to the right every specified seconds
	function enableAutoScroll() {
		g.autoScroll = setInterval(function(){
			navEventHandler(g.rightArrow);
		}, g.interval);
	}
	
	//disables the slide to scroll to the right every specified seconds
	function disableAutoScroll() {
		clearInterval(g.autoScroll);
		clearTimeout(g.autoScrollDelay);
		g.autoScrollDelay = setTimeout(function(){
			enableAutoScroll();
		}, g.pause);
	}
})(jQuery);