% ----------------------------------------------------------------------------
% the XSIM package - auxfile module
% 
%   eXercise Sheets IMproved
% 
% ----------------------------------------------------------------------------
% Clemens Niederberger
% Web:    https://github.com/cgnieder/xsim
% E-Mail: contact@mychemistry.eu
% ----------------------------------------------------------------------------
% Copyright 2017--2020 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.
% ----------------------------------------------------------------------------
% If you have any ideas, questions, suggestions or bugs to report, please
% feel free to contact me.
% ----------------------------------------------------------------------------
\XSIMmodule{auxfile}{writing stuff to an auxiliary file}

\prg_new_conditional:Npnn \xsim_if_use_aux: {p,T,F,TF}
  {
    \bool_if:NTF \g_xsim_use_aux_bool
      { \prg_return_true: }
      { \prg_return_false: }
  }

\cs_new_protected:Npn \xsim_write_to_aux:n #1
  {
    \legacy_if:nT {@filesw}
      {
        \xsim_if_use_aux:TF
          { \iow_now:Nn \@auxout {#1} }
          { \iow_now:Nn \l__xsim_aux_file_iow {#1} }
      }
  }
\cs_generate_variant:Nn \xsim_write_to_aux:n {x}

% --------------------------------------------------------------------------

\cs_new_protected:Npn \XSIM #1 { \use:c {XSIMaux#1} }

\cs_new_protected:Npn \xsim_new_aux_property:cpn #1
  { \cs_new_protected:cpn {XSIMaux#1} }

\cs_new_protected:Npn \xsim_add_property_to_aux:nn #1#2
  {
    \xsim_verbose:n { Writing~ command~ \XSIM {#1}~ to~ aux~ file }
    \xsim_write_to_aux:x { \token_to_str:N \XSIM {#1} #2 }
  }

\xsim_at_begin_document:n
  {
    \iow_now:Nx \@auxout
      { \token_to_str:N \providecommand \token_to_str:N \XSIM [1] {} }
  }

% ----------------------------------------------------------------------------

\xsim_if_use_aux:F
  {
    \iow_new:N \l__xsim_aux_file_iow
    \xsim_at_begin_document:n
      { \iow_open:Nn \l__xsim_aux_file_iow { \c_sys_jobname_str .xsim } }
  }

\cs_new_protected:Npn \xsim_close_aux:
  {
    \xsim_if_use_aux:F
      {
        \iow_close:N \l__xsim_aux_file_iow
        \legacy_if:nT {@filesw}
          { \iow_now:Nx \@auxout { \token_to_str:N \XSIM {readaux} } }
      }
  }

\xsim_new_aux_property:cpn {readaux}
  {
    \file_if_exist:nT { \c_sys_jobname_str .xsim }
      { \file_input:n { \c_sys_jobname_str .xsim } }
  }

% ----------------------------------------------------------------------------
% list for recording values that need to be written to the aux file and
% updated at begin document

\str_new:N \l__xsim_split_aux_lists_str
\keys_define:nn {xsim}
  {
    split-aux-lists .code:n    = \str_set:Nn \l__xsim_split_aux_lists_str {#1} ,
    split-aux-lists .initial:n = ||
  }

% define list:
% #1: name
\cs_new_protected:Npn \xsim_new_list:n #1
  {
    \xsim_verbose:n { Defining~ new~ auxfile~ list~ `#1'. }
    \prop_new:c {g__xsim_list_#1_prop}
    \seq_new:c {g__xsim_list_#1_seq}
    \seq_new:c {g__xsim_list_recorded_#1_seq}
    \xsim_new_aux_property:cpn {#1} ##1
      {
        \prop_gclear:c {g__xsim_list_#1_prop}
        \tl_if_blank:nF {##1}
          {
            \seq_gset_split:cVx {g__xsim_list_#1_seq}
              \l__xsim_split_aux_lists_str
              { \tl_to_str:n {##1} }
            \seq_map_inline:cn {g__xsim_list_#1_seq}
              { \prop_gput:cnn {g__xsim_list_#1_prop} {####1} {} }
          }
      }
    \xsim_at_begin_document:n
      {
        \seq_gclear:c {g__xsim_list_recorded_#1_seq}
        \seq_set_eq:Nc \l__xsim_tmpa_seq {g__xsim_list_#1_seq}
        \seq_map_inline:Nn \l__xsim_tmpa_seq
          {
            \str_set:Nn \l__xsim_tmpa_str {##1}
            \seq_gput_right:cV {g__xsim_list_recorded_#1_seq} \l__xsim_tmpa_str
          }
        \seq_gremove_duplicates:c {g__xsim_list_recorded_#1_seq}
      }
  }

% add to or remove from list:
% #1: name
% #2: entry
\cs_new_protected:Npn \xsim_add_to_list:nn #1#2
  {
    \xsim_verbose:n { Adding~ `#2'~ to~ list~ `#1'. }
    \str_set:Nn \l__xsim_tmpa_str {#2}
    \prop_gput:cnn {g__xsim_list_#1_prop} {#2} {}
    \seq_if_in:cVT {g__xsim_list_#1_seq} \l__xsim_tmpa_str
      { \seq_gremove_all:cV {g__xsim_list_#1_seq} \l__xsim_tmpa_str }
    \seq_gput_right:cV {g__xsim_list_#1_seq} \l__xsim_tmpa_str
  }
\cs_generate_variant:Nn \xsim_add_to_list:nn {nx}

% #1: name
% #2: entry
\cs_new_protected:Npn \xsim_remove_from_list:nn #1#2
  {
    \xsim_verbose:n { Removing~ `#2'~ to~ list~ `#1'. }
    \str_set:Nn \l__xsim_tmpa_str {#2}
    \prop_if_in:cnT {g__xsim_list_#1_prop} {#2}
      { \prop_gremove:cn {g__xsim_list_#1_prop} {#2} }
    \seq_if_in:cVT {g__xsim_list_#1_seq} \l__xsim_tmpa_str
      { \seq_gremove_all:cV {g__xsim_list_#1_seq} \l__xsim_tmpa_str }
    \seq_if_in:cVT {g__xsim_list_recorded#1_seq} \l__xsim_tmpa_str
      { \seq_gremove_all:cV {g__xsim_list_recorded_#1_seq} \l__xsim_tmpa_str }
  }
\cs_generate_variant:Nn \xsim_remove_from_list:nn {nx}

% check if in list:
% #1: name
% #2: entry
\prg_new_conditional:Npnn \xsim_if_in_list:nn #1#2 {p,T,F,TF}
  {
    \prop_if_in:cnTF {g__xsim_list_#1_prop} {#2}
      { \prg_return_true: }
      { \prg_return_false: }
  }
\cs_generate_variant:Nn \xsim_if_in_list:nnTF {nx}
\cs_generate_variant:Nn \xsim_if_in_list:nnT  {nx}

\cs_new:Npn \xsim_list_show:n #1
  { \prop_show:c {g__xsim_list_#1_prop}  }

\bool_new:N \l__xsim_empty_lists_bool
\cs_new_protected:Npn \xsim_empty_lists:
  { \bool_set_true:N \l__xsim_empty_lists_bool }

% update list (should be used inside \xsim_at_end_document:n):
% #1: name
\cs_new_protected:Npn \xsim_update_list:n #1
  {
    \xsim_verbose:n { Updating~ list~ `#1'. }
    \seq_remove_duplicates:c {g__xsim_list_#1_seq}
    \seq_remove_duplicates:c {g__xsim_list_recorded_#1_seq}
    \str_set:Nx \l__xsim_tmpa_str
      { \seq_use:cn {g__xsim_list_#1_seq} {} }
    \str_set:Nx \l__xsim_tmpb_str
      { \seq_use:cn {g__xsim_list_recorded_#1_seq} {} }
    \str_if_eq:NNF \l__xsim_tmpa_str \l__xsim_tmpb_str
      { \xsim_rerun: }
    \bool_if:NF \l__xsim_empty_lists_bool
      {
        \xsim_add_property_to_aux:nn {#1}
          { { \seq_use:cV {g__xsim_list_#1_seq} \l__xsim_split_aux_lists_str } }
      }
  }

% loop over list:
% #1: name
% #2: code
\cs_new_protected:Npn \xsim_foreach_list_entry:nn #1#2
  { \seq_map_inline:cn {g__xsim_list_recorded_#1_seq} {#2} }

\cs_new_protected:Npn \xsim_foreach_new_list_entry:nn #1#2
  { \seq_map_inline:cn {g__xsim_list_#1_seq} {#2} }

% length of a list:
% #1: name
\cs_new:Npn \xsim_list_count:n #1
  { \seq_count:c {g__xsim_list_recorded_#1_seq} }

% item of a list:
% #1: name
% #2: integer
\cs_new:Npn \xsim_list_item:nn #1#2
  { \seq_item:cn {g__xsim_list_recorded_#1_seq} {#2} }

% ----------------------------------------------------------------------------
\file_input_stop:
