jQuery.fn.channelchanger = function(options) 
{
	// =========================================================
	// == Settings =============================================
	// =========================================================
	var settings = jQuery.extend({
		onChange: function(){},
		page: ".navigation .page",
		next: ".navigation .next",
		prev: ".navigation .prev",
		pane: ".panes .pane",
		activePageClass: "active",
		disabledNavigationClass: "disabled",
		autorotate: false,
		durationSelector: "duration",
		duration: 7,
		wrap: false,
		stopOnNavigate: false,
		video: { },
		animation: "fade",
		startingPane: 1
	}, options);
		
	settings.video = jQuery.extend({
		selector: "[video]",
		onLoad: function() {
			this.play();
		}
	}, settings.video)
	
	settings.form = jQuery(this);
	settings.videoEnabled = (jQuery().fpvideo != null);
	
	// =========================================================
	// == Navigation ===========================================
	// =========================================================
	var navigation = new Object();
	navigation.nextRotation = null;
	navigation.inTransition = false;
	navigation.SetPanesAndNavigation = function(newPane, oldPane) {
		if(newPane.length == 0 || navigation.inTransition)
			return;
		
		// Animate the transition
		if(oldPane.length > 0) {
			navigation.inTransition = true;
			if(settings.animation == "fade") {
				oldPane.fadeOut(400, function() { 
					newPane.fadeIn(400, function() {
						navigation.inTransition = false;
					}); 
				});
			} else if(settings.animation == "slideHorizontal") {
				var isNext = oldPane.nextAll().is(newPane);
				oldPane.slide((isNext) ? "left" : "right", { onComplete: function() { navigation.inTransition = false; } })
				newPane.slide((isNext) ? "left" : "right");
			} else if(settings.animation == "none") {
				oldPane.hide();
				newPane.show();
				navigation.inTransition = false;
			}
		}
		else newPane.show();
		
		// Detect and play any videos
		var videoFound = false;
		if(settings.videoEnabled) {
			oldPane.find(settings.video.selector).stop();
			videoFound = newPane.find(settings.video.selector).length > 0;
		}
		
		// Reset animated gifs
		newPane.find("img[src$='.gif']").each(function() {
			this.src = this.src;
		});
		
		// Update the pager class
		settings.form.find(settings.page + "." + settings.activePageClass).removeClass(settings.activePageClass);
		settings.form.find(settings.page + ":eq(" + newPane.index(settings.pane) + ")").addClass(settings.activePageClass);
		
		// Update the prev/next class
		if(!settings.wrap) {
			var hasNext = (newPane.next().length > 0);
			var hasPrev = (newPane.prev().length > 0);
			
			settings.form.find(settings.next).toggleClass(settings.disabledNavigationClass, !hasNext);
			settings.form.find(settings.prev).toggleClass(settings.disabledNavigationClass, !hasPrev);
		}
		
		settings.onChange(newPane, oldPane, this);
		
		// Continue on
		if(settings.autorotate && !videoFound) {
			navigation.Play(newPane.attr(settings.durationSelector));
		}
	}
	navigation.GoToPage = function(paneIndex) {
		var currentPane = settings.form.find(settings.pane + ":visible");
		var targetPane 	= settings.form.find(settings.pane + ":eq(" + paneIndex + ")");

		if(settings.stopOnNavigate)
			navigation.Stop();
		
		navigation.SetPanesAndNavigation(targetPane, currentPane);	
	}
	navigation.MovePrevious = function() {
		var currentPane = settings.form.find(settings.pane + ":visible");
		var prevPane	= currentPane.prev(settings.pane);
		if(prevPane.length == 0 && settings.wrap)
			prevPane = settings.form.find(settings.pane + ":last");

		if(prevPane.length == 0)
			return;
			
		navigation.SetPanesAndNavigation(prevPane, currentPane);
	}
	navigation.MoveNext = function() {
		var currentPane = settings.form.find(settings.pane + ":visible");
		var nextPane	= currentPane.next(settings.pane);
		if(nextPane.length == 0 && settings.wrap)
			nextPane = settings.form.find(settings.pane + ":first");
			
		if(nextPane.length == 0)
			return;

		navigation.SetPanesAndNavigation(nextPane, currentPane);
	}
	navigation.Pause = function() {
		settings.autorotate = false;
		clearTimeout(navigation.nextRotation);
	}
	navigation.Play = function(duration) {
		duration = duration || settings.duration;
			
		settings.autorotate = true;
		clearTimeout(navigation.nextRotation);
		navigation.nextRotation = setTimeout(navigation.MoveNext, duration * 1000);
	}
	navigation.Stop = function() {
		settings.autorotate = false;
		clearTimeout(navigation.nextRotation);
	}
	
	// =========================================================
	// == Initialization =======================================
	// =========================================================
	// Set up any videos
	if(settings.videoEnabled) {
		if(settings.autorotate) {
			settings.video.onFinish = function() {
				setTimeout(function() {
					navigation.MoveNext();
				}, 500);
			};
		}		
		settings.form.find(settings.video.selector).fpvideo(settings.video);
	}
	
	// Show the current pane
	var currentAnimation = settings.animation;
	settings.animation = "none";
	navigation.GoToPage(settings.startingPane - 1);
	settings.animation = currentAnimation;
	
	var currentPane = settings.form.find(settings.pane + ":visible");
	
	// Mark the current pane as active
	settings.form.find(settings.page + ":eq(" + settings.form.find(settings.pane).index(currentPane) + ")").addClass(settings.activePageClass);
	
	// Update the next and previous buttons
	if(!settings.wrap) {
		settings.form.find(settings.prev).addClass(settings.disabledNavigationClass);
		if(currentPane.next().length == 0)
			settings.form.find(settings.next).addClass(settings.disabledNavigationClass);
	}
		
	// =========================================================
	// == Events ===============================================
	// =========================================================	
	// Click of the specific page button
	settings.form.find(settings.page).click(function() {
		var index = settings.form.find(settings.page).index(this);
		
		navigation.GoToPage(index);
	});
	// Click of the previous button
	settings.form.find(settings.prev).click(function() {
		if(jQuery(this).hasClass(settings.disabledNavigationClass))
			return;

		navigation.MovePrevious();
	});
	// Click of the next button
	settings.form.find(settings.next).click(function() {
		if(jQuery(this).hasClass(settings.disabledNavigationClass))
			return;

		navigation.MoveNext();
	});
	
	return navigation;
}

