/**
 * jQuery Swipe And Drag Plugin v1.0
 * 
 * Copyright 2011, Version Industries
 * Licensed under the GPL
 * http://www.gnu.org/licenses/gpl.html
 *
 * @author Carlos Alberto Padilla Contreras carlos@versionindustries.com
 *
 *
 * This plugin will allow users to drag content either vertically or horizontally, never in both directions.
 * It will automatically set the CSS for the element chosen and for its immediate children.
 *
 * It works by giving the contaier element a set width and height, and setting the overflow property to hidden.
 * Then it positions the children accordingly, and scrolls the container.
 *
 * Settings:
 *
 * direction: string that can be either 'horizontal' or 'vertical'.
 * useSnapPoints: boolean that indicates whether the scrolling will be forced to stop at certain points.
 * snapPoints: array of numbers indicating where it will stop, if useSnapPoints is set to true.
 * enableKeyboardArrows: boolean that indicates whether the scroll should move when the keyboard arrows are pressed.
 * nextButton: string that indicates the ID attribute of the HTML element to use as the next button.
 * previousButton: string that indicates the ID attribute of the HTML element to use as the previous button.
 * navButtons: selector for an element containing <a> elements with classes having the index as the last character.
 *
 * All settings are optional.
 */
	/**
	 * Returns an array with the duplicate elements removed, leaving the original intact.
	 * @param arr {array} The array from which the duplicates will be sliced.
	 * @type Array
	 */
/*function removeDuplicates(arr){
	var i;
	var o = {};
	var l = arr.length;
	for(i = 0; i < l; i++){
		o[arr[i]] = arr[i];
	}
	arr = [];
	for(i in o){
		arr.push(o[i]);
	}
	return arr;
};

/**
 * Remove items from an array that are not of a certain type.
 * @param arr {array} The array to filter
 * @param filter {string} What type of item should be left.
 */
function filterArray(arr, filter){
	var i;
	var l = arr.length;
	switch(filter){
		case 'int':
			for(i = 0; i < l; i++){
				var a = parseInt(arr[i],10);
				if(a !== NaN){
					arr[i] = a;
				}
				else{
					arr.slice(i, 1);
				}
			}
			break;
	}
};

