
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { __extends } from "tslib";
import Eventful from 'tvrender/lib/core/Eventful.js';
import * as eventTool from 'tvrender/lib/core/event.js';
import * as interactionMutex from './interactionMutex.js';
import { isString, bind, defaults, clone } from 'tvrender/lib/core/util.js';
import requestAnimationFrame from 'tvrender/lib/animation/requestAnimationFrame.js';
var isMac = /(Mac|iPhone|iPod|iPad)/i.test(window.navigator.userAgent);
;
function getDistance(p1, p2) {
  var xDiff = p1.clientX - p2.clientX;
  var yDiff = p1.clientY - p2.clientY;
  return Math.sqrt(xDiff * xDiff + yDiff * yDiff);
}
var RoamController = /** @class */function (_super) {
  __extends(RoamController, _super);
  function RoamController(zr) {
    var _this = _super.call(this) || this;
    _this._prevPinchScale = 1;
    _this._zr = zr;
    // Avoid two roamController bind the same handler
    var mousedownHandler = bind(_this._mousedownHandler, _this);
    var mousemoveHandler = bind(_this._mousemoveHandler, _this);
    var mouseupHandler = bind(_this._mouseupHandler, _this);
    var mousewheelHandler = bind(_this._mousewheelHandler, _this);
    var pinchHandler = bind(_this._pinchHandler, _this);
    /**
     * Notice: only enable needed types. For example, if 'zoom'
     * is not needed, 'zoom' should not be enabled, otherwise
     * default mousewheel behaviour (scroll page) will be disabled.
     */
    _this.enable = function (controlType, opt) {
      // Disable previous first
      this.disable();
      this._opt = defaults(clone(opt) || {}, {
        zoomOnMouseWheel: true,
        moveOnMouseMove: true,
        // By default, wheel do not trigger move.
        moveOnMouseWheel: 'shift',
        preventDefaultMouseMove: true
      });
      if (controlType == null) {
        controlType = true;
      }
      if (controlType === true || controlType === 'move' || controlType === 'pan') {
        zr.on('mousedown', mousedownHandler);
        zr.on('mousemove', mousemoveHandler);
        zr.on('mouseup', mouseupHandler);
      }
      if (controlType === true || controlType === 'scale' || controlType === 'zoom') {
        zr.on('mousewheel', mousewheelHandler);
        zr.on('pinch', pinchHandler);
      }
    };
    _this.disable = function () {
      zr.off('mousedown', mousedownHandler);
      zr.off('mousemove', mousemoveHandler);
      zr.off('mouseup', mouseupHandler);
      zr.off('mousewheel', mousewheelHandler);
      zr.off('pinch', pinchHandler);
    };
    return _this;
  }
  RoamController.prototype.isDragging = function () {
    return this._dragging;
  };
  RoamController.prototype.isPinching = function () {
    return this._pinching;
  };
  RoamController.prototype.setPointerChecker = function (pointerChecker) {
    this.pointerChecker = pointerChecker;
  };
  RoamController.prototype.dispose = function () {
    this.disable();
  };
  RoamController.prototype._mousedownHandler = function (e) {
    if (eventTool.isMiddleOrRightButtonOnMouseUpDown(e)) {
      return;
    }
    var el = e.target;
    while (el) {
      if (el.draggable) {
        return;
      }
      // check if host is draggable
      el = el.__hostTarget || el.parent;
    }
    var x = e.offsetX;
    var y = e.offsetY;
    // Only check on mosedown, but not mousemove.
    // Mouse can be out of target when mouse moving.
    if (this.pointerChecker && this.pointerChecker(e, x, y)) {
      // if (e.event?.touches?.length > 1) {
      //     this._prevPinchScale = 1;
      //     this._startPinchDistance = getDistance(e.event.touches[0], e.event.touches[1]);
      // }
      this._x = x;
      this._y = y;
      this._startX = x;
      this._startY = y;
      this._dragging = true;
      if (this.kineticScrollId) {
        this.kineticScrollId && cancelAnimationFrame(this.kineticScrollId);
        this.kineticScrollId = null;
      }
      if (this.kineticScroll) {
        this.kineticScroll = null;
      }
    }
  };
  RoamController.prototype._mousemoveHandler = function (e) {
    if (!this._dragging || !isAvailableBehavior('moveOnMouseMove', e, this._opt) || e.gestureEvent === 'pinch' || interactionMutex.isTaken(this._zr, 'globalPan')) {
      return;
    }
    var x = e.offsetX;
    var y = e.offsetY;
    var oldX = this._x;
    var oldY = this._y;
    var dx = x - oldX;
    var dy = y - oldY;
    if (e.zrByTouch) {
      // if (dx && dx < 1) {
      //     return;
      // }
      dx = Math.floor(dx);
      dy = Math.floor(dy);
      x = oldX + dx;
      y = oldY + dy;
      if (!dx && !dy) {
        return;
      }
    }
    this._x = x;
    this._y = y;
    this._opt.preventDefaultMouseMove && eventTool.stop(e.event);
    trigger(this, 'pan', 'moveOnMouseMove', e, {
      dx: dx,
      dy: dy,
      oldX: oldX,
      oldY: oldY,
      newX: x,
      newY: y,
      isAvailableBehavior: null,
      isTouch: e.event.zrByTouch
    });
  };
  RoamController.prototype._mouseupHandler = function (e) {
    if (!eventTool.isMiddleOrRightButtonOnMouseUpDown(e)) {
      var x = e.offsetX;
      var y = e.offsetY;
      var oldX = this._startX;
      var oldY = this._startY;
      var dx = x - oldX;
      var dy = y - oldY;
      if (this._dragging && (dx || dy)) {
        trigger(this, 'dragEnd', 'moveOnMouseMove', e, {
          isAvailableBehavior: null
        });
        this._startKineticScroll();
      }
      this._dragging = false;
      if (this._startPinchDistance) {
        this._startPinchDistance = undefined;
      }
    }
  };
  RoamController.prototype._mousewheelHandler = function (e) {
    var shouldZoom = isAvailableBehavior('zoomOnMouseWheel', e, this._opt);
    var shouldMove = isAvailableBehavior('moveOnMouseWheel', e, this._opt);
    var wheelDelta = e.wheelDelta;
    var absWheelDeltaDelta = Math.abs(wheelDelta);
    var originX = e.offsetX;
    var originY = e.offsetY;
    // wheelDelta maybe -0 in chrome mac.
    if (wheelDelta === 0 || !shouldZoom && !shouldMove) {
      return;
    }
    // If both `shouldZoom` and `shouldMove` is true, trigger
    // their event both, and the final behavior is determined
    // by event listener themselves.
    if (shouldZoom && !shouldMove) {
      // Convenience:
      // Mac and VM Windows on Mac: scroll up: zoom out.
      // Windows: scroll up: zoom in.
      // FIXME: Should do more test in different environment.
      // wheelDelta is too complicated in difference nvironment
      // (https://developer.mozilla.org/en-US/docs/Web/Events/mousewheel),
      // although it has been normallized by zrender.
      // wheelDelta of mouse wheel is bigger than touch pad.
      var factor = absWheelDeltaDelta > 3 ? 1.4 : absWheelDeltaDelta > 1 ? 1.2 : 1.1;
      var scale = wheelDelta > 0 ? factor : 1 / factor;
      checkPointerAndTrigger(this, 'zoom', 'zoomOnMouseWheel', e, {
        scale: scale,
        originX: originX,
        originY: originY,
        isAvailableBehavior: null,
        inSitu: isMac ? e.event.metaKey : e.event.ctrlKey
      });
    }
    if (shouldMove) {
      // FIXME: Should do more test in different environment.
      var absDelta = Math.abs(wheelDelta);
      // wheelDelta of mouse wheel is bigger than touch pad.
      var scrollDelta = (wheelDelta > 0 ? 1 : -1) * (absDelta > 3 ? 0.4 : absDelta > 1 ? 0.15 : 0.05);
      checkPointerAndTrigger(this, 'scrollMove', 'moveOnMouseWheel', e, {
        scrollDelta: scrollDelta,
        originX: originX,
        originY: originY,
        isAvailableBehavior: null
      });
    }
  };
  RoamController.prototype._pinchHandler = function (e) {
    if (interactionMutex.isTaken(this._zr, 'globalPan')) {
      return;
    }
    // const scale = e.pinchScale > 1 ? 1.03 : 1 / 1.03;
    // const scale = e.pinchScale;
    var touches = e.event.touches;
    if (e.pinchScale === 1) {
      this._prevPinchScale = 1;
      this._startPinchDistance = getDistance(touches[0], touches[1]);
      this._originX = Math.floor(e.pinchX);
      return;
    }
    if (!this._startPinchDistance) {
      return;
    }
    var currentDistance = getDistance(touches[0], touches[1]);
    var scale = currentDistance / this._startPinchDistance;
    var zoomScale = (scale - this._prevPinchScale) * 5;
    this._prevPinchScale = scale;
    // if (e.pinchScale === 1) {
    //     console.log('%c [ e ]-316', 'font-size:13px; background:pink; color:#bf2c9f;', e)
    // }
    // const now = Date.now();
    // if (this._lastPinchTime && now - this._lastPinchTime < 16) {
    //     return;
    // }
    // this._lastPinchTime = now;
    checkPointerAndTrigger(this, 'zoom', 'zoomOnMouseWheel', e, {
      scale: zoomScale,
      originX: this._originX || e.pinchX,
      originY: e.pinchY,
      isAvailableBehavior: null,
      inSitu: true,
      isPinch: true
    });
  };
  RoamController.prototype._kineticScroll = function () {
    var _this = this;
    if (!this.kineticScroll) {
      return;
    }
    var now = Date.now();
    if (!this.kineticScroll.finished(now)) {
      var newPos = this.kineticScroll.getPosition(now);
      trigger(this, 'kineticScroll', 'moveOnMouseMove', null, {
        isAvailableBehavior: null,
        lastBarRightSideDiffBarCount: Math.round(newPos / this.minScrollUnit) * this.minScrollUnit
      });
      this.kineticScrollId = requestAnimationFrame(function () {
        return _this._kineticScroll();
      });
    } else {
      trigger(this, 'dragEnd', 'moveOnMouseMove', {}, {
        isAvailableBehavior: null
      });
    }
  };
  RoamController.prototype._startKineticScroll = function () {
    if (!this.kineticScroll) {
      return;
    }
    this.kineticScroll.start(this.startPositionX, Date.now());
    this._kineticScroll();
  };
  return RoamController;
}(Eventful);
function checkPointerAndTrigger(controller, eventName, behaviorToCheck, e, contollerEvent) {
  if (controller.pointerChecker && controller.pointerChecker(e, contollerEvent.originX, contollerEvent.originY)) {
    // When mouse is out of roamController rect,
    // default befavoius should not be be disabled, otherwise
    // page sliding is disabled, contrary to expectation.
    eventTool.stop(e.event);
    trigger(controller, eventName, behaviorToCheck, e, contollerEvent);
  }
}
function trigger(controller, eventName, behaviorToCheck, e, contollerEvent) {
  // Also provide behavior checker for event listener, for some case that
  // multiple components share one listener.
  contollerEvent.isAvailableBehavior = bind(isAvailableBehavior, null, behaviorToCheck, e);
  // TODO should not have type issue.
  controller.trigger(eventName, contollerEvent);
}
// settings: {
//     zoomOnMouseWheel
//     moveOnMouseMove
//     moveOnMouseWheel
// }
// The value can be: true / false / 'shift' / 'ctrl' / 'alt'.
function isAvailableBehavior(behaviorToCheck, e, settings) {
  var setting = settings[behaviorToCheck];
  return !behaviorToCheck || setting && (!isString(setting) || e.event[setting + 'Key']);
}
export default RoamController;