// ==========================================================================
//
// Guestures
// Adds touch guestures, handles click and tap events
//
// ==========================================================================
(function(window, document, $) {
	'use strict';

	var requestAFrame = (function() {
		return (
			window.requestAnimationFrame ||
			window.webkitRequestAnimationFrame ||
			window.mozRequestAnimationFrame ||
			window.oRequestAnimationFrame ||
			// if all else fails, use setTimeout
			function(callback) {
				return window.setTimeout(callback, 1000 / 60);
			}
		);
	})();

	var cancelAFrame = (function() {
		return (
			window.cancelAnimationFrame ||
			window.webkitCancelAnimationFrame ||
			window.mozCancelAnimationFrame ||
			window.oCancelAnimationFrame ||
			function(id) {
				window.clearTimeout(id);
			}
		);
	})();

	var pointers = function(e) {
		var result = [];

		e = e.originalEvent || e || window.e;
		e =
			e.touches && e.touches.length
				? e.touches
				: e.changedTouches && e.changedTouches.length
				? e.changedTouches
				: [e];

		for (var key in e) {
			if (e[key].pageX) {
				result.push({ x: e[key].pageX, y: e[key].pageY });
			} else if (e[key].clientX) {
				result.push({ x: e[key].clientX, y: e[key].clientY });
			}
		}

		return result;
	};

	var distance = function(point2, point1, what) {
		if (!point1 || !point2) {
			return 0;
		}

		if (what === 'x') {
			return point2.x - point1.x;
		} else if (what === 'y') {
			return point2.y - point1.y;
		}

		return Math.sqrt(
			Math.pow(point2.x - point1.x, 2) +
				Math.pow(point2.y - point1.y, 2),
		);
	};

	var isClickable = function($el) {
		if (
			$el.is(
				'a,area,button,[role="button"],input,label,select,summary,textarea',
			) ||
			$.isFunction($el.get(0).onclick) ||
			$el.data('selectable')
		) {
			return true;
		}

		// Check for attributes like data-envirabox-next or data-envirabox-close
		for (
			var i = 0, atts = $el[0].attributes, n = atts.length;
			i < n;
			i++
		) {
			if (atts[i].nodeName.substr(0, 14) === 'data-envirabox-') {
				return true;
			}
		}

		return false;
	};

	var hasScrollbars = function(el) {
		var overflowY = window.getComputedStyle(el)['overflow-y'];
		var overflowX = window.getComputedStyle(el)['overflow-x'];

		var vertical =
			(overflowY === 'scroll' || overflowY === 'auto') &&
			el.scrollHeight > el.clientHeight;
		var horizontal =
			(overflowX === 'scroll' || overflowX === 'auto') &&
			el.scrollWidth > el.clientWidth;

		return vertical || horizontal;
	};

	var isScrollable = function($el) {
		var rez = false;

		while (true) {
			rez = hasScrollbars($el.get(0));

			if (rez) {
				break;
			}

			$el = $el.parent();

			if (
				!$el.length ||
				$el.hasClass('envirabox-stage') ||
				$el.is('body')
			) {
				break;
			}
		}

		return rez;
	};

	var Guestures = function(instance) {
		var self = this;

		self.instance = instance;

		self.$bg = instance.$refs.bg;
		self.$stage = instance.$refs.stage;
		self.$container = instance.$refs.container;

		self.destroy();

		self.$container.on(
			'touchstart.eb.touch mousedown.eb.touch',
			$.proxy(self, 'ontouchstart'),
		);
	};

	Guestures.prototype.destroy = function() {
		this.$container.off('.eb.touch');
	};

	Guestures.prototype.ontouchstart = function(e) {
		var self = this;

		var $target = $(e.target);
		var instance = self.instance;
		var current = instance.current;
		var $content = current.$content;

		var isTouchDevice = e.type == 'touchstart';

		// Do not respond to both events
		if (isTouchDevice) {
			self.$container.off('mousedown.eb.touch');
		}

		// Ignore clicks while zooming or closing
		if (
			!current ||
			self.instance.isAnimating ||
			self.instance.isClosing
		) {
			e.stopPropagation();
			e.preventDefault();

			return;
		}

		// Ignore right click
		if (e.originalEvent && e.originalEvent.button == 2) {
			return;
		}

		// Ignore taping on links, buttons, input elements
		if (
			!$target.length ||
			isClickable($target) ||
			isClickable($target.parent())
		) {
			return;
		}

		// Ignore clicks on the scrollbar
		if (
			e.originalEvent.clientX >
			$target[0].clientWidth + $target.offset().left
		) {
			return;
		}

		self.startPoints = pointers(e);

		// Prevent zooming if already swiping
		if (
			!self.startPoints ||
			(self.startPoints.length > 1 && instance.isSliding)
		) {
			return;
		}

		self.$target = $target;
		self.$content = $content;
		self.canTap = true;
		self.opts = current.opts.touch;

		$(document).off('.eb.touch');

		$(document).on(
			isTouchDevice
				? 'touchend.eb.touch touchcancel.eb.touch'
				: 'mouseup.eb.touch mouseleave.eb.touch',
			$.proxy(self, 'ontouchend'),
		);
		$(document).on(
			isTouchDevice ? 'touchmove.eb.touch' : 'mousemove.eb.touch',
			$.proxy(self, 'ontouchmove'),
		);

		if (
			!(self.opts || instance.canPan()) ||
			!($target.is(self.$stage) || self.$stage.find($target).length)
		) {
			// Prevent ghosting
			if ($target.is('img')) {
				e.preventDefault();
			}

			return;
		}

		e.stopPropagation();

		if (
			!(
				$.envirabox.isMobile &&
				(isScrollable(self.$target) ||
					isScrollable(self.$target.parent()))
			)
		) {
			e.preventDefault();
		}

		self.canvasWidth = Math.round(current.$slide[0].clientWidth);
		self.canvasHeight = Math.round(current.$slide[0].clientHeight);

		self.startTime = new Date().getTime();
		self.distanceX = self.distanceY = self.distance = 0;

		self.isPanning = false;
		self.isSwiping = false;
		self.isZooming = false;

		self.sliderStartPos = self.sliderLastPos || { top: 0, left: 0 };
		self.contentStartPos = $.envirabox.getTranslate(self.$content);
		self.contentLastPos = null;

		if (self.startPoints.length === 1 && !self.isZooming) {
			self.canTap = !instance.isSliding;

			if (
				current.type === 'image' &&
				(self.contentStartPos.width > self.canvasWidth + 1 ||
					self.contentStartPos.height > self.canvasHeight + 1)
			) {
				$.envirabox.stop(self.$content);

				self.$content.css('transition-duration', '0ms');

				self.isPanning = true;
			} else {
				self.isSwiping = true;
			}

			self.$container.addClass('envirabox-controls--isGrabbing');
		}

		if (
			self.startPoints.length === 2 &&
			!instance.isAnimating &&
			!current.hasError &&
			current.type === 'image' &&
			(current.isLoaded || current.$ghost)
		) {
			self.isZooming = true;

			self.isSwiping = false;
			self.isPanning = false;

			$.envirabox.stop(self.$content);

			self.$content.css('transition-duration', '0ms');

			self.centerPointStartX =
				(self.startPoints[0].x + self.startPoints[1].x) * 0.5 -
				$(window).scrollLeft();
			self.centerPointStartY =
				(self.startPoints[0].y + self.startPoints[1].y) * 0.5 -
				$(window).scrollTop();

			self.percentageOfImageAtPinchPointX =
				(self.centerPointStartX - self.contentStartPos.left) /
				self.contentStartPos.width;
			self.percentageOfImageAtPinchPointY =
				(self.centerPointStartY - self.contentStartPos.top) /
				self.contentStartPos.height;

			self.startDistanceBetweenFingers = distance(
				self.startPoints[0],
				self.startPoints[1],
			);
		}
	};

	Guestures.prototype.ontouchmove = function(e) {
		var self = this;

		self.newPoints = pointers(e);

		if (
			$.envirabox.isMobile &&
			(isScrollable(self.$target) ||
				isScrollable(self.$target.parent()))
		) {
			e.stopPropagation();

			self.canTap = false;

			return;
		}

		if (
			!(self.opts || self.instance.canPan()) ||
			!self.newPoints ||
			!self.newPoints.length
		) {
			return;
		}

		self.distanceX = distance(
			self.newPoints[0],
			self.startPoints[0],
			'x',
		);
		self.distanceY = distance(
			self.newPoints[0],
			self.startPoints[0],
			'y',
		);

		self.distance = distance(self.newPoints[0], self.startPoints[0]);

		// Skip false ontouchmove events (Chrome)
		if (self.distance > 0) {
			if (
				!(
					self.$target.is(self.$stage) ||
					self.$stage.find(self.$target).length
				)
			) {
				return;
			}

			e.stopPropagation();
			e.preventDefault();

			if (self.isSwiping) {
				self.onSwipe();
			} else if (self.isPanning) {
				self.onPan();
			} else if (self.isZooming) {
				self.onZoom();
			}
		}
	};

	Guestures.prototype.onSwipe = function() {
		var self = this;

		var swiping = self.isSwiping;
		var left = self.sliderStartPos.left || 0;
		var angle;

		if (swiping === true) {
			if (Math.abs(self.distance) > 10) {
				self.canTap = false;

				if (self.instance.group.length < 2 && self.opts.vertical) {
					self.isSwiping = 'y';
				} else if (
					self.instance.isSliding ||
					self.opts.vertical === false ||
					(self.opts.vertical === 'auto' &&
						$(window).width() > 800)
				) {
					self.isSwiping = 'x';
				} else {
					angle = Math.abs(
						(Math.atan2(self.distanceY, self.distanceX) *
							180) /
							Math.PI,
					);

					self.isSwiping = angle > 45 && angle < 135 ? 'y' : 'x';
				}

				self.instance.isSliding = self.isSwiping;

				// Reset points to avoid jumping, because we dropped first swipes to calculate the angle
				self.startPoints = self.newPoints;

				$.each(self.instance.slides, function(index, slide) {
					$.envirabox.stop(slide.$slide);

					slide.$slide.css('transition-duration', '0ms');

					slide.inTransition = false;

					if (slide.pos === self.instance.current.pos) {
						self.sliderStartPos.left = $.envirabox.getTranslate(
							slide.$slide,
						).left;
					}
				});

				// self.instance.current.isMoved = true;
				// Stop slideshow
				if (
					self.instance.SlideShow &&
					self.instance.SlideShow.isActive
				) {
					self.instance.SlideShow.stop();
				}
			}
		} else {
			if (swiping == 'x') {
				// Sticky edges
				if (
					self.distanceX > 0 &&
					(self.instance.group.length < 2 ||
						(self.instance.current.index === 0 &&
							!self.instance.current.opts.loop))
				) {
					left = left + Math.pow(self.distanceX, 0.8);
				} else if (
					self.distanceX < 0 &&
					(self.instance.group.length < 2 ||
						(self.instance.current.index ===
							self.instance.group.length - 1 &&
							!self.instance.current.opts.loop))
				) {
					left = left - Math.pow(-self.distanceX, 0.8);
				} else {
					left = left + self.distanceX;
				}
			}

			self.sliderLastPos = {
				top:
					swiping == 'x'
						? 0
						: self.sliderStartPos.top + self.distanceY,
				left: left,
			};

			if (self.requestId) {
				cancelAFrame(self.requestId);

				self.requestId = null;
			}

			self.requestId = requestAFrame(function() {
				if (self.sliderLastPos) {
					$.each(self.instance.slides, function(index, slide) {
						var pos = slide.pos - self.instance.currPos;

						$.envirabox.setTranslate(slide.$slide, {
							top: self.sliderLastPos.top,
							left:
								self.sliderLastPos.left +
								pos * self.canvasWidth +
								pos * slide.opts.gutter,
						});
					});

					self.$container.addClass('envirabox-is-sliding');
				}
			});
		}
	};

	Guestures.prototype.onPan = function() {
		var self = this;

		var newOffsetX, newOffsetY, newPos;

		self.canTap = false;

		if (self.contentStartPos.width > self.canvasWidth) {
			newOffsetX = self.contentStartPos.left + self.distanceX;
		} else {
			newOffsetX = self.contentStartPos.left;
		}

		newOffsetY = self.contentStartPos.top + self.distanceY;

		newPos = self.limitMovement(
			newOffsetX,
			newOffsetY,
			self.contentStartPos.width,
			self.contentStartPos.height,
		);

		newPos.scaleX = self.contentStartPos.scaleX;
		newPos.scaleY = self.contentStartPos.scaleY;

		self.contentLastPos = newPos;

		if (self.requestId) {
			cancelAFrame(self.requestId);

			self.requestId = null;
		}

		self.requestId = requestAFrame(function() {
			$.envirabox.setTranslate(self.$content, self.contentLastPos);
		});
	};

	// Make panning sticky to the edges
	Guestures.prototype.limitMovement = function(
		newOffsetX,
		newOffsetY,
		newWidth,
		newHeight,
	) {
		var self = this;

		var minTranslateX, minTranslateY, maxTranslateX, maxTranslateY;

		var canvasWidth = self.canvasWidth;
		var canvasHeight = self.canvasHeight;

		var currentOffsetX = self.contentStartPos.left;
		var currentOffsetY = self.contentStartPos.top;

		var distanceX = self.distanceX;
		var distanceY = self.distanceY;

		// Slow down proportionally to traveled distance
		minTranslateX = Math.max(0, canvasWidth * 0.5 - newWidth * 0.5);
		minTranslateY = Math.max(0, canvasHeight * 0.5 - newHeight * 0.5);

		maxTranslateX = Math.min(
			canvasWidth - newWidth,
			canvasWidth * 0.5 - newWidth * 0.5,
		);
		maxTranslateY = Math.min(
			canvasHeight - newHeight,
			canvasHeight * 0.5 - newHeight * 0.5,
		);

		if (newWidth > canvasWidth) {
			// ->
			if (distanceX > 0 && newOffsetX > minTranslateX) {
				newOffsetX =
					minTranslateX -
						1 +
						Math.pow(
							-minTranslateX + currentOffsetX + distanceX,
							0.8,
						) || 0;
			}

			// <-
			if (distanceX < 0 && newOffsetX < maxTranslateX) {
				newOffsetX =
					maxTranslateX +
						1 -
						Math.pow(
							maxTranslateX - currentOffsetX - distanceX,
							0.8,
						) || 0;
			}
		}

		if (newHeight > canvasHeight) {
			// \/
			if (distanceY > 0 && newOffsetY > minTranslateY) {
				newOffsetY =
					minTranslateY -
						1 +
						Math.pow(
							-minTranslateY + currentOffsetY + distanceY,
							0.8,
						) || 0;
			}

			// \
			if (distanceY < 0 && newOffsetY < maxTranslateY) {
				newOffsetY =
					maxTranslateY +
						1 -
						Math.pow(
							maxTranslateY - currentOffsetY - distanceY,
							0.8,
						) || 0;
			}
		}

		return {
			top: newOffsetY,
			left: newOffsetX,
		};
	};

	Guestures.prototype.limitPosition = function(
		newOffsetX,
		newOffsetY,
		newWidth,
		newHeight,
	) {
		var self = this;

		var canvasWidth = self.canvasWidth;
		var canvasHeight = self.canvasHeight;

		if (newWidth > canvasWidth) {
			newOffsetX = newOffsetX > 0 ? 0 : newOffsetX;
			newOffsetX =
				newOffsetX < canvasWidth - newWidth
					? canvasWidth - newWidth
					: newOffsetX;
		} else {
			// Center horizontally
			newOffsetX = Math.max(0, canvasWidth / 2 - newWidth / 2);
		}

		if (newHeight > canvasHeight) {
			newOffsetY = newOffsetY > 0 ? 0 : newOffsetY;
			newOffsetY =
				newOffsetY < canvasHeight - newHeight
					? canvasHeight - newHeight
					: newOffsetY;
		} else {
			// Center vertically
			newOffsetY = Math.max(0, canvasHeight / 2 - newHeight / 2);
		}

		return {
			top: newOffsetY,
			left: newOffsetX,
		};
	};

	Guestures.prototype.onZoom = function() {
		var self = this;

		// Calculate current distance between points to get pinch ratio and new width and height
		var currentWidth = self.contentStartPos.width;
		var currentHeight = self.contentStartPos.height;

		var currentOffsetX = self.contentStartPos.left;
		var currentOffsetY = self.contentStartPos.top;

		var endDistanceBetweenFingers = distance(
			self.newPoints[0],
			self.newPoints[1],
		);

		var pinchRatio =
			endDistanceBetweenFingers / self.startDistanceBetweenFingers;

		var newWidth = Math.floor(currentWidth * pinchRatio);
		var newHeight = Math.floor(currentHeight * pinchRatio);

		// This is the translation due to pinch-zooming
		var translateFromZoomingX =
			(currentWidth - newWidth) * self.percentageOfImageAtPinchPointX;
		var translateFromZoomingY =
			(currentHeight - newHeight) *
			self.percentageOfImageAtPinchPointY;

		// Point between the two touches
		var centerPointEndX =
			(self.newPoints[0].x + self.newPoints[1].x) / 2 -
			$(window).scrollLeft();
		var centerPointEndY =
			(self.newPoints[0].y + self.newPoints[1].y) / 2 -
			$(window).scrollTop();

		// And this is the translation due to translation of the centerpoint
		// between the two fingers
		var translateFromTranslatingX =
			centerPointEndX - self.centerPointStartX;
		var translateFromTranslatingY =
			centerPointEndY - self.centerPointStartY;

		// The new offset is the old/current one plus the total translation
		var newOffsetX =
			currentOffsetX +
			(translateFromZoomingX + translateFromTranslatingX);
		var newOffsetY =
			currentOffsetY +
			(translateFromZoomingY + translateFromTranslatingY);

		var newPos = {
			top: newOffsetY,
			left: newOffsetX,
			scaleX: self.contentStartPos.scaleX * pinchRatio,
			scaleY: self.contentStartPos.scaleY * pinchRatio,
		};

		self.canTap = false;

		self.newWidth = newWidth;
		self.newHeight = newHeight;

		self.contentLastPos = newPos;

		if (self.requestId) {
			cancelAFrame(self.requestId);

			self.requestId = null;
		}

		self.requestId = requestAFrame(function() {
			$.envirabox.setTranslate(self.$content, self.contentLastPos);
		});
	};

	Guestures.prototype.ontouchend = function(e) {
		var self = this;
		var dMs = Math.max(new Date().getTime() - self.startTime, 1);

		var swiping = self.isSwiping;
		var panning = self.isPanning;
		var zooming = self.isZooming;

		self.endPoints = pointers(e);

		self.$container.removeClass('envirabox-controls--isGrabbing');

		$(document).off('.eb.touch');

		if (self.requestId) {
			cancelAFrame(self.requestId);

			self.requestId = null;
		}

		self.isSwiping = false;
		self.isPanning = false;
		self.isZooming = false;

		if (self.canTap) {
			return self.onTap(e);
		}

		self.speed = 366;

		// Speed in px/ms
		self.velocityX = (self.distanceX / dMs) * 0.5;
		self.velocityY = (self.distanceY / dMs) * 0.5;

		self.speedX = Math.max(
			self.speed * 0.5,
			Math.min(
				self.speed * 1.5,
				(1 / Math.abs(self.velocityX)) * self.speed,
			),
		);

		if (panning) {
			self.endPanning();
		} else if (zooming) {
			self.endZooming();
		} else {
			self.endSwiping(swiping);
		}

		return;
	};

	Guestures.prototype.endSwiping = function(swiping) {
		var self = this;
		var ret = false;

		self.instance.isSliding = false;
		self.sliderLastPos = null;

		// Close if swiped vertically / navigate if horizontally
		if (swiping == 'y' && Math.abs(self.distanceY) > 50) {
			// Continue vertical movement
			$.envirabox.animate(
				self.instance.current.$slide,
				{
					top:
						self.sliderStartPos.top +
						self.distanceY +
						self.velocityY * 150,
					opacity: 0,
				},
				150,
			);

			ret = self.instance.close(true, 300);
		} else if (
			swiping == 'x' &&
			self.distanceX > 50 &&
			self.instance.group.length > 1
		) {
			ret = self.instance.previous(self.speedX);
		} else if (
			swiping == 'x' &&
			self.distanceX < -50 &&
			self.instance.group.length > 1
		) {
			ret = self.instance.next(self.speedX);
		}

		if (ret === false && (swiping == 'x' || swiping == 'y')) {
			self.instance.jumpTo(self.instance.current.index, 150);
		}

		self.$container.removeClass('envirabox-is-sliding');
	};

	// Limit panning from edges
	// ========================
	Guestures.prototype.endPanning = function() {
		var self = this;
		var newOffsetX, newOffsetY, newPos;

		if (!self.contentLastPos) {
			return;
		}

		if (self.opts.momentum === false) {
			newOffsetX = self.contentLastPos.left;
			newOffsetY = self.contentLastPos.top;
		} else {
			// Continue movement
			newOffsetX =
				self.contentLastPos.left + self.velocityX * self.speed;
			newOffsetY =
				self.contentLastPos.top + self.velocityY * self.speed;
		}

		newPos = self.limitPosition(
			newOffsetX,
			newOffsetY,
			self.contentStartPos.width,
			self.contentStartPos.height,
		);

		newPos.width = self.contentStartPos.width;
		newPos.height = self.contentStartPos.height;

		$.envirabox.animate(self.$content, newPos, 330);
	};

	Guestures.prototype.endZooming = function() {
		var self = this;

		var current = self.instance.current;

		var newOffsetX, newOffsetY, newPos, reset;

		var newWidth = self.newWidth;
		var newHeight = self.newHeight;

		if (!self.contentLastPos) {
			return;
		}

		newOffsetX = self.contentLastPos.left;
		newOffsetY = self.contentLastPos.top;

		reset = {
			top: newOffsetY,
			left: newOffsetX,
			width: newWidth,
			height: newHeight,
			scaleX: 1,
			scaleY: 1,
		};

		// Reset scalex/scaleY values; this helps for perfomance and does not break animation
		$.envirabox.setTranslate(self.$content, reset);

		if (newWidth < self.canvasWidth && newHeight < self.canvasHeight) {
			self.instance.scaleToFit(150);
		} else if (newWidth > current.width || newHeight > current.height) {
			self.instance.scaleToActual(
				self.centerPointStartX,
				self.centerPointStartY,
				150,
			);
		} else {
			newPos = self.limitPosition(
				newOffsetX,
				newOffsetY,
				newWidth,
				newHeight,
			);

			// Switch from scale() to width/height or animation will not work correctly
			$.envirabox.setTranslate(
				self.content,
				$.envirabox.getTranslate(self.$content),
			);

			$.envirabox.animate(self.$content, newPos, 150);
		}
	};

	Guestures.prototype.onTap = function(e) {
		var self = this;
		var $target = $(e.target);

		var instance = self.instance;
		var current = instance.current;

		var endPoints = (e && pointers(e)) || self.startPoints;

		var tapX = endPoints[0]
			? endPoints[0].x - self.$stage.offset().left
			: 0;
		var tapY = endPoints[0]
			? endPoints[0].y - self.$stage.offset().top
			: 0;

		var where;

		var process = function(prefix) {
			var action = current.opts[prefix];

			if ($.isFunction(action)) {
				action = action.apply(instance, [current, e]);
			}

			if (!action) {
				return;
			}

			switch (action) {
				case 'close':
					instance.close(self.startEvent);

					break;

				case 'toggleControls':
					instance.toggleControls(true);

					break;

				case 'next':
					instance.next();

					break;

				case 'nextOrClose':
					if (instance.group.length > 1) {
						instance.next();
					} else {
						instance.close(self.startEvent);
					}

					break;

				case 'zoom':
					if (
						current.type == 'image' &&
						(current.isLoaded || current.$ghost)
					) {
						if (instance.canPan()) {
							instance.scaleToFit();
						} else if (instance.isScaledDown()) {
							instance.scaleToActual(tapX, tapY);
						} else if (instance.group.length < 2) {
							instance.close(self.startEvent);
						}
					}

					break;
			}
		};

		// Ignore right click
		if (e.originalEvent && e.originalEvent.button == 2) {
			return;
		}

		// Skip if current slide is not in the center
		if (instance.isSliding) {
			return;
		}

		// Skip if clicked on the scrollbar
		if (tapX > $target[0].clientWidth + $target.offset().left) {
			return;
		}

		// Check where is clicked
		if (
			$target.is(
				'.envirabox-bg,.envirabox-inner,.envirabox-outer,.envirabox-container',
			)
		) {
			where = 'Outside';
		} else if ($target.is('.envirabox-slide')) {
			where = 'Slide';
		} else if (
			instance.current.$content &&
			instance.current.$content.has(e.target).length
		) {
			where = 'Content';
		} else {
			return;
		}

		// Check if this is a double tap
		if (self.tapped) {
			// Stop previously created single tap
			clearTimeout(self.tapped);
			self.tapped = null;

			// Skip if distance between taps is too big
			if (
				Math.abs(tapX - self.tapX) > 50 ||
				Math.abs(tapY - self.tapY) > 50 ||
				instance.isSliding
			) {
				return this;
			}

			// OK, now we assume that this is a double-tap
			process('dblclick' + where);
		} else {
			// Single tap will be processed if user has not clicked second time within 300ms
			// or there is no need to wait for double-tap
			self.tapX = tapX;
			self.tapY = tapY;

			if (
				current.opts['dblclick' + where] &&
				current.opts['dblclick' + where] !==
					current.opts['click' + where]
			) {
				self.tapped = setTimeout(function() {
					self.tapped = null;

					process('click' + where);
				}, 300);
			} else {
				process('click' + where);
			}
		}

		return this;
	};

	$(document).on('onActivate.eb', function(e, instance) {
		if (instance && !instance.Guestures) {
			instance.Guestures = new Guestures(instance);
		}
	});

	$(document).on('beforeClose.eb', function(e, instance) {
		if (instance && instance.Guestures) {
			instance.Guestures.destroy();
		}
	});
})(window, document, window.jQuery || jQuery);