(function($){

/* "Constans" */
var FPS = 20;
var ua = navigator.userAgent;
var mobile = ua.match(/ipad|ipod|iphone|android|opera mini|blackberry/i);
var OFFSET_FACTOR = (mobile) ? 0.4 : 0.1;
var TIME_BETWEEN_SCROLLS = 5;
var SNAP_THRESHOLD = 5;
var KEYBOARD_UP = 38;
var KEYBOARD_DOWN = 40;
var KEYBOARD_LEFT = 37;
var KEYBOARD_RIGHT = 39;
var DEFAULT_SCROLL = 30;
var KEYPRESS_SCROLL = 30; // remove if you have time
var LOOKBOOK_HEIGHT = 562;
var LOOKBOOK_WIDTH = 883;

/* globals */
var isScrolling = false;
var stopScrolling = false;
var currentTimeout = 0;

/**
 * Smoothly stops the target after it has been dragged or swiped.
 * @param distance {integer} Length of the last movement of the target, which
 * determines the direction and the strength of the swipe or drag.
 */
function gentlyStopScroll(target, distance){
	var one_less = (distance > 0) ? -1 : 1;
	var options = target.data('user_options');
	var directionIndex = (options.direction === 'horizontal') ? 0 : 1;
	var scrollIntervalID;
	function easeScroll(){
		if(directionIndex){
			target.scrollTop(target.scrollTop() - distance);
		}
		else{
			target.scrollLeft(target.scrollLeft() - distance);
		}
		distance += one_less;
		if(distance === 0){
			clearInterval(scrollIntervalID);
			isScrolling = false;
		}
	}
	clearInterval(scrollIntervalID);
	distance = parseInt(distance, 10);
	scrollIntervalID = setInterval(easeScroll, 1000/FPS);
	isScrolling = true;
	target.data('scrollIntervalID',scrollIntervalID);
};

/**
 * Scrolls the target to the next snap point.
 * @param distance {Integer} Determines the direction in which the target
 * will be scrolled.
 */
function scrollToSnapPoint(target, distance, useIndex){
	var nextSnap = getNextSnap(target, distance, useIndex); //console.log('nextSnap: ' + nextSnap);
	var currentLookbook = target.parent('.lookbook');
	var options = target.data('user_options');
	var directionIndex = (options.direction === 'horizontal') ? 0 : 1;
	var currentOffset = (directionIndex === 1) ? target.scrollTop() : target.scrollLeft();
	var pixelsToSnap = nextSnap - currentOffset;
	var scrollIntervalID;
	var offset = Math.floor(pixelsToSnap*OFFSET_FACTOR);
	clearInterval(scrollIntervalID);
	distance = Math.round(distance);
	isScrolling = true; stopScrolling = false;
	(function scrollToSnap(){
		//console.log(pixelsToSnap);
		if(Math.abs(pixelsToSnap) < 2){
			//clearInterval(scrollIntervalID);
			if(directionIndex === 1){
				target.scrollTop(nextSnap);
			}
			else{
				target.scrollLeft(nextSnap); //console.log('currentOffset: ' + target.scrollLeft());
			}
			isScrolling = false;
			currentLookbook.swipeAndDrag('showOrHidePrevAndNext');
			currentLookbook.swipeAndDrag('selectCorrectCircle');
			//$("#lookbooks").data('currentLookbook').swipeAndDrag('showOrHidePrevAndNext');
			//$("#lookbooks").data('currentLookbook').swipeAndDrag('selectCorrectCircle');
		}
		else{
			if(Math.abs(pixelsToSnap) > SNAP_THRESHOLD && Math.abs(offset) > 2){
				offset = Math.floor(pixelsToSnap*OFFSET_FACTOR);
			}
			else{
				offset = (pixelsToSnap > 0) ? 1 : -1; 
			}
			if(directionIndex === 1){
				target.scrollTop(target.scrollTop() + offset);
			}
			else{
				target.scrollLeft(target.scrollLeft() + offset);
			}
			pixelsToSnap -= offset;
			if(!stopScrolling){
				currentTimeout = setTimeout(scrollToSnap,TIME_BETWEEN_SCROLLS);
			}
		}
	})();
	//scrollIntervalID = setInterval(scrollToSnap, 1000/FPS);
	//target.data('scrollIntervalID',scrollIntervalID);
};

/**
 * Returns the next snap point.
 * @param direction {integer} A positive value indicates to get the smallest snap
 * point bigger than the current offset. A negative value is the opposite.
 * @type Integer
 */
function getNextSnap(target, direction, useIndex){
	var options = target.data('user_options');
	var directionIndex = (options.direction === 'horizontal') ? 0 : 1;
	var i;
	var l = options.snapPoints.length; //console.log(options.snapPoints);
	var currentOffset = (directionIndex === 1) ? target.scrollTop() : target.scrollLeft();
	var maxOffset = target.width();

	if(useIndex !== undefined && useIndex === true){
		return options.snapPoints[direction];
	}
	if(direction === 0){
		return currentOffset;
	}
	if(direction > 0){
		if(options.snapPoints[0] > currentOffset){
			return 0;
		}
		for(i = 1; i < l; i++){
			if(options.snapPoints[i] >= currentOffset){
				return options.snapPoints[i-1];
			}
		}
	}
	else{
		if(options.snapPoints[l-1] < currentOffset){
			return maxOffset;
		}
		for(i = 0; i < l; i++){
			if(options.snapPoints[i] > currentOffset){
				return options.snapPoints[i];
			}
		}
		// in case all snap points are smaller than the current offset
		return maxOffset;
	}
	return false;
};

/**
 * Finishes a drag of the target by resetting event handlers and variables, and calls
 * the appropiate function to stop the movement.
 */
var endDrag = function(e){
	var target = (e.srcElement === undefined) ? e.target : e.srcElement;
	target = $(target).parents('.swipe-and-drag-container').first();
	var options = target.data('user_options');
	var directionIndex = (options.direction === 'horizontal') ? 0 : 1;
	var mouseCoordinates = target.data('mouseCoordinates');
	var eventIndex = target.data('eventIndex');
	var touches = target.data('touches');
	$(window).unbind('mousemove mouseup mouseleave');
	if(mouseCoordinates.length > 1){
		var totalDragDistance = mouseCoordinates[mouseCoordinates.length-1][directionIndex] - mouseCoordinates[mouseCoordinates.length-2][directionIndex];
		if(options.useSnapPoints){
			scrollToSnapPoint(target, totalDragDistance);
		}
		else{
			gentlyStopScroll(target, totalDragDistance);
		}
	}
	target.data('mouseCoordinates',[]);
	target.data('touches',[]);
	target.data('eventIndex',1);
};

/**
 * Handles a drag of the target by scrolling the target on mouse move, and sets the
 * event listeners for when the mouse button is released.
 */
function startDrag(target, originalPosition){
	clearInterval(target.data('scrollIntervalID'));
	stopScrolling = true; clearTimeout(currentTimeout);
	var options = target.data('user_options');
	var directionIndex = (options.direction === 'horizontal') ? 0 : 1;
	var mouseCoordinates = target.data('mouseCoordinates');
	var eventIndex = target.data('eventIndex');
	$(window).bind('mouseup mouseleave', endDrag);
	//target.bind('mouseup mouseleave', endDrag);
	target.stop();
	$(window).bind('mousemove', function(e) { 
		mouseCoordinates.push([e.screenX, e.screenY]); // save coordinates of latest touch
		if(mouseCoordinates.length > 1){
			var drag_distance = mouseCoordinates[eventIndex-1][directionIndex] - mouseCoordinates[eventIndex][directionIndex];
			target.data('eventIndex',eventIndex+1);
			if(directionIndex){
				target.scrollTop(target.scrollTop() + drag_distance);
			}
			else{
				target.scrollLeft(target.scrollLeft() + drag_distance);
			}
		}
	});
};
			
var methods = {
	init: function(user_options){
		return this.each(function(){
			// create default options
			var options = {
				direction: 'vertical',
				snapPoints: [],
				useSnapPoints: false,
				enableKeyboardArrows: true,
				nextButton: false,
				previousButton: false,
				navButtons: false
			};

			// add user defined options
			jQuery.extend(options, user_options);// console.log(options);
			
			// whether to create default snap points, by the width or height of the child elements.
			var createSnapPoints = (options.useSnapPoints && !options.snapPoints.length) ? true : false;
			var left = 0;
			var top = 0;
			var width = 0;
			var numberOfChildren = 0;
			var widthOfFirstChildren = 0;
			// set css for the selected direction
			switch(options.direction){
			case 'horizontal':
				$(this).children().each(function(){
					numberOfChildren++;
					if(numberOfChildren === 1){
						widthOfFirstChildren = $(this).width();
					}
					$(this).css({position:'absolute', left:left+'px'});//'float','left');
					left += LOOKBOOK_WIDTH;//$(this).width();
					if(createSnapPoints){
						options.snapPoints.push(left);
					}
				});
				$(this).css({
					width:(numberOfChildren * LOOKBOOK_WIDTH).toString() + 'px',
					height:LOOKBOOK_HEIGHT+'px'
				});
				$(this).parent('.lookbook').css({
					width:LOOKBOOK_WIDTH+'px'
				});
				break;
			case 'vertical':
				$(this).css('overflow-y','hidden');
				$(this).children().each(function(){
					top += $(this).height();
					if(createSnapPoints){
						options.snapPoints.push(top);
					}
				});
				break;
			}
			$(this).css({
				overflow:'hidden',
				position:'relative'
			});

			options.snapPoints.unshift(0);
			options.snapPoints.pop();
			filterArray(options.snapPoints, 'int');
			//options.snapPoints = removeDuplicates(options.snapPoints);
			options.snapPoints.sort(function(a,b){ return a-b; });
		
			/* Wrap div around <ul> */
			$(this).wrap('<div class="swipe-and-drag-container" />');
			var directionIndex = (options.direction === 'horizontal') ? 0 : 1;
			var touches = [];
			var mouseCoordinates = [];
			var eventIndex = 1;
			var target = $(this).parent();
			target.data('user_options',options);
			target.data('scrollIntervalID',0);
			target.data('mouseCoordinates',[]);
			target.data('eventIndex',1);
			target.data('touches',[]);
		
			$(this).bind('touchstart', function(e){
				stopScrolling = true; clearTimeout(currentTimeout);
			});

			$(this).bind('touchmove', function(e){
				e.originalEvent.preventDefault();
				target.stop(); // stop any ongoing scroll animation
				var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
				touches.push([touch.screenX, touch.screenY]); // save coordinates of latest touch
				if(touches.length > 1){
					var touchDistance = touches[eventIndex-1][directionIndex] - touches[eventIndex][directionIndex];
					eventIndex++;
					
					if(directionIndex){
						target.scrollTop(target.scrollTop() + touchDistance);
					}
					else{
						target.scrollLeft(target.scrollLeft() + touchDistance);
					}
				}
			});
			
			target.bind('touchend',function(){
				var touchDistance = touches[touches.length - 1][directionIndex] - touches[touches.length - 2][directionIndex];
				touches = [];
				eventIndex = 1;
				if(options.useSnapPoints){
					scrollToSnapPoint(target, touchDistance);
				}
				else{
					gentlyStopScroll(target, touchDistance/3);
				}
			});
			
			/* Prevent the browsers default action on a left click, which is usually
			   to select text, drag images, etc.
			*/
			target.bind('mousedown', function(e){
				if(e.button === 0){
					e.preventDefault();
				}
				startDrag(target, [e.screenX, e.screenY]);
			});

		});
	}, // end init
	
	scrollForward: function(){
		return this.each(function(){
			var target = $(this).children('.swipe-and-drag-container').first();
			var options = target.data('user_options');
			if(options.useSnapPoints){
				scrollToSnapPoint(target, -1);
			}
			else{
				gentlyStopScroll(target, -DEFAULT_SCROLL);
			}
			$(this).swipeAndDrag('selectCorrectCircle');
			//$("#lookbooks").data('currentLookbook').swipeAndDrag('selectCorrectCircle');
		});
	},

	scrollBackwards: function(){
		return this.each(function(){
			var target = $(this).children('.swipe-and-drag-container').first();
			var options = target.data('user_options');
			if(options.useSnapPoints){
				scrollToSnapPoint(target, 1);
			}
			else{
				gentlyStopScroll(target, KEYPRESS_SCROLL);
			}
			$(this).swipeAndDrag('selectCorrectCircle');
			//$("#lookbooks").data('currentLookbook').swipeAndDrag('selectCorrectCircle');
		});
	},

	scrollToIndex: function(index){
		return this.each(function(){
			var target = $(this).children('.swipe-and-drag-container').first();
			var options = target.data('user_options');
			if(options.useSnapPoints){
				scrollToSnapPoint(target, index, true);
			}
			$(this).swipeAndDrag('selectCorrectCircle');
			//$("#lookbooks").data('currentLookbook').swipeAndDrag('selectCorrectCircle');
		});
	},

	selectCorrectCircle: function(){
		return this.each(function(){
			var target = $(this).children('.swipe-and-drag-container').first();
			var options = target.data('user_options');
			var index;
			if(options.useSnapPoints){
				$(".lookbook-circles > a").each(function(){
					index = parseInt($(this).attr('class').charAt($(this).attr('class').length-1),10);
					if(target.scrollLeft() === options.snapPoints[index]){
						$(this).addClass('selected-round-button');
						$(this).siblings().removeClass('selected-round-button');
					}
				});
			}
		});
	},

	showOrHidePrevAndNext: function(){
		return this.each(function(){
			var target = $(this).children('.swipe-and-drag-container').first();
			var options = target.data('user_options');
			var directionIndex = (options.direction === 'horizontal') ? 0 : 1;
			var currentOffset = (directionIndex === 1) ? target.scrollTop() : target.scrollLeft();
			var l = options.snapPoints.length;
			if(currentOffset === options.snapPoints[l-1]){
				$("#"+options.nextButton).fadeOut('slow');
			}
			else if(currentOffset < options.snapPoints[l-1] && $("#"+options.nextButton).css('display') === 'none'){
				$("#"+options.nextButton).fadeIn('slow');
			}
			if(currentOffset === 0){
				$("#"+options.previousButton).fadeOut('slow');
			}
			else if(currentOffset > 0 && $("#"+options.previousButton).css('display') === 'none'){
				$("#"+options.previousButton).fadeIn('slow');
			}
		});
	}

} // end methods


$.fn.swipeAndDrag = function(method){
	if(methods[method]){
		return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
	}
	else if( typeof method === 'object' || ! method ){
		return methods.init.apply( this, arguments );
	}
	else{
		$.error( 'Method ' +  method + ' does not exist on swipeAndDrag' );
	}    
}	

})(jQuery); // end swipe

		/*
		if(options.nextButton){
			$('#'+options.nextButton).click(function(){
			});
		}

		if(options.previousButton){
			$('#'+options.previousButton).click(function(){
			});
		}

		if(options.navButtons){
			$(options.navButtons + ' > a').live('click',function(){
				var index = parseInt($(this).attr('class').charAt($(this).attr('class').length-1),10);
				console.log(index);
				scrollToSnapPoint(options.snapPoints[index]);
				return false;
			});
		}
		*/
		/**
		 * Enable scrolling by the keyboard arrows if options.enableKeyboardArrows
		 * is set to true, and if the event is not fired by an input element.
		 */ /*
		if(options.enableKeyboardArrows){
			$(window).bind('keydown', function(e){
				if(!$(e.target).is(':input')){
					if(directionIndex){
						switch(e.which){
							case KEYBOARD_UP:
								if(options.useSnapPoints){
									scrollToSnapPoint(1);
								}
								else{
									gentlyStopScroll(KEYPRESS_SCROLL);
								}
								break;
							case KEYBOARD_DOWN:
								if(options.useSnapPoints){
									scrollToSnapPoint(-1);
								}
								else{
									gentlyStopScroll(-KEYPRESS_SCROLL);
								}
								break;
						}
					}
					else{
						switch(e.which){
							case KEYBOARD_LEFT:
								if(options.useSnapPoints){
									scrollToSnapPoint(1);
								}
								else{
									gentlyStopScroll(KEYPRESS_SCROLL);
								}
								break;
							case KEYBOARD_RIGHT:
								if(options.useSnapPoints){
									scrollToSnapPoint(-1);
								}
								else{
									gentlyStopScroll(-KEYPRESS_SCROLL);
								}
								break;
						}
					}
				}
			});
		} */

