# Source: composer/swipe-composer.js

    /**
     * @module montage/composer/swipe-composer
     * @requires montage
     * @requires montage/composer/composer
     */
    var Montage = require("../core/core").Montage,
        Composer = require("./composer").Composer;

    /**
     * @class SwipeComposer
     * @classdesc `Composer` for detecting swipe gestures.
     * @extends Composer
     */
    exports.SwipeComposer = Composer.specialize( /** @lends SwipeComposer# */ {

        load: {
            value: function () {
                document.addEventListener("touchstart", this, true);
            }
        },

        unload: {
            value: function () {
                document.removeEventListener("touchstart", this, true);
            }
        },

        _startX: {
            enumerable: false,
            value: 0
        },

        _startY: {
            enumerable: false,
            value: 0
        },

        _deltaX: {
            enumerable: false,
            value: 0
        },

        _deltaY: {
            enumerable: false,
            value: 0
        },

        /**
         * The number of pixels a gesture must continue to be recognized as a
         * swipe.
         * @type {number}
         */
        _threshold: {
            enumerable: false,
            value: 50
        },

        /**
         * The maximum angle (in degrees) away from horizontal or vertical
         * for a gesture to be recognized as a swipe.
         * @type {number}
         */
        _thresholdSwipeAngle: {
            enumerable: false,
            value: 20
        },

        _startTimestamp: {
            enumerable: false,
            value: 0
        },

        captureTouchstart: {
            value: function (event) {
                this._reset();
                var touches = event.touches,
                    touch = touches[0];
                this._startX = touch.clientX;
                this._startY = touch.clientY;
                this._startTimestamp = event.timeStamp;
                document.addEventListener("touchmove", this, true);
                document.addEventListener("touchend", this, true);
                document.addEventListener("touchcancel", this, true);
            }
        },

        _reset: {
            enumerable: false,
            value: function () {
                this._startX = 0;
                this._startY = 0;
                this._deltaX = 0;
                this._deltaY = 0;
                this._startSwipeAngle = null;
            }
        },

        _startSwipeAngle: {
            enumerable: false,
            value: null
        },

        captureTouchcancel: {
            value: function (event) {
                document.removeEventListener("touchmove", this, true);
                document.removeEventListener("touchend", this, true);
                document.removeEventListener("touchcancel", this, true);
            }
        },

        captureTouchmove: {
            value: function (event) {
                event.preventDefault();
                var touches = event.changedTouches[0], swipeEvent, direction;

                this._deltaX = touches.clientX - this._startX;
                this._deltaY = touches.clientY - this._startY;

                var dX = this._deltaX,
                    dY = this._deltaY,
                    threshold = this._threshold,
                    swipeAngle = this._findSwipeAngle(dX, dY);

                if (
                    this._startSwipeAngle !== null &&
                        Math.abs(this._startSwipeAngle - swipeAngle) > this._thresholdSwipeAngle
                ) {
                    //Direction changed; Abort touch
                    //this.captureTouchcancel();
                    this._startSwipeAngle = null;
                }

                if (this._startSwipeAngle === null) {
                    this._startSwipeAngle = swipeAngle;
                    this._startX = touches.clientX;
                    this._startY = touches.clientY;
                    this._deltaX = 0;
                    this._deltaY = 0;
                }

                if (dX > threshold && dY > threshold) {
                    direction = "DIAGONAL";
                } else if (dX > threshold && dY < threshold) {
                    if (this._deltaX > 0) {
                        direction = "RIGHT";
                    } else {
                        direction = "LEFT";
                    }
                } else if (dX < threshold && dY > threshold) {
                    if (this._deltaY > 0) {
                        direction = "DOWN";
                    } else {
                        direction = "UP";
                    }
                }

                if (dX !== 0 || dY !== 0) {
                    swipeEvent = document.createEvent("CustomEvent");
                    swipeEvent.initCustomEvent("swipemove", true, false, null);
                    swipeEvent.direction = direction;
                    swipeEvent.angle = this._startSwipeAngle;
                    swipeEvent.velocity = this._findVelocity((event.timeStamp - this._startTimestamp));
                    swipeEvent.startX = this._startX;
                    swipeEvent.startY = this._startY;
                    swipeEvent.dX = this._deltaX;
                    swipeEvent.dY = this._deltaY;

                    this.dispatchEvent(swipeEvent);
                }
            }
        },

        _findSwipeAngle: {
            enumerable: false,
            value: function (dX, dY) {
                var swipeAngle = -1 * (Math.atan2(dY, dX) * 180 / 3.14);
                return swipeAngle.toFixed(2);
            }
        },

        captureTouchend: {
            value: function (event) {

                if (!event) {
                    return;
                }

                var deltaX = Math.abs(this._deltaX),
                    deltaY = Math.abs(this._deltaY),
                    threshold = this._threshold,
                    direction,
                    swipeEvent;

                if (deltaX < threshold && deltaY < threshold) {
                    this.captureTouchcancel();
                    return;
                }

                document.removeEventListener("touchmove", this, true);

                if (deltaX > threshold && deltaY > threshold) {
                    direction = "DIAGONAL";
                } else if (deltaX > threshold && deltaY < threshold) {
                    if (this._deltaX > 0) {
                        direction = "RIGHT";
                    } else {
                        direction = "LEFT";
                    }
                } else if (deltaX < threshold && deltaY > threshold) {
                    if (this._deltaY > 0) {
                        direction = "DOWN";
                    } else {
                        direction = "UP";
                    }
                }

                swipeEvent = document.createEvent("CustomEvent");
                swipeEvent.initCustomEvent("swipe", true, false, null);
                swipeEvent.direction = direction;
                swipeEvent.angle = this._startSwipeAngle;
                swipeEvent.velocity = this._findVelocity((event.timeStamp - this._startTimestamp));
                swipeEvent.startX = this._startX;
                swipeEvent.startY = this._startY;
                swipeEvent.dX = this._deltaX;
                swipeEvent.dY = this._deltaY;

                this.dispatchEvent(swipeEvent);
            }
        },

        _findVelocity: {
            enumerable: false,
            value: function (deltaTime) {
                return (Math.sqrt(/*xSquare*/(this._deltaX * this._deltaX) + /*ySquare*/(this._deltaY * this._deltaY)) / /*deltaTime*/(deltaTime));

            }
        }

    });