/**
 * A simple event recognizer which knows when you double tap.
 */
Ext.define('Ext.event.gesture.DoubleTap', {
 
    extend: 'Ext.event.gesture.SingleTouch',
 
    priority: 300,
 
    config: {
        /**
         * @cfg {Number} 
         * The maximum distance a touch can move without canceling recognition
         */
        moveDistance: 8,
        /**
         * @cfg {Number} 
         * The minimum distance the second tap can occur from the first tap and still
         * be considered a doubletap
         */
        tapDistance: 24,
        maxDuration: 300
    },
 
    handledEvents: ['singletap', 'doubletap'],
 
    /**
     * @member Ext.dom.Element
     * @event singletap
     * Fires when there is a single tap.
     * @param {Ext.event.Event} event The {@link Ext.event.Event} event encapsulating the DOM event.
     * @param {HTMLElement} node The target of the event.
     * @param {Object} options The options object passed to Ext.mixin.Observable.addListener.
     */
 
    /**
     * @member Ext.dom.Element
     * @event doubletap
     * Fires when there is a double tap.
     * @param {Ext.event.Event} event The {@link Ext.event.Event} event encapsulating the DOM event.
     * @param {HTMLElement} node The target of the event.
     * @param {Object} options The options object passed to Ext.mixin.Observable.addListener.
     */
 
    singleTapTimer: null,
 
    startTime: 0,
 
    lastTapTime: 0,
 
    onTouchStart: function(e) {
        var me = this,
            ret = me.callParent([e]),
            lastStartPoint;
 
        if (ret !== false) {
            me.isStarted = true;
 
            // the start point of the last touch that occurred.
            lastStartPoint = me.lastStartPoint = e.changedTouches[0].point;
 
            // the start point of the "first" touch in this gesture
            me.startPoint = me.startPoint || lastStartPoint;
 
            me.startTime = e.time;
 
            Ext.undefer(me.singleTapTimer);
        }
 
        return ret;
    },
 
    onTouchMove: function(e) {
        var me = this,
            point = e.changedTouches[0].point,
            scale = Ext.Element.getViewportScale(),
            // account for scale so that move distance is actual screen pixels, not page pixels
            distance = Math.round(Math.abs(point.getDistanceTo(me.lastStartPoint) * scale));
 
        if (distance >= me.getMoveDistance()) {
            return me.cancel(e);
        }
    },
 
    onTouchEnd: function(e) {
        var me = this,
            maxDuration = me.getMaxDuration(),
            time = e.time,
            target = e.target,
            lastTapTime = me.lastTapTime,
            lastTarget = me.lastTarget,
            point = e.changedTouches[0].point,
            duration, scale, distance;
 
        me.lastTapTime = time;
        me.lastTarget = target;
 
        if (lastTapTime) {
            duration = time - lastTapTime;
 
            if (duration <= maxDuration) {
                scale = Ext.Element.getViewportScale();
                // account for scale so that move distance is actual screen pixels, not page pixels
                distance = Math.round(Math.abs(point.getDistanceTo(me.startPoint) * scale));
 
                if (distance <= me.getTapDistance()) {
                    if (target !== lastTarget) {
                        return me.cancel(e);
                    }
 
                    me.lastTarget = null;
                    me.lastTapTime = 0;
 
                    me.fire('doubletap', e, {
                        touch: e.changedTouches[0],
                        duration: duration
                    });
 
                    return me.callParent([e]);
                }
            }
        }
 
        if (time - me.startTime > maxDuration) {
            me.fire('singletap', e);
            me.reset();
        }
        else {
            me.setSingleTapTimer(e);
        }
    },
 
    setSingleTapTimer: function(e) {
        var me = this;
 
        me.singleTapTimer = Ext.defer(function() {
            me.fire('singletap', e);
            me.reset();
        }, me.getMaxDuration());
    },
 
    reset: function() {
        var me = this;
 
        Ext.undefer(me.singleTapTimer);
 
        me.startTime = me.lastTapTime = 0;
 
        me.lastStartPoint = me.startPoint = me.singleTapTimer = null;
 
        return me.callParent();
    }
}, function(DoubleTap) {
    var gestures = Ext.manifest.gestures;
    
    DoubleTap.instance = new DoubleTap(gestures && gestures.doubleTap);
});