"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.watermarkProps = exports.default = void 0;
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
var _vue = require("vue");
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _type = require("../_util/type");
var _propsUtil = require("../_util/props-util");
var _internal = require("../theme/internal");
var _utils = require("./utils");
var _useClips = _interopRequireWildcard(require("./useClips"));
var _useSingletonCache = _interopRequireDefault(require("./useSingletonCache"));
var _useRafDebounce = _interopRequireDefault(require("./useRafDebounce"));
var _useWatermark = _interopRequireDefault(require("./useWatermark"));
var _useMutateObserver = require("./useMutateObserver");
var _context = require("./context");
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 watermarkProps = () => ({
  zIndex: Number,
  rotate: Number,
  width: Number,
  height: Number,
  image: String,
  content: (0, _type.someType)([String, Array]),
  font: (0, _type.objectType)(),
  rootClassName: String,
  gap: (0, _type.arrayType)(),
  offset: (0, _type.arrayType)(),
  inherit: Boolean,
  onRemove: Function
});
exports.watermarkProps = watermarkProps;
function getSizeDiff(prev, next) {
  return prev.size === next.size ? prev : next;
}
const fixedStyle = {
  position: 'relative',
  overflow: 'hidden'
};
const Watermark = (0, _vue.defineComponent)({
  name: 'AWatermark',
  inheritAttrs: false,
  props: (0, _propsUtil.initDefaultProps)(watermarkProps(), {
    zIndex: 9,
    rotate: -22,
    font: {},
    gap: [100, 100],
    inherit: true
  }),
  setup(props, {
    attrs,
    slots
  }) {
    const [, token] = (0, _internal.useToken)();
    const fontSize = (0, _vue.computed)(() => {
      var _a, _b;
      return (_b = (_a = props.font) === null || _a === void 0 ? void 0 : _a.fontSize) !== null && _b !== void 0 ? _b : token.value.fontSizeLG;
    });
    const fontWeight = (0, _vue.computed)(() => {
      var _a, _b;
      return (_b = (_a = props.font) === null || _a === void 0 ? void 0 : _a.fontWeight) !== null && _b !== void 0 ? _b : 'normal';
    });
    const fontStyle = (0, _vue.computed)(() => {
      var _a, _b;
      return (_b = (_a = props.font) === null || _a === void 0 ? void 0 : _a.fontStyle) !== null && _b !== void 0 ? _b : 'normal';
    });
    const fontFamily = (0, _vue.computed)(() => {
      var _a, _b;
      return (_b = (_a = props.font) === null || _a === void 0 ? void 0 : _a.fontFamily) !== null && _b !== void 0 ? _b : 'sans-serif';
    });
    const color = (0, _vue.computed)(() => {
      var _a, _b;
      return (_b = (_a = props.font) === null || _a === void 0 ? void 0 : _a.color) !== null && _b !== void 0 ? _b : token.value.colorFill;
    });
    const textAlign = (0, _vue.computed)(() => {
      var _a;
      return (_a = props.font.textAlign) !== null && _a !== void 0 ? _a : 'center';
    });
    const gapX = (0, _vue.computed)(() => {
      var _a, _b;
      return (_b = (_a = props.gap) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : 100;
    });
    const gapY = (0, _vue.computed)(() => {
      var _a, _b;
      return (_b = (_a = props.gap) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : 100;
    });
    const gapXCenter = (0, _vue.computed)(() => gapX.value / 2);
    const gapYCenter = (0, _vue.computed)(() => gapY.value / 2);
    const offsetLeft = (0, _vue.computed)(() => {
      var _a, _b;
      return (_b = (_a = props.offset) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : gapXCenter.value;
    });
    const offsetTop = (0, _vue.computed)(() => {
      var _a, _b;
      return (_b = (_a = props.offset) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : gapYCenter.value;
    });
    const markStyle = (0, _vue.computed)(() => {
      var _a;
      const markStyle = {
        zIndex: (_a = props.zIndex) !== null && _a !== void 0 ? _a : 9,
        position: 'absolute',
        left: 0,
        top: 0,
        width: '100%',
        height: '100%',
        pointerEvents: 'none',
        backgroundRepeat: 'repeat'
      };
      /** Calculate the style of the offset */
      let positionLeft = offsetLeft.value - gapXCenter.value;
      let positionTop = offsetTop.value - gapYCenter.value;
      if (positionLeft > 0) {
        markStyle.left = `${positionLeft}px`;
        markStyle.width = `calc(100% - ${positionLeft}px)`;
        positionLeft = 0;
      }
      if (positionTop > 0) {
        markStyle.top = `${positionTop}px`;
        markStyle.height = `calc(100% - ${positionTop}px)`;
        positionTop = 0;
      }
      markStyle.backgroundPosition = `${positionLeft}px ${positionTop}px`;
      return markStyle;
    });
    const container = (0, _vue.ref)(null);
    const subElements = (0, _vue.ref)(new Set());
    const targetElements = (0, _vue.computed)(() => {
      const list = container.value ? [container.value] : [];
      return [...list, ...Array.from(subElements.value)];
    });
    // ============================ Content =============================
    /**
     * Get the width and height of the watermark. The default values are as follows
     * Image: [120, 64]; Content: It's calculated by content;
     */
    const getMarkSize = ctx => {
      var _a, _b;
      let defaultWidth = 120;
      let defaultHeight = 64;
      if (!props.image && ctx.measureText) {
        ctx.font = `${Number(fontSize.value)}px ${fontFamily.value}`;
        const contents = (0, _utils.toList)(props.content);
        const sizes = contents.map(item => {
          const metrics = ctx.measureText(item);
          return [metrics.width, metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent];
        });
        defaultWidth = Math.ceil(Math.max(...sizes.map(size => size[0])));
        defaultHeight = Math.ceil(Math.max(...sizes.map(size => size[1]))) * contents.length + (contents.length - 1) * _useClips.FontGap;
      }
      return [(_a = props.width) !== null && _a !== void 0 ? _a : defaultWidth, (_b = props.height) !== null && _b !== void 0 ? _b : defaultHeight];
    };
    const getClips = (0, _useClips.default)();
    const getClipsCache = (0, _useSingletonCache.default)();
    const watermarkInfo = (0, _vue.ref)(null);
    // Generate new Watermark content
    const renderWatermark = () => {
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      if (ctx) {
        const ratio = (0, _utils.getPixelRatio)();
        const [markWidth, markHeight] = getMarkSize(ctx);
        const drawCanvas = drawContent => {
          const params = [drawContent || '', props.rotate, ratio, markWidth, markHeight, {
            color: color.value,
            fontSize: fontSize.value,
            fontStyle: fontStyle.value,
            fontWeight: fontWeight.value,
            fontFamily: fontFamily.value,
            textAlign: textAlign.value
          }, gapX.value, gapY.value];
          const [nextClips, clipWidth] = getClipsCache(params, () => getClips(...params));
          watermarkInfo.value = [nextClips, clipWidth];
        };
        if (props.image) {
          const img = new Image();
          img.onload = () => {
            drawCanvas(img);
          };
          img.onerror = () => {
            drawCanvas(props.content);
          };
          img.crossOrigin = 'anonymous';
          img.referrerPolicy = 'no-referrer';
          img.src = props.image;
        } else {
          drawCanvas(props.content);
        }
      }
    };
    const syncWatermark = (0, _useRafDebounce.default)(renderWatermark);
    // ============================= Effect =============================
    // Append watermark to the container
    const [appendWatermark, removeWatermark, isWatermarkEle] = (0, _useWatermark.default)(markStyle, props.onRemove);
    (0, _vue.watch)([() => watermarkInfo.value, () => targetElements.value], ([rawWatermarkInfo, rawTargetElements]) => {
      if (rawWatermarkInfo) {
        rawTargetElements.forEach(holder => {
          appendWatermark(rawWatermarkInfo[0], rawWatermarkInfo[1], holder);
        });
      }
    });
    // ============================ Observe =============================
    const onMutate = mutations => {
      const mergedStyle = (0, _extends2.default)((0, _extends2.default)({}, fixedStyle), attrs.style || {});
      mutations.forEach(mutation => {
        if ((0, _utils.reRendering)(mutation, isWatermarkEle)) {
          syncWatermark();
        } else if (mutation.target === container.value && mutation.attributeName === 'style') {
          // We've only force container not modify.
          // Not consider nest case.
          const keyStyles = Object.keys(fixedStyle);
          for (let i = 0; i < keyStyles.length; i += 1) {
            const key = keyStyles[i];
            const oriValue = mergedStyle[key];
            const currentValue = container.value.style[key];
            if (oriValue && oriValue !== currentValue) {
              container.value.style[key] = oriValue;
            }
          }
        }
      });
    };
    (0, _useMutateObserver.useMutateObserver)(targetElements, onMutate);
    (0, _vue.watch)([() => props.rotate, () => props.zIndex, () => props.width, () => props.height, () => props.image, () => props.content, color, fontSize, fontWeight, fontStyle, fontFamily, textAlign, gapX, gapY, offsetLeft, offsetTop], () => {
      syncWatermark();
    }, {
      flush: 'post',
      immediate: true
    });
    if (props.inherit) {
      (0, _context.useProvideWatermark)({
        add(ele) {
          const clone = new Set(subElements.value);
          clone.add(ele);
          subElements.value = clone;
        },
        remove(ele) {
          removeWatermark(ele);
          const clone = new Set(subElements.value);
          clone.delete(ele);
          subElements.value = getSizeDiff(subElements.value, clone);
        }
      });
    }
    return () => {
      var _a;
      return (0, _vue.createVNode)("div", (0, _objectSpread2.default)((0, _objectSpread2.default)({}, attrs), {}, {
        "ref": container,
        "class": [attrs.class, props.rootClassName],
        "style": [fixedStyle, attrs.style]
      }), [(_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)]);
    };
  }
});
var _default = exports.default = (0, _type.withInstall)(Watermark);