'use strict';

var Extensions = require('../../extensions/Extensions.js');
var CanvasPool = require('../../rendering/renderers/shared/texture/CanvasPool.js');
var TexturePool = require('../../rendering/renderers/shared/texture/TexturePool.js');
var types = require('../../rendering/renderers/types.js');
var isSafari = require('../../utils/browser/isSafari.js');
var warn = require('../../utils/logging/warn.js');
var PoolGroup = require('../../utils/pool/PoolGroup.js');
var getPo2TextureFromSource = require('../text/utils/getPo2TextureFromSource.js');
var HTMLTextRenderData = require('./HTMLTextRenderData.js');
var extractFontFamilies = require('./utils/extractFontFamilies.js');
var getFontCss = require('./utils/getFontCss.js');
var getSVGUrl = require('./utils/getSVGUrl.js');
var getTemporaryCanvasFromImage = require('./utils/getTemporaryCanvasFromImage.js');
var loadSVGImage = require('./utils/loadSVGImage.js');
var measureHtmlText = require('./utils/measureHtmlText.js');

"use strict";
class HTMLTextSystem {
  constructor(renderer) {
    this._activeTextures = {};
    this._renderer = renderer;
    this._createCanvas = renderer.type === types.RendererType.WEBGPU;
  }
  /**
   * @param options
   * @deprecated Use getTexturePromise instead
   */
  getTexture(options) {
    return this.getTexturePromise(options);
  }
  /**
   * Increases the reference count for a texture.
   * @param text - The HTMLText instance associated with the texture.
   */
  getManagedTexture(text) {
    const textKey = text.styleKey;
    if (this._activeTextures[textKey]) {
      this._increaseReferenceCount(textKey);
      return this._activeTextures[textKey].promise;
    }
    const promise = this._buildTexturePromise(text).then((texture) => {
      this._activeTextures[textKey].texture = texture;
      return texture;
    });
    this._activeTextures[textKey] = {
      texture: null,
      promise,
      usageCount: 1
    };
    return promise;
  }
  /**
   * Gets the current reference count for a texture associated with a text key.
   * @param textKey - The unique key identifying the text style configuration
   * @returns The number of Text instances currently using this texture
   */
  getReferenceCount(textKey) {
    return this._activeTextures[textKey]?.usageCount ?? null;
  }
  _increaseReferenceCount(textKey) {
    this._activeTextures[textKey].usageCount++;
  }
  /**
   * Decreases the reference count for a texture.
   * If the count reaches zero, the texture is cleaned up.
   * @param textKey - The key associated with the HTMLText instance.
   */
  decreaseReferenceCount(textKey) {
    const activeTexture = this._activeTextures[textKey];
    if (!activeTexture)
      return;
    activeTexture.usageCount--;
    if (activeTexture.usageCount === 0) {
      if (activeTexture.texture) {
        this._cleanUp(activeTexture.texture);
      } else {
        activeTexture.promise.then((texture) => {
          activeTexture.texture = texture;
          this._cleanUp(activeTexture.texture);
        }).catch(() => {
          warn.warn("HTMLTextSystem: Failed to clean texture");
        });
      }
      this._activeTextures[textKey] = null;
    }
  }
  /**
   * Returns a promise that resolves to a texture for the given HTMLText options.
   * @param options - The options for the HTMLText.
   * @returns A promise that resolves to a Texture.
   */
  getTexturePromise(options) {
    return this._buildTexturePromise(options);
  }
  async _buildTexturePromise(options) {
    const { text, style, resolution, textureStyle } = options;
    const htmlTextData = PoolGroup.BigPool.get(HTMLTextRenderData.HTMLTextRenderData);
    const fontFamilies = extractFontFamilies.extractFontFamilies(text, style);
    const fontCSS = await getFontCss.getFontCss(fontFamilies);
    const measured = measureHtmlText.measureHtmlText(text, style, fontCSS, htmlTextData);
    const width = Math.ceil(Math.ceil(Math.max(1, measured.width) + style.padding * 2) * resolution);
    const height = Math.ceil(Math.ceil(Math.max(1, measured.height) + style.padding * 2) * resolution);
    const image = htmlTextData.image;
    const uvSafeOffset = 2;
    image.width = (width | 0) + uvSafeOffset;
    image.height = (height | 0) + uvSafeOffset;
    const svgURL = getSVGUrl.getSVGUrl(text, style, resolution, fontCSS, htmlTextData);
    await loadSVGImage.loadSVGImage(image, svgURL, isSafari.isSafari() && fontFamilies.length > 0);
    const resource = image;
    let canvasAndContext;
    if (this._createCanvas) {
      canvasAndContext = getTemporaryCanvasFromImage.getTemporaryCanvasFromImage(image, resolution);
    }
    const texture = getPo2TextureFromSource.getPo2TextureFromSource(
      canvasAndContext ? canvasAndContext.canvas : resource,
      image.width - uvSafeOffset,
      image.height - uvSafeOffset,
      resolution
    );
    if (textureStyle)
      texture.source.style = textureStyle;
    if (this._createCanvas) {
      this._renderer.texture.initSource(texture.source);
      CanvasPool.CanvasPool.returnCanvasAndContext(canvasAndContext);
    }
    PoolGroup.BigPool.return(htmlTextData);
    return texture;
  }
  returnTexturePromise(texturePromise) {
    texturePromise.then((texture) => {
      this._cleanUp(texture);
    }).catch(() => {
      warn.warn("HTMLTextSystem: Failed to clean texture");
    });
  }
  _cleanUp(texture) {
    TexturePool.TexturePool.returnTexture(texture, true);
    texture.source.resource = null;
    texture.source.uploadMethodId = "unknown";
  }
  destroy() {
    this._renderer = null;
    for (const key in this._activeTextures) {
      if (this._activeTextures[key])
        this.returnTexturePromise(this._activeTextures[key].promise);
    }
    this._activeTextures = null;
  }
}
/** @ignore */
HTMLTextSystem.extension = {
  type: [
    Extensions.ExtensionType.WebGLSystem,
    Extensions.ExtensionType.WebGPUSystem,
    Extensions.ExtensionType.CanvasSystem
  ],
  name: "htmlText"
};

exports.HTMLTextSystem = HTMLTextSystem;
//# sourceMappingURL=HTMLTextSystem.js.map
