/******************************************************************************/
/*                                                                            */
/* numberFigures.js - Number figures and code listings for paged.js documents */
/* ========================================================================== */
/*                                                                            */
/* This program is part of the Rexx Parser package                            */
/* [See https://rexx.epbcn.com/rexx-parser/]                                  */
/*                                                                            */
/* Copyright (c) 2026 Josep Maria Blasco <josep.maria.blasco@epbcn.com>       */
/*                                                                            */
/* License: Apache License 2.0 (https://www.apache.org/licenses/LICENSE-2.0)  */
/*                                                                            */
/* Version history:                                                           */
/*                                                                            */
/* Date     Version Details                                                   */
/* -------- ------- --------------------------------------------------------- */
/* 20260310    0.5  First version.                                            */
/* 20260312         Add listing caption-position and custom label support     */
/* 20260312         Add figure caption-position and custom label support      */
/*                                                                            */
/******************************************************************************/

/*
  Purpose:

  This script numbers figures and code listings in paged.js documents.

  It handles three cases:

  1. Pandoc images with captions: <figure><img ...><figcaption>...</figcaption></figure>
     These are numbered as "Figure 1", "Figure 2", etc.

  2. Pandoc non-Rexx code blocks with captions:
       <div class="sourceCode" data-caption="..."><pre>...</pre></div>
     These are wrapped in a <figure class="listing"> and numbered
     as "Listing 1", "Listing 2", etc.

  3. Rexx code blocks with captions (generated by FencedCode.cls):
       <div class="highlight-rexx-..." data-caption="..."><pre>...</pre></div>
     These are also wrapped in a <figure class="listing"> and numbered
     as "Listing 1", "Listing 2", etc.

  The labels are localized: the script reads the lang attribute of the
  <html> element to determine the language.

  Figures and listings are numbered independently.

  Numbering is optional: if a caption is present but the document does
  not request numbering, the caption is displayed without a number.
  Numbering is activated by adding the class "number-figures" to
  div.content.

  Dual-mode operation (same pattern as createToc.js and numberSections.js):

  - If Paged is available (Print pipeline), the processing is done
    via a beforeParsed handler.

  - If Paged is not available (Render pipeline via pagedjs-cli),
    the processing is done immediately as an IIFE.
*/

(function() {

  /* -----------------------------------------------------------------------*/
  /* Localized labels                                                       */
  /* -----------------------------------------------------------------------*/

  function getLabels(content) {
    var root = content.documentElement
            || (content.ownerDocument && content.ownerDocument.documentElement)
            || document.documentElement;
    var lang = (root && root.getAttribute("lang")) || "en";
    lang = lang.toLowerCase().substring(0, 2);

    var figureLabels = {
      "en": "Figure",    "es": "Figura",   "fr": "Figure",
      "de": "Abbildung", "it": "Figura",   "pt": "Figura",
      "nl": "Figuur",    "ca": "Figura",   "gl": "Figura"
    };
    var listingLabels = {
      "en": "Listing",   "es": "Listado",  "fr": "Listing",
      "de": "Listing",   "it": "Listato",  "pt": "Listagem",
      "nl": "Listing",   "ca": "Llistat",  "gl": "Listaxe"
    };

    return {
      figure:  figureLabels[lang]  || "Figure",
      listing: listingLabels[lang] || "Listing"
    };
  }

  /* -----------------------------------------------------------------------*/
  /* numberFigures — the core logic                                         */
  /* -----------------------------------------------------------------------*/

  function numberFigures(content) {

    var container = content.querySelector("div.content");
    if (!container) return;

    var doNumber = container.classList.contains("number-figures");
    var labels   = getLabels(content);

    /* Read listing options from data-* attributes on div.content         */
    var listingPosition = container.getAttribute("data-listing-caption-position")
                       || "above";
    var listingLabel    = container.getAttribute("data-listing-label")
                       || "";

    /* Read figure options from data-* attributes on div.content          */
    var figurePosition  = container.getAttribute("data-figure-caption-position")
                       || "below";
    var figureLabel     = container.getAttribute("data-figure-label")
                       || "";

    var figureCounter  = 0;
    var listingCounter = 0;

    /* -----------------------------------------------------------------  */
    /* Step 1: Wrap code blocks that have data-caption in <figure>        */
    /*         This covers both Pandoc sourceCode and Rexx highlight divs */
    /* -----------------------------------------------------------------  */

    var captionedDivs = container.querySelectorAll("div[data-caption]");

    for (var i = 0; i < captionedDivs.length; i++) {
      var div = captionedDivs[i];
      var captionText = div.getAttribute("data-caption");
      if (!captionText) continue;

      /* Wrap in <figure class="listing">                                */
      var figure = document.createElement("figure");
      figure.className = "listing";
      div.parentNode.insertBefore(figure, div);
      figure.appendChild(div);

      /* Create <figcaption>                                              */
      var figcaption = document.createElement("figcaption");

      listingCounter++;
      if (doNumber) {
        var theLabel = listingLabel || labels.listing;
        var numSpan = document.createElement("span");
        numSpan.className = "figure-number";
        numSpan.textContent = theLabel + "\u00A0" + listingCounter
                            + ":\u2002";
        figcaption.appendChild(numSpan);
      }

      figcaption.appendChild(document.createTextNode(captionText));

      /* Position: above (before code) or below (after code)             */
      if (listingPosition === "below")
        figure.appendChild(figcaption);
      else
        figure.insertBefore(figcaption, div);

      /* Remove the data-caption attribute (it has been consumed)        */
      div.removeAttribute("data-caption");
    }

    /* -----------------------------------------------------------------  */
    /* Step 2: Number existing <figure> elements (Pandoc images)          */
    /*         These already have <figcaption> — just prepend the number  */
    /*         Pandoc places <figcaption> after <img> (below).  If the    */
    /*         author requests "above", move it before the <img>.         */
    /* -----------------------------------------------------------------  */

    var figures = container.querySelectorAll("figure:not(.listing)");

    for (var j = 0; j < figures.length; j++) {
      var fig = figures[j];
      var fc  = fig.querySelector("figcaption");
      if (!fc) continue;

      figureCounter++;
      if (doNumber) {
        var theFigLabel = figureLabel || labels.figure;
        var numSpan = document.createElement("span");
        numSpan.className = "figure-number";
        numSpan.textContent = theFigLabel + "\u00A0" + figureCounter
                            + ":\u2002";
        fc.insertBefore(numSpan, fc.firstChild);
      }

      /* Position: move figcaption above the image if requested          */
      if (figurePosition === "above")
        fig.insertBefore(fc, fig.firstChild);
    }
  }

  /* -----------------------------------------------------------------------*/
  /* Mode selection                                                         */
  /* -----------------------------------------------------------------------*/

  if (typeof Paged !== "undefined") {

    /* Print pipeline — register a paged.js handler                        */

    class FigureNumberHandler extends Paged.Handler {
      constructor(chunker, polisher, caller) {
        super(chunker, polisher, caller);
      }
      beforeParsed(content) {
        numberFigures(content);
      }
    }

    Paged.registerHandlers(FigureNumberHandler);

  } else {

    /* Render pipeline — number figures immediately                        */

    numberFigures(document);

  }

})();