"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.initializeMathJax = exports.getGlobal = exports.fixMathElements = exports.fixMathElement = exports["default"] = exports.MathJaxVersion = void 0;

var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));

var _normalization = require("./normalization");

var _SerializedMmlVisitor = require("mathjax-full/js/core/MmlTree/SerializedMmlVisitor");

var _TexError = _interopRequireDefault(require("mathjax-full/js/input/tex/TexError"));

var visitor = new _SerializedMmlVisitor.SerializedMmlVisitor();

var toMMl = function toMMl(node) {
  return visitor.visitTree(node);
};

var NEWLINE_BLOCK_REGEX = /\\embed\{newLine\}\[\]/g;
var NEWLINE_LATEX = '\\newline ';
var mathRenderingKEY = '@pie-lib/math-rendering@2';
var mathRenderingAccessibleKEY = '@pie-lib/math-rendering-accessible@1';
var MathJaxVersion = '3.2.2';
exports.MathJaxVersion = MathJaxVersion;

var getGlobal = function getGlobal() {
  // TODO does it make sense to use version?
  // const key = `${pkg.name}@${pkg.version.split('.')[0]}`;
  // It looks like Ed made this change when he switched from mathjax3 to mathjax-full
  // I think it was supposed to make sure version 1 (using mathjax3) is not used
  // in combination with version 2 (using mathjax-full)
  // TODO higher level wrappers use this instance of math-rendering, and if 2 different instances are used, math rendering is not working
  //  so I will hardcode this for now until a better solution is found
  if (typeof window !== 'undefined') {
    if (!window[mathRenderingAccessibleKEY]) {
      window[mathRenderingAccessibleKEY] = {};
    }

    return window[mathRenderingAccessibleKEY];
  } else {
    return {};
  }
};

exports.getGlobal = getGlobal;

var fixMathElement = function fixMathElement(element) {
  if (element.dataset.mathHandled) {
    return;
  }

  var property = 'innerText';

  if (element.textContent) {
    property = 'textContent';
  }

  if (element[property]) {
    element[property] = (0, _normalization.wrapMath)((0, _normalization.unWrapMath)(element[property]).unwrapped); // because mathquill doesn't understand line breaks, sometimes we end up with custom elements on prompts/rationale/etc.
    // we need to replace the custom embedded elements with valid latex that Mathjax can understand

    element[property] = element[property].replace(NEWLINE_BLOCK_REGEX, NEWLINE_LATEX);
    element.dataset.mathHandled = true;
  }
};

exports.fixMathElement = fixMathElement;

var fixMathElements = function fixMathElements() {
  var el = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : document;
  var mathElements = el.querySelectorAll('[data-latex]');
  mathElements.forEach(function (item) {
    return fixMathElement(item);
  });
};

exports.fixMathElements = fixMathElements;

var adjustMathMLStyle = function adjustMathMLStyle() {
  var el = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : document;
  var nodes = el.querySelectorAll('math');
  nodes.forEach(function (node) {
    return node.setAttribute('displaystyle', 'true');
  });
};

var createPlaceholder = function createPlaceholder(element) {
  var _element$previousSibl;

  if (!element.previousSibling || !((_element$previousSibl = element.previousSibling.classList) !== null && _element$previousSibl !== void 0 && _element$previousSibl.contains('math-placeholder'))) {
    var _element$parentNode;

    // Store the original display style before setting it to 'none'
    element.dataset.originalDisplay = element.style.display || '';
    element.style.display = 'none';
    var placeholder = document.createElement('span');
    placeholder.style.cssText = 'height: 10px; width: 50px; display: inline-block; vertical-align: middle; justify-content: center; background: #fafafa; border-radius: 4px;';
    placeholder.classList.add('math-placeholder');
    (_element$parentNode = element.parentNode) === null || _element$parentNode === void 0 ? void 0 : _element$parentNode.insertBefore(placeholder, element);
  }
};

var removePlaceholdersAndRestoreDisplay = function removePlaceholdersAndRestoreDisplay() {
  document.querySelectorAll('.math-placeholder').forEach(function (placeholder) {
    var _targetElement$datase;

    var targetElement = placeholder.nextElementSibling;

    if (targetElement && ((_targetElement$datase = targetElement.dataset) === null || _targetElement$datase === void 0 ? void 0 : _targetElement$datase.originalDisplay) !== undefined) {
      targetElement.style.display = targetElement.dataset.originalDisplay;
      delete targetElement.dataset.originalDisplay;
    }

    placeholder.remove();
  });
};

