% --------------------------------------------------------------------------
% the ENOTEZ package
% 
%   Endnotes for LaTeX2e
% 
% --------------------------------------------------------------------------
% Clemens Niederberger
% Web:    https://bitbucket.org/cgnieder/enotez/
% E-Mail: contact@mychemistry.eu
% --------------------------------------------------------------------------
% Copyright 2011-2012 Clemens Niederberger
% 
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3
% of this license or (at your option) any later version.
% The latest version of this license is in
%   http://www.latex-project.org/lppl.txt
% and version 1.3 or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
% 
% This work has the LPPL maintenance status `maintained'.
% 
% The Current Maintainer of this work is Clemens Niederberger.
% --------------------------------------------------------------------------
% The enotez package consists of the files
%  - enotez.sty, enotez_en.tex, enotez_en.pdf, README
% --------------------------------------------------------------------------
% If you have any ideas, questions, suggestions or bugs to report, please
% feel free to contact me.
% --------------------------------------------------------------------------
\RequirePackage{ expl3 , xparse , l3keys2e , xtemplate }
\ProvidesExplPackage
  {enotez}
  {2012/07/24}
  {0.3a}
  {Endnotes for LaTeX2e}

% --------------------------------------------------------------------------
% variables:
\bool_new:N \l_enotez_print_note_bool
\bool_new:N \l_enotez_reset_bool
\bool_new:N \l_enotez_totoc_bool
\bool_new:N \l_enotez_hyperref_bool
\bool_new:N \l_enotez_hyperfootnotes_bool
\bool_new:N \l_enotez_split_bool

\tl_new:N   \l_enotez_tmpa_tl
\tl_new:N   \l_enotez_tmpb_tl
\tl_new:N   \l_enotez_tmpc_tl
\tl_new:N   \l_enotez_totoc_tl
\tl_new:N   \l_enotez_list_name_tl
\tl_set:Nn  \l_enotez_list_name_tl { Notes }
\tl_new:N   \l_enotez_endnote_text_tl
\tl_new:N   \l_enotez_endnote_mark_tl
\tl_new:N   \l_enotez_list_instance_tl
\tl_set:Nn  \l_enotez_list_instance_tl { plain }
\tl_new:N   \l_enotez_split_tl
\tl_new:N   \l_enotez_splitted_list_sectioning_tl
\tl_new:N   \l_enotez_splitted_title_tl
\tl_set:Nn  \l_enotez_splitted_title_tl { Notes~from~<name>~<ref> }
\tl_new:N   \l_enotez_list_splitted_title_tl

\int_new:N  \g_enotez_endnote_id_int
\int_zero:N \g_enotez_endnote_id_int
\int_new:N  \g_enotez_endnote_mark_int
\int_zero:N \g_enotez_endnote_mark_int
\int_new:N  \g_enotez_list_printed_int
\int_zero:N \g_enotez_list_printed_int
\int_new:N  \l_enotez_tmpa_int

\prop_new:N \g_enotez_endnote_text_prop
\prop_new:N \g_enotez_endnote_mark_prop
\prop_new:N \g_enotez_endnote_split_prop
\prop_new:N \g_enotez_endnote_sect_prop
\prop_new:N \g_enotez_endnote_man_prop

% --------------------------------------------------------------------------
% options:
\cs_new_eq:NN \enotez_counter_format:n \int_to_arabic:n
\cs_generate_variant:Nn \enotez_counter_format:n { V }

\keys_define:nn { enotez }
  {
    list-name        .tl_set:N           = \l_enotez_list_name_tl                ,
    reset            .bool_set:N         = \l_enotez_reset_bool                  ,
    counter-format   .choice_code:n      =
      \cs_set_eq:Nc \enotez_counter_format:n { int_to_ \l_keys_choice_tl :n }    ,
    counter-format   .generate_choices:n =
      { arabic , alph , Alph , roman , Roman }                                   ,
    totoc            .choice_code:n      =
      \tl_if_eq:VnTF \l_keys_choice_tl { false }
        { \bool_set_false:N \l_enotez_totoc_bool }
        {
          \bool_set_true:N \l_enotez_totoc_bool
          \tl_set_eq:NN \l_enotez_totoc_tl \l_keys_choice_tl
        }                                                                        ,
    totoc            .generate_choices:n =
      { section , chapter , false }                                              ,
    split            .choice_code:n      =
      \tl_if_eq:VnTF \l_keys_choice_tl { false }
        { \bool_set_false:N \l_enotez_split_bool }
        { \bool_set_true:N \l_enotez_split_bool }
      \tl_set_eq:NN \l_enotez_split_tl \l_keys_choice_tl                         ,
    split            .generate_choices:n =
      { section , chapter , false }                                              ,
    split-sectioning .tl_set:N           = \l_enotez_splitted_list_sectioning_tl ,
    split-title      .tl_set:N           = \l_enotez_splitted_title_tl           ,
    list-style       .tl_set:N           = \l_enotez_list_instance_tl            ,
  }
\cs_generate_variant:Nn \tl_if_eq:nnTF { Vn , nx }
\cs_generate_variant:Nn \tl_if_eq:nnT  { xx }

% --------------------------------------------------------------------------
% typeset the actual mark:
% #1: id
% #2: mark
\cs_new:Npn \enotez_write_mark:nn #1#2
  {
    \bool_if:NTF \l_enotez_hyperfootnotes_bool
      { \textsuperscript { \hyperlink { enz.#1 } { #2 } } }
      { \textsuperscript { #2 } }
  }

% the internal endnote:
\cs_new:Npn \enotez_endnote:nn #1#2
  {
    \int_gincr:N \g_enotez_endnote_id_int
    \quark_if_no_value:nTF { #1 }
      {
        \int_gincr:N \g_enotez_endnote_mark_int
        \enotez_write_mark:nn
          { \int_use:N \g_enotez_endnote_id_int }
          { \enotez_counter_format:V \g_enotez_endnote_mark_int }
        \tl_set:Nn \l_tmpa_tl { chapter }
        \bool_if:nTF { \l_enotez_split_bool && \tl_if_eq_p:NN \l_enotez_split_tl \l_tmpa_tl }
          {
            \enotez_save_note:xxxxnn
              { \int_use:N \g_enotez_endnote_id_int }
              { \int_use:N \g_enotez_endnote_mark_int }
              { \int_use:N \g_enotez_list_printed_int }
              { \thechapter }
              { a }
              { #2 }
          }
          {
            \enotez_save_note:xxxxnn
              { \int_use:N \g_enotez_endnote_id_int }
              { \int_use:N \g_enotez_endnote_mark_int }
              { \int_use:N \g_enotez_list_printed_int }
              { \thesection }
              { a }
              { #2 }
          }
      }
      {
        \enotez_write_mark:nn { \int_use:N \g_enotez_endnote_id_int } { #1 }
        \tl_set:Nn \l_tmpa_tl { chapter }
        \bool_if:nTF { \l_enotez_split_bool && \tl_if_eq_p:NN \l_enotez_split_tl \l_tmpa_tl }
          {
            \enotez_save_note:xnxxnn
              { \int_use:N \g_enotez_endnote_id_int }
              { #1 }
              { \int_use:N \g_enotez_list_printed_int }
              { \thechapter }
              { m }
              { #2 }
          }
          {
            \enotez_save_note:xnxxnn
              { \int_use:N \g_enotez_endnote_id_int }
              { #1 }
              { \int_use:N \g_enotez_list_printed_int }
              { \thesection }
              { m }
              { #2 }
          }
      }
  }

% --------------------------------------------------------------------------
% in some cases caption making commands need to be patched. preparations:
\cs_new:Npn \enotez_tmp_endnote:nn {}

\cs_new:Npn \enotez_caption_endnote:nn #1#2
  {
    \IfNoValueTF { #1 }
      {
        \enotez_write_mark:nn
          { \int_use:N \g_enotez_endnote_id_int }
          { \enotez_counter_format:V \g_enotez_endnote_mark_int }
      }
      { \enotez_write_mark:nn { \int_use:N \g_enotez_endnote_id_int } { #1 } }
  }

\cs_new:Npn \enotez@koma@disable
  { \cs_set_eq:NN \enotez_endnote:nn \enotez_caption_endnote:nn }

\cs_new:Npn \enotez@memoir@disable
  {
    \cs_set_eq:NN \enotez_tmp_endnote:nn \enotez_endnote:nn
    \cs_set_eq:NN \enotez_endnote:nn \enotez_caption_endnote:nn
  }

\cs_new:Npn \enotez@memoir@enable
  { \cs_set_eq:NN \enotez_endnote:nn \enotez_tmp_endnote:nn }

\cs_new:Npn \enotez@caption@disable
  {
    \patchcmd \caption@@make
      { \caption@@@make }
      { \enotez@koma@disable\caption@@@make }
      {}{}
  }

% if we're in a KOMA class, \@@makecaption needs to be patched:
\AtBeginDocument
  {
    \@ifpackageloaded { caption }
      { \RequirePackage { etoolbox } \enotez@caption@disable }
      {
        \cs_if_free:NF \KOMAClassName
          {
            \RequirePackage { etoolbox }
            \patchcmd \@@makecaption
              { \setlength{\@tempdima}{\cap@width} }
              { \enotez@koma@disable\setlength{\@tempdima}{\cap@width} }{}{}
          }
      }
  }

% if we're in memoir, \@makecaption needs to be patched:
\@ifclassloaded { memoir }
  {
    \AtBeginDocument
      {
        \@ifpackageloaded { caption } { }
          {
            \RequirePackage { etoolbox }
            \patchcmd \@makecaption
              { \let\@contfnote\footnote }
              { \enotez@memoir@disable\let\@contfnote\footnote }{}{}
            \patchcmd \@makecaption
              { \let\footnote\@contfnote }
              { \enotez@memoir@enable\let\footnote\@contfnote }{}{}
          }
      }
  }{}

% --------------------------------------------------------------------------
% save the notes to the aux file:
% #1 global id
% #2 mark
% #3 split id
% #4 section/chapter
% #5 a/m (automatic/manually)
% #6 text
\cs_new:Npn \enotez_save_note:nnnnnn #1#2#3#4#5#6
  { \iow_now:Nn \@auxout { \enotez@note { #1 } { #2 } { #3 } { #4 } { #5 } { #6 } } }
\cs_generate_variant:Nn \enotez_save_note:nnnnnn { xxxxnn , xnxxnn }

\cs_new:Npn \enotez@note #1#2#3#4#5#6
  {
    \expandafter \xdef \csname enotez@#1@note \endcsname { #2 }
    \prop_gput:Nnn \g_enotez_endnote_mark_prop  { #1 } { #2 }
    \prop_gput:Nnn \g_enotez_endnote_split_prop { #1 } { #3 }
    \prop_gput:Nnn \g_enotez_endnote_sect_prop  { #1 } { #4 }
    \prop_gput:Nnn \g_enotez_endnote_man_prop   { #1 } { #5 }
    \prop_gput:Nnn \g_enotez_endnote_text_prop  { #1 } { #6 }
  }

% a try to check if a rerun is necessary:
\AtEndDocument
  {
    \cs_set:Npn \enotez@note #1#2#3#4#5#6
      {
        \def\reserved@a{#2}
        \expandafter\ifx\csname enotez@#1@note \endcsname\reserved@a\else
        \@tempswatrue\fi
      }
  }

% --------------------------------------------------------------------------
% the actual user command; I would use \NewDocumentCommand but that would
% disable compatibility with `fnpct'
\cs_new_protected:Npn \endnote
  {
    \peek_meaning_ignore_spaces:NTF [
      { \enotez_endnote_aux:w }
      { \enotez_endnote:nn { \q_no_value } }
  }

\cs_new:Npn \enotez_endnote_aux:w [#1]#2
  { \enotez_endnote:nn { #1 } { #2 } }

% --------------------------------------------------------------------------
% the list of notes
\DeclareObjectType { enotez-list } { 1 }

\DeclareTemplateInterface { enotez-list } { paragraph } { 1 }
  {
    heading       : function 1 = \section*{#1}   ,
    format        : tokenlist  = \footnotesize   ,
    number        : function 1 = \enmark{#1}     ,
    number-format : tokenlist  = \normalfont     ,
    notes-sep     : length     = .5\baselineskip ,
  }

\DeclareTemplateCode { enotez-list } { paragraph } { 1 }
  {
    heading       = \enotez_list_heading:n          ,
    format        = \l_enotez_list_format_tl        ,
    number        = \enotez_list_number:n           ,
    number-format = \l_enotez_list_number_format_tl ,
    notes-sep     = \l_enotez_list_notes_sep_dim    ,
  }
  {
    \AssignTemplateKeys
    \bool_if:NT \l_enotez_totoc_bool
      {
        \bool_if:NT \l_enotez_hyperref_bool { \phantomsection }
        \addcontentsline { toc } { \l_enotez_totoc_tl } { \l_enotez_list_name_tl }
      }
    \enotez_list_heading:n { \l_enotez_list_name_tl }
        \group_begin:
      \tl_use:N \l_enotez_list_format_tl
      \int_zero:N \l_enotez_tmpa_int
      \int_do_while:nn { \l_enotez_tmpa_int <= \g_enotez_list_printed_int }
        {
          \prop_map_inline:Nn \g_enotez_endnote_mark_prop
            {
              \tl_if_eq:xxT
                { \int_use:N \l_enotez_tmpa_int }
                { \prop_get:Nn \g_enotez_endnote_split_prop { ##1 } }
                {
                  \enotez_get_split_title:n { ##1 }
                  \enotez_get_note:nn { #1 } { ##1 }
                  \bool_if:NT \l_enotez_print_note_bool
                    {
                      \par\noindent
                      \llap
                        {
                          \enotez_list_number:n
                            {
                              \bool_if:NT \l_enotez_hyperfootnotes_bool
                                {
                                  \box_move_up:nn { 1em }
                                    { \hbox:n { \hypertarget { enz.##1 } { } } }
                                }
                              \tl_use:N \l_enotez_list_number_format_tl
                              \tl_if_eq:nxTF { a }
                                { \prop_get:Nn \g_enotez_endnote_man_prop { ##1 } }
                                { \enotez_counter_format:V \l_enotez_endnote_mark_tl }
                                { \tl_use:N \l_enotez_endnote_mark_tl }
                            }
                          \tl_use:N \c_space_tl
                        }
                      \tl_use:N \l_enotez_endnote_text_tl
                    }
                }
              \par
              \dim_compare:nT { \l_enotez_list_notes_sep_dim != 0pt }
                { \addvspace { \l_enotez_list_notes_sep_dim } }
            }
          \int_incr:N \l_enotez_tmpa_int
        }
    \group_end:
  }

\DeclareTemplateInterface { enotez-list } { list } { 1 }
  {
    heading       : function 1 = \section*{#1} ,
    format        : tokenlist  = \footnotesize ,
    number        : function 1 = \enmark{#1}   ,
    number-format : tokenlist  = \normalfont   ,
    list-type     : tokenlist  = description   ,
  }

\DeclareTemplateCode { enotez-list } { list } { 1 }
  {
    heading       = \enotez_list_heading:n          ,
    format        = \l_enotez_list_format_tl        ,
    number        = \enotez_list_number:n           ,
    number-format = \l_enotez_list_number_format_tl ,
    list-type     = \l_enotez_list_type_tl
  }
  {
    \AssignTemplateKeys
    \bool_if:NT \l_enotez_totoc_bool
      {
        \bool_if:NT \l_enotez_hyperref_bool { \phantomsection }
        \addcontentsline { toc } { \l_enotez_totoc_tl } { \l_enotez_list_name_tl }
      }
    \enotez_list_heading:n { \l_enotez_list_name_tl }
    \group_begin:
      \tl_use:N \l_enotez_list_format_tl
      \int_zero:N \l_enotez_tmpa_int
      \int_do_while:nn { \l_enotez_tmpa_int <= \g_enotez_list_printed_int }
        {
          \prop_map_inline:Nn \g_enotez_endnote_mark_prop
            {
              \tl_clear:N \l_enotez_tmpc_tl
              \tl_if_eq:xxT
                { \int_use:N \l_enotez_tmpa_int }
                { \prop_get:Nn \g_enotez_endnote_split_prop { ##1 } }
                { \tl_put_right:Nn \l_enotez_tmpc_tl { ##1 } }
              \tl_if_blank:VF \l_enotez_tmpc_tl
                {
                  \enotez_get_split_title:n { ##1 }
                  \begin{\l_enotez_list_type_tl}
                }
              \tl_if_eq:xxT
                { \int_use:N \l_enotez_tmpa_int }
                { \prop_get:Nn \g_enotez_endnote_split_prop { ##1 } }
                {
                  \enotez_get_note:nn { #1 } { ##1 }
                  \bool_if:NT \l_enotez_print_note_bool
                    {
                      \item
                        [
                          \enotez_list_number:n
                            {
                              \bool_if:NT \l_enotez_hyperfootnotes_bool
                                {
                                  \box_move_up:nn { 1em }
                                    { \hbox:n { \hypertarget { enz.##1 } { } } }
                                }
                              \tl_use:N \l_enotez_list_number_format_tl
                              \tl_if_eq:nxTF { a }
                                { \prop_get:Nn \g_enotez_endnote_man_prop { ##1 } }
                                { \enotez_counter_format:V \l_enotez_endnote_mark_tl }
                                { \tl_use:N \l_enotez_endnote_mark_tl }
                            }
                        ]
                      \tl_use:N \l_enotez_endnote_text_tl
                    }
                }
              \tl_if_blank:VF \l_enotez_tmpc_tl { \end{\l_enotez_list_type_tl} }
            }
          \int_incr:N \l_enotez_tmpa_int
        }
    \group_end:
  }

% some default styles:
\DeclareInstance { enotez-list } { plain } { paragraph } {  }
\DeclareInstance { enotez-list } { description } { list } {  }
\DeclareInstance { enotez-list } { itemize } { list } { list-type = itemize }

% the titles in between the splits:
\cs_new:Npn \enotez_read_splitted_title:nn #1#2
  {
    \group_begin:
      \tl_set:Nn \l_tmpa_tl { #1 }
      \tl_replace_all:Nnn \l_tmpa_tl { <name> }
        { \enotez_first_upper:V \l_enotez_split_tl }
      \tl_replace_all:Nnn \l_tmpa_tl { <ref> }
        { \prop_get:Nn \g_enotez_endnote_sect_prop { #2 } }
      \tl_use:N \l_tmpa_tl
    \group_end:
  }
\cs_generate_variant:Nn \enotez_read_splitted_title:nn { V }

\cs_new:Npn \enotez_first_upper:n #1
  { \tl_to_uppercase:n { \tl_head:n { #1 } } \tl_tail:n { #1 } }
\cs_generate_variant:Nn \enotez_first_upper:n { V }

% determine which note's next:
\cs_new:Npn \enotez_get_note:nn #1#2
  {
    \IfBooleanTF { #1 }
      {
        \prop_get:NnN \g_enotez_endnote_mark_prop { #2 } \l_enotez_endnote_mark_tl
        \prop_get:NnN \g_enotez_endnote_text_prop { #2 } \l_enotez_endnote_text_tl
        \bool_set_true:N \l_enotez_print_note_bool
      }
      {
        \prop_get:NnN \g_enotez_endnote_split_prop { #2 } \l_enotez_tmpa_tl
        \bool_if:NTF \l_enotez_split_bool
          {
            \bool_set_true:N \l_enotez_print_note_bool
            \prop_gpop:NnN \g_enotez_endnote_mark_prop { #2 } \l_enotez_endnote_mark_tl
            \prop_gpop:NnN \g_enotez_endnote_text_prop { #2 } \l_enotez_endnote_text_tl
          }
          {
            \int_compare:nTF { \l_enotez_tmpa_tl = \g_enotez_list_printed_int }
              {
                \bool_set_true:N \l_enotez_print_note_bool
                \prop_gpop:NnN \g_enotez_endnote_mark_prop { #2 } \l_enotez_endnote_mark_tl
                \prop_gpop:NnN \g_enotez_endnote_text_prop { #2 } \l_enotez_endnote_text_tl
                \prop_gdel:Nn  \g_enotez_endnote_split_prop { #2 }
              }
              { \bool_set_false:N \l_enotez_print_note_bool }
          }
      }
  }

\cs_new:Npn \enotez_get_split_title:n #1
  {
    \prop_get:NnN \g_enotez_endnote_split_prop { #1 } \l_enotez_tmpa_tl
    \bool_if:NT \l_enotez_split_bool
      {
        \tl_if_eq:NNF \l_enotez_tmpa_tl \l_enotez_tmpb_tl
          {
            \tl_if_blank:VTF \l_enotez_splitted_list_sectioning_tl
              {
                \tl_if_eq:VnTF \l_enotez_split_tl { section }
                  { \subsection* }
                  { \section* }
              }
              { \use:c { \l_enotez_splitted_list_sectioning_tl } }
            {
              \enotez_read_splitted_title:Vn
                \l_enotez_splitted_title_tl { #1 }
            }
          }
      }
    \prop_get:NnN \g_enotez_endnote_split_prop { #1 } \l_enotez_tmpb_tl
  }

% the mark in the list:
\cs_new:Npn \enmark #1 { #1 . }

% internal printendnotes:
\cs_new:Npn \enotez_print_endnotes:nn #1#2
  {
    \IfNoValueTF { #2 }
      { \UseInstance { enotez-list } { \l_enotez_list_instance_tl } }
      { \UseInstance { enotez-list } { #2 } }
    { #1 }
    \bool_if:NF \l_enotez_split_bool
      {
        \bool_if:NTF \l_enotez_reset_bool
          { \int_gzero:N \g_enotez_endnote_mark_int }
        \int_gincr:N \g_enotez_list_printed_int
      }
  }

% the user command:
\NewDocumentCommand \printendnotes { so }
  {
    \bool_if:NTF \l_enotez_split_bool
      { \enotez_print_endnotes:nn { \BooleanFalse } { #2 } }
      { \enotez_print_endnotes:nn { #1 } { #2 } }
  }

% --------------------------------------------------------------------------
% process the options:
\ProcessKeysOptions { enotez }

\AtBeginDocument
  {
    \bool_if:NT \l_enotez_split_bool
      {
        \tl_if_eq:VnTF \l_enotez_split_tl { section }
          {
            \tl_put_left:Nn \section
              {
                \int_gincr:N \g_enotez_list_printed_int
                \bool_if:NT \l_enotez_reset_bool
                  { \int_gzero:N \g_enotez_endnote_mark_int }
              }
          }
          {
            \tl_put_left:Nn \chapter
              {
                \int_gincr:N \g_enotez_list_printed_int
                \bool_if:NT \l_enotez_reset_bool
                  { \int_gzero:N \g_enotez_endnote_mark_int }
              }
          }
      }
    \@ifpackageloaded { hyperref }
      {
        \bool_set_true:N \l_enotez_hyperref_bool
        \ifHy@hyperfootnotes
          \bool_set_true:N \l_enotez_hyperfootnotes_bool
        \else
          \bool_set_false:N \l_enotez_hyperfootnotes_bool
        \fi
      }
      {
        \bool_set_false:N \l_enotez_hyperref_bool
        \bool_set_false:N \l_enotez_hyperfootnotes_bool
      }
  }

% --------------------------------------------------------------------------
% the setup command:
\NewDocumentCommand \setenotez { +m }
  { \keys_set:nn { enotez } { #1 } \ignorespaces }

\tex_endinput:D
% --------------------------------------------------------------------------
% HISTORY:
2012/07/03 v0.1  - first public version on bitbucket
2012/07/05 v0.2  - added preliminary `split' option
                 - enable endnotes in captions with KOMA classes, `memoir' and
                   the `caption' package
2012/07/06 v0.2a - made the splitted list titles customizable
2012/07/07 v0.3  - list-building rewritten due to a design flaw
2012/07/24 v0.3a - adapted to deprecated functions in l3kernel and l3packages,
                   removed debugging leftover

% --------------------------------------------------------------------------
% TODO:
- make the headings obey the `totoc' option?