% \iffalse meta-comment
%
%% File: tagpdf-mc-shared.dtx
%
% Copyright (C) 2019-2023 Ulrike Fischer
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file
%
%    https://www.latex-project.org/lppl.txt
%
% This file is part of the "tagpdf bundle" (The Work in LPPL)
% and all files in that bundle must be distributed together.
%
% -----------------------------------------------------------------------
%
% The development version of the bundle can be found at
%
%    https://github.com/u-fischer/tagpdf
%
% for those people who are interested.
%<*driver>
\DocumentMetadata{}
\documentclass{l3doc}
\usepackage{array,booktabs,caption}
\hypersetup{pdfauthor=Ulrike Fischer,
 pdftitle=tagpdf-mc module (tagpdf)}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
% \title{^^A
%   The \pkg{tagpdf-mc-shared} module\\ Code related to Marked Content (mc-chunks), code shared by all modes  ^^A
%   \\ Part of the tagpdf package
% }
%
% \author{^^A
%  Ulrike Fischer\thanks
%    {^^A
%      E-mail:
%        \href{mailto:fischer@troubleshooting-tex.de}
%          {fischer@troubleshooting-tex.de}^^A
%    }^^A
% }
%
% \date{Version 0.98k, released 2023-08-04}
% \maketitle
% \begin{documentation}
% \section{Public Commands}
%  \begin{function}{\tag_mc_begin:n,\tag_mc_end:}
%   \begin{syntax}
%     \cs{tag_mc_begin:n}\Arg{key-values}\\
%     \cs{tag_mc_end:}
%   \end{syntax}
% These commands insert the end code of the marked content.
% They don't end a group and in generic mode it doesn't matter
% if they are in another group as the starting commands.
% In generic mode both commands check if they are correctly nested
% and issue a warning if not.
% \end{function}
%
%  \begin{function}{\tag_mc_use:n}
%   \begin{syntax}
%     \cs{tag_mc_use:n}\Arg{label}
%   \end{syntax}
% These command allow to record a marked content that was stashed away before
% into the current structure. A marked content can be used only once --
% the command will issue a warning if an mc is use a second time.
% \end{function}
%
%  \begin{function}[added = 2019-11-20]
%   {
%     \tag_mc_artifact_group_begin:n, \tag_mc_artifact_group_end:
%   }
%   \begin{syntax}
%     \cs{tag_mc_artifact_group_begin:n} \Arg{name}\\
%     \cs{tag_mc_artifact_group_end:}
%   \end{syntax}
%   This command pair creates a group with an artifact marker at the begin
%   and the end. Inside the group the tagging commands are disabled.
%   It allows to mark a complete region as artifact without having to worry
%   about user commands with tagging commands.
%   \meta{name} should be a value allowed also for the |artifact| key.
%   It pushes and pops mc-chunks at the begin and end.
%   TODO: document is in tagpdf.tex
%   \end{function}
%
%  \begin{function}[added = 2021-04-22]
%   {
%     \tag_mc_end_push:, \tag_mc_begin_pop:n
%   }
%   \begin{syntax}
%     \cs{tag_mc_end_push:} \\
%     \cs{tag_mc_begin_pop:n}\Arg{key-values}
%   \end{syntax}
% If there is an open mc chunk,
% \cs{tag_mc_end_push:} ends it and pushes its tag of the (global) stack.
% If there is no open chunk, it puts $-1$ on the stack (for debugging)
% \cs{tag_mc_begin_pop:n} removes a value from the stack. If it is different from
% $-1$ it opens a tag with it.
% The reopened mc chunk looses info like the alt text for now.
% \end{function}
%
% \begin{function}[pTF, EXP]{\tag_mc_if_in:}
%   \begin{syntax}
%     \cs{tag_mc_if_in:TF} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Determines if a mc-chunk is open.
% \end{function}

% \begin{function}[ EXP,added=2023-06-11]{\tag_mc_reset_box:N}
%   \begin{syntax}
%     \cs{tag_mc_reset:N} \Arg{box} 
%   \end{syntax}
%   This resets in lua mode the mc attributes to the one currently in use.
%   It does nothing in generic mode.
% \end{function}
%
% \section{Public keys}
% The following keys can be used with |\tag_mc_begin:n|, |\tagmcbegin|,
% |\tag_mc_begin_pop:n|,
%
% \begin{function}{tag (mc-key)}
% This key is required, unless artifact is used.
% The value is a tag like |P| or |H1| without a slash at the begin,
% this is added by the code.
% It is possible to setup new tags.
% The value of the key is expanded, so it can be a command.
% The expansion is passed unchanged to the PDF,
% so it should with a starting slash give a valid PDF name
% (some ascii with numbers like \texttt{H4} is fine).
% \end{function}
%
% \begin{function}{artifact (mc-key)}
%  This will setup the marked content as an artifact. The key should be used
%  for content that should be ignored.
%  The key can take one of the values |pagination|,
%  |layout|,  |page|,  |background| and |notype|
%  (this is the default).
% \end{function}
%
% \begin{function}{raw (mc-key)}
% This key allows  to add more entries to the properties dictionary.
% The value must be correct, low-level PDF. E.g.
% \verb+raw=/Alt (Hello)+ will insert an alternative Text.
% \end{function}
%
% \begin{function}{alt (mc-key)}
%  This key inserts an \texttt{/Alt} value in the property dictionary of the BDC operator.
%  The value is handled as verbatim string, commands are not expanded.
%  The value will be expanded first once. If it is empty, nothing will happen.
% \end{function}
%
% \begin{function}{actualtext (mc-key)}
%  This key inserts an \texttt{/ActualText} value in the property dictionary
%  of the BDC operator. The value is handled as verbatim string,
%  commands are not expanded.
%  The value will be expanded first once. If it is empty, nothing will happen.
% \end{function}
%
% \begin{function}{label (mc-key)}
%  This key sets a label by which one can call the marked content
%  later in another structure
%  (if it has been stashed with the |stash| key).
%  Internally the label name will start with \texttt{tagpdf-}.
% \end{function}
%
% \begin{function}{stash (mc-key)}
% This \enquote{stashes} an mc-chunk: it is not inserted into the current structure.
% It should be normally be used along with a label to be able to use the mc-chunk
% in another place.
% \end{function}
% \end{documentation}
% \begin{implementation}
% The code is splitted into three parts: code shared by all engines,
% code specific to luamode and code not used by luamode.
% \section{Marked content code -- shared}
%    \begin{macrocode}
%<@@=tag>
%<*header>
\ProvidesExplPackage {tagpdf-mc-code-shared} {2023-08-04} {0.98k}
  {part of tagpdf - code related to marking chunks -
   code shared by generic and luamode }
%</header>
%    \end{macrocode}
%
% \subsection{Variables and counters}
% MC chunks must be counted.
% I use a latex counter for the absolute count, so that it is added to
% |\cl@@ckpt| and restored e.g. in tabulars and align.
% |\int_new:N  \c@g_@@_MCID_int| and
% |\tl_put_right:Nn\cl@@ckpt{\@elt{g_uf_test_int}}|
% would work too, but as the name is not expl3 then too, why bother?
% The absolute counter can be used to label and to check if the page
% counter needs a reset.
%
% \begin{variable}{g_@@_MCID_abs_int}
%    \begin{macrocode}
%<*base>
\newcounter { g_@@_MCID_abs_int }
%    \end{macrocode}
% \end{variable}
% \begin{macro}{\@@_get_data_mc_counter:}
% This command allows \cs{tag_get:n} to get the current
% state of the mc counter with the keyword |mc_counter|. 
% By comparing the numbers it can be used to check the number of 
% structure commands in a piece of code.
%    \begin{macrocode}
\cs_new:Npn \@@_get_data_mc_counter:
  {
    \int_use:N \c@g_@@_MCID_abs_int
  }
%</base>
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_get_mc_abs_cnt:}
% A (expandable) function to get the current value of the cnt.
% TODO: duplicate of the previous one, this should be cleaned up.
%    \begin{macrocode}
%<*shared>
\cs_new:Npn \@@_get_mc_abs_cnt: { \int_use:N \c@g_@@_MCID_abs_int }
%    \end{macrocode}
% \end{macro}
% 
% \begin{variable}{\g_@@_MCID_tmp_bypage_int}
% The following hold the temporary by page number assigned to a mc.
% It must be defined in the shared code to avoid problems with labels.
%    \begin{macrocode}
\int_new:N \g_@@_MCID_tmp_bypage_int
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\g_@@_in_mc_bool}
% This booleans record if a mc is open, to test nesting.
%    \begin{macrocode}
\bool_new:N \g_@@_in_mc_bool
%    \end{macrocode}
% \end{variable}
% \begin{variable}{\g_@@_mc_parenttree_prop}
% For every chunk we need to know the structure it is in, to
% record this in the parent tree. We store this in a property.\\
% key:   absolute number of the mc (tagmcabs)\\
% value: the structure number the mc is in
%    \begin{macrocode}
\@@_prop_new:N \g_@@_mc_parenttree_prop
%    \end{macrocode}
% \end{variable}
%
%\begin{variable}{\g_@@_mc_parenttree_prop}
% Some commands (e.g. links) want to close a previous mc and reopen it after
% they did their work. For this we create a stack:
%    \begin{macrocode}
\seq_new:N \g_@@_mc_stack_seq
%    \end{macrocode}
% \end{variable}
%
%\begin{variable}{\l_@@_mc_artifact_type_tl}
% Artifacts can have various types like Pagination or Layout. This stored
% in this variable.
%    \begin{macrocode}
\tl_new:N \l_@@_mc_artifact_type_tl
%    \end{macrocode}
% \end{variable}
%
%\begin{variable}{\l_@@_mc_key_stash_bool,\l_@@_mc_artifact_bool}
%This booleans store the stash and artifact status of the mc-chunk.
%    \begin{macrocode}
\bool_new:N \l_@@_mc_key_stash_bool
\bool_new:N \l_@@_mc_artifact_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%  {
%   \l_@@_mc_key_tag_tl,
%   \g_@@_mc_key_tag_tl,
%   \l_@@_mc_key_label_tl,
%   \l_@@_mc_key_properties_tl
%  }
% Variables used by the keys. |\l_@@_mc_key_properties_tl|
% will collect a number of values. TODO: should this be a pdfdict now?
%    \begin{macrocode}
\tl_new:N \l_@@_mc_key_tag_tl
\tl_new:N \g_@@_mc_key_tag_tl
\tl_new:N \l_@@_mc_key_label_tl
\tl_new:N \l_@@_mc_key_properties_tl
%    \end{macrocode}
% \end{variable}
%
%
% \subsection{Functions}
% \begin{macro}{\_@@_mc_handle_mc_label:n}
% The commands labels a mc-chunk. It is used if the user explicitly
% labels the mc-chunk with the |label| key. The argument is the
% value provided by the user. It stores the attributes\\
% |tagabspage|: the absolute page, |\g_shipout_readonly_int|,\\
% |tagmcabs|: the absolute mc-counter |\c@g_@@_MCID_abs_int|,\\
% |tagmcid|: the ID of the chunk on the page |\g_@@_MCID_tmp_bypage_int|, this
%  typically settles down after a second compilation.
%  The reference command is defined in tagpdf.dtx and is based on l3ref.
%    \begin{macrocode}
\cs_new:Nn \_@@_mc_handle_mc_label:n
  {
    \@@_ref_label:en{tagpdf-#1}{mc}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_mc_set_label_used:n}
% Unlike with structures we can't check if a labeled mc has been used by
% looking at the P key, so we use a dedicated csname for the test
%    \begin{macrocode}
\cs_new_protected:Npn \@@_mc_set_label_used:n #1 %#1 labelname
  {
    \tl_new:c { g_@@_mc_label_\tl_to_str:n{#1}_used_tl }
  }
%</shared>
%    \end{macrocode}
%
% \end{macro}
% \begin{macro}{\tag_mc_use:n}
% These command allow to record a marked content that was stashed away before
% into the current structure. A marked content can be used only once --
% the command will issue a warning if an mc is use a second time.
% The argument is a label name set with the |label| key.
%
% TODO: is testing for struct the right test?
%    \begin{macrocode}
%<base>\cs_new_protected:Npn \tag_mc_use:n #1 { \@@_whatsits: }
%<*shared>
\cs_set_protected:Npn \tag_mc_use:n #1 %#1: label name
  {
    \@@_check_if_active_struct:T
      {
        \tl_set:Nx  \l_@@_tmpa_tl { \@@_ref_value:nnn{tagpdf-#1}{tagmcabs}{} }
        \tl_if_empty:NTF\l_@@_tmpa_tl
          {
            \msg_warning:nnn {tag} {mc-label-unknown} {#1}
          }
          {
            \cs_if_free:cTF { g_@@_mc_label_\tl_to_str:n{#1}_used_tl }
              {
                \@@_mc_handle_stash:x { \l_@@_tmpa_tl }
                \@@_mc_set_label_used:n {#1}
              }
              {
                 \msg_warning:nnn {tag}{mc-used-twice}{#1}
              }
          }
       }
  }
%</shared>
%    \end{macrocode}
% \end{macro}
% \begin{macro}
%   {
%     \tag_mc_artifact_group_begin:n,
%     \tag_mc_artifact_group_end:
%   }
% This opens an artifact of the type given in the argument,
% and then stops all tagging. It creates a group.
% It pushes and pops mc-chunks at the begin and end.
%    \begin{macrocode}
%<base>\cs_new_protected:Npn \tag_mc_artifact_group_begin:n #1 {}
%<base>\cs_new_protected:Npn \tag_mc_artifact_group_end:{}
%<*shared>
\cs_set_protected:Npn \tag_mc_artifact_group_begin:n #1
 {
  \tag_mc_end_push:
  \tag_mc_begin:n {artifact=#1}
  \tag_stop_group_begin:
 }

\cs_set_protected:Npn \tag_mc_artifact_group_end:
 {
  \tag_stop_group_end:
  \tag_mc_end:
  \tag_mc_begin_pop:n{}
 }
%</shared>
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\tag_mc_reset_box:N}
% This allows to reset the mc-attributes in box. On base and generic mode it should do 
% nothing.
%    \begin{macrocode}
%<base>\cs_new_protected:Npn \tag_mc_reset_box:N #1 {}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\tag_mc_end_push:, \tag_mc_begin_pop:n}
%
%    \begin{macrocode}
%<base>\cs_new_protected:Npn \tag_mc_end_push: {}
%<base>\cs_new_protected:Npn \tag_mc_begin_pop:n #1 {}
%<*shared>
\cs_set_protected:Npn \tag_mc_end_push:
  {
    \@@_check_if_active_mc:T
      {
        \@@_mc_if_in:TF
          {
            \seq_gpush:Nx \g_@@_mc_stack_seq { \tag_get:n {mc_tag} }
            \@@_check_mc_pushed_popped:nn
              { pushed }
              { \tag_get:n {mc_tag} }
            \tag_mc_end:
          }
          {
            \seq_gpush:Nn \g_@@_mc_stack_seq {-1}
            \@@_check_mc_pushed_popped:nn { pushed }{-1}
          }
      }
  }

\cs_set_protected:Npn \tag_mc_begin_pop:n #1
  {
    \@@_check_if_active_mc:T
      {
        \seq_gpop:NNTF \g_@@_mc_stack_seq \l_@@_tmpa_tl
          {
            \tl_if_eq:NnTF \l_@@_tmpa_tl {-1}
              {
                \@@_check_mc_pushed_popped:nn {popped}{-1}
              }
              {
                \@@_check_mc_pushed_popped:nn {popped}{\l_@@_tmpa_tl}
                \tag_mc_begin:n {tag=\l_@@_tmpa_tl,#1}
              }
          }
          {
            \@@_check_mc_pushed_popped:nn {popped}{empty~stack,~nothing}
          }
      }
  }
%    \end{macrocode}
% \end{macro}
% 
% \subsection{Keys}
% This are the keys where the code can be shared between the modes.
%
% \begin{macro}{stash (mc-key),__artifact-bool,__artifact-type}
% the two internal artifact keys are use to define the public |artifact|.
% For now we add support for the subtypes Header and Footer.
% Watermark,PageNum, LineNum,Redaction,Bates will be added if some use case
% emerges. If some use case for /BBox and /Attached emerges, it will be perhaps
% necessary to adapt the code.
%    \begin{macrocode}
\keys_define:nn { @@ / mc }
  {
    stash                    .bool_set:N    = \l_@@_mc_key_stash_bool,
    __artifact-bool          .bool_set:N    = \l_@@_mc_artifact_bool,
    __artifact-type          .choice:,
    __artifact-type / pagination .code:n    =
      {
        \tl_set:Nn \l_@@_mc_artifact_type_tl { Pagination }
      },
    __artifact-type / pagination/header .code:n    =
      {
        \tl_set:Nn \l_@@_mc_artifact_type_tl { Pagination/Subtype/Header }
      },
    __artifact-type / pagination/footer .code:n    =
      {
        \tl_set:Nn \l_@@_mc_artifact_type_tl { Pagination/Subtype/Footer }
      },
    __artifact-type / layout     .code:n    =
      {
        \tl_set:Nn \l_@@_mc_artifact_type_tl { Layout }
      },
    __artifact-type / page       .code:n    =
      {
        \tl_set:Nn \l_@@_mc_artifact_type_tl { Page }
      },
    __artifact-type / background .code:n    =
      {
        \tl_set:Nn \l_@@_mc_artifact_type_tl { Background }
      },
    __artifact-type / notype     .code:n    =
      {
        \tl_set:Nn \l_@@_mc_artifact_type_tl {}
      },
    __artifact-type /      .code:n    =
      {
        \tl_set:Nn \l_@@_mc_artifact_type_tl {}
      },
  }
%    \end{macrocode}
% \end{macro}
%    \begin{macrocode}
%</shared>
%    \end{macrocode}
% \end{implementation}
% \PrintIndex