jQuery.fn.slide = function(direction, options) {
	var settings = jQuery.extend({
		onComplete: function(){},
		duration: 0.75
	}, options);

	var $this = jQuery(this);
	var	show = !$this.is(":visible");
	var isHorizontal 	= (direction == "left" || direction == "right")
	var positioner 		= (isHorizontal) ? "left" : "top";
	var distance 		= (isHorizontal) ? $this.outerWidth() : $this.outerHeight();
	var movePositive 	= (direction == "right" || direction == "down");
	
	$this.css("position", "absolute");
	$this.css(positioner, "0");
	$this.parent().css({
		"overflow": "hidden",
		"position": "relative"
	})
	
	if(show)
	{
		var sign = (movePositive) ? "-" : "";	
		$this.css(positioner, sign + distance + "px");
		$this.show();
	}
	else $this.css(positioner, "0");  	
	
	var horzDistance 	= (isHorizontal) ? distance : 0;
	var vertDistance 	= (isHorizontal) ? 0 : distance;	
	var action 			= (movePositive) ? "+=" : "-="; 
	$this.animate({
		left: action + horzDistance,
		top: action + vertDistance
	}, settings.duration * 1000, function() { 
		settings.onComplete(); 
		if(!show)
			$this.hide(); 
	});
}

jQuery.fn.slideLeft = function(options) {
	var $this = jQuery(this).slide("left", options);
}
jQuery.fn.slideRight = function(options) {
	var $this = jQuery(this).slide("right", options);
}
jQuery.fn.slideUp = function(options) {
	var $this = jQuery(this).slide("up", options);
}
jQuery.fn.slideDown = function(options) {
	var $this = jQuery(this).slide("down", options);
}
