\ProvidesExplPackage {tagpdf-struct-code} {2019/07/02} {0.61}
 {part of tagpdf - code related to storing structure}

% I will use a latex counter for the structure count
% to have a chance to avoid double structures in align etc

\newcounter  { g__uftag_struct_abs_int }
\int_gzero:N \c@g__uftag_struct_abs_int


\zref@newprop {tagstruct} [0] { \int_use:N \c@g__uftag_struct_abs_int }
\zref@newlist {uftagzrlstruct}
\zref@addprop {uftagzrlstruct}{tagstruct}

% a sequence stores structnum -> the obj numbers
% to allow easy mapping over the structures

\__uftag_seq_new:N  \g__uftag_struct_objR_seq

% a sequence for the structure stack. When a sequence is opened it's number is put on the stack.
\seq_new:N    \g__uftag_struct_stack_seq
\seq_gpush:Nn \g__uftag_struct_stack_seq {0}

%this variables will hold the top entry and the parent on the stack
\tl_new:N     \l__uftag_struct_stack_parent_tmp_tl
\tl_new:N     \g__uftag_struct_stack_current_tl

% I need at least one structure: the StructTreeRoot
% normally it should have only one kid, e.g. the document element.

% The data of the StructTreeRoot and the StructElem are in properties:
% \g__uftag_struct_0_prop for the root
% \g__uftag_struct_N_prop, N >=1
% they have all the keys
% objnum    - number,
% Type      - StructTreeRoot or StructElem
% num - number (identical to the num in the name, or 0 for the root)
% and the keys from the two following lists
% (the root has a special set of properties).
% the values of the prop should be already escaped properly
% when the entries are created (title,lange,alt,E,actualtext)


\seq_const_from_clist:Nn \c__uftag_struct_StructTreeRoot_entries_seq
 {%p. 857/858
  Type,              % always /StructTreeRoot
  K,                 % kid, dictionary or array of dictionaries
  IDTree,            % currently unused
  ParentTree,        % required,obj ref to the parent tree
  ParentTreeNextKey, %optional
  RoleMap,
  ClassMap
 }

\seq_const_from_clist:Nn \c__uftag_struct_StructElem_entries_seq
 {%p 858 f
  Type,              %always /StructElem
  S,                 %tag/type
  P,                 %parent
  ID,                %optional
  Pg,                %obj num of starting page, optional
  K,                 %kids
  A,                 %attributes, probably unused
  C,                 %class ""
  %R,
  T,                 %title, value in () or <>
  Lang,              %language
  Alt,               % value in () or <>
  E,                 %abreviation
  ActualText
  }

% I need an output handler for each prop, to get expandable output
% see https://tex.stackexchange.com/questions/424208/expandable-version-of-a-expl3-command/424213#424213

\cs_new:Nn \__uftag_struct_output_prop_aux:nn %#1 num, #2 key
 {
  \prop_if_in:cnT
   { g__uftag_struct_#1_prop }
   { #2 }
   {
     \c_space_tl/#2~ \prop_item:cn{ g__uftag_struct_#1_prop } { #2 }
   }
 }

\cs_new:Nn \__uftag_new_output_prop_handler:n
 {
  \cs_new:cn { __uftag_struct_output_prop_#1:n }
   {
    \__uftag_struct_output_prop_aux:nn {#1}{##1}
   }
 }


% the first one, the StructTreeRoot is special, so
% created manually:
\__uftag_prop_new:c { g__uftag_struct_0_prop }
\__uftag_new_output_prop_handler:n {0}
\tl_gset:Nn \g__uftag_struct_stack_current_tl {0}

\__uftag_seq_new:c  { g__uftag_struct_kids_0_seq}

\__uftag_prop_gput:cno
 { g__uftag_struct_0_prop }
 { objnum}
 { \c_uftag_tree_obj_structtreeroot_tl }

\__uftag_prop_gput:cno
 { g__uftag_struct_0_prop }
 { Type }
 { /StructTreeRoot }

% the constants are defined in the tree code.
\__uftag_prop_gput:cnx
 { g__uftag_struct_0_prop }
 { ParentTree }
 { \c__uftag_tree_obj_parenttree_tl\c_space_tl 0\c_space_tl R }

\__uftag_prop_gput:cnx
 { g__uftag_struct_0_prop }
 { RoleMap }
 { \c__uftag_tree_obj_rolemap_tl\c_space_tl 0\c_space_tl R }

\__uftag_prop_gput:cno
 { g__uftag_struct_0_prop }
 { entries }
 { StructTreeRoot }

\__uftag_prop_gput:cno
 { g__uftag_struct_0_prop }
 { num }
 { 0 }

% commands to store the kids
% I don't compare the page objects number yet, but always add the /Pg key, perhaps later

\cs_new:Nn \__uftag_struct_kid_mc_gput_right:nn %#1 structure num, #2 MCID absnum%
 {
  \__uftag_store_pdfpageref:Nn \l_tmpa_tl { \zref@extractdefault{mcid-#2}{tagabspage}{1} }
  \__uftag_seq_gput_right:cx
   { g__uftag_struct_kids_#1_seq }
   { <<
     /Type\c_space_tl/MCR\c_space_tl
     /Pg\c_space_tl\l_tmpa_tl\c_space_tl0\c_space_tl R\c_space_tl
     /MCID\c_space_tl\zref@extractdefault{mcid-#2}{tagmcid}{1}
    >>
   }
 }

\cs_new:Nn\__uftag_struct_kid_struct_gput_right:nn %#1 num of parent struct, #2 kid struct
 {
  \__uftag_seq_gput_right:cx
  { g__uftag_struct_kids_#1_seq }
  {
   \prop_item:cn
    { g__uftag_struct_#2_prop }
    { objnum }
   \c_space_tl 0 \c_space_tl R
  }
 }

\cs_new:Nn\__uftag_struct_kid_link_gput_right:nn %#1 num of parent struct, #2 obj number of link
 {
  \__uftag_pdfobj:Nn \l__uftag_tmpa_tl
  {
    <<
     /Type \c_space_tl /OBJR \c_space_tl
     /Obj  \c_space_tl #2 \c_space_tl 0 \c_space_tl R
   >>
  }
  \__uftag_seq_gput_right:cx
   { g__uftag_struct_kids_#1_seq }
   {
    \l__uftag_tmpa_tl \c_space_tl 0 \c_space_tl R
   }
 }

\cs_generate_variant:Nn\__uftag_struct_kid_link_gput_right:nn { nx}

\cs_new:Nn\__uftag_struct_exchange_kid_command:N %N= seq
 {
  \seq_gpop_left:NN #1 \l_tmpa_tl
  \regex_replace_once:nnN
   {\c{\__uftag_mc_insert_mcid_kids:n}}
   {\c{\__uftag_mc_insert_mcid_single_kids:n}}
   \l_tmpa_tl
  \seq_gput_left:NV #1 \l_tmpa_tl
 }
\cs_generate_variant:Nn\__uftag_struct_exchange_kid_command:N { c }

\cs_new:Nn \__uftag_struct_fill_kid_key:n %#1 is the struct num
 {
  \int_case:nnF
  {
   \seq_count:c
    {
     g__uftag_struct_kids_\prop_item:cn{ g__uftag_struct_#1_prop }{num}_seq
    }
  }
  {
   { 0 }
    { } %no kids, do nothing
   { 1 } % 1 kid, insert
    {
     % in this case we in luamode need a special command in luamode to get the array right. See issue #13
     \bool_if:NT\g__uftag_mode_lua_bool
      {
       \__uftag_struct_exchange_kid_command:c
        {g__uftag_struct_kids_\prop_item:cn{ g__uftag_struct_#1_prop }{num}_seq}
      }
     \__uftag_prop_gput:cnx { g__uftag_struct_#1_prop } {K}
      {
       \seq_item:cn
        {
         g__uftag_struct_kids_\prop_item:cn{ g__uftag_struct_#1_prop }{num}_seq
        }{1}
      }
    } %
  }
  { %many kids, use an array
   \__uftag_prop_gput:cnx { g__uftag_struct_#1_prop } {K}
    {
     [
      \seq_use:cn
       {
        g__uftag_struct_kids_\prop_item:cn{ g__uftag_struct_#1_prop }{num}_seq
       }
       {
        \c_space_tl
       }
     ]
    }
  }
 }

% this command can be used for roots and structure elements
% #1 is a num

\tl_new:N \l_uftag_struct_dict_content_tl

\cs_new:Nn \__uftag_struct_get_dict_content:n
 {
  \tl_set:Nn \l_uftag_struct_dict_content_tl {<<}
  \seq_map_inline:cn
   {
    c__uftag_struct_\prop_item:cn{ g__uftag_struct_#1_prop }{entries}_entries_seq
   }
   {
    \tl_put_right:Nx
    \l_uftag_struct_dict_content_tl
    {
     \prop_if_in:cnT
     { g__uftag_struct_#1_prop }
     { ##1 }
     {
      \c_space_tl/##1~\prop_item:cn{ g__uftag_struct_#1_prop } { ##1 }
     }
    }
   }
  \tl_put_right:Nn \l_uftag_struct_dict_content_tl { >> }
 }


% #1 is the struct num
\cs_new:Nn \__uftag_struct_write_obj:n
 {
  \prop_if_in:cnTF
   { g__uftag_struct_#1_prop }
   { objnum }
   {
    \__uftag_struct_fill_kid_key:n { #1 }
    %\prop_show:c { g__uftag_struct_#1_prop }
    \__uftag_struct_get_dict_content:n { #1 }
    \__uftag_pdfuseobjnum:xx
     { \prop_item:cn { g__uftag_struct_#1_prop } {objnum} }
     {
      \l_uftag_struct_dict_content_tl
     }
   }
   {
   \msg_error:nnn {uftag} { struct-no-objnum } { #1}
   }
 }

% keys for the user commands
% should I pass the values (e.g. the tag) through an escape command?
\keys_define:nn { uftag / struct }
 {
  label .tl_set:N      = \l__uftag_struct_key_label_tl,
  stash .bool_set:N    = \l__uftag_struct_elem_stash_bool,
  tag   .code:n        = % S property
   {%%????????? \pdfescapename??
    \tl_set:Nx \l__uftag_tmpa_tl { #1 }
    \bool_if:NT \g__uftag_check_tags_bool
     {
      \__uftag_check_structure_tag:N \l__uftag_tmpa_tl
     }
    \__uftag_prop_gput:cnx
     { g__uftag_struct_\int_eval:n {\c@g__uftag_struct_abs_int}_prop }
     { S }
     { /\exp_not:V\l__uftag_tmpa_tl }
   },
  title .code:n        = % T property
   {
    \str_set_convert:Nnon
     \l__uftag_tmpa_str
     { #1 }
     { \g__uftag_inputencoding_tl }
     { utf16/hex }
    \__uftag_prop_gput:cnx
     { g__uftag_struct_\int_eval:n {\c@g__uftag_struct_abs_int}_prop }
     { T }
     { <\l__uftag_tmpa_str> }
   },
  title-o .code:n        = % T property
   {
    \str_set_convert:Nnon
     \l__uftag_tmpa_str
     { #1 }
     { \g__uftag_inputencoding_tl }
     { utf16/hex }
    \__uftag_prop_gput:cnx
     { g__uftag_struct_\int_eval:n {\c@g__uftag_struct_abs_int}_prop }
     { T }
     { <\l__uftag_tmpa_str> }
   },
  alttext .code:n      = % Alt property
   {
    \str_set_convert:Nnon
     \l__uftag_tmpa_str
     { #1 }
     { \g__uftag_inputencoding_tl }
     { utf16/hex }
    \__uftag_prop_gput:cnx
     { g__uftag_struct_\int_eval:n {\c@g__uftag_struct_abs_int}_prop }
     { Alt }
     { <\l__uftag_tmpa_str> }
   },
   alttext-o .code:n      = % Alt property
   {
    \str_set_convert:Noon
     \l__uftag_tmpa_str
     { #1 }
     { \g__uftag_inputencoding_tl }
     { utf16/hex }
    \__uftag_prop_gput:cnx
     { g__uftag_struct_\int_eval:n {\c@g__uftag_struct_abs_int}_prop }
     { Alt }
     { <\l__uftag_tmpa_str> }
   },
   actualtext .code:n  = % ActualText property
   {
    \str_set_convert:Nnon
    \l__uftag_tmpa_str
    { #1 }
    { \g__uftag_inputencoding_tl }
    { utf16/hex }
    \__uftag_prop_gput:cnx
     { g__uftag_struct_\int_eval:n {\c@g__uftag_struct_abs_int}_prop }
     { ActualText }
     { <\l__uftag_tmpa_str>}
   },
   actualtext-o .code:n  = % ActualText property
   {
    \str_set_convert:Noon
    \l__uftag_tmpa_str
    { #1 }
    { \g__uftag_inputencoding_tl }
    { utf16/hex }
    \__uftag_prop_gput:cnx
     { g__uftag_struct_\int_eval:n {\c@g__uftag_struct_abs_int}_prop }
     { ActualText }
     { <\l__uftag_tmpa_str>}
   },
}


\cs_new_protected:Nn \uftag_struct_begin:n
 {
  \group_begin:
  \int_gincr:N \c@g__uftag_struct_abs_int
  \__uftag_prop_new:c  { g__uftag_struct_\int_eval:n { \c@g__uftag_struct_abs_int }_prop }
  \__uftag_new_output_prop_handler:n {\int_eval:n { \c@g__uftag_struct_abs_int }}
  \__uftag_seq_new:c  { g__uftag_struct_kids_\int_eval:n { \c@g__uftag_struct_abs_int }_seq}
  \__uftag_pdfreserveobjnum:N \l_tmpa_tl
  \__uftag_prop_gput:cno
   { g__uftag_struct_\int_eval:n { \c@g__uftag_struct_abs_int }_prop }
   { objnum}
   { \l_tmpa_tl }
  \__uftag_prop_gput:cnx
   { g__uftag_struct_\int_eval:n { \c@g__uftag_struct_abs_int }_prop }
   { num}
   { \int_eval:n { \c@g__uftag_struct_abs_int } }
  \__uftag_prop_gput:cno
   { g__uftag_struct_\int_eval:n { \c@g__uftag_struct_abs_int }_prop }
   { Type }
   { /StructElem }
  \__uftag_prop_gput:cno
   { g__uftag_struct_\int_eval:n { \c@g__uftag_struct_abs_int }_prop }
   { entries }
   { StructElem }
  \keys_set:nn {uftag / struct} { #1 }
  \__uftag_check_structure_has_tag:n { \int_eval:n {\c@g__uftag_struct_abs_int} }
  \tl_if_empty:NF
   {\l__uftag_struct_key_label_tl}
   {
     \zref@labelbylist{tagpdfstruct-\l__uftag_struct_key_label_tl}{uftagzrlstruct}
   }
   %get the potential parent from the stack:
   \seq_get:NNF
    \g__uftag_struct_stack_seq
    \l__uftag_struct_stack_parent_tmp_tl
    {
     \msg_error:nn { uftag } { struct-faulty-nesting }
    }
   \seq_gpush:NV \g__uftag_struct_stack_seq        \c@g__uftag_struct_abs_int
   \tl_gset:NV   \g__uftag_struct_stack_current_tl \c@g__uftag_struct_abs_int
   %\seq_show:N   \g__uftag_struct_stack_seq
   \bool_if:NF
    \l__uftag_struct_elem_stash_bool
    {%set the  parent
     \__uftag_prop_gput:cnx
      { g__uftag_struct_\int_eval:n {\c@g__uftag_struct_abs_int}_prop }
      { P }
      {
       \prop_item:cn { g__uftag_struct_\l__uftag_struct_stack_parent_tmp_tl _prop} { objnum }~0~R
      }
     %record this structure as kid:
     %\tl_show:N \g__uftag_struct_stack_current_tl
     %\tl_show:N \l__uftag_struct_stack_parent_tmp_tl
    \__uftag_struct_kid_struct_gput_right:nn
     { \l__uftag_struct_stack_parent_tmp_tl }
     { \g__uftag_struct_stack_current_tl }
     %\prop_show:c { g__uftag_struct_\g__uftag_struct_stack_current_tl _prop }
     %\seq_show:c {g__uftag_struct_kids_\l__uftag_struct_stack_parent_tmp_tl _seq}
    }
    %\prop_show:c { g__uftag_struct_\g__uftag_struct_stack_current_tl _prop }
    %\seq_show:c {g__uftag_struct_kids_\l__uftag_struct_stack_parent_tmp_tl _seq}
  \group_end:
 }

\cs_new_protected:Nn \uftag_struct_end:
 {%take the current structure num from the stack:
  %the objects are written later, lua mode hasn't all needed info yet
  %\seq_show:N \g__uftag_struct_stack_seq
  \seq_gpop:NNTF \g__uftag_struct_stack_seq \l_tmpa_tl
   {
    \int_compare:nNnT {\l__uftag_loglevel_int} > { 0 }
     {
      \__uftag_check_info_closing_struct:o { \g__uftag_struct_stack_current_tl }
     }
   }
   { \__uftag_check_no_open_struck: }
  % get the previous one, shouldn't be empty as the root should be there
  \seq_get:NNTF \g__uftag_struct_stack_seq \l_tmpa_tl
   {
    \tl_gset:NV   \g__uftag_struct_stack_current_tl \l_tmpa_tl
   }
   {
    \__uftag_check_no_open_struck:
   }
 }

\cs_new_protected:Nn \uftag_struct_use:n %#1 is the label
 {
  \prop_if_exist:cTF
   { g__uftag_struct_\zref@extractdefault{tagpdfstruct-#1}{tagstruct}{unknown}_prop } %??????????
   {
    \__uftag_check_struct_used:n {#1}
    %add the label structure as kid to the current structure (can be the root)
    \__uftag_struct_kid_struct_gput_right:nn
     { \g__uftag_struct_stack_current_tl }
     { \zref@extractdefault{tagpdfstruct-#1}{tagstruct}{0} }
     %add the current structure to the labeled one as parents
    \__uftag_prop_gput:cnx
     { g__uftag_struct_\zref@extractdefault{tagpdfstruct-#1}{tagstruct}{0}_prop }
     { P }
     {
      \prop_item:cn { g__uftag_struct_\g__uftag_struct_stack_current_tl _prop} { objnum }~0~R
     }
   }
   {\msg_warning:nnn{uftag}{struct-label-unknown}{#1}}
 }


%%%% Code to tag links
%%%% this works for url, see exp-link.pdf.
%%%% it must be checked for other links

\cs_new_protected:Nn \__uftag_struct_finish_link:
{
 \bool_if:NT \g_uftag_active_struct_bool
 {
 %get the number of the parent link structure:
 \seq_get:NNF
    \g__uftag_struct_stack_seq
    \l__uftag_struct_stack_parent_tmp_tl
    {
     \msg_error:nn { uftag } { struct-faulty-nesting }
    }
  %put the obj number of link annot in the kid entry:
  \__uftag_struct_kid_link_gput_right:nx
  {
   \l__uftag_struct_stack_parent_tmp_tl
  }
  {
   \int_use:N\__uftag_pdf_lastlink:
  }
 % add the parent obj number to the parent tree:
  \__uftag_parenttree_add_objr:nn
  {
   \int_use:N\c@g__uftag_parenttree_obj_int
  }
  {
   \prop_item:cn{ g__uftag_struct_\l__uftag_struct_stack_parent_tmp_tl _prop }
   { objnum }
  }
 % increase the int:
 \stepcounter{ g__uftag_parenttree_obj_int }
 }
}

\endinput