var removeExcessMjxContainers = function removeExcessMjxContainers(content) {
  var elements = content.querySelectorAll('[data-latex][data-math-handled="true"]');
  elements.forEach(function (element) {
    var mjxContainers = element.querySelectorAll('mjx-container'); // Check if there are more than one mjx-container children.

    if (mjxContainers.length > 1) {
      for (var i = 1; i < mjxContainers.length; i++) {
        mjxContainers[i].parentNode.removeChild(mjxContainers[i]);
      }
    }
  });
};

var renderContentsWithMathJax = function renderContentsWithMathJax(el) {
  // el sometimes is an array
  // renderMath is used like that in pie-print-support and pie-element-extensions
  // there seems to be no reason for that, however, it's better to handle the case here
  if (el instanceof Array) {
    el.forEach(function (elNode) {
      return renderContentWithMathJax(elNode);
    });
  } else {
    renderContentWithMathJax(el);
  }
};

var renderContentWithMathJax = function renderContentWithMathJax(executeOn) {
  executeOn = executeOn || document.body; // this happens for charting - mark-label; we receive a ref which is not yet ready ( el = { current: null })
  //  we have to fix this in charting

  if (!(executeOn instanceof HTMLElement)) return;
  fixMathElements(executeOn);
  adjustMathMLStyle(executeOn);
  var mathJaxInstance = getGlobal().instance;

  if (mathJaxInstance) {
    // Reset and clear typesetting before processing the new content
    // Reset the tex labels (and automatic equation number).
    mathJaxInstance.texReset(); //  Reset the typesetting system (font caches, etc.)

    mathJaxInstance.typesetClear(); // Use typesetPromise for asynchronous typesetting
    // Using MathJax.typesetPromise() for asynchronous typesetting to handle situations where additional code needs to be loaded (e.g., for certain TeX commands or characters).
    // This ensures typesetting waits for any needed resources to load and complete processing, unlike the synchronous MathJax.typeset() which can't handle such dynamic loading.

    mathJaxInstance.typesetPromise([executeOn]).then(function () {
      try {
        removePlaceholdersAndRestoreDisplay();
        removeExcessMjxContainers(executeOn);
        var updatedDocument = mathJaxInstance.startup.document;
        var list = updatedDocument.math.list;

        for (var item = list.next; (0, _typeof2["default"])(item.data) !== 'symbol'; item = item.next) {
          var mathMl = toMMl(item.data.root);
          var parsedMathMl = mathMl.replaceAll('\n', '');
          item.data.typesetRoot.setAttribute('data-mathml', parsedMathMl);
          item.data.typesetRoot.setAttribute('tabindex', '-1');
        } // If the original input was a string, return the parsed MathML

      } catch (e) {
        console.error('Error post-processing MathJax typesetting:', e.toString());
      } // Clearing the document if needed


      mathJaxInstance.startup.document.clear();
    })["catch"](function (error) {
      //  If there was an internal error, put the message into the output instead
      console.error('Error in typesetting with MathJax:', error);
    });
  }
};

var convertMathJax2ToMathJax3 = function convertMathJax2ToMathJax3() {
  // Make MathJax v2 compatible with v3
  //  https://docs.mathjax.org/en/v3.2-latest/upgrading/v2.html#version-2-compatibility-example
  //  Replace the require command map with a new one that checks for
  //    renamed extensions and converts them to the new names.
  var CommandMap = MathJax._.input.tex.SymbolMap.CommandMap;
  var requireMap = MathJax.config.startup.requireMap;
  var RequireLoad = MathJax._.input.tex.require.RequireConfiguration.RequireLoad;
  var RequireMethods = {
    Require: function Require(parser, name) {
      var required = parser.GetArgument(name);

      if (required.match(/[^_a-zA-Z0-9]/) || required === '') {
        throw new _TexError["default"]('BadPackageName', 'Argument for %1 is not a valid package name', name);
      }

      if (requireMap.hasOwnProperty(required)) {
        required = requireMap[required];
      }

      RequireLoad(parser, required);
    }
  };
  new CommandMap('require', {
    require: 'Require'
  }, RequireMethods); //
  // Add a replacement for MathJax.Callback command
  //

  MathJax.Callback = function (args) {
    if (Array.isArray(args)) {
      if (args.length === 1 && typeof args[0] === 'function') {
        return args[0];
      } else if (typeof args[0] === 'string' && args[1] instanceof Object && typeof args[1][args[0]] === 'function') {
        return Function.bind.apply(args[1][args[0]], args.slice(1));
      } else if (typeof args[0] === 'function') {
        return Function.bind.apply(args[0], [window].concat(args.slice(1)));
      } else if (typeof args[1] === 'function') {
        return Function.bind.apply(args[1], [args[0]].concat(args.slice(2)));
      }
    } else if (typeof args === 'function') {
      return args;
    }

    throw Error("Can't make callback from given data");
  }; //
  // Add a replacement for MathJax.Hub commands
  //


  MathJax.Hub = {
    Queue: function Queue() {
      for (var i = 0, m = arguments.length; i < m; i++) {
        var fn = MathJax.Callback(arguments[i]);
        MathJax.startup.promise = MathJax.startup.promise.then(fn);
      }

      return MathJax.startup.promise;
    },
    Typeset: function Typeset(elements, callback) {
      var promise = MathJax.typesetPromise(elements);

      if (callback) {
        promise = promise.then(callback);
      }

      return promise;
    },
    Register: {
      MessageHook: function MessageHook() {
        console.log('MessageHooks are not supported in version 3');
      },
      StartupHook: function StartupHook() {
        console.log('StartupHooks are not supported in version 3');
      },
      LoadHook: function LoadHook() {
        console.log('LoadHooks are not supported in version 3');
      }
    },
    Config: function Config() {
      console.log('MathJax configurations should be converted for version 3');
    }
  };
};

var initializeMathJax = function initializeMathJax(callback) {
  if (window.mathjaxLoadedP) {
    return;
  }

  var PreviousMathJaxIsUsed = window.MathJax && window.MathJax.version && window.MathJax.version !== MathJaxVersion && window.MathJax.version[0] === '2';
  var texConfig = {
    macros: {
      parallelogram: "\\lower.2em{\\Huge\\unicode{x25B1}}",
      overarc: '\\overparen',
      napprox: '\\not\\approx',
      longdiv: '\\enclose{longdiv}'
    },
    displayMath: [['$$', '$$'], ['\\[', '\\]']]
  };

  if (PreviousMathJaxIsUsed) {
    texConfig.autoload = {
      color: [],
      // don't autoload the color extension
      colorv2: ['color'] // do autoload the colorv2 extension

    };
  } // Create a new promise that resolves when MathJax is ready


  window.mathjaxLoadedP = new Promise(function (resolve) {
    // Set up the MathJax configuration
    window.MathJax = {
      startup: {
        //
        //  Mapping of old extension names to new ones
        //
        requireMap: PreviousMathJaxIsUsed ? {
          AMSmath: 'ams',
          AMSsymbols: 'ams',
          AMScd: 'amscd',
          HTML: 'html',
          noErrors: 'noerrors',
          noUndefined: 'noundefined'
        } : {},
        typeset: false,
        ready: function ready() {
          if (PreviousMathJaxIsUsed) {
            convertMathJax2ToMathJax3();
          }

          var mathjax = MathJax._.mathjax.mathjax;
          var STATE = MathJax._.core.MathItem.STATE;
          var Menu = MathJax._.ui.menu.Menu.Menu;
          var rerender = Menu.prototype.rerender;

          Menu.prototype.rerender = function () {
            var _this = this;

            var start = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : STATE.TYPESET;
            mathjax.handleRetriesFor(function () {
              return rerender.call(_this, start);
            });
          };

          MathJax.startup.defaultReady(); // Set the MathJax instance in the global object

          var globalObj = getGlobal();
          globalObj.instance = MathJax;
          window.mathjaxLoadedComplete = true;
          console.log('MathJax has initialised!', new Date().toString()); // in this file, initializeMathJax is called with a callback that has to be executed when MathJax was loaded

          if (callback) {
            callback();
          } // but previous versions of math-rendering-accessible they're expecting window.mathjaxLoadedP to be a Promise, so we also keep the
          //  resolve here;


          resolve();
        }
      },
      loader: {
        load: ['input/mml'],
        // I just added preLoad: () => {} to prevent the console error: "MathJax.loader.preLoad is not a function",
        //  which is being called because in math-rendering-accessible/render-math we're having this line:
        //  import * as mr from '../math-rendering';
        //  which takes us to: import { AllPackages } from 'mathjax-full/js/input/tex/AllPackages';
        //  which tries to call MathJax.loader.preLoad.
        // Understand that AllPackages is NOT needed in math-rendering-accessible, so it is not a problem if we hardcode this function.
        // The better solution would be for math-rendering-accessible to import math-rendering only IF needed,
        //  but that's actually complicated and could cause other issues.
        preLoad: function preLoad() {},
        // function to call if a component fails to load
        // eslint-disable-next-line no-console
        failed: function failed(error) {
          return console.log("MathJax(".concat(error["package"] || '?', "): ").concat(error.message));
        }
      },
      tex: texConfig,
      chtml: {
        fontURL: 'https://unpkg.com/mathjax-full@3.2.2/ts/output/chtml/fonts/tex-woff-v2',
        displayAlign: 'center'
      },
      customKey: '@pie-lib/math-rendering-accessible@1',
      options: {
        enableEnrichment: true,
        sre: {
          speech: 'deep'
        },
        menuOptions: {
          settings: {
            assistiveMml: true,
            collapsible: false,
            explorer: false
          }
        }
      }
    }; // Load the MathJax script

    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = "https://cdn.jsdelivr.net/npm/mathjax@".concat(MathJaxVersion, "/es5/tex-chtml-full.js");
    script.async = true;
    document.head.appendChild(script); // at this time of the execution, there's no document.body; setTimeout does the trick

    setTimeout(function () {
      if (!window.mathjaxLoadedComplete) {
        var _document, _document$body;

        var mathElements = (_document = document) === null || _document === void 0 ? void 0 : (_document$body = _document.body) === null || _document$body === void 0 ? void 0 : _document$body.querySelectorAll('[data-latex]');
        (mathElements || []).forEach(createPlaceholder);
      }
    });
  });
};

