/**
* HaANS - Handsome and Awesome New Slider
* HaANS.js
* Version: 1.6
* Author: Tenga
* 
**/


// Launcher object
var HaANS = new function(){
	this.launch = function(c){
		var i = new _HaANS().launch(c);
		return i;
	}
}

// Actual HaANS object
function _HaANS(){
	var HaANS = this,
	
	// Defaults
	settings = {
		wrapper: false,
		items: false,
		upLeftArrow: null,
		downRightArrow: null,
		itemsPerViewport: 3,
		direction: 'horizontal',
		infinite: true,
		edgeToStart: false,
		edgeToStartDuration: 2,
		slidePer: 'item',
		autoSlide: false,
		autoSlideDelay: 3,
		transitionLength: 0.3,
		middleDetection: false,
		viewportMargin: 'auto',
		pauseAutoSlideOn: 'all',
		
		onItemMiddle: null,
		onChangeMiddle: null,
		onInitStart: null,
		onInitEnd: null,
		onNext: null,
		onPrev: null,
		onNextMove: null,
		onPrevMove: null,
		onMouseHoverSlider: null,
		onMouseHoverControls: null,
		onMouseHoverViewport: null,
		onMouseLeaveSlider: null,
		onMouseLeaveControls: null,
		onMouseLeaveViewport: null,
		onAutoSlide: null
	},
	
	// Function globals
	initialized = false,
	debug = false,
	
	items = [],
	itemDimensions = [],
	itemsCount = 0,
	averageItemDimension = 0,
	maxTravel = 0,
	cloneLeftDimension = 0,
	cloneRightDimension = 0,
	contentDimension = 0,
	viewportDimension = 0,
	
	slidOnce = false,
	arrowsBoundOnce = false,
	mouseOverSlider = false,
	mouseOverControls = false,
	controlsActive = false,
	
	dimensionWord = 'width',
	marginEdge = 'margin-left',
	
	$wrapper = null,
	wrapperName = null,
	$viewport = null,
	$contentArea = null,
	
	// Events
	prefix = 'HaANS',
	slider_init_start = prefix + '_init_start',
	slider_init_end = prefix + '_init_end',
	slider_next = prefix + '_next',
	slider_prev = prefix + '_prev',
	slider_next_move = prefix + '_next_move',
	slider_prev_move = prefix + '_prev_move',
	slider_looped = prefix + '_trans_looped',
	slider_autoslide = prefix + '_autoslide',
	slider_mouse_hover_slider = prefix + '_mouse_hover_slider',
	slider_mouse_hover_controls = prefix + '_mouse_hover_controls',
	slider_mouse_hover_viewport = prefix + '_mouse_hover_viewport',
	slider_mouse_leave_slider = prefix + '_mouse_leave_slider',
	slider_mouse_leave_controls = prefix + '_mouse_leave_controls',
	slider_mouse_leave_viewport = prefix + '_mouse_leave_viewport';
	
	// Helpers
	function trigger(event,callback){
		if (callback) callback.call(items);
		$wrapper.trigger(event);
	}
	
	function fetch_dimensions(){
		$(settings.items).each(function(index,value){
			var prevFloat = $(this).css('float');
			$(this).css('float','left');
			
			itemDimensions[index] = {
				x : $(this).outerWidth(),
				y : $(this).outerHeight(),
				xm : $(this).outerWidth(true),
				ym : $(this).outerHeight(true)
			}
			
			if(settings.direction == 'horizontal'){
				if(index < settings.itemsPerViewport){
					viewportDimension = viewportDimension + itemDimensions[index].xm;
				}
				contentDimension = contentDimension + itemDimensions[index].xm;
			}
			
			if(settings.direction == 'vertical'){
				if(index < settings.itemsPerViewport){
					viewportDimension = viewportDimension + itemDimensions[index].ym;
				}
				contentDimension = contentDimension + itemDimensions[index].ym;
			}
			
			
			$(this).css('float',prevFloat);
		});
		
		$viewport.css(dimensionWord , viewportDimension);
		
		$(settings.items).remove();
		insert_slides();
		
		if(debug){
			console.log('--------------------');
			console.log('HaANS: Item dimensions are:');
			console.log(itemDimensions);
			console.log('--------------------');
		}
	}
	
	HaANS.goToSlide = function(id){
		unbind_arrows();
		var nextOffset = id * averageItemDimension;
		if(settings.infinite === true) nextOffset = nextOffset + (averageItemDimension * settings.itemsPerViewport);
		if(nextOffset > 0) nextOffset = nextOffset * -1;
		if(nextOffset < maxTravel) nextOffset = maxTravel;
		
		if(settings.direction == 'horizontal'){
			$contentArea.animate({
				'margin-left' : nextOffset
			}, settings.transitionLength * 1000,function(){
				if(settings.middleDetection) detect_middle();
				bind_arrows();
			});
		} else if(settings.direction == 'vertical'){
			$contentArea.animate({
				'margin-top' : nextOffset
			}, settings.transitionLength * 1000,function(){
				if(settings.middleDetection) detect_middle();
				bind_arrows();
			});
		}
	}
	
	function negative_slide(){
		unbind_arrows();
		trigger(slider_prev, settings.onPrev);
		
		var currentOffset = parseInt($contentArea.css(marginEdge));
		var nextOffset = 0;
		var transLength = settings.transitionLength;
		
		if(settings.slidePer == 'viewport'){
			nextOffset = currentOffset + viewportDimension;
		} else {
			nextOffset = currentOffset + averageItemDimension;
		}
		
		if(nextOffset <= 0) trigger(slider_prev_move, settings.onPrevMove);
		
		if(nextOffset > 0 && settings.edgeToStart && !settings.infinite) {
			nextOffset = maxTravel;
			transLength = settings.edgeToStartDuration;
		} else if(nextOffset >= 0) {
			nextOffset = 0;
		}
		
		if(settings.direction == 'horizontal'){
			
			$contentArea.animate({
				'margin-left' : nextOffset
			}, transLength * 1000, function(){
				if(nextOffset >= 0 && settings.infinite === true){
					$contentArea.css(
						marginEdge , maxTravel + (averageItemDimension * settings.itemsPerViewport)
					);
				}
				if(settings.middleDetection) detect_middle();
				bind_arrows();
			});
			
		} else if(settings.direction == 'vertical'){
			
			$contentArea.animate({
				'margin-top' : nextOffset
			}, transLength * 1000, function(){
				if(nextOffset >= 0 && settings.infinite === true){
					$contentArea.css(
						marginEdge , maxTravel + (averageItemDimension * settings.itemsPerViewport)
					);
				}
				if(settings.middleDetection) detect_middle();
				bind_arrows();
			});
		}
		
	}
	
	function positive_slide(){
		unbind_arrows();
		trigger(slider_next, settings.onNext);
		
		var currentOffset = parseInt($contentArea.css(marginEdge));
		var nextOffset = maxTravel;
		var transLength = settings.transitionLength;
		
		if(settings.slidePer == 'viewport'){
			nextOffset = currentOffset - viewportDimension;
		} else {
			nextOffset = currentOffset - averageItemDimension;
		}
		
		if(nextOffset >= maxTravel) trigger(slider_next_move, settings.onNextMove);
		
		if(nextOffset < maxTravel && settings.edgeToStart && !settings.infinite) {
			nextOffset = 0;
			transLength = settings.edgeToStartDuration;
		} else if(nextOffset <= maxTravel) {
			nextOffset = maxTravel;
		}
		
		if(settings.direction == 'horizontal'){
			
			$contentArea.animate({
				'margin-left' : nextOffset
			}, transLength * 1000, function(){
				if(nextOffset <= maxTravel && settings.infinite === true){
					$contentArea.css(
						marginEdge , (averageItemDimension * settings.itemsPerViewport) * -1
					);
				}
				if(settings.middleDetection) detect_middle();
				bind_arrows();
			});
			
		} else if(settings.direction == 'vertical'){
			
			$contentArea.animate({
				'margin-top' : nextOffset
			}, transLength * 1000, function(){
				if(nextOffset <= maxTravel && settings.infinite === true){
					$contentArea.css(
						marginEdge , (averageItemDimension * settings.itemsPerViewport) * -1
					);
				}
				if(settings.middleDetection) detect_middle();
				bind_arrows();
			});
			
		}
		
	}
	
	function unbind_arrows(){
		if(settings.upLeftArrow !== null){
			$(settings.upLeftArrow).unbind('.HaANS_click');
		}
		
		if(settings.downRightArrow !== null){
			$(settings.downRightArrow).unbind('.HaANS_click');
		}
		
		controlsActive = false;
	}
	
	function bind_arrows(){
		if(settings.upLeftArrow !== null){
			$(settings.upLeftArrow).bind({
				'click.HaANS_click': function(){
					negative_slide();
				}
			});
			
			if(arrowsBoundOnce === false){
				$(settings.upLeftArrow).bind({
					'mouseenter.HaANS_hover': function(){
						mouseOverControls = true;
						trigger(slider_mouse_hover_controls, settings.onMouseHoverControls);
					},
					'mouseleave.HaANS_hover': function(){
						mouseOverControls = false;
						trigger(slider_mouse_leave_controls, settings.onMouseLeaveControls);
					}
				});
			}
		}
		
		if(settings.downRightArrow !== null){
			$(settings.downRightArrow).bind({
				'click.HaANS_click': function(){
					positive_slide();
				}
			});
			
			if(arrowsBoundOnce === false){
				$(settings.downRightArrow).bind({
					'mouseenter.HaANS_hover': function(){
						mouseOverControls = true;
						trigger(slider_mouse_hover_controls, settings.onMouseHoverControls);
					},
					'mouseleave.HaANS_hover': function(){
						mouseOverControls = false;
						trigger(slider_mouse_leave_controls, settings.onMouseLeaveControls);
					}
				});
			}
		}
		
		arrowsBoundOnce = true;
		controlsActive = true;
	}
	
	function insert_slides(){
		if(settings.infinite === true){
			for(i = (itemsCount - settings.itemsPerViewport); i < itemsCount; i++){
				var clone = items.eq(i).clone();
				clone.addClass('clone_l').appendTo($contentArea);
				
				if(settings.direction == 'horizontal'){
					contentDimension = contentDimension + itemDimensions[i].xm;
					cloneRightDimension = cloneRightDimension + itemDimensions[i].xm;
				} else if(settings.direction == 'vertical'){
					contentDimension = contentDimension + itemDimensions[i].ym;
					cloneRightDimension = cloneRightDimension + itemDimensions[i].ym;
				}
			}	
		}
		
		for(i = 0; i < itemsCount; i++){
			var clone = items.eq(i).clone();
			clone.appendTo($contentArea);
		}
		
		if(settings.infinite === true){
			for(i = 0; i < settings.itemsPerViewport; i++){
				var clone = items.eq(i).clone();
				clone.addClass('clone_r').appendTo($contentArea);
				
				if(settings.direction == 'horizontal'){
					contentDimension = contentDimension + itemDimensions[i].xm;
					cloneLeftDimension = cloneLeftDimension + itemDimensions[i].xm;
				} else if(settings.direction == 'vertical'){
					contentDimension = contentDimension + itemDimensions[i].ym;
					cloneLeftDimension = cloneLeftDimension + itemDimensions[i].ym;
				}
			}
		}
		
		if(settings.infinite === true){
			averageItemDimension = contentDimension / (itemsCount + (settings.itemsPerViewport * 2));
		} else {
			averageItemDimension = contentDimension / itemsCount;
		}
		
		maxTravel = (contentDimension - viewportDimension) * -1;
		$contentArea.css(dimensionWord , contentDimension).css(marginEdge , cloneLeftDimension * -1);
		
		if(settings.middleDetection) detect_middle();
		
		if(settings.autoSlide){
			(function autoScrollTimeout(){
				if(slidOnce === true) autoslide();
				else slidOnce = true;
				setTimeout(autoScrollTimeout, settings.autoSlideDelay * 1000);
			})();
		}
	}
	
	function detect_middle(){
		if(settings.itemsPerViewport > 1 && !((settings.itemsPerViewport % 2) == 0)){
			var currentItems = $(settings.items);
			var sideItems = (settings.itemsPerViewport - 1) / 2;
			var middleOffset = averageItemDimension * sideItems;
			
			if(settings.onChangeMiddle) settings.onChangeMiddle.call(currentItems);
			
			currentItems.each(function(index,value){
				
				var itemPosition = $(this).position();
				
				if(settings.direction == 'horizontal'){
					if(itemPosition.left >= (middleOffset - 5) && itemPosition.left <= (middleOffset + (averageItemDimension - 5))){
						if(settings.onItemMiddle) settings.onItemMiddle.call($(this));
					}
				} else if(settings.direction == 'vertical'){
					if(itemPosition.top >= (middleOffset - 5) && itemPosition.top <= (middleOffset + (averageItemDimension - 5))){
						if(settings.onItemMiddle) settings.onItemMiddle.call($(this));
					}
				}
			});
		} else if(debug){
			console.log('HaANS_GenericError: middleDetection failed, itemsPerViewport isnt more than 1 or an odd number');
		}
		
	}
	
	function autoslide(){
		if(settings.pauseAutoSlideOn == 'all' && (mouseOverControls || mouseOverSlider)) return false;
		if(settings.pauseAutoSlideOn == 'controls' && mouseOverControls) return false;
		if(settings.pauseAutoSlideOn == 'slider' && mouseOverSlider) return false;
		if(!controlsActive) return false;
		trigger(slider_autoslide, settings.onAutoSlide);
		positive_slide();
		return true;
	}
	
	//HaANS Initialization function
	HaANS.launch = function(config){
		
		// Check if jQuery is present, don't go on if it isn't.
		if(typeof jQuery == 'undefined'){
			throw('HaANS_InitError: jQuery is not present or loaded');
		} else {
			
			// Don't launch again if this instance of HaANS has already been launched
			if(initialized == false){
				$.extend(settings,config);
				
				if(settings.direction == 'vertical'){
					dimensionWord = 'height';
					marginEdge = 'margin-top';
				}
				
				// Check if mandatory options have been set
				if(!settings.wrapper || !settings.items){
					$.error('HaANS_InitError: No wrapper or item element specified');
				} else {
					
					// And off we go
					
					// Initialize instance variables
					$wrapper = $(settings.wrapper);
					trigger(slider_init_start, settings.onInitStart);
					
					wrapperName = settings.wrapper.substr(1);
					items = $(settings.items).clone();
					itemsCount = items.length;
					
					if(itemsCount < settings.itemsPerViewport){
						settings.itemsPerViewport = itemsCount;	
					}
					
					// Construct viewport and required items
					$viewport = $('<div>').appendTo(settings.wrapper).attr('class',wrapperName + '_viewport').css({
						overflow: 'hidden',
						margin: settings.viewportMargin,
						position: 'relative'
					}).bind({
						'mouseenter.HaANS_hover': function(){
							trigger(slider_mouse_hover_viewport, settings.onMouseHoverViewport);
						},
						'mouseleave.HaANS_hover': function(){
							trigger(slider_mouse_leave_viewport, settings.onMouseLeaveViewport);
						}
					});
					
					$wrapper.bind({
						'mouseenter.HaANS_hover': function(){
							mouseOverSlider = true;
							trigger(slider_mouse_hover_slider, settings.onMouseHoverSlider);
						},
						'mouseleave.HaANS_hover': function(){
							mouseOverSlider = false;
							trigger(slider_mouse_leave_slider, settings.onMouseLeaveSlider);
						}
					});
					
					$contentArea = $('<div>').appendTo($viewport).attr('class',wrapperName + '_content');
					
					// If there are images in the wrapper, wait until elements have loaded and measure them
					var imagesInContent = $wrapper.find('img').not(function(){
						return this.complete
					}).load(function(){
						if( --imagesInContent === 0){
							fetch_dimensions();
						}
					}).length;
					
					// If there are no images, measure anyways
					if(imagesInContent === 0){
						fetch_dimensions();
					}
					
					bind_arrows();
					
					if(debug) {
						console.log('--------------------');
						console.log('HaANS: Launched with following configuration:');
						console.log(settings);
						console.log('--------------------');
						console.log('HaANS: Items contain:');
						console.log(items);
						console.log('--------------------');
					}
					
					initialized = true;
					trigger(slider_init_end, settings.onInitEnd);
					
					return HaANS;
				}
				
			} else {
				$.error('HaANS_InitError: Already launched, you can\'t launch the same instance of the slider again');
			}
		}
	}
}

