function gswiper_get_active_slide($swiperRoot)
{
	var $activeSlide = $swiperRoot.find('.swiper-slide-active');
	//This happens when there's only one banner.
	if($activeSlide.length == 0)
		$activeSlide = $swiperRoot.find('.swiper-slide');
	return $activeSlide;
}

function gswiper_on_tap($swiperRoot, swiper, func)
{
	// This condition block is to use swiper.on() instead of $.on() to avoid dragging-release-trigger-tap.
	// !!! Super Tricky: Do NOT use this condition block for PC or Shopee Android client. Reasons:
	// 1. Some PCs (such as Chris' Windows PC) will trigger Swiper's onTouchMove for a mouse click for unknown reasons, which will in turn disable subsequent click event.
	// 2. Our own Android app will eat the touchend event and swiper will never trigger 'tap'.
	if(!isPC() && swiper && (!isShopeeApp() || !isAndroid()))
	{
		//!!!Tricky: swiper uses "onClick"/"onTap" instead of "click"/"tap"!!!
		if(isPC())
			swiper.on('onClick', func);
		else
			swiper.on('onTap', func);
	}
	// This condition block handles the PC and Android Shopee client cases.
	else
	{
		var event = isPC() ? 'click' : 'tap';
		// off() is necessary. Otherwise on Android will double-trigger tap.
		$swiperRoot.off(event).on(event, function(e){
			func(null, e);
		});
	}
}

function setDefault(options, key, defaultValue)
{
	// Note: should use "===". If use "==", it will wrongly match null with undefined.
	if(undefined === options[key])
		options[key] = defaultValue;
}

// !!! Disable 3D transform for swiper because it crashes iPhone 6 Plus!
// !!! DO NOT disable for Android as it would be too slow!!!
if(isIOS() && isShopeeApp())
	Swiper.prototype.support.transforms3d = false;

/**
 *
 * @param swiperRootClassName 	- name of root class
 * @param options - contains the following values:
 *	{
 	*	loop: true, 			- default is true; true means can go from last slide to first slide and vice versa.
  	*	followFinger: true 		- default is true; means slides can be moved by finger movement.
  	*	initialSlide: 0 		- default is 0; the initial slide.
	*	autoplayMs: null		- default is null; or an integer value of milliseconds for the slides to auto transit to next.
	*	pagination: $(...)		- default is $('.swiper-pagination', $swiperRoot); set to null if you don't want outer swiper to interfere with inner swipers (for example a tab-view contains a banner-view).
	*	nextButton: $(...)		- default is $('.swiper-button-next', $swiperRoot); set to null if you don't want outer swiper to interfere with inner swipers (for example a tab-view contains a banner-view).
	*	prevButton: $(...)		- default is $('.swiper-button-prev', $swiperRoot); set to null if you don't want outer swiper to interfere with inner swipers (for example a tab-view contains a banner-view).
	*	onSlideChangeStart: null- default is null; the callback function for slide change start.
	*	onSlideChangeEnd: null	- default is null; the callback function for slide change end.
	*	onSliderMove: null		- !!! NOTE the name is "onSliderMove" not "onSlideMove" !!! default is null; the callback function for slide movement;
	*	onTouchStart: null		- default is null; the callback function for touch start event.
	*	onTouchMove: null		- default is null; the callback function for touch move event.
	*	onTouchEnd: null		- default is null; the callback function for touch end event.
 *	}
 * @param isBannerMode 			- default is true; true will trigger some special internal initializations. Look at code to know more.
 * @returns {Swiper}
 */
function gswiper_init(swiperRootClassName, options, isBannerMode)
{
	isBannerMode = (isBannerMode == undefined ? false : isBannerMode);
	options = (options == undefined ? {} : options);

	var $swiperRoot = $(swiperRootClassName);
	var $originalSlides = $swiperRoot.find('.swiper-slide');

	setDefault(options, 'loop', true);
	setDefault(options, 'followFinger', true);
	setDefault(options, 'initialSlide', 0);
	setDefault(options, 'autoplayMs', null);
	setDefault(options, 'direction', 'horizontal');
	setDefault(options, 'pagination', $originalSlides.length == 1 ? null : $('.swiper-pagination', $swiperRoot));
	setDefault(options, 'paginationClickable', true);

	setDefault(options, 'longSwipes', true);
	setDefault(options, 'longSwipesRatio', isBannerMode ? 0.05 : 0.1);
	setDefault(options, 'longSwipesMs', isBannerMode ? 10 : 30);
	setDefault(options, 'shortSwipes', isBannerMode);
	setDefault(options, 'autoplayDisableOnInteraction', false);
	setDefault(options, 'onlyExternal', false);

	// Navigation arrows
	setDefault(options, 'nextButton', $('.swiper-button-next', $swiperRoot));
	setDefault(options, 'prevButton', $('.swiper-button-prev', $swiperRoot));
	setDefault(options, 'onSlideChangeStart', null);
	setDefault(options, 'onSlideChangeEnd', null);
	setDefault(options, 'onSliderMove', null);
	setDefault(options, 'onTouchStart', null);
	setDefault(options, 'onTouchMove', null);
	setDefault(options, 'onTouchEnd', null);

	// Note: DO NOT initialize swiper if there's only one banner. Otherwise it would still auto-rotation and still be draggable.
	// Changed to swiper.lockSwipes()
	if($originalSlides.length != 0)
	{
		// !!! Tricky: DO NOT DO THIS if the swiper items need vertical scroll (for example subcate item lists), as our Android client's special handling will badly interfere with vertical scrolling.
		if(isBannerMode)
		{
			__android_markNodeAsSwipeable__($swiperRoot);
		}

		//Swiper by default has a transition to these indicators, which look weird when page is initially loaded (they fly into screen).
		//Putting this style in gswiper.css somehow doesn't work on slower phones.
		if(options.pagination)
			$(options.pagination).css({'transition': 'none'});

		var swiper = new Swiper(swiperRootClassName, options);

		// 151016: With new Android client, this is no longer needed. This logic will interfere with sub-cate tabs (refer to category.js).
		// This is to workaround the Android bug that will not fire touchend to Swiper when vertical swipes happen.
		// Note: DO NOT DO THIS FOR PC. It will mess up the click events on Windows, making banner not clickable.
		if(isBannerMode && isAndroid() && isShopeeApp())
		{
			var touchDownX = -1;
			swiper.on('touchStart', function(swiper, e)
			{
				if(e.touches && e.touches.length > 0)
				{
					touchDownX = e.touches[0].pageX;
				}
			});
			swiper.on('touchEnd', function(e)
			{
				touchDownX = -1;
			});

			$(window).on('touchcancel', function(e)
			{
				var touches = e.originalEvent.changedTouches;
				if(touchDownX != -1 && touches && touches.length > 0)
				{
					var x = touches[0].pageX;
					if(x < touchDownX)
						swiper.slideNext();
					else if(x > touchDownX)
						swiper.slidePrev();
					touchDownX = -1;
				}
			});
		}

		// !!! Tricky: This is to avoid a strange issue on Android App's delayed auto loading of images (see Android code).
		// If we don't do this, somehow the duplicated slides' images (if delayed by web) won't be loaded by Android app.
		if(isAndroid() && isShopeeApp())
		{
			$swiperRoot.find('.swiper-slide-duplicate').find('img').each(function(){
				var $self = $(this);
				var _src = $self.attr('_src');
				if(_src)
					$self.attr('_src', _src + '?dup');
			});
		}

		if($originalSlides.length == 1)
		{
			swiper.lockSwipes();
		}
		else
		{
			swiper.unlockSwipes();
			// Show < > buttons for PC.
			if(isPC())
			{
				$swiperRoot.find('.swiper-button-prev').show();
				$swiperRoot.find('.swiper-button-next').show();
			}
		}
		return swiper;
	}
	return null;
}
