(function($) {
	$.fn.mediaScroller = function (options) {
		return this.each(
			function (i) {
				// merge defaults with options passed at run-time
				opts = $.extend({}, $.fn.mediaScroller.defaults, options);
				// set up our globals
				lockSlider = false;
				$mediaScroller = this;
				scrollerObj = {};
				$controls = $('a.control', $mediaScroller).bind('click', $.fn.mediaScroller.slide);
				$categoryList = $('> ul.media-categories', $mediaScroller);
				$categoryListLinks = $('li.media-category a', $categoryList)
					.bind('mouseenter mouseleave', $.fn.mediaScroller.updateTitle)
					.bind('click', $.fn.mediaScroller.changeCategory);
				$currentCategoryTitle = $('#currentMediaCategoryTitle', $categoryList);
				// set up the scroller list items in a discrete method so it can be called directly on ajax complete
				$.fn.mediaScroller.createScrollerItems();
			}
		);
	};
	// this method handles setting up the scroller-specific items
	$.fn.mediaScroller.createScrollerItems = function () {
		// no scrolling until the appropriate vars are set
		lockSlider = true;
		scrollerObj.$scroller = $('ul.scroller-items', $mediaScroller);
		scrollerObj.$items = $('li', scrollerObj.$scroller);
		scrollerObj.oneStepWidth = scrollerObj.$items.outerWidth();
		scrollerObj.fullSet = (scrollerObj.$items.length * scrollerObj.oneStepWidth) + scrollerObj.oneStepWidth;
		scrollerObj.maxOffset = scrollerObj.fullSet - (scrollerObj.oneStepWidth * 3);
		scrollerObj.slideBy = opts.slideBy * scrollerObj.oneStepWidth;
		// set the ul to be wide enough to accomodate all images on one line, and adjust the initial offset
		var initialOffset = scrollerObj.$items.length > 2 ? 0 : scrollerObj.oneStepWidth;
		scrollerObj.$scroller.css({
			 'left' : initialOffset + 'px'
			,'width' : scrollerObj.fullSet
		});
		// okay, now we can allow sliding
		lockSlider = false;
	}
	// this method handles the actual sliding
	$.fn.mediaScroller.slide = function (e) {
		e.preventDefault();
		// only slide if it's not locked
		if (!lockSlider) {
			var $this = $(e.currentTarget);
			var direction = $this.attr('id');
			var currentOffset = parseInt(scrollerObj.$scroller.css('left'));
			// make sure the offset is always a multiple of oneItem for smooth scrolling
			currentOffset = scrollerObj.oneStepWidth * Math.round(currentOffset / scrollerObj.oneStepWidth);
			var newOffset = 0;
			// moving left, so subtract the slideBy from the current offset
			if (direction == 'scrollerPrevious' && currentOffset < scrollerObj.oneStepWidth) {
				newOffset = currentOffset + scrollerObj.slideBy;
			}
			// moving right, so add the slideBy to the current offset
			else if (direction == 'scrollerNext' && currentOffset > -scrollerObj.maxOffset) {
				newOffset = currentOffset - scrollerObj.slideBy;
			}
			// We've either been called incorrectly, the HTML is wrong, or the offset exceeds the maximum.
			// Either way, don't do anything.
			else {return false;}
			// animate the scroller by setting it's left offset to the new value calculated above.
			scrollerObj.$scroller
				.stop()
				.animate(
					 {'left' : newOffset + 'px'}
					,opts.slideSpeed
					,opts.easing
				);
		}
	};
	// this method handles updating the category title on hover
	$.fn.mediaScroller.updateTitle = function (e) {
		var $this = $(e.currentTarget);
		// if the user is hovering on a category link, set $currentCategoryTitle's content to the link's title attribute.
		// otherwise, reset $currentCategoryTitle to the default (stored in $currentCategoryTitle's title attribute)
		var categoryTitle = e.type == 'mouseenter' ? $this.attr('title') : $currentCategoryTitle.attr('title');
		$currentCategoryTitle.text(categoryTitle);
	}
	// this method handles the category switching
	$.fn.mediaScroller.changeCategory = function (e) {
		e.preventDefault();
		var $this = $(e.currentTarget);
		// easier to type...
		var $scroller = scrollerObj.$scroller;
		// the new categoryID
		var newCatID = $this.attr('href').replace('#', '');
		// since we're changing categories, we need to make sure we set $currentCategoryTitle appropriately
		$currentCategoryTitle
			.attr('title', $this.attr('title'))
			.html($this.attr('title'));
		// toggle who has the current class
		$categoryListLinks.filter('.current').removeClass('current');
		$this.addClass('current');
		// send the new category ID to the scrollerItems tag
		$.ajax({
			 type: 'GET'
			,url: '/modules/media/tags/scrollerItems.cfm'
			,data: 'categoryID=' + newCatID
			,dataType: 'json'
			,success: function(scroller) {
				// no sliding while the category is changing
				lockSlider = true;
				var initialOffset = scroller.ITEMCOUNT > 2 ? 0 : scrollerObj.oneStepWidth;
				// once the call is made and data is returned, we need to update the actual scroller HTML
				// process: fade out => empty items => insert new items => fade in => reinit scroller vars
				// reinit the scroller vars (lengths, offsets, widths, etc) so sliding will work with new images.
				$scroller
					.fadeOut(
						 opts.fadeSpeed
						,function () {
							$scroller
								.css('left', initialOffset + 'px')
								.empty()
								.html(scroller.items)
								.fadeIn(
									 opts.fadeSpeed
									,$.fn.mediaScroller.createScrollerItems
								);
						}
					);
			}
		});
	}
	// defaults
	$.fn.mediaScroller.defaults = {
		 easing: 'swing'
		,fadeSpeed: 500
		,slideBy: 1
		,slideSpeed: 500
	};
})(jQuery);