% \iffalse meta-comment
%
%% File: tagpdf-tree.dtx
%
% Copyright (C) 2019-2020 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.
%
% \fi
%
%    \begin{macrocode}
%<@@=tag>
%<*tree>
\ProvidesExplPackage {tagpdf-tree-code} {2021/05/14} {0.81}
 {part of tagpdf - code related to writing trees and dictionaries to the pdf}

%this does the actual finishing:
%Is \AddToHook{enddocument/end} the best places??
\hook_gput_code:nnn{begindocument}{tagpdf}
  {
    \bool_if:NT \g_@@_active_tree_bool
      {
        \sys_if_output_pdf:TF
          {
            \AddToHook{enddocument/end} { \tag_finish_structure: }
          }
          {
            \AddToHook{shipout/lastpage} { \tag_finish_structure: }
          }
      }
  }


% the StructTreeRoot
% we better get the object number in any case:
% deprecated
%\@@_pdfreserveobjnum:N \l_tmpa_tl
%\tl_const:Nx \c_@@_tree_obj_structtreeroot_tl { \l_tmpa_tl }

%new
\pdf_object_new:nn { @@/struct/0 }{ dict }

 %need to think about the best place ...
\hook_gput_code:nnn{begindocument}{tagpdf}
  {
    \bool_if:NT \g_@@_active_struct_bool
      {
        \pdfmanagement_add:nnx
          { Catalog }
          { StructTreeRoot }
          { \pdf_object_ref:n { @@/struct/0 } }
      }
  }
\cs_new_protected:Nn \@@_tree_write_structtreeroot:
  {
    \@@_struct_write_obj:n { 0 }
  }

\cs_new_protected:Nn \@@_tree_write_structelements:
  {
    \int_step_inline:nnnn {1}{1}{\c@g_@@_struct_abs_int}
      {
        %\prop_show:c {g_@@_struct_##1_prop}
        \@@_struct_write_obj:n { ##1 } %write the object
      }
  }


%the ParentTree
% deprecated
%\@@_pdfreserveobjnum:N \l_tmpa_tl
%\tl_const:Nx \c_@@_tree_obj_parenttree_tl    { \l_tmpa_tl }

%new
\pdf_object_new:nn { @@/tree/parenttree }{ dict }

% we have two sets of entries in the parent tree:
% page streams and real objects.
% The numbers must be distinct and ordered
% So we rely on abspage and put the real objects at the end
% I use a counter to have a chance to get the correct number
% if code is process twice.
\newcounter  { g_@@_parenttree_obj_int }
\hook_gput_code:nnn{begindocument}{tagpdf}
  {
    \int_gset:Nn
      \c@g_@@_parenttree_obj_int
      { \@@_ref_value_lastpage:nn{abspage}{100}  }
  }

% we need to record the obj references:

\tl_new:N \g_@@_parenttree_objr_tl

\cs_new_protected:Nn \@@_parenttree_add_objr:nn %#1 Structparent number, #2 objref
  {
    \tl_gput_right:Nx \g_@@_parenttree_objr_tl
      {
        #1 \c_space_tl #2 ^^J
      }
  }

\tl_new:N \l_@@_parenttree_content_tl

\cs_new_protected:Nn \@@_tree_fill_parenttree:
  {
    \int_step_inline:nnnn{1}{1}{\@@_ref_value_lastpage:nn{abspage}{-1}} %not quite clear if labels are needed. See lua code
      { %page ##1\par
        \prop_clear:N \l_tmpa_prop
        \int_step_inline:nnnn{1}{1}{\@@_ref_value_lastpage:nn{tagmcabs}{-1}}
          {
            %mcid####1
            \int_compare:nT%F
              {\@@_ref_value:enn{mcid-####1}{tagabspage}{-1}=##1} %mcid is on current page
              {% yes\par
                \prop_put:Nxx
                  \l_tmpa_prop
                  {\@@_ref_value:enn{mcid-####1}{tagmcid}{-1}}
                  {\prop_item:Nn \g_@@_mc_parenttree_prop {####1}}
              }
          }
          %\prop_show:N \l_tmpa_prop
        \tl_put_right:Nx\l_@@_parenttree_content_tl
          {
            \int_eval:n {##1-1}\c_space_tl
            [\c_space_tl %]
          }
        \int_step_inline:nnnn
          {0}
          {1}
          { \prop_map_function:NN \l_tmpa_prop\@@_prop_count:nn -1 }
          {
            \prop_get:NnNTF \l_tmpa_prop {####1} \l_tmpb_tl
              {% page#1:mcid##1:\l_tmpb_tl :content
                \tl_put_right:Nx \l_@@_parenttree_content_tl
                  {
                    \prop_item:cn { g_@@_struct_\l_tmpb_tl _prop } {objref}
                    \c_space_tl
                  }
                %\tl_show:N \l_@@_parenttree_content_tl
              }
              {
                \msg_warning:nn { tag } {tree-mcid-index-wrong}
              }
          }
        \tl_put_right:Nn
          \l_@@_parenttree_content_tl
          {%[
            ]^^J
          }
      }
  }

%lua mode must/can do it differently
\cs_new_protected:Nn \@@_tree_lua_fill_parenttree:
  {
    \tl_set:Nn \l_@@_parenttree_content_tl
      {
        \directlua
          {
            ltx.@@.func.output_parenttree
              (
                \int_use:N\g_shipout_readonly_int
              )
          }
      }
  }



\cs_new_protected:Nn \@@_tree_write_parenttree:
  {
    \bool_if:NTF \g_@@_mode_lua_bool
      {
        \@@_tree_lua_fill_parenttree:
      }
      {
        \@@_tree_fill_parenttree:
      }
    \tl_put_right:NV \l_@@_parenttree_content_tl\g_@@_parenttree_objr_tl
    \pdf_object_write:nx  { @@/tree/parenttree }
      {
        /Nums\c_space_tl [\l_@@_parenttree_content_tl]
      }
  }

%the Rolemap tree

\pdf_object_new:nn { @@/tree/rolemap }{ dict }

\cs_new_protected:Nn \@@_tree_write_rolemap:
  {
    \pdf_object_write:nx  { @@/tree/rolemap }
      {
        \pdfdict_use:n{g_@@_role/RoleMap_dict}
      }
  }

%classmap, should only be written, if values has been used

\cs_new_protected:Nn \@@_tree_write_classmap:
  {
    \tl_gclear:N \g_@@_attr_class_content_tl
    \seq_gremove_duplicates:N \g_@@_attr_class_used_seq
    \seq_set_map:NNn \l_tmpa_seq \g_@@_attr_class_used_seq
      {
        /##1\c_space_tl
        <<
          \prop_item:Nn
            \g_@@_attr_entries_prop
            {##1}
        >>
      }
    \tl_gset:Nx \g_@@_attr_class_content_tl
      {
        \seq_use:Nn
          \l_tmpa_seq
          { \iow_newline: }
      }
    \tl_if_empty:NF
      \g_@@_attr_class_content_tl
      {
        \pdf_object_new:nn { @@/tree/classmap }{ dict }
     %   \@@_pdfreserveobjnum:N \l_tmpa_tl
     %   \tl_const:Nx \c_@@_tree_obj_classmap_tl { \l_tmpa_tl }
        \pdf_object_write:nx
          { @@/tree/classmap }
          { \g_@@_attr_class_content_tl }
        \@@_prop_gput:cnx
          { g_@@_struct_0_prop }
          { ClassMap }
          { \pdf_object_ref:n { @@/tree/classmap }  }
      }
  }

% namespaces are only relevant for pdf2.0 but we don't care
\pdf_object_new:nn{ @@/tree/namespaces }{array}
\cs_new_protected:Npn \@@_tree_write_namespaces:
  {
    \prop_map_inline:Nn \g_@@_role_NS_prop
      {
        \pdfdict_if_empty:nF {g_@@_role/RoleMapNS_##1_dict}
          {
            \pdf_object_write:nx {@@/RoleMapNS/##1}
              {
                \pdfdict_use:n {g_@@_role/RoleMapNS_##1_dict}
              }
            \pdfdict_gput:nnx{g_@@_role/Namespace_##1_dict}
              {RoleMapNS}{\pdf_object_ref:n {@@/RoleMapNS/##1}}
          }
        \pdf_object_write:nx{tag/NS/##1}
          {
             \pdfdict_use:n {g_@@_role/Namespace_##1_dict}
          }
      }
    \pdf_object_write:nx {@@/tree/namespaces}
      {
        \prop_map_tokens:Nn \g_@@_role_NS_prop{\use_ii:nn}
      }
  }


\cs_new_protected:Nn \tag_finish_structure:
  {
    \@@_tree_write_parenttree:
    \@@_tree_write_rolemap:
    \@@_tree_write_classmap:
    \@@_tree_write_namespaces:
    \@@_tree_write_structelements: %this is rather slow!!
    \@@_tree_write_structtreeroot:
  }


%StructParents !!! we need a better hook for \g__pdf_BACKEND_thispage_shipout_tl!!
% No actually
\hook_gput_code:nnn{begindocument}{tagpdf}
  {
    \bool_if:NT\g_@@_active_tree_bool
      {
       \hook_gput_code:nnn{shipout/before} { tagpdf/structparents }
         {
             \pdfmanagement_add:nnx
               { Page }
               {StructParents}
               {\int_eval:n { \g_shipout_readonly_int}}
         }
      }
  }

%</tree>
%    \end{macrocode}
