// ==========================================================================
// Project:  Ember Touch 
// Copyright: ©2011 Strobe Inc. and contributors.
// License:   Licensed under MIT license (see license.js)
// ==========================================================================

var get = Em.get;
var set = Em.set;

/**
  @class

  Manages multiplegesture recognizers that are associated with a view.
  This class is instantiated automatically by Em.View and you wouldn't
  interact with it yourself.

  Em.GestureManager mainly acts as a composite for the multiple gesture
  recognizers associated with a view. Whenever it gets a touch event, it
  relays it to the gestures. The other main resposibility of
  Em.GestureManager is to handle re-dispatching of events to the view.

  @extends Em.Object
*/
Em.GestureManager = Em.Object.extend({

  /**
    An array containing all the gesture recognizers associated with a
    view. This is set automatically by Em.View.

    @default null
    @type Array
  */
  gestures: null,
  view: null,

  /**
    Relays touchStart events to all the gesture recognizers to the
    specified view

    @return Boolen
  */
  touchStart: function(evt, view) {
    return this._invokeEvent('touchStart',evt);
  },

  /**
    Relays touchMove events to all the gesture recognizers to the
    specified view

    @return Boolen
  */
  touchMove: function(evt, view) {
    return this._invokeEvent('touchMove',evt);
  },

  /**
    Relays touchEnd events to all the gesture recognizers to the
    specified view

    @return Boolen
  */
  touchEnd: function(evt, view) {
    return this._invokeEvent('touchEnd',evt);
  },

  /**
    Relays touchCancel events to all the gesture recognizers to the
    specified view

    @return Boolen
  */
  touchCancel: function(evt, view) {
    return this._invokeEvent('touchCancel',evt);
  },

  /**
    Relays an event to the gesture recognizers. Used internally
    by the touch event listeners. Propagates the event to the parentViews.

    @private
    @return Boolean
  */
  _invokeEvent: function(eventName, eventObject) {

    var gestures = this.get('gestures'),
        gesture,
        handler,
        result = true;

    // view can response directly to touch events
    handler = this.view[eventName];
    if (Em.typeOf(handler) === 'function') {
      handler.call(this.view, eventObject);
    }


    //appGestureManager allow to pass touchEvents at the App Level  
    var gesturesCanReceiveTouchEvent = Em.AppGestureManager.get('isBlocked')? Em.AppGestureManager.shouldReceiveTouch(this.view) : true;

    if ( gesturesCanReceiveTouchEvent ) {

      for (var i=0, l=gestures.length; i < l; i++) {
        gesture = gestures[i];
        handler = gesture[eventName];

        if (Em.typeOf(handler) === 'function') {

          var gestureDelegate = gesture.get('delegate'),
              isValid;

          //gestureDelegate allow to pass touchEvents depending on gesture state  
          if ( !gestureDelegate ) {
            isValid = true;
          } else {

            isValid = this._applyDelegateRules( gestureDelegate,  gesture, this.view, eventObject );
            if ( isValid === undefined ) {
              isValid = gestureDelegate.shouldReceiveTouch( gesture, this.view, eventObject );
            }

          }

          if ( isValid ) {
            result = handler.call(gesture, eventObject);
          }

        }
      }

    }
    
    // browser delivers the event to the DOM element
    // bubble the event to the parentView
    var parentView = this.view.get('parentView');
    if ( parentView ) {
      var manager = parentView.get('eventManager');
      if ( manager ) { manager._invokeEvent(eventName, eventObject); }
      
    }

    return result;

  },

  _applyDelegateRules: function(gestureDelegate, gesture, view, event) {

    var rules = gestureDelegate.rules,
        length = rules.length;

    if ( length > 0 ) {

      var i,
          result;

      for (i=0;i<length;i++) {
        result = rules[i].shouldReceiveTouch(gesture, view, event);
        if ( result !== undefined ) {
          return result;
        }
      }
    }

    return undefined;

  }

});

@@ -2147,24 +2147,29 @@
 es'),%0A      
+  l =
   gesture,%0A 
@@ -2165,16 +2165,24 @@
  gesture
+s.length
 ,%0A      
@@ -2398,17 +2398,38 @@
 %0A    %7D%0A%0A
-%0A
+    if ( l %3E 0 ) %7B%0A%0A  
     //ap
@@ -2489,16 +2489,18 @@
 Level  %0A
+  
     var 
@@ -2624,25 +2624,26 @@
 ew) : true;%0A
-%0A
+  
     if ( ges
@@ -2683,39 +2683,105 @@
     
-for (var i=0, l=gestures.length
+  var gesture,%0A            gestureDelegate,%0A            isValid,%0A            i;%0A%0A        for (i=0
 ; i 
@@ -2796,24 +2796,26 @@
 ) %7B%0A        
+  
 gesture = ge
@@ -2825,16 +2825,18 @@
 res%5Bi%5D;%0A
+  
         
@@ -2866,16 +2866,18 @@
 Name%5D;%0A%0A
+  
         
@@ -2920,35 +2920,33 @@
 ') %7B%0A%0A          
-var
+ 
  gestureDelegate
@@ -2975,34 +2975,13 @@
 te')
-,%0A              isValid
 ;%0A%0A
+  
     
@@ -3065,24 +3065,26 @@
  %0A          
+  
 if ( !gestur
@@ -3101,32 +3101,34 @@
 ) %7B%0A            
+  
 isValid = true;%0A
@@ -3123,24 +3123,26 @@
 lid = true;%0A
+  
           %7D 
@@ -3153,32 +3153,34 @@
  %7B%0A%0A            
+  
 isValid = this._
@@ -3256,32 +3256,34 @@
  );%0A            
+  
 if ( isValid ===
@@ -3289,32 +3289,34 @@
 = undefined ) %7B%0A
+  
               is
@@ -3398,35 +3398,39 @@
  );%0A            
+  
 %7D%0A%0A
+  
           %7D%0A%0A   
@@ -3418,32 +3418,34 @@
 %0A            %7D%0A%0A
+  
           if ( i
@@ -3451,24 +3451,26 @@
 isValid ) %7B%0A
+  
             
@@ -3510,24 +3510,39 @@
 entObject);%0A
+            %7D%0A%0A
           %7D%0A
@@ -3533,33 +3533,32 @@
  %7D%0A%0A          %7D%0A
-%0A
         %7D%0A      
@@ -3543,32 +3543,33 @@
     %7D%0A        %7D%0A
+%0A
       %7D%0A%0A    %7D%0A 

clean up _invokeEvent