/*
 * multiscroll.js 0.1.7 Beta
 * https://github.com/alvarotrigo/multiscroll.js
 * MIT licensed
 * Copyright (C) 2013 alvarotrigo.com - A project by Alvaro Trigo
 */

"use strict";
(function($, window, document, Math, undefined) {

	$.fn.multiscroll = function(options) {
		var MS = $.fn.multiscroll;

		// Create some defaults, extending them with any options that were provided
		options = $.extend({
			'verticalCentered' : true,
			'scrollingSpeed': 700,
			'easing': 'easeInQuart',
			'menu': false,
			'sectionsColor': [],
			'anchors':[],
			'navigation': false,
			'navigationPosition': 'right',
			'navigationColor': '#000',
			'navigationTooltips': [],
			'loopBottom': false,
			'loopTop': false,
			'css3': false,
			'paddingTop': 0,
			'paddingBottom': 0,
			'fixedElements': null,
			'normalScrollElements': null,
			'keyboardScrolling': true,
			'touchSensitivity': 5,

			// Custom selectors
			'sectionSelector': '.ms-section',
			'leftSelector': '.ms-left',
			'rightSelector': '.ms-right',

			//events
			'afterLoad': null,
			'onLeave': null,
			'afterRender': null,
			'afterResize': null
		}, options);

		//Defines the delay to take place before being able to scroll to the next section
		//BE CAREFUL! Not recommened to change it under 400 for a good behavior in laptops and
		//Apple devices (laptops, mouses...)
		var scrollDelay = 600;

		var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints));

		// adding class namef for right and left blocks
		if (options.rightSelector !== '.ms-right') {
			$(options.rightSelector).addClass('ms-right');
		}

		if (options.leftSelector !== '.ms-left') {
			$(options.leftSelector).addClass('ms-left');
		}

		var numberSections = $('.ms-left').find('.ms-section').length;
		var isMoving = false;
		var nav;
		var windowHeight = $(window).height();


		addMouseWheelHandler();
		addTouchHandler();

		//if css3 is not supported, it will use jQuery animations
		if(options.css3){
			options.css3 = support3d();
		}

		$('html, body').css({
			'overflow' : 'hidden',
			'height' : '100%'
		});

		//adding class names to each sections
		if (options.sectionSelector !== '.ms-section') {
			$(options.sectionSelector).each(function(){
				$(this).addClass('ms-section');
			});
		}

		//creating the navigation dots
		if (options.navigation) {
			$('body').append('<div id="multiscroll-nav"><ul></ul></div>');
			nav = $('#multiscroll-nav');

			nav.css('color', options.navigationColor);
			nav.addClass(options.navigationPosition);
		}

		$('.ms-right, .ms-left').css({
			'width': '50%',
			'position': 'absolute',
			'height': '100%',
			'-ms-touch-action': 'none'
		});

		$('.ms-right').css({
			'right': '1px', //http://stackoverflow.com/questions/23675457/chrome-and-opera-creating-small-padding-when-using-displaytable
			'top': '0',
			'-ms-touch-action': 'none',
			'touch-action': 'none'
		});

		$('.ms-left').css({
			'left': '0',
			'top': '0',
			'-ms-touch-action': 'none',
			'touch-action': 'none'
		});


		$('.ms-left .ms-section, .ms-right .ms-section').each(function(){
			var sectionIndex = $(this).index();

			if(options.paddingTop || options.paddingBottom){
				$(this).css('padding', options.paddingTop  + ' 0 ' + options.paddingBottom + ' 0');
			}

			if (typeof options.sectionsColor[sectionIndex] !==  'undefined') {
				$(this).css('background-color', options.sectionsColor[sectionIndex]);
			}

			if (typeof options.anchors[sectionIndex] !== 'undefined') {
				$(this).attr('data-anchor', options.anchors[sectionIndex]);
			}

			if(options.verticalCentered){
				addTableClass($(this));
			}

			//only for the left panel
			if($(this).closest('.ms-left').length && options.navigation) {
				var link = '';
				if(options.anchors.length){
					link = options.anchors[sectionIndex];
				}
				var tooltip = options.navigationTooltips[sectionIndex];
				if(typeof tooltip === 'undefined'){
					tooltip = '';
				}
				if (options.navigation) {
					nav.find('ul').append('<li data-tooltip="' + tooltip + '"><a href="#' + link + '"><span></span></a></li>');
				}
			}
		});

		//inverting the right panel
		$('.ms-right').html( $('.ms-right').find('.ms-section').get().reverse());

		$('.ms-left .ms-section, .ms-right .ms-section').each(function(){
			var sectionIndex = $(this).index();

			$(this).css({
				'height': '100%'
			});


			if(!sectionIndex && options.navigation ){
				//activating the navigation bullet
				nav.find('li').eq(sectionIndex).find('a').addClass('active');
			}
		}).promise().done(function(){

			//if no active section is defined, the 1st one will be the default one
			if(!$('.ms-left .ms-section.active').length){
				$('.ms-right').find('.ms-section').last().addClass('active');
				$('.ms-left').find('.ms-section').first().addClass('active');
			}

			//vertical centered of the navigation + first bullet active
			if(options.navigation){
				nav.css('margin-top', '-' + (nav.height()/2) + 'px');
			}
			$.isFunction( options.afterRender ) && options.afterRender.call( this);

			//scrolling to the defined active section and adjusting right and left panels
			silentScroll();

			//setting the class for the body element
			setBodyClass();

			$(window).on('load', function() {
				scrollToAnchor();
			});
		});


		//detecting any change on the URL to scroll to the given anchor link
		//(a way to detect back history button as we play with the hashes on the URL)
		$(window).on('hashchange', hashChangeHandler);

		function hashChangeHandler(){
			var value =  window.location.hash.replace('#', '');
			var sectionAnchor = value;

			if(sectionAnchor.length){
				var section = $('.ms-left').find('[data-anchor="'+sectionAnchor+'"]');

				var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' );

				if (isFirstScrollMove || sectionAnchor !== lastScrolledDestiny){
					scrollPage(section);
				}
			}
		};


		/**
		* Sliding with arrow keys, both, vertical and horizontal
		*/
		$(document).keydown(keydownHandler);


		var keydownId;
		function keydownHandler(e) {
			clearTimeout(keydownId);

			var activeElement = $(document.activeElement);

			if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') &&
				options.keyboardScrolling){
				var keyCode = e.which;

				//preventing the scroll with arrow keys & spacebar & Page Up & Down keys
				var keyControls = [40, 38, 32, 33, 34];
				if($.inArray(keyCode, keyControls) > -1){
					e.preventDefault();
				}

				keydownId = setTimeout(function(){
					onkeydown(e);
				},150);
			}
		}

		/**
		 * Sliding with arrow keys, both, vertical and horizontal
		 */
		function onkeydown(e){
			var shiftPressed = e.shiftKey;

			switch (e.which) {
				//up
				case 38:
				case 33:
					MS.moveSectionUp();
					break;

				//down
				case 32: //spacebar
					if(shiftPressed){
						MS.moveSectionUp();
						break;
					}
				case 40:
				case 34:
					MS.moveSectionDown();
					break;

				//Home
				case 36:
					MS.moveTo(1);
					break;

				//End
				case 35:
					MS.moveTo( $('.ms-left .ms-section').length);
					break;

				default:
					return; // exit this handler for other keys
			}
		}

		/**
		 * Disabling any action when pressing of the mouse wheel (Chrome, IE, Opera, Safari)
		 */
		$(document).mousedown(function(e) {
			if(e.button == 1){
				e.preventDefault();
				return false;
			}
		});

		//navigation action
		$(document).on('click', '#multiscroll-nav a', function(e){
			e.preventDefault();
			var index = $(this).parent().index();
			scrollPage($('.ms-left .ms-section').eq(index));
		});

		//navigation tooltips
		$(document).on({
			mouseenter: function(){
				var tooltip = $(this).data('tooltip');
				$('<div class="multiscroll-tooltip ' + options.navigationPosition +'">' + tooltip + '</div>').hide().appendTo($(this)).fadeIn(200);
			},
			mouseleave: function(){
				$(this).find('.multiscroll-tooltip').fadeOut(200, function() {
					$(this).remove();
				});
			}
		}, '#multiscroll-nav li');


		if(options.normalScrollElements){
			$(document).on('mouseenter', options.normalScrollElements, function () {
				MS.setMouseWheelScrolling(false);
			});

			$(document).on('mouseleave', options.normalScrollElements, function(){
				MS.setMouseWheelScrolling(true);
			});
		}


		//when resizing the site, we adjust the heights of the sections
		$(window).on('resize', doneResizing);

		/**
		 * When resizing is finished, we adjust the slides sizes and positions
		 */
		function doneResizing() {
			windowHeight = $(window).height();
			$('.ms-tableCell').each(function() {
				$(this).css({ height: getTableHeight($(this).parent()) });
			});
			silentScroll();
			$.isFunction( options.afterResize ) && options.afterResize.call( this);
		}

		function silentScroll(){
			//moving the right section to the bottom
			if(options.css3){
				transformContainer($('.ms-left'), 'translate3d(0px, -' + $('.ms-left').find('.ms-section.active').position().top + 'px, 0px)', false);
				transformContainer($('.ms-right'), 'translate3d(0px, -' + $('.ms-right').find('.ms-section.active').position().top + 'px, 0px)', false);
			}else{
				$('.ms-left').css('top', -$('.ms-left').find('.ms-section.active').position().top );
				$('.ms-right').css('top', -$('.ms-right').find('.ms-section.active').position().top );
			}
		}

		MS.moveSectionUp = function(){
			var prev = $('.ms-left .ms-section.active').prev('.ms-section');

			if(!prev.length && options.loopTop){
				prev = $('.ms-left .ms-section').last();
			}

			if (prev.length) {
				scrollPage(prev);
			}
		};

		MS.moveSectionDown = function (){
			var next = $('.ms-left .ms-section.active').next('.ms-section');

			if(!next.length && options.loopBottom ){
				next = $('.ms-left .ms-section').first();
			}

			if(next.length){
				scrollPage(next);
			}
		};

		MS.moveTo = function (section){
			var destiny = '';

			if(isNaN(section)){
				destiny = $('.ms-left [data-anchor="'+section+'"]');
			}else{
				destiny = $('.ms-left .ms-section').eq( (section -1) );
			}

			scrollPage(destiny);
		};

		function scrollPage(leftDestination){
			var leftDestinationIndex = leftDestination.index();
			var rightDestination = $('.ms-right').find('.ms-section').eq( numberSections -1 - leftDestinationIndex);
			var rightDestinationIndex = numberSections - 1 - leftDestinationIndex;
			var anchorLink  = leftDestination.data('anchor');
			var activeSection = $('.ms-left .ms-section.active');
			var leavingSection = activeSection.index() + 1;
			var yMovement = getYmovement(leftDestination);

			//preventing from activating the MouseWheelHandler event
			//more than once if the page is scrolling
			isMoving = true;

			var topPos = {
				'left' : leftDestination.position().top,
				'right': rightDestination.position().top
			};

			rightDestination.addClass('active').siblings().removeClass('active');
			leftDestination.addClass('active').siblings().removeClass('active');

			setURLHash(anchorLink);

			// Use CSS3 translate functionality or...
			if (options.css3){
				//callback (onLeave)
				$.isFunction(options.onLeave) && options.onLeave.call(this, leavingSection, (leftDestinationIndex + 1), yMovement);

				var translate3dLeft = 'translate3d(0px, -' + topPos['left'] + 'px, 0px)';
				var translate3dRight = 'translate3d(0px, -' + topPos['right'] + 'px, 0px)';

				transformContainer($('.ms-left'), translate3dLeft, true);
				transformContainer($('.ms-right'), translate3dRight, true);

				setTimeout(function () {
					//callback (afterLoad)
					$.isFunction(options.afterLoad) && options.afterLoad.call(this, anchorLink, (leftDestinationIndex + 1));

					setTimeout(function () {
						isMoving = false;
					}, scrollDelay);
				}, options.scrollingSpeed);
			}else{
				//callback (onLeave)
				$.isFunction(options.onLeave) && options.onLeave.call(this, leavingSection, (leftDestinationIndex + 1), yMovement);

				$('.ms-left').animate({
					'top': -topPos['left']
				}, options.scrollingSpeed, options.easing, function(){
					$.isFunction(options.afterLoad) && options.afterLoad.call(this, anchorLink, (leftDestinationIndex + 1));

					setTimeout(function () {
						isMoving = false;
					}, scrollDelay);
				});

				$('.ms-right').animate({
					'top': -topPos['right']
				}, options.scrollingSpeed, options.easing);
			}

			//flag to avoid callingn `scrollPage()` twice in case of using anchor links
			lastScrolledDestiny = anchorLink;

			activateMenuElement(anchorLink);
			activateNavDots(anchorLink, leftDestinationIndex);
		}

		/**
		* Removes the auto scrolling action fired by the mouse wheel and tackpad.
		* After this function is called, the mousewheel and trackpad movements won't scroll through sections.
		*/
		function removeMouseWheelHandler(){
			if (document.addEventListener) {
				document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper
				document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox
			} else {
				document.detachEvent("onmousewheel", MouseWheelHandler); //IE 6/7/8
			}
		}

		/**
		* Adds the auto scrolling action for the mouse wheel and tackpad.
		* After this function is called, the mousewheel and trackpad movements will scroll through sections
		*/
		function addMouseWheelHandler(){
			if (document.addEventListener) {
				document.addEventListener("mousewheel", MouseWheelHandler, false); //IE9, Chrome, Safari, Oper
				document.addEventListener("wheel", MouseWheelHandler, false); //Firefox
			} else {
				document.attachEvent("onmousewheel", MouseWheelHandler); //IE 6/7/8
			}
		}

		/**
		 * Detecting mousewheel scrolling
		 *
		 * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html
		 * http://www.sitepoint.com/html5-javascript-mouse-wheel/
		 */
		function MouseWheelHandler(e) {
			// cross-browser wheel delta
			e = window.event || e;
			var delta = Math.max(-1, Math.min(1,
					(e.wheelDelta || -e.deltaY || -e.detail)));

			if (!isMoving) { //if theres any #

				//scrolling down?
				if (delta < 0) {
					MS.moveSectionDown();
				}

				//scrolling up?
				else {
					MS.moveSectionUp();
				}
			}


			return false;
		}

		/**
		* Adds a css3 transform property to the container class with or without animation depending on the animated param.
		*/
		function transformContainer(container, translate3d, animated){
			container.toggleClass('ms-easing', animated);

			container.css(getTransforms(translate3d));
		}


		/**
		* Returns the transform styles for all browsers
		*/
		function getTransforms(translate3d){
			return {
				'-webkit-transform': translate3d,
				'-moz-transform': translate3d,
				'-ms-transform':translate3d,
				'transform': translate3d
			};
		}

		/**
		 * Activating the website navigation dots according to the given slide name.
		 */
		function activateNavDots(name, sectionIndex){
			if(options.navigation){
				$('#multiscroll-nav').find('.active').removeClass('active');
				if(name){
					$('#multiscroll-nav').find('a[href="#' + name + '"]').addClass('active');
				}else{
					$('#multiscroll-nav').find('li').eq(sectionIndex).find('a').addClass('active');
				}
			}
		}

		/**
		 * Activating the website main menu elements according to the given slide name.
		 */
		function activateMenuElement(name){
			if(options.menu){
				$(options.menu).find('.active').removeClass('active');
				$(options.menu).find('[data-menuanchor="'+name+'"]').addClass('active');
			}
		}

		/**
		* Retuns `up` or `down` depending on the scrolling movement to reach its destination
		* from the current section.
		*/
		function getYmovement(destiny){
			var fromIndex = $('.ms-left .ms-section.active').index();
			var toIndex = destiny.index();

			if(fromIndex > toIndex){
				return 'up';
			}
			return 'down';
		}


		/**
		* Sets the URL hash for a section with slides
		*/
		function setURLHash(anchorLink){
			if(options.anchors.length){
				location.hash = anchorLink;
			}

			setBodyClass();
		}

		 /**
		* Sets a class for the body of the page depending on the active section / slide
		*/
		function setBodyClass(){
			var section = $('.ms-left .ms-section.active');
			var sectionAnchor = section.data('anchor');
			var sectionIndex = section.index();

			var text = String(sectionIndex);

			if(options.anchors.length){
				text = sectionAnchor;
			}

			//changing slash for dash to make it a valid CSS style
			text = text.replace('/', '-').replace('#','');

			//removing previous anchor classes
			var classRe = new RegExp('\\b\\s?' + 'ms-viewing' + '-[^\\s]+\\b', "g");
			$('body')[0].className = $('body')[0].className.replace(classRe, '');

			//adding the current anchor
			$('body').addClass('ms-viewing-' + text);
		}


		/**
		* Checks for translate3d support
		* @return boolean
		* http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support
		*/
		function support3d() {
			var el = document.createElement('p'),
				has3d,
				transforms = {
					'webkitTransform':'-webkit-transform',
					'OTransform':'-o-transform',
					'msTransform':'-ms-transform',
					'MozTransform':'-moz-transform',
					'transform':'transform'
				};

			// Add it to the body to get the computed style.
			document.body.insertBefore(el, null);

			for (var t in transforms) {
				if (el.style[t] !== undefined) {
					el.style[t] = "translate3d(1px,1px,1px)";
					has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
				}
			}

			document.body.removeChild(el);

			return (has3d !== undefined && has3d.length > 0 && has3d !== "none");
		}

		/**
		* Wraps an element in order to center it vertically by using a class style.
		*/
		function addTableClass(element){
			element.addClass('ms-table').wrapInner('<div class="ms-tableCell" style="height: ' + getTableHeight(element) + 'px" />');
		}

		/**
		* Gets the height of the section after removing the paddings.
		*/
		function getTableHeight(section){
			var sectionHeight = windowHeight;

			if(options.paddingTop || options.paddingBottom){
			    var paddings = parseInt(section.css('padding-top'), 10) + parseInt(section.css('padding-bottom'), 10);
				sectionHeight = (windowHeight - paddings);
			}

			return sectionHeight;
		}


		/**
		* Scrolls the page to the existent anchor in the URL
		*/
		function scrollToAnchor(){
			//getting the anchor link in the URL and deleting the `#`
			var sectionAnchor =  window.location.hash.replace('#', '');
			var section = $('.ms-left .ms-section[data-anchor="'+sectionAnchor+'"]');

			if(sectionAnchor.length){  //if theres any #
				scrollPage(section);
			}
		}

		/**
		* Adds or remove the possiblity of scrolling through sections by using the keyboard arrow keys
		*/
		MS.setKeyboardScrolling = function (value){
			options.keyboardScrolling = value;
		};

		/**
		* Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad.
		*/
		MS.setMouseWheelScrolling = function (value){
			if(value){
				addMouseWheelHandler();
			}else{
				removeMouseWheelHandler();
			}
		};

		/**
		* Defines the scrolling speed
		*/
		MS.setScrollingSpeed = function(value){
			options.scrollingSpeed = value;
		};



		var touchStartY = 0;
		var touchStartX = 0;
		var touchEndY = 0;
		var touchEndX = 0;

		/* Detecting touch events

		* As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it.
		* This way, the touchstart and the touch moves shows an small difference between them which is the
		* used one to determine the direction.
		*/
		function touchMoveHandler(event){
			var e = event.originalEvent;

			if(isReallyTouch(e)){
				//preventing the easing on iOS devices
				event.preventDefault();

				var activeSection = $('.ms-left .ms-section.active');

				if (!isMoving) { //if theres any #
					var touchEvents = getEventsPage(e);
					touchEndY = touchEvents['y'];
					touchEndX = touchEvents['x'];


					//is the movement greater than the minimum resistance to scroll?
					if (Math.abs(touchStartY - touchEndY) > ($(window).height() / 100 * options.touchSensitivity)) {

						if (touchStartY > touchEndY) {
							MS.moveSectionDown();

						} else if (touchEndY > touchStartY) {
							MS.moveSectionUp();
						}
					}
				}
			}
		}

		/**
		* As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen
		* this way we make sure that is really a touch event what IE is detecting.
		*/
		function isReallyTouch(e){
			//if is not IE   ||  IE is detecting `touch` or `pen`
			return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse';
		}


		/**
		* Handler to get he coordinates of the starting touch
		*/
		function touchStartHandler(event){
			var e = event.originalEvent;

			if(isReallyTouch(e)){
				var touchEvents = getEventsPage(e);
				touchStartY = touchEvents['y'];
				touchStartX = touchEvents['x'];
			}
		}


		/**
		* Adds the possibility to auto scroll through sections on touch devices.
		*/
		function addTouchHandler(){
			if(isTouch){
				//Microsoft pointers
				MSPointer = getMSPointer();

				$(document).off('touchstart ' +  MSPointer.down).on('touchstart ' + MSPointer.down, touchStartHandler);
				$(document).off('touchmove ' + MSPointer.move).on('touchmove ' + MSPointer.move, touchMoveHandler);
			}
		}

		/**
		* Removes the auto scrolling for touch devices.
		*/
		function removeTouchHandler(){
			if(isTouch){
				//Microsoft pointers
				MSPointer = getMSPointer();

				$(document).off('touchstart ' + MSPointer.down);
				$(document).off('touchmove ' + MSPointer.move);
			}
		}

		/*
		* Returns and object with Microsoft pointers (for IE<11 and for IE >= 11)
		* http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx
		*/
		function getMSPointer(){
			var pointer;

			//IE >= 11
			if(window.PointerEvent){
				pointer = { down: "pointerdown", move: "pointermove"};
			}

			//IE < 11
			else{
				pointer = { down: "MSPointerDown", move: "MSPointerMove"};
			}

			return pointer;
		}

		/**
		* Gets the pageX and pageY properties depending on the browser.
		* https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854
		*/
		function getEventsPage(e){
			var events = [];

			events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY);
			events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX);

			//in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008
			if(isTouch && isReallyTouch(e)){
				events.y = e.touches[0].pageY;
				events.x = e.touches[0].pageX;
			}

			return events;
		}

		/**
		* Destroy multiscroll.js plugin's events
		*/
		MS.destroy = function() {
			MS.setKeyboardScrolling(false);
			MS.setMouseWheelScrolling(false);

			$(window)
				.off('hashchange', hashChangeHandler)
				.off('resize', doneResizing);

			$(document)
				.off('mouseenter', '#multiscroll-nav li')
				.off('mouseleave', '#multiscroll-nav li')
				.off('click', '#multiscroll-nav a');
		};

		/**
		* Build multiscroll.js plugin's events after destroy
		*/
		MS.build = function() {
			MS.setKeyboardScrolling(true);
			MS.setMouseWheelScrolling(true);

			$(window)
				.on('hashchange', hashChangeHandler)
				.on('resize', doneResizing);

			$(document)
				.on('mouseenter', '#multiscroll-nav li')
				.on('mouseleave', '#multiscroll-nav li')
				.on('click', '#multiscroll-nav a');
		};

	};
})(jQuery, window, document, Math);