exports.initializeMathJax = initializeMathJax;

var renderMath = function renderMath(el, renderOpts) {
  var usedForMmlOutput = typeof el === 'string';
  var executeOn = document.body;

  if (!usedForMmlOutput) {
    // If math-rendering was not available, then:
    //  If window.mathjaxLoadedComplete, it means that we initialised MathJax using the function from this file,
    //  and it means MathJax is successfully completed, so we can already use it
    if (window.mathjaxLoadedComplete) {
      renderContentsWithMathJax(el);
    } else if (window.mathjaxLoadedP) {
      //  However, because there is a small chance that MathJax was initialised by a previous version of math-rendering-accessible,
      //    we need to keep the old handling method, which means adding the .then.catch on window.mathjaxLoadedP Promise.
      // We still want to set window.mathjaxLoadedComplete, to prevent adding .then.catch after the first initialization
      //  (again, in case MathJax was initialised by a previous math-rendering-accessible version)
      window.mathjaxLoadedP.then(function () {
        window.mathjaxLoadedComplete = true;
        renderContentsWithMathJax(el);
      })["catch"](function (error) {
        return console.error('Error in initializing MathJax:', error);
      });
    }
  } else {
    // Here we're handling the case when renderMath is being called for mmlOutput
    if (window.MathJax && window.mathjaxLoadedP) {
      var div = document.createElement('div');
      div.innerHTML = el;
      executeOn = div;

      try {
        MathJax.texReset();
        MathJax.typesetClear();
        window.MathJax.typeset([executeOn]);
        var updatedDocument = window.MathJax.startup.document;
        var list = updatedDocument.math.list;
        var item = list.next;
        var mathMl = toMMl(item.data.root);
        var parsedMathMl = mathMl.replaceAll('\n', '');
        return parsedMathMl;
      } catch (error) {
        console.error('Error rendering math:', error.message);
      }

      return el;
    }

    return el;
  }
}; // this function calls itself


(function () {
  initializeMathJax(renderContentWithMathJax);
  window[mathRenderingKEY] = {
    instance: {
      Typeset: renderMath
    }
  };
})();

var _default = renderMath;
exports["default"] = _default;
//# sourceMappingURL=render-math.js.map