/**
 * A simple event recognizer which knows when you rotate.
 */
Ext.define('Ext.event.gesture.Rotate', {
    extend: 'Ext.event.gesture.MultiTouch',

    priority: 700,

    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) {
        if (!this.isTracking) {
            return;
        }

        var touches = e.touches,
            lastAngle = this.lastAngle,
            firstPoint, secondPoint, angle, nextAngle, previousAngle, diff;

        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;
            }
        }

        this.lastAngle = angle;

        if (!this.isStarted) {
            this.isStarted = true;

            this.startAngle = angle;

            this.fire('rotatestart', e, {
                touches: touches,
                angle: angle,
                rotation: 0
            });
        }
        else {
            this.fire('rotate', e, {
                touches: touches,
                angle: angle,
                rotation: angle - this.startAngle
            });
        }

        this.lastTouches = Ext.Array.clone(touches);
    },

    fireEnd: function(e) {
        this.lastAngle = null;
        this.fire('rotateend', e);
    },

    fireCancel: function(e) {
        this.lastAngle = null;
        this.fire('rotatecancel', e);
    },

    reset: function() {
        var me = this;

        me.lastTouches = me.lastAngle = me.startAngle = null;

        this.callParent();
    }
}, function(Rotate) {
    var gestures = Ext.manifest.gestures;
    Rotate.instance = new Rotate(gestures && gestures.rotate);
});
