"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Slide = void 0;
var _web = require("@react-spring/web");
var _ahooks = require("ahooks");
var _react = _interopRequireWildcard(require("react"));
var _bound = require("../../utils/bound");
var mat = _interopRequireWildcard(require("../../utils/matrix"));
var _rubberband = require("../../utils/rubberband");
var _useDragAndPinch = require("../../utils/use-drag-and-pinch");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
const classPrefix = `adm-image-viewer`;
const Slide = props => {
  const {
    dragLockRef,
    maxZoom,
    imageRender,
    index
  } = props;
  const initialMartix = (0, _react.useRef)([]);
  const controlRef = (0, _react.useRef)(null);
  const imgRef = (0, _react.useRef)(null);
  const [{
    matrix
  }, api] = (0, _web.useSpring)(() => ({
    matrix: mat.create(),
    config: {
      tension: 200
    }
  }));
  const controlSize = (0, _ahooks.useSize)(controlRef);
  const imgSize = (0, _ahooks.useSize)(imgRef);
  const pinchLockRef = (0, _react.useRef)(false);
  /**
   * Calculate the min and max value of x and y
   */
  const getMinAndMax = nextMatrix => {
    if (!controlSize || !imgSize) return {
      x: {
        position: 0,
        minX: 0,
        maxX: 0
      },
      y: {
        position: 0,
        minY: 0,
        maxY: 0
      }
    };
    const controlLeft = -controlSize.width / 2;
    const controlTop = -controlSize.height / 2;
    const imgLeft = -imgSize.width / 2;
    const imgTop = -imgSize.height / 2;
    const zoom = mat.getScaleX(nextMatrix);
    const scaledImgWidth = zoom * imgSize.width;
    const scaledImgHeight = zoom * imgSize.height;
    const minX = controlLeft - (scaledImgWidth - controlSize.width);
    const maxX = controlLeft;
    const minY = controlTop - (scaledImgHeight - controlSize.height);
    const maxY = controlTop;
    const [x, y] = mat.apply(nextMatrix, [imgLeft, imgTop]);
    return {
      x: {
        position: x,
        minX,
        maxX
      },
      y: {
        position: y,
        minY,
        maxY
      }
    };
  };
  /**
   * Check if is reach the bound
   */
  const getReachBound = (position, min, max, buffer = 0) => {
    return [position <= min - buffer, position >= max + buffer];
  };
  /**
   * Limit the matrix in the bound
   */
  const boundMatrix = (nextMatrix, type, last = false) => {
    if (!controlSize || !imgSize) return nextMatrix;
    const zoom = mat.getScaleX(nextMatrix);
    const scaledImgWidth = zoom * imgSize.width;
    const scaledImgHeight = zoom * imgSize.height;
    const {
      x: {
        position: x,
        minX,
        maxX
      },
      y: {
        position: y,
        minY,
        maxY
      }
    } = getMinAndMax(nextMatrix);
    if (type === 'translate') {
      let boundedX = x;
      let boundedY = y;
      if (scaledImgWidth > controlSize.width) {
        boundedX = last ? (0, _bound.bound)(x, minX, maxX) : (0, _rubberband.rubberbandIfOutOfBounds)(x, minX, maxX, zoom * 50);
      } else {
        boundedX = -scaledImgWidth / 2;
      }
      if (scaledImgHeight > controlSize.height) {
        boundedY = last ? (0, _bound.bound)(y, minY, maxY) : (0, _rubberband.rubberbandIfOutOfBounds)(y, minY, maxY, zoom * 50);
      } else {
        boundedY = -scaledImgHeight / 2;
      }
      return mat.translate(nextMatrix, boundedX - x, boundedY - y);
    }
    if (type === 'scale' && last) {
      const [boundedX, boundedY] = [scaledImgWidth > controlSize.width ? (0, _bound.bound)(x, minX, maxX) : -scaledImgWidth / 2, scaledImgHeight > controlSize.height ? (0, _bound.bound)(y, minY, maxY) : -scaledImgHeight / 2];
      return mat.translate(nextMatrix, boundedX - x, boundedY - y);
    }
    return nextMatrix;
  };
  (0, _useDragAndPinch.useDragAndPinch)({
    onDrag: state => {
      var _a;
      if (state.first) {
        const {
          x: {
            position: x,
            minX,
            maxX
          }
        } = getMinAndMax(matrix.get());
        initialMartix.current = getReachBound(x, minX, maxX);
        return;
      }
      if (state.pinching) return state.cancel();
      if (state.tap && state.elapsedTime > 0 && state.elapsedTime < 1000) {
        // 判断点击时间>0是为了过滤掉非正常操作，例如用户长按选择图片之后的取消操作（也是一次点击）
        (_a = props.onTap) === null || _a === void 0 ? void 0 : _a.call(props);
        return;
      }
      const currentZoom = mat.getScaleX(matrix.get());
      if (dragLockRef) {
        dragLockRef.current = currentZoom !== 1;
      }
      if (!pinchLockRef.current && currentZoom <= 1) {
        api.start({
          matrix: mat.create()
        });
      } else {
        const currentMatrix = matrix.get();
        const offset = [state.offset[0] - mat.getTranslateX(currentMatrix), state.offset[1] - mat.getTranslateY(currentMatrix)];
        const nextMatrix = mat.translate(currentMatrix, ...(state.last ? [offset[0] + state.velocity[0] * state.direction[0] * 200, offset[1] + state.velocity[1] * state.direction[1] * 200] : offset));
        api.start({
          matrix: boundMatrix(nextMatrix, 'translate', state.last),
          immediate: !state.last
        });
        const {
          x: {
            position: x,
            minX,
            maxX
          }
        } = getMinAndMax(nextMatrix);
        if (state.last && initialMartix.current.some(i => i) && getReachBound(x, minX, maxX).some(i => i)) {
          if (dragLockRef) {
            dragLockRef.current = false;
          }
          api.start({
            matrix: mat.create()
          });
        }
      }
    },
    onPinch: state => {
      var _a;
      pinchLockRef.current = !state.last;
      const [d] = state.offset;
      if (d < 0) return;
      let mergedMaxZoom;
      if (maxZoom === 'auto') {
        mergedMaxZoom = controlSize && imgSize ? Math.max(controlSize.height / imgSize.height, controlSize.width / imgSize.width) : 1;
      } else {
        mergedMaxZoom = maxZoom;
      }
      const nextZoom = state.last ? (0, _bound.bound)(d, 1, mergedMaxZoom) : d;
      (_a = props.onZoomChange) === null || _a === void 0 ? void 0 : _a.call(props, nextZoom);
      if (state.last && nextZoom <= 1) {
        api.start({
          matrix: mat.create()
        });
        if (dragLockRef) {
          dragLockRef.current = false;
        }
      } else {
        if (!controlSize) return;
        const currentMatrix = matrix.get();
        const currentZoom = mat.getScaleX(currentMatrix);
        const originOffsetX = state.origin[0] - controlSize.width / 2;
        const originOffsetY = state.origin[1] - controlSize.height / 2;
        let nextMatrix = mat.translate(currentMatrix, -originOffsetX, -originOffsetY);
        nextMatrix = mat.scale(nextMatrix, nextZoom / currentZoom);
        nextMatrix = mat.translate(nextMatrix, originOffsetX, originOffsetY);
        api.start({
          matrix: boundMatrix(nextMatrix, 'scale', state.last),
          immediate: !state.last
        });
        if (dragLockRef) {
          dragLockRef.current = true;
        }
      }
    }
  }, {
    target: controlRef,
    drag: {
      from: () => [mat.getTranslateX(matrix.get()), mat.getTranslateY(matrix.get())],
      pointer: {
        touch: true
      }
    },
    pinch: {
      from: () => [mat.getScaleX(matrix.get()), 0],
      pointer: {
        touch: true
      }
    }
  });
  const customRendering = typeof imageRender === 'function' && imageRender(props.image, {
    ref: imgRef,
    index: index !== null && index !== void 0 ? index : 0
  });
  return _react.default.createElement("div", {
    className: `${classPrefix}-slide`
  }, _react.default.createElement("div", {
    className: `${classPrefix}-control`,
    ref: controlRef
  }, _react.default.createElement(_web.animated.div, {
    className: `${classPrefix}-image-wrapper`,
    style: {
      matrix
    }
  }, customRendering ? customRendering : _react.default.createElement("img", {
    ref: imgRef,
    src: props.image,
    draggable: false,
    alt: props.image
  }))));
};
exports.Slide = Slide;