(function($) {
	
	$.fn.carousel = function(options) {
	
		var defaults = {
	    	numberVisible : 1,
	    	type : 'back_forward',
			pageBackFwd : true,
	    	controlPosition: 'after',
			pageCallback: null,
			backCallback: null,
			forwardCallback: null
	  	};
	  	
  		// Extend our default options with those provided.
  		var o = $.extend(defaults, options);
				
		return $.each( this, function() {		
			var elements = $(this).children();
			var elemWidth = elements.width();
			var elemHeight = elements.height();
		
			var source = $(this);
			var id = source.attr('id');
			var height = source.height();
			var width = source.width();
			
			// Inject Carousel Mark-up
			$(this).after('<div id="'+ id +'"><div class="carousel_content"><div><ul></ul></div></div></div>');
			
			// Remove original content
			$(this).remove();
			
			var content = $('#' + id + ' .carousel_content');
			
			switch(o.type) {
				
				case 'paging' :
					// Inject page controls
					var noPages = Math.ceil( elements.length / o.numberVisible );
					
					// Set width of content to maximum
					content.height(height).width(width);
					
					if ( noPages > 1) {
						
						var ctrlString = '<div class="carousel_pages">';
						
						if ( o.pageBackFwd ) {
							ctrlString += '<a class="back" href="#">&laquo;</a>&nbsp;';
						}
						
						for(var i=1; i<=noPages; i++ ) {
							ctrlString += '<a class="page_click" rel="'+ i +'" href="#">'+ i +'</a>&nbsp;';
						}
						
						if ( o.pageBackFwd ) {
							ctrlString += '<a class="forward" href="#">&raquo;</a>';
						}
						
						ctrlString += '</div>';
						
						if ( o.controlPosition == 'after' ) {
							$('#' + id + ' .carousel_content').after(ctrlString);
						}
						
						if ( o.controlPosition == 'before' ) {
							$('#' + id + ' .carousel_content').before(ctrlString);
						}
						
						if ( o.controlPosition == 'both' ) {
							$('#' + id + ' .carousel_content').after(ctrlString);
							$('#' + id + ' .carousel_content').before(ctrlString);
						}
						
						// Grab ze buttons
						var backBtn = $('#' + id + ' .carousel_pages .back');
						var fwdBtn = $('#' + id + ' .carousel_pages .forward');
						var classBtns = $('#' + id + ' .carousel_pages .page_click');
						
						// Set-up Button functionality
						var ptr = 1;
						
						checkBtns = function() {
							if ( ptr > 1 ) {
								backBtn.removeClass('disabled');
							} else {
								backBtn.addClass('disabled');
							}
							
							if ( ptr < noPages ) {
								fwdBtn.removeClass('disabled');
							} else {
								fwdBtn.addClass('disabled');
							}
							
							$.each( $('#' + id + ' .carousel_pages a'), function() {
								var thisId = $(this).attr('rel');
								
								if ( thisId == ptr ) {
									$(this).addClass('current');
								} else {
									$(this).removeClass('current');
								}
								
							});
						}
						
						function move() {
							slide.stop().animate({'left' : ( ( -elemWidth * Math.ceil( ( elements.length /  noPages ) ) ) ) * (ptr - 1) }, 1000, 'easeInOutExpo');
						}
						
						backBtn.click(function(e){
							if ( ptr > 1 ) {
								ptr--;			
								
								move();
								
								checkBtns();
								
								e.preventDefault();
								
							}
						});
						
						fwdBtn.click(function(e){
							
							if ( ptr < noPages ) {
								ptr++;
								
								move();
								
								checkBtns();
								
								e.preventDefault();
								
							}
							
						});
						
						classBtns.click(function(e){
							
							if ( o.pageCallback != null ) {
								o.pageCallback();
							}
							
							ptr = $(e.currentTarget).attr('rel');
							
							move();
							
							checkBtns();
							
							e.preventDefault();
							
						});
						
						checkBtns();
					}
				break;
				
				case 'back_forward' :
				default:
					// Inject Back Button
					$('#' + id + ' .carousel_content').before('<div class="back" class="button">&laquo;</div>');
					var backBtn = $('#' + id + ' .back');
					backBtn.height(height).width('5%');
				
					// Inject Forward Button
					$('#' + id + ' .carousel_content').after('<div class="forward" class="button">&raquo;</div>');
					var fwdBtn = $('#' + id + ' .forward');
					fwdBtn.height(height).width('5%');
				
					// Reduce width of content to accomadate back and forward buttons
					content.height(height).width('90%');
					
					// Set-up Button functionality						
					var ptr = 0;
					
					checkBtns = function() {
						if ( ptr > 0 ) {
							backBtn.removeClass('disabled');
						} else {
							backBtn.addClass('disabled');
						}
						
						if ( ptr < ( elements.length - o.numberVisible )) {
							fwdBtn.removeClass('disabled');
						} else {
							fwdBtn.addClass('disabled');
						}
					}
					
					backBtn.mouseover(function() { $(this).addClass('active'); }).mouseout(function() { $(this).removeClass('active') });
					
					backBtn.click(function(e){
						if ( ptr > 0 ) {
							ptr--;				
							
							slide.stop().animate({'left' : -elemWidth * ptr }, 200);
							
							checkBtns();
						}
						
					});
					
					fwdBtn.mouseover(function() { $(this).addClass('active'); }).mouseout(function() { $(this).removeClass('active') });
					
					fwdBtn.click(function(e){
						
						if ( ptr < ( elements.length - o.numberVisible )) {
							ptr++;
							
							slide.stop().animate({'left' : -elemWidth * ptr }, 200);
							
							checkBtns();
						}
						
					});
					
					checkBtns();
				break;
			}
			
			// Format Injected Content
			$('#' + id + ' div').css('display', 'block').css('float', 'left');
			
			var aperture = content.children('div');
			aperture.height(elemHeight).width('100%').css('overflow', 'hidden').css('position', 'relative');
			
			var slide = aperture.children('ul');
			slide.height(elemHeight).width(elemWidth * elements.length).css('position', 'absolute').css('left', 0);
			
			// Inject Elements into Carousel
			$.each(elements, function() {
				
				slide.append('<li>' + $(this).html() + '</li>');
				
			});
			slide.children('li').css('display', 'block').css('float', 'left').width(elemWidth);
		});
		
	};

})(jQuery);
