export class PointerEvents {
    constructor(ele, pointerDown, pointerMove, pointerUp, zone, option) {
        this.ele = ele;
        this.pointerDown = pointerDown;
        this.pointerMove = pointerMove;
        this.pointerUp = pointerUp;
        this.zone = zone;
        this.option = option;
        this.rmTouchStart = null;
        this.rmTouchMove = null;
        this.rmTouchEnd = null;
        this.rmTouchCancel = null;
        this.rmMouseStart = null;
        this.rmMouseMove = null;
        this.rmMouseUp = null;
        this.lastTouchEvent = 0;
        this.mouseWait = 2 * 1000;
        this.bindTouchEnd = this.handleTouchEnd.bind(this);
        this.bindMouseUp = this.handleMouseUp.bind(this);
        this.rmTouchStart = listenEvent(ele, 'touchstart', zone, option, this.handleTouchStart.bind(this));
        this.rmMouseStart = listenEvent(ele, 'mousedown', zone, option, this.handleMouseDown.bind(this));
    }
    handleTouchStart(ev) {
        this.lastTouchEvent = Date.now() + this.mouseWait;
        if (!this.pointerDown(ev)) {
            return;
        }
        if (!this.rmTouchMove && this.pointerMove) {
            this.rmTouchMove = listenEvent(this.ele, 'touchmove', this.zone, this.option, this.pointerMove);
        }
        if (!this.rmTouchEnd) {
            this.rmTouchEnd = listenEvent(this.ele, 'touchend', this.zone, this.option, this.bindTouchEnd);
        }
        if (!this.rmTouchCancel) {
            this.rmTouchCancel = listenEvent(this.ele, 'touchcancel', this.zone, this.option, this.bindTouchEnd);
        }
    }
    handleMouseDown(ev) {
        if (this.lastTouchEvent > Date.now()) {
            console.debug('mousedown event dropped because of previous touch');
            return;
        }
        if (!this.pointerDown(ev)) {
            return;
        }
        if (!this.rmMouseMove && this.pointerMove) {
            this.rmMouseMove = listenEvent(document, 'mousemove', this.zone, this.option, this.pointerMove);
        }
        if (!this.rmMouseUp) {
            this.rmMouseUp = listenEvent(document, 'mouseup', this.zone, this.option, this.bindMouseUp);
        }
    }
    handleTouchEnd(ev) {
        this.stopTouch();
        this.pointerUp && this.pointerUp(ev);
    }
    handleMouseUp(ev) {
        this.stopMouse();
        this.pointerUp && this.pointerUp(ev);
    }
    stopTouch() {
        this.rmTouchMove && this.rmTouchMove();
        this.rmTouchEnd && this.rmTouchEnd();
        this.rmTouchCancel && this.rmTouchCancel();
        this.rmTouchMove = null;
        this.rmTouchEnd = null;
        this.rmTouchCancel = null;
    }
    stopMouse() {
        this.rmMouseMove && this.rmMouseMove();
        this.rmMouseUp && this.rmMouseUp();
        this.rmMouseMove = null;
        this.rmMouseUp = null;
    }
    stop() {
        this.stopTouch();
        this.stopMouse();
    }
    destroy() {
        this.rmTouchStart && this.rmTouchStart();
        this.rmTouchStart = null;
        this.rmMouseStart && this.rmMouseStart();
        this.rmMouseStart = null;
        this.stop();
        this.pointerDown = null;
        this.pointerMove = null;
        this.pointerUp = null;
        this.ele = null;
    }
}
export class UIEventManager {
    constructor(zoneWrapped = true) {
        this.zoneWrapped = zoneWrapped;
        this.events = [];
    }
    listenRef(ref, eventName, callback, option) {
        return this.listen(ref.nativeElement, eventName, callback, option);
    }
    pointerEvents(config) {
        let element = config.element;
        if (!element) {
            element = config.elementRef.nativeElement;
        }
        if (!element || !config.pointerDown) {
            console.error('PointerEvents config is invalid');
            return;
        }
        let zone = config.zone || this.zoneWrapped;
        let options = config.nativeOptions || false;
        let submanager = new PointerEvents(element, config.pointerDown, config.pointerMove, config.pointerUp, zone, options);
        let removeFunc = () => submanager.destroy();
        this.events.push(removeFunc);
        return submanager;
    }
    listen(element, eventName, callback, option = false) {
        if (!element) {
            return;
        }
        let removeFunc = listenEvent(element, eventName, this.zoneWrapped, option, callback);
        this.events.push(removeFunc);
        return removeFunc;
    }
    unlistenAll() {
        for (let event of this.events) {
            event();
        }
        this.events.length = 0;
    }
}
function listenEvent(ele, eventName, zoneWrapped, option, callback) {
    let rawEvent = ('__zone_symbol__addEventListener' in ele && !zoneWrapped);
    if (rawEvent) {
        ele.__zone_symbol__addEventListener(eventName, callback, option);
        return () => ele.__zone_symbol__removeEventListener(eventName, callback);
    }
    else {
        ele.addEventListener(eventName, callback, option);
        return () => ele.removeEventListener(eventName, callback);
    }
}
