var WebPullToRefresh = (function () {
	'use strict';

	/**
	 * Hold all of the default parameters for the module
	 * @type {object}
	 */
	var defaults = {
		// ID of the element holding pannable content area
		contentEl: 'content',

		// ID of the element holding pull to refresh loading area
		ptrEl: 'ptr',

		// Number of pixels of panning until refresh
		distanceToRefresh: 70,

		// Pointer to function that does the loading and returns a promise
		loadingFunction: false,

		// Dragging resistance level
		resistance: 2.5
	};

	/**
	 * Hold all of the merged parameter and default module options
	 * @type {object}
	 */
	var options = {};

	/**
	 * Pan event parameters
	 * @type {object}
	 */
	var pan = {
		enabled: false,
		distance: 0,
		startingPositionY: 0
	};

    /**
     * Keeps track of initial touch Y coordinate to determine which directive we're panning
     */
    var startTouchY = 0;

	/**
	 * Easy shortener for handling adding and removing body classes.
	 */
	var bodyClass = document.body.classList;

    /**
     * Keeps track of whether PTR should be enabled or disabled.
     */
    var ptrEnabled = true;

    /**
     * Keeps track of whether the user is currently pulling to refresh.
     */
    var ptrPulling = false;

	/**
	 * Initialize pull to refresh and bind touch events.
	 *
	 * @param {object=} params - Setup parameters for pull to refresh
	 */
	var init = function( params ) {
		params = params || {};
		options = {
			contentEl: params.contentEl || document.getElementById( defaults.contentEl ),
			ptrEl: params.ptrEl || document.getElementById( defaults.ptrEl ),
			distanceToRefresh: params.distanceToRefresh || defaults.distanceToRefresh,
			loadingFunction: params.loadingFunction || defaults.loadingFunction,
			resistance: params.resistance || defaults.resistance
		};

		if ( ! options.contentEl || ! options.ptrEl ) {
			return false;
		}

        // Instead of initializing hammerjs pan event listeners, we're
        // initializing touch events instead and calling the original pan
        // functions depending on touchmove direction. There were issues
        // scrolling on iOS when the hammerjs event listeners were added.

        $(options.contentEl).on("touchstart", function (e) {
            startTouchY = e.originalEvent.touches[0].clientY;
            _panStart(e);
        });

        $(options.contentEl).on("touchmove", function (e) {
            var touchY = e.originalEvent.touches[0].clientY;
            e.distance = (touchY - startTouchY);
            if (e.distance > 0) {
                _panDown(e);
            } else if (e.distance < 0) {
                _panUp(e);
            }
        });

        $(options.contentEl).on("touchend", function (e) {
            _panEnd(e);
        });
	};

    var enable = function(enabled) {
        ptrEnabled = enabled;
    };

	/**
	 * Determine whether pan events should apply based on scroll position on panstart
	 *
	 * @param {object} e - Event object
	 */
	var _panStart = function(e) {

        // Don't respond to new panstart events if ptr is already active
        if (bodyClass.contains('ptr-loading')) {
            return;
        }

        if (!ptrEnabled) {
            if (pan.distance != 0) {
                _doReset();
                pan.distance = 0;
		        pan.enabled = false;
            }
            return;
		}

        // Using content scrollTop instead of document.body
		pan.startingPositionY = options.contentEl.scrollTop;

		if ( pan.startingPositionY === 0 ) {
			pan.enabled = true;
		}
	};

	/**
	 * Handle element on screen movement when the pandown events is firing.
	 *
	 * @param {object} e - Event object
	 */
	var _panDown = function(e) {

		if ( ! pan.enabled ) {
			return;
		}

        if (!ptrEnabled) {
            if (pan.distance != 0) {
                _doReset();
                pan.distance = 0;
		        pan.enabled = false;
            }
            return;
		}

		e.preventDefault();
		pan.distance = e.distance / options.resistance;

		_setContentPan();
		_setBodyClass();
	};

	/**
	 * Handle element on screen movement when the panup events is firing.
	 *
	 * @param {object} e - Event object
	 */
	var _panUp = function(e) {
		if ( ! pan.enabled || pan.distance === 0 ) {
			return;
		}

        if (!ptrEnabled) {
            if (pan.distance != 0) {
                _doReset();
                pan.distance = 0;
		        pan.enabled = false;
            }
            return;
		}

		e.preventDefault();

		if ( pan.distance < e.distance / options.resistance ) {
			pan.distance = 0;
		} else {
			pan.distance = e.distance / options.resistance;
		}

		_setContentPan();
		_setBodyClass();
	};

	/**
	 * Set the CSS transform on the content element to move it on the screen.
	 */
	var _setContentPan = function() {
		// Use transforms to smoothly animate elements on desktop and mobile devices
		options.contentEl.style.transform = options.contentEl.style.webkitTransform = 'translate3d( 0, ' + pan.distance + 'px, 0 )';
		options.ptrEl.style.transform = options.ptrEl.style.webkitTransform = 'translate3d( 0, ' + ( pan.distance ) + 'px, 0 )';
	};

	/**
	 * Set/remove the loading body class to show or hide the loading indicator after pull down.
	 */
	var _setBodyClass = function() {

        if (!ptrPulling) {
            var ptrPullingEvent = new Event('ptr-pulling-started');
            document.dispatchEvent(ptrPullingEvent);
            ptrPulling = true;
        }

        bodyClass.add('ptr-pulling');

		if ( pan.distance > options.distanceToRefresh ) {
			bodyClass.add( 'ptr-refresh' );
		} else {
			bodyClass.remove( 'ptr-refresh' );
		}
	};

	/**
	 * Determine how to animate and position elements when the panend event fires.
	 *
	 * @param {object} e - Event object
	 */
	var _panEnd = function(e) {

        // Previously calling e.preventDefault() here, but this blocked clicks
        // from working on Android.

		options.contentEl.style.transform = options.contentEl.style.webkitTransform = '';
		options.ptrEl.style.transform = options.ptrEl.style.webkitTransform = '';

        if ( ! pan.enabled ) {
			return;
		}

		if ( document.body.classList.contains( 'ptr-refresh' ) ) {
			_doLoading();
		}
		else if (pan.distance != 0) { //STAN EDIT: Only reset if we have started a pull down refresh
			_doReset();
			//console.log("reset");
		}

		pan.distance = 0;
		pan.enabled = false;
	};

	/**
	 * Position content and refresh elements to show that loading is taking place.
	 */
	var _doLoading = function() {
		bodyClass.add( 'ptr-loading' );

		// If no valid loading function exists, just reset elements
		if ( ! options.loadingFunction ) {
			return _doReset();
		}

		// The loading function should return a promise
		var loadingPromise = options.loadingFunction();

		// For UX continuity, make sure we show loading for at least one second before resetting
		setTimeout( function() {
			// Once actual loading is complete, reset pull to refresh
			loadingPromise.then( _doReset );
		}, 1000 );
	};

	/**
	 * Reset all elements to their starting positions before any paning took place.
	 */
	var _doReset = function() {
		bodyClass.remove( 'ptr-loading' );
		bodyClass.remove( 'ptr-refresh' );
		bodyClass.add( 'ptr-reset' );

        setTimeout(function() {
			bodyClass.remove( 'ptr-reset' );
            bodyClass.remove('ptr-pulling');

            if (ptrPulling) {
                var ptrPullingEvent = new Event('ptr-pulling-ended');
                document.dispatchEvent(ptrPullingEvent);
                ptrPulling = false;
            }
        }, 250);
	};

	return {
		init: init,
        enable: enable
	}

})();