(function(angular){
	"use strict";
        angular.module("mde.swipeToRefresh")
		.directive("mdeSwipeToRefresh", mdeSwipeToRefreshDirective);


	var State = {
		None: "None",
		Updating: "Updating",
		Pulling: "Pulling"
	};

	function mdeSwipeToRefreshDirective($q, $timeout, mdeSwipeToRefreshConfig){
		return{
			restrict: "A",
            require: "?^mdeSwipeToRefreshScrollHost",
			transclude: true,
			scope:{
                mdeOnRefresh: "&?",
                mdeOnCancel: "&?",
                mdeScrollHostSelector: "@?",
                mdeThreshold: "=?"
			},
			templateUrl: "swipe-to-refresh/swipe-to-refresh.html",
			link: linkFn
		};

		function linkFn(scope, elem, attrs, mdeSwipeToRefreshScrollHost){
			elem.bind("touchstart", touchStart);
			var scrollHost, startY;
			if(mdeSwipeToRefreshScrollHost){
                scrollHost = mdeSwipeToRefreshScrollHost.getElement();
            }
            else if(scope.mdeScrollHostSelector){
			    var el = elem.parent();
			    while( el[0] != document.body){
                    el = el.parent();
                    if(el[0].matches(scope.mdeScrollHostSelector)){
                        scrollHost = el;
                        break;
                    }
                }
                // if mdeScrollHostSelector doesn't matches anything, fallback to body
                scrollHost = scrollHost || el;
            }
            else{
                // default to body
                scrollHost = angular.element(document.body);
            }
            scope.mdeThreshold = scope.mdeThreshold || mdeSwipeToRefreshConfig.threshold;

            scope.State = State;
            scope.progress = 0;
            scope.state = State.None;


            function touchStart(event){
                if(scope.state != State.None){
                    return;
                }
                startY = event.touches[0].pageY;
                elem.one("touchend", touchEnd);
                elem.bind("touchmove", touchMove);

                if(scrollHost[0].scrollTop == 0){
                    scope.$apply(function(){
                        scope.progress = 0;
                        scope.movement = 0;
                    });
                }
            }

            function touchMove(event) {
                if(scrollHost[0].scrollTop > 0){
                    return;
                }
                var movement = event.touches[0].pageY - startY;

                if(movement > 0 && scope.state != State.Pulling){
                    $timeout(function (){
                        scope.state = State.Pulling;
                    })
                }

                if(scope.state == State.Pulling){
                    event.preventDefault();
                }


                if(movement > 0){
                    scope.$apply(function(){
                    	scope.movement = Math.min(calculateMovement(movement, scope.mdeThreshold));
                        scope.progress = Math.min( scope.movement/scope.mdeThreshold, 1);
                        // console.log(movement, "=>", scope.movement);
                    });
				}
				else if(scope.movement > 0){
                    scope.$apply(function(){
                        scope.movement = 0;
                        scope.progress = 0;
                    });
                }


            }
            function touchEnd(event){
                elem.unbind("touchmove", touchMove);
                scope.$apply(function(){
                	if(scope.progress == 1){
                        scope.state = State.Updating;
                        scope.movement = scope.mdeThreshold;
                        $q.when((scope.mdeOnRefresh || angular.noop)()).finally(function(){
                            scope.state = State.None;
                        })
                    }
                    else{
                        if(scope.movement > 0){
                            (scope.mdeOnCancel || angular.noop)();
                            scope.movement = 0;
                        }
                        $timeout(function(){
                            scope.state = State.None;
                        },100);
					}
                });
            }
		}
	}
    function calculateMovement(movement, activationThreshold) {
        /*
         These are observations on Nexus 5 for how pulling is calculated based on touch movement.
         It seems there is kind of a logarithmic relation going on (as it also feels so).
         Note that Pixels need to be divided by 3 to become comparable to web (assuming proper viewport tag exists)

         touch movement(x)	=> 	pull (y)
         72, 40
         170, 100
         240, 143
         304, 180 => near threshold
         448, 250
         592, 310
         745, 360
         904, 395
         1254, 430
         * */
        return 2 * activationThreshold * log10((movement + activationThreshold) / activationThreshold);
    }
    function log10(x){
        return Math.log(x)/Math.LN10;
        // we don't use Math.log10 as it's only available in ES6
    }
})(angular);
@@ -2049,57 +2049,8 @@
 0)%7B%0A
-                    scope.$apply(function()%7B%0A    
     
@@ -2077,36 +2077,32 @@
 e.progress = 0;%0A
-    
                 
@@ -2137,33 +2137,46 @@
                 
-%7D
+scope.$digest(
 );%0A             
@@ -2703,33 +2703,32 @@
              %7D%0A%0A
-%0A
                 
@@ -2769,54 +2769,8 @@
     
-scope.$apply(function()%7B%0A                    %09
 scop
@@ -2853,36 +2853,32 @@
                 
-  
-  
 scope.progress =
@@ -2951,81 +2951,22 @@
     
-    // console.log(movement, %22=%3E%22, scope.movement);%0A                    %7D
+scope.$digest(
 );%0A%09
@@ -3007,57 +3007,8 @@
 0)%7B%0A
-                    scope.$apply(function()%7B%0A    
     
@@ -3035,36 +3035,32 @@
 e.movement = 0;%0A
-    
                 
@@ -3095,33 +3095,46 @@
                 
-%7D
+scope.$digest(
 );%0A             

call $digest instead of $apply on touchmove events