(function($) {
	/**
	 * Extends the jcarousel plugin with event oriented processing. Usage is similar to jcarousel:
	 * 
	 *	<ul id="mycarousel" class="jcarousel-skin-myskin">
	 *		<li class="jcarousel-item-1">
	 *			<img src="images/image1.png" />
	 *		</li>
	 *		<li class="jcarousel-item-2">
	 *			<img src="images/image2.png" />
	 *		</li>
	 *		<li class="jcarousel-item-3">
	 *			<img src="images/image3.png" />
	 *		</li>
	 *		<li class="jcarousel-item-4">
	 *			<img src="images/image4.png" />
	 *		</li>
	 *		<li class="jcarousel-item-5">
	 *			<img src="images/image5.png" />
	 *		</li>
	 *		<li class="jcarousel-item-6">
	 *			<img src="images/image6.png" />
	 *		</li>
	 *	</ul>
	 *	<script>
 	 *	$('#mycarousel').jcarousel({
	 *		scroll: 1,
	 *		animation: "slow",
	 *		auto: 4,
	 *		wrap: "last",
	 *		buttonNextHTML: null,
	 *		buttonPrevHTML: null,
	 *		eventNamespace: "com.cobaltgroup.ws.action.herocarousel.mypage",
	 *		// Carousel Callbacks -- REQUIRED
	 *		itemLoadCallback: function(scope) {scope.onItemLoad()},
	 *		initCallback: function(scope) {scope.onInit()}
	 *	});
	 *	</script>
	 *
	 * NOTE: The two callbacks must be included to get the EventManager integration and this extensions to the base functionality.
	 * It sucks, but can't be helped (unless someone can tell me how to create a child class in Jquery).
	 *
	 * The following events are published through the EventManager system (the same system used for pixel tagging):
	 * 
	 * **.initialized – Fires when the carousel is initialized, 'size' property is set in publisherData object
	 * **.displayed – Fires when a new image is displayed, 'index' and 'prevIndex' properties are set in publisherData object
	 * **.atHead – Fires when the “at beginning” status changes, 'state' property is set in publisherData object
	 * **.atTail – Fires when the “at end” status changes, 'state' property is set in publisherData object
	 * 
	 * The following events are monitored:
	 * 
	 * **.next – Go to the next image
	 * **.previous – Go to the previous image
	 * **.goto – Go to the a specific image, 'index' property must be set in publisherData object
	 * **.stop – Stop periodically updating the image
	 * **.start – Start periodically updating the image
	 * 
	 */
	
	if (!jQuery.jcarousel) {
		console.error("jquery.jcarousel.js plugin required");
	}

	if (!EventManager) {
		console.error("EventManager.js required")
	}
	
	jQuery.jcarousel.fn.extend({
		// Return a fully qualified namespace string
		fqEventName: function(evName) {
			return [this.options.eventNamespace, evName].join('.');
		},
		// Event handlers
		onItemLoad: function() {
			var index = this.first, prevIndex = this.prevFirst;
			EventManager.publish({
				eventName: this.fqEventName('displayed'),
				publisherData: { index: index, prevIndex: prevIndex }
			});
			var firstIndex = 1;
			var lastIndex = jQuery(this.list).find('li').length;
			if (index == firstIndex) {
				EventManager.publish({
					eventName: this.fqEventName('atHead'),
					publisherData: { state: true }
				});
			}
			else if (!prevIndex || prevIndex == firstIndex) {
				EventManager.publish({
					eventName: this.fqEventName('atHead'),
					publisherData: { state: false }
				});
			}
			if (index == lastIndex) {
				EventManager.publish({
					eventName: this.fqEventName('atTail'),
					publisherData: { state: true }
				});
			}
			else if (!prevIndex || prevIndex == lastIndex) {
				EventManager.publish({
					eventName: this.fqEventName('atTail'),
					publisherData: { state: false }
				});
			}
		},
		onGoto: function(e, pubData) {
			this.scroll(pubData.index);
		},
		onPrev: function(e) {
			this.prev();
		},
		onNext: function(e) {
			this.next();
		},
		onStop: function() {
			// Remove the mousemove event
			this.container.unbind('mousemove');
			
			// Stop the carousel
			this.stopAuto();
		},
		onStart: function() {
			// Remove the mousemove event
			this.container.unbind('mousemove');
			
			// Start the carousel
			this.startAuto();
		},
		onInit: function() {
			var self = this;
			// Set up mouse over/out to stop/start auto scrolling
			this.container.hover(function(e) {
				EventManager.publish({
					eventName: self.fqEventName('stop'),
					publisherData: e,
					scope: self
				});
			}, function(e) {
				EventManager.publish({
					eventName: self.fqEventName('start'),
					publisherData: e,
					scope: self
				});
			}).mousemove(function(e) {
				// This is added to stop the scrolling when the mouse starts over the carousel. Removed by the start and stop events.
				EventManager.publish({
					eventName: self.fqEventName('stop'),
					publisherData: e,
					scope: self
				});
			});
			
			// Set up listener for goto image event
			EventManager.subscribe({
				eventName: this.fqEventName('goto'),
				callback: this.onGoto,
				scope: this
			});
			
			// Set up listener for the previous event
			EventManager.subscribe({
				eventName: this.fqEventName('previous'),
				scope: this,
				callback: this.onPrev
			});
			
			// Set up the listener for the next event
			EventManager.subscribe({
				eventName: this.fqEventName('next'),
				scope: this,
				callback: this.onNext
			});
			
			// Set up listener for stop event({
			EventManager.subscribe({
				eventName: this.fqEventName('stop'),
				scope: this,
				callback: this.onStop
			});

			// Set up listener for start event({
			EventManager.subscribe({
				eventName: this.fqEventName('start'),
				scope: this,
				callback: this.onStart
			});
			EventManager.publish({
				eventName: this.fqEventName('initialized'),
				publisherData: { size: jQuery(this.list).find('li').length }
			});
		}
	});
})(jQuery);


