/**
 * A simple event recognizer which knows when you rotate.
 */
Ext.define('Ext.event.gesture.Rotate', {
    extend: 'Ext.event.gesture.MultiTouch',
 
    priority: 800,
 
    handledEvents: ['rotatestart', 'rotate', 'rotateend', 'rotatecancel'],
 
    /**
     * @member Ext.dom.Element
     * @event rotatestart
     * Fired once when a rotation has started.
     * @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 rotate
     * Fires continuously when there is rotation (the touch must move for this to be fired).
     * When listening to this, ensure you know about the {@link Ext.event.Event#angle} and {@link Ext.event.Event#rotation}
     * properties in the `event` object.
     * @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 rotateend
     * Fires when a rotation event has ended.
     * @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.
     */
 
    /**
     * @property {Number} angle
     * The angle of the rotation.
     *
     * **This is only available when the event type is `rotate`**
     * @member Ext.event.Event
     */
 
    /**
     * @property {Number} rotation
     * A amount of rotation, since the start of the event.
     *
     * **This is only available when the event type is `rotate`**
     * @member Ext.event.Event
     */
 
    startAngle: 0,
 
    lastTouches: null,
 
    lastAngle: null,
 
    onTouchMove: function(e) {
        var me = this,
            touches, lastAngle, firstPoint, secondPoint, angle, nextAngle, previousAngle,
            diff;
 
        if (me.isTracking) {
            touches = e.touches;
            lastAngle = me.lastAngle;
 
            firstPoint = touches[0].point;
            secondPoint = touches[1].point;
 
            angle = firstPoint.getAngleTo(secondPoint);
 
            if (lastAngle !== null) {
                diff = Math.abs(lastAngle - angle);
                nextAngle = angle + 360;
                previousAngle = angle - 360;
 
                if (Math.abs(nextAngle - lastAngle) < diff) {
                    angle = nextAngle;
                } else if (Math.abs(previousAngle - lastAngle) < diff) {
                    angle = previousAngle;
                }
            }
 
            me.lastAngle = angle;
 
            if (!me.isStarted) {
                me.isStarted = true;
 
                me.startAngle = angle;
 
                me.fire('rotatestart', e, {
                    touches: touches,
                    angle: angle,
                    rotation: 0
                });
            } else {
                me.fire('rotate', e, {
                    touches: touches,
                    angle: angle,
                    rotation: angle - me.startAngle
                });
            }
 
            me.lastTouches = Ext.Array.clone(touches);
        }
    },
 
    onTouchEnd: function(e) {
        if (this.isStarted) {
            this.fire('rotateend', e);
        }
 
        return this.callParent([e]);
    },
 
    onCancel: function(e) {
        this.fire('rotatecancel', e, null, true);
    },
 
    reset: function() {
        var me = this;
 
        me.lastTouches = me.lastAngle = me.startAngle = null;
 
        return this.callParent();
    }
}, function(Rotate) {
    var gestures = Ext.manifest.gestures;
    Rotate.instance = new Rotate(gestures && gestures.rotate);
});