Source: known_substance.js

/**
 * Classes for handling substance lookup functionality.
 *
 * @license BSD, see LICENSE.md.
 */

/**
 * Represents a known substance with its name and GWP value.
 */
class KnownSubstance {
  /**
   * Creates a new KnownSubstance.
   *
   * @param {string} name - The substance name.
   * @param {number} gwp - The GWP value as a number.
   */
  constructor(name, gwp) {
    const self = this;
    self._name = name;
    self._gwp = gwp;
  }

  /**
   * Gets the substance name.
   *
   * @returns {string} The substance name.
   */
  getName() {
    const self = this;
    return self._name;
  }

  /**
   * Gets the GWP value.
   *
   * @returns {number} The GWP value as a number.
   */
  getGwp() {
    const self = this;
    return self._gwp;
  }
}

/**
 * Manages a library of known substances with flexible name matching.
 */
class SubstanceLibraryKeeper {
  /**
   * Creates a new SubstanceLibraryKeeper.
   *
   * @param {Object} jsonData - JSON object mapping substance names to GWP values.
   */
  constructor(jsonData) {
    const self = this;
    self._substanceMap = new Map();

    // Initialize the map with normalized keys
    for (const [name, gwp] of Object.entries(jsonData)) {
      const normalizedKey = self._getSubstanceKey(name);
      self._substanceMap.set(normalizedKey, new KnownSubstance(name, gwp));
    }
  }

  /**
   * Gets a substance by name using flexible matching.
   *
   * @param {string} name - The substance name to look up.
   * @returns {KnownSubstance|null} The substance if found, null otherwise.
   */
  getSubstance(name) {
    const self = this;
    if (!name) {
      return null;
    }

    const normalizedKey = self._getSubstanceKey(name.trim());
    return self._substanceMap.get(normalizedKey) || null;
  }

  /**
   * Normalizes substance names for flexible matching.
   * Converts to lowercase and removes whitespace and punctuation including hyphens and colons.
   *
   * @param {string} name - The substance name to normalize.
   * @returns {string} The normalized key for lookup.
   * @private
   */
  _getSubstanceKey(name) {
    const self = this;
    return name.toLowerCase().replace(/[\s\-_\.,:\(\)\[\]]/g, "");
  }
}

/**
 * Presenter for GWP lookup functionality in the UI.
 */
class GwpLookupPresenter {
  /**
   * Creates a new GwpLookupPresenter.
   *
   * @param {HTMLElement} lookupLink - The lookup link element.
   * @param {HTMLElement} substanceInput - The substance name input element.
   * @param {HTMLElement} ghgInput - The GHG value input element.
   * @param {HTMLElement} ghgUnitsInput - The GHG units select element.
   * @param {string} jsonPath - Path to the JSON data file.
   */
  constructor(lookupLink, substanceInput, ghgInput, ghgUnitsInput, jsonPath) {
    const self = this;
    self._lookupLink = lookupLink;
    self._substanceInput = substanceInput;
    self._ghgInput = ghgInput;
    self._ghgUnitsInput = ghgUnitsInput;
    self._jsonPath = jsonPath;
    self._libraryKeeper = null;

    // Set up click handler
    self._lookupLink.addEventListener("click", (event) => {
      self._onLookupClick(event);
    });
  }

  /**
   * Gets a substance by name (public interface for testing).
   *
   * @param {string} name - The substance name to look up.
   * @returns {KnownSubstance|null} The substance if found and library is loaded.
   */
  getSubstance(name) {
    const self = this;
    return self._libraryKeeper ? self._libraryKeeper.getSubstance(name) : null;
  }

  /**
   * Handles lookup link clicks.
   *
   * @param {Event} event - The click event.
   * @private
   */
  async _onLookupClick(event) {
    const self = this;
    event.preventDefault();

    try {
      const substanceName = self._substanceInput.value.trim();

      if (!substanceName) {
        self._showAlert("Please enter a substance name before looking up GWP values.");
        return Promise.resolve();
      }

      // Load library if not already loaded
      if (!self._libraryKeeper) {
        await self._loadLibrary();
      }

      const substance = self._libraryKeeper.getSubstance(substanceName);

      if (substance) {
        // Update the GHG input with the found value
        const gwpValue = substance.getGwp();
        self._ghgInput.value = isNaN(gwpValue) ? "" : gwpValue.toString();

        // Ensure units are set to kgCO2e / kg (which matches our data)
        self._ghgUnitsInput.value = "kgCO2e / kg";

        self._showAlert(
          `Found GWP value for ${substance.getName()}: ${substance.getGwp()} kgCO2e/kg. ` +
          "Please confirm this value is correct and current for your specific simulation.",
        );
      } else {
        self._showAlert(
          `No GWP value found for '${substanceName}'. Please enter the value manually ` +
          "or check the substance name spelling.",
        );
      }
    } catch (error) {
      console.error("Error during GWP lookup:", error);
      self._showAlert(
        "Error loading substance database. Please try again or enter the value manually.",
      );
    }
  }

  /**
   * Loads the substance library from JSON data.
   *
   * @returns {Promise<void>} Promise that resolves when library is loaded.
   * @private
   */
  async _loadLibrary() {
    const self = this;
    const response = await fetch(self._jsonPath);
    if (!response.ok) {
      throw new Error(`Failed to load substance data: ${response.status}`);
    }

    const jsonData = await response.json();
    self._libraryKeeper = new SubstanceLibraryKeeper(jsonData);
  }

  /**
   * Shows an alert message to the user.
   *
   * @param {string} message - The message to display.
   * @private
   */
  _showAlert(message) {
    const self = this;
    alert(message);
  }
}

export {KnownSubstance, SubstanceLibraryKeeper, GwpLookupPresenter};