"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const dom = require("../../dom.js");
const async = require("../../../common/async.js");
const cancellation = require("../../../common/cancellation.js");
const htmlContent = require("../../../common/htmlContent.js");
const iconLabels = require("../../../common/iconLabels.js");
const lifecycle = require("../../../common/lifecycle.js");
const types = require("../../../common/types.js");
const nls = require("../../../../nls.js");
var __awaiter = globalThis && globalThis.__awaiter || function(thisArg, _arguments, P, generator) {
  function adopt(value) {
    return value instanceof P ? value : new P(function(resolve) {
      resolve(value);
    });
  }
  return new (P || (P = Promise))(function(resolve, reject) {
    function fulfilled(value) {
      try {
        step(generator.next(value));
      } catch (e) {
        reject(e);
      }
    }
    function rejected(value) {
      try {
        step(generator["throw"](value));
      } catch (e) {
        reject(e);
      }
    }
    function step(result) {
      result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
    }
    step((generator = generator.apply(thisArg, _arguments || [])).next());
  });
};
function setupNativeHover(htmlElement, tooltip) {
  if (types.isString(tooltip)) {
    htmlElement.title = iconLabels.stripIcons(tooltip);
  } else if (tooltip === null || tooltip === void 0 ? void 0 : tooltip.markdownNotSupportedFallback) {
    htmlElement.title = tooltip.markdownNotSupportedFallback;
  } else {
    htmlElement.removeAttribute("title");
  }
}
class UpdatableHoverWidget {
  constructor(hoverDelegate, target, fadeInAnimation) {
    this.hoverDelegate = hoverDelegate;
    this.target = target;
    this.fadeInAnimation = fadeInAnimation;
  }
  update(content, focus) {
    var _a;
    return __awaiter(this, void 0, void 0, function* () {
      if (this._cancellationTokenSource) {
        this._cancellationTokenSource.dispose(true);
        this._cancellationTokenSource = void 0;
      }
      if (this.isDisposed) {
        return;
      }
      let resolvedContent;
      if (content === void 0 || types.isString(content) || content instanceof HTMLElement) {
        resolvedContent = content;
      } else if (!types.isFunction(content.markdown)) {
        resolvedContent = (_a = content.markdown) !== null && _a !== void 0 ? _a : content.markdownNotSupportedFallback;
      } else {
        if (!this._hoverWidget) {
          this.show(nls.localize("iconLabel.loading", "Loading..."), focus);
        }
        this._cancellationTokenSource = new cancellation.CancellationTokenSource();
        const token = this._cancellationTokenSource.token;
        resolvedContent = yield content.markdown(token);
        if (resolvedContent === void 0) {
          resolvedContent = content.markdownNotSupportedFallback;
        }
        if (this.isDisposed || token.isCancellationRequested) {
          return;
        }
      }
      this.show(resolvedContent, focus);
    });
  }
  show(content, focus) {
    const oldHoverWidget = this._hoverWidget;
    if (this.hasContent(content)) {
      const hoverOptions = {
        content,
        target: this.target,
        showPointer: this.hoverDelegate.placement === "element",
        hoverPosition: 2,
        skipFadeInAnimation: !this.fadeInAnimation || !!oldHoverWidget
        // do not fade in if the hover is already showing
      };
      this._hoverWidget = this.hoverDelegate.showHover(hoverOptions, focus);
    }
    oldHoverWidget === null || oldHoverWidget === void 0 ? void 0 : oldHoverWidget.dispose();
  }
  hasContent(content) {
    if (!content) {
      return false;
    }
    if (htmlContent.isMarkdownString(content)) {
      return !!content.value;
    }
    return true;
  }
  get isDisposed() {
    var _a;
    return (_a = this._hoverWidget) === null || _a === void 0 ? void 0 : _a.isDisposed;
  }
  dispose() {
    var _a, _b;
    (_a = this._hoverWidget) === null || _a === void 0 ? void 0 : _a.dispose();
    (_b = this._cancellationTokenSource) === null || _b === void 0 ? void 0 : _b.dispose(true);
    this._cancellationTokenSource = void 0;
  }
}
function setupCustomHover(hoverDelegate, htmlElement, content) {
  let hoverPreparation;
  let hoverWidget;
  const hideHover = (disposeWidget, disposePreparation) => {
    var _a;
    if (disposeWidget) {
      hoverWidget === null || hoverWidget === void 0 ? void 0 : hoverWidget.dispose();
      hoverWidget = void 0;
    }
    if (disposePreparation) {
      hoverPreparation === null || hoverPreparation === void 0 ? void 0 : hoverPreparation.dispose();
      hoverPreparation = void 0;
    }
    (_a = hoverDelegate.onDidHideHover) === null || _a === void 0 ? void 0 : _a.call(hoverDelegate);
  };
  const triggerShowHover = (delay, focus, target) => {
    return new async.TimeoutTimer(() => __awaiter(this, void 0, void 0, function* () {
      if (!hoverWidget || hoverWidget.isDisposed) {
        hoverWidget = new UpdatableHoverWidget(hoverDelegate, target || htmlElement, delay > 0);
        yield hoverWidget.update(content, focus);
      }
    }), delay);
  };
  const onMouseOver = () => {
    if (hoverPreparation) {
      return;
    }
    const toDispose = new lifecycle.DisposableStore();
    const onMouseLeave = (e) => hideHover(false, e.fromElement === htmlElement);
    toDispose.add(dom.addDisposableListener(htmlElement, dom.EventType.MOUSE_LEAVE, onMouseLeave, true));
    const onMouseDown = () => hideHover(true, true);
    toDispose.add(dom.addDisposableListener(htmlElement, dom.EventType.MOUSE_DOWN, onMouseDown, true));
    const target = {
      targetElements: [htmlElement],
      dispose: () => {
      }
    };
    if (hoverDelegate.placement === void 0 || hoverDelegate.placement === "mouse") {
      const onMouseMove = (e) => target.x = e.x + 10;
      toDispose.add(dom.addDisposableListener(htmlElement, dom.EventType.MOUSE_MOVE, onMouseMove, true));
    }
    toDispose.add(triggerShowHover(hoverDelegate.delay, false, target));
    hoverPreparation = toDispose;
  };
  const mouseOverDomEmitter = dom.addDisposableListener(htmlElement, dom.EventType.MOUSE_OVER, onMouseOver, true);
  const hover = {
    show: (focus) => {
      hideHover(false, true);
      triggerShowHover(0, focus);
    },
    hide: () => {
      hideHover(true, true);
    },
    update: (newContent) => __awaiter(this, void 0, void 0, function* () {
      content = newContent;
      yield hoverWidget === null || hoverWidget === void 0 ? void 0 : hoverWidget.update(content);
    }),
    dispose: () => {
      mouseOverDomEmitter.dispose();
      hideHover(true, true);
    }
  };
  return hover;
}
exports.setupCustomHover = setupCustomHover;
exports.setupNativeHover = setupNativeHover;
