// Andy LeMay - May 2010 - Steal at will!
//
// Assumptions:
//
// 1) Provided elements are of a consistent width and height


;(function($){
	
	// Class definition:
	
	var ASLImageRotator = function(pElements, pSettings){
		
		var _elements = $(pElements);
		var _settings = pSettings;
		var _isAutoRotating = false;
		var _currentItemIndex = 0;
		var _lastRotationTimestamp = new Date().getTime();
		var _currentRotationTimeout = 0;
		
		// add this instance to the DOM node of the parent element
		_elements.parent().data('ASLImageRotator', this);
		
		// used to call public methods from internal private methods
		var _obj = this;
		
		this.startAutoRotation = function(){
			if(!_isAutoRotating){
				_isAutoRotating = true;
				_currentRotationTimeout = setTimeout(this.showNextItem, _settings.autoplayInterval);
			}
		};
		
		this.stopAutoRotation = function(){
			if(_isAutoRotating){
				_isAutoRotating = false;
			}
		};
		
		this.pauseRotation = function(){
			clearTimeout(_currentRotationTimeout);
		};
		
		this.resumeRotation = function(){
			_currentRotationTimeout = setTimeout(this.showNextItem, _settings.autoplayInterval);
		};
		
		this.showNextItem = function(){
			
			// if we have enough elements to have a 'next' item
			if(_elements.length > 1){
				// if we're at the last item
				if(_currentItemIndex == _elements.length - 1){
					_obj.showItemByItemIndex(0);
				}
				// if we're not at the last item
				else{
					_obj.showItemByItemIndex(_currentItemIndex + 1);
				}
			}
		};
		
		this.showPrevItem = function(){
			
			// if we have enough elements to have a 'prev' item
			if(_elements.length > 1){
				// if we're at the first item
				if(_currentItemIndex == 0){
					_obj.showItemByItemIndex(_elements.length - 1);
				}
				else{
					_obj.showItemByItemIndex(_currentItemIndex - 1);
				}
			}
		};
		
		this.showItemByItemIndex = function(pIndex){
			
			// grab a reference to the existing item
			var __currentItem = $(_elements[_currentItemIndex]);
				
			_currentItemIndex = pIndex;
			
			var __newItem = $(_elements[_currentItemIndex]);
			
			//move the new item to the top of the display stack
			__newItem.appendTo(__newItem.parent());
			
			// initialize some animate() options
			var __newItemAnimateOptions = {};
			
			// if this new item needs to scroll in
			if(_settings.scrollIn){
				// position it based on where it needs to scroll from
				switch(_settings.scrollFrom){
					case "top":
						__newItem.css("top", -_settings.viewportHeight + "px");
						break;
					case "bottom":
						__newItem.css("top", _settings.viewportHeight);
						break;
					case "left":
						__newItem.css("left", -_settings.viewportWidth);
						break;
					case "right":
						__newItem.css("left", _settings.viewportWidth);
						break;	
				}
				__newItemAnimateOptions.top = 0;
				__newItemAnimateOptions.left = 0;
			}
			// if this new item doesn't need to scroll in
			else{
				// position it at 0,0
				__newItem.css({"top": 0 + "px", "left": 0 + "px"});
			}
			
			// if this new item needs to fade in
			if(_settings.fadeIn){
				// make it transparent
				__newItem.css("opacity", 0);
				__newItemAnimateOptions.opacity = 1;
				
			}
			
			// animate the new item
			var __completeFunc;
			if(_settings.onComplete != null){
				__completeFunc = _settings.onComplete;
			}
			else{
				if(_settings.autoplay){
					__completeFunc = setTimeout(_obj.showNextItem, _settings.autoplayInterval);
				}
				else{
					__completeFunc	= function(){};
				}
			}
			
			__newItem.animate(__newItemAnimateOptions, {duration: _settings.transitionDuration, easing: "easeInOutCubic", complete:__completeFunc});
			
			// initialize some animate() options for the currently displayed item
			var __currentItemAnimateOptions = {};
			
			// if we need to scroll the old item out
			if(_settings.scrollOut){
				// adjust the target animate options based on where it needs to scroll to
				switch(_settings.scrollFrom){
					case "top":
						__currentItemAnimateOptions.top = _settings.viewportHeight;
						break;
					case "bottom":
						__currentItemAnimateOptions.top = -_settings.viewportHeight;
						break;
					case "left":
						__currentItemAnimateOptions.top = _settings.viewportWidth;
						break;
					case "right":
						__currentItemAnimateOptions.top = -_settings.viewportWidth;
						break;	
				}
			}
			// if it doesn't need to scroll out
			else{
				// position it at 0,0
				__currentItem.css({"top": 0 + "px", "left": 0 + "px"});
			}
			
			// if it needs to fade out
			if(_settings.fadeOut){
				__currentItemAnimateOptions.opacity = 0;
			}
			
			// animate the current item
			__currentItem.animate(__currentItemAnimateOptions, {duration: _settings.transitionDuration, easing: "easeInOutCubic"});
		};
		
		// private
		
		var debug = function(pSource, pMessage, pLevel) {
			if(window.console && window.console.log){
				window.console.log("[" + pLevel + "]: " + pSource + ": " + pMessage);
			}
		};
		// init
		debug(_settings.id, "Instanced with " + _elements.length + " items...", "INFO");
		
		// reverse the order of our <li> items so that the first listed item is sitting on the top of the stack
		_elements.each(
			function(){
				$(this).prependTo($(this).parent());
			}
		);
		
		if(_settings.autoplay){
			this.startAutoRotation();
		}
	}

	// jQuery Wrapper:
	jQuery.fn.aslImageRotator = function(pOptions){
		
		var defaultSettings = {
			id: "aslImageRotator",
			viewportWidth: 200,
			viewportHeight: 200,
			autoplay: false,
			autoplayInterval: 2000,
			pauseAndResumeOnMouse: true,
			fadeIn: true,
			fadeOut: false,
			scrollIn: false,
			scrollOut: false,
			scrollFrom: "bottom",
			scrollAmount: 100,
			transitionDuration: 1000,
			onComplete: null
		};
	
		var settings = $.extend(defaultSettings, pOptions);
		
		return new ASLImageRotator(this, settings);
	}
	
})(jQuery);
