% --------------------------------------------------------------------------
% the CHEMMACROS package
%
%   comprehensive support for typesetting chemistry documents
%
% --------------------------------------------------------------------------
% Clemens Niederberger
% --------------------------------------------------------------------------
% https://github.org/cgnieder/chemmacros/
% contact@mychemistry.eu
% --------------------------------------------------------------------------
% If you have any ideas, questions, suggestions or bugs to report, please
% feel free to contact me.
% --------------------------------------------------------------------------
% Copyright 2011-2019 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 chemmacros package consists of the following files
%  - chemmacros.sty, chemmacros4.sty, chemmacros5.sty,
%  - chemmacros_en.tex, chemmacros_en.pdf,
%  - quite a number of module files following the naming scheme
%    chemmacros.module.*.code.tex
%  - README
 % --------------------------------------------------------------------------
\RequirePackage{expl3,xparse,l3keys2e}
\ExplSyntaxOn

% --------------------------------------------------------------------------
% package information:
\ProvidesExplPackage
  {chemmacros5}
  {\c_chemmacros_date_tl}
  {\c_chemmacros_version_tl}
  {\c_chemmacros_info_tl \c_space_tl (CN)}

% --------------------------------------------------------------------------
\msg_new:nnn {chemmacros} {package-option}
  {
    Unknown~ option~ `#1'!~ Since~ v5.0~ chemmacros~ has~ no~ package~
    options~ any~ more!
  }

\msg_new:nnn {chemmacros} {module-not-available}
  {
    The~ module~ `#1'~ is~ only~ available~ in~ compatibility~ mode~ #2~ or~
    higher.
  }

\cs_generate_variant:Nn \msg_warning:nnn { nnV }

\keys_define:nn {chemmacros/package-options}
  {
    compatibility .code:n = ,
    unknown       .code:n =
      \msg_warning:nnV {chemmacros} {package-option} \CurrentOption
  }

\ProcessKeysPackageOptions {chemmacros/package-options}

% --------------------------------------------------------------------------
% messages:
\msg_new:nnn {chemmacros} {module-missing}
  {
    You've~ requested~ the~ chemmacros~ module~ `#1'~ but~ it~ appears~ to~
    be~ missing~ on~ your~ system.~ Maybe~ you've~ misspelled~ the~ name?~
    Loading~ the~ module~ will~ abort~ \msg_line_context:
  }

\msg_new:nnn {chemmacros} {loading-module}
  {
    (chemmacros) \c_space_tl \c_space_tl \c_space_tl \c_space_tl
    Loading~ module~ `#1'...
  }

% --------------------------------------------------------------------------
% variants of kernel functions:
\cs_generate_variant:Nn \tl_if_eq:nnTF       { xx , V }
\cs_generate_variant:Nn \seq_set_split:Nnn   { Nnx }
\cs_generate_variant:Nn \prop_item:Nn        { NV }
\cs_generate_variant:Nn \seq_item:Nn         { cV }
\cs_generate_variant:Nn \int_to_arabic:n     { V }
\cs_generate_variant:Nn \tl_replace_once:Nnn { NnV }
\cs_generate_variant:Nn \prop_gput:Nnn       { cxx , NVf }
\cs_generate_variant:Nn \msg_error:nnn       { nnV }
\cs_generate_variant:Nn \msg_warning:nnn     { nnV }
\cs_generate_variant:Nn \msg_warning:nnnn    { nnV }
\cs_generate_variant:Nn \vbox_set:Nn         { NV }
\cs_generate_variant:Nn \keys_define:nn      { x } 
\cs_generate_variant:Nn \keys_set:nn         { x , nx }

% --------------------------------------------------------------------------
% temporary variables:
\tl_new:N    \l__chemmacros_tmpa_tl
\tl_new:N    \l__chemmacros_tmpb_tl
\tl_new:N    \l__chemmacros_tmpc_tl
\tl_new:N    \l__chemmacros_tmpd_tl

\bool_new:N  \l__chemmacros_tmpa_bool
\bool_new:N  \l__chemmacros_tmpb_bool
\bool_new:N  \l__chemmacros_tmpc_bool

\dim_new:N   \l__chemmacros_tmpa_dim
\dim_new:N   \l__chemmacros_tmpb_dim
\dim_new:N   \l__chemmacros_tmpc_dim

\seq_new:N   \l__chemmacros_tmpa_seq
\seq_new:N   \l__chemmacros_tmpb_seq
\seq_new:N   \l__chemmacros_tmpc_seq

\int_new:N   \l__chemmacros_tmpa_int
\int_new:N   \l__chemmacros_tmpb_int
\int_new:N   \l__chemmacros_tmpc_int

\box_new:N   \l__chemmacros_tmpa_box
\box_new:N   \l__chemmacros_tmpb_box
\box_new:N   \l__chemmacros_tmpc_box

\clist_new:N \l__chemmacros_tmpa_clist
\clist_new:N \l__chemmacros_tmpb_clist
\clist_new:N \l__chemmacros_tmpc_clist

% --------------------------------------------------------------------------
% module mechanism:
\tl_const:Nn \c__chemmacros_module_extension_tl {code.tex}
\tl_const:Nn \c__chemmacros_module_prefix_tl    {chemmacros.module}

\seq_new:N \g__chemmacros_loaded_modules_seq
\prop_new:N \g__chemmacros_loaded_modules_prop

\cs_new_protected:Npn \chemmacros_load_modules:n #1
  { \clist_map_inline:nn {#1} { \chemmacros_load_module:n {##1} } }

\cs_new_protected:Npn \chemmacros_load_module:n #1
  {
    \tl_set:Nx \l__chemmacros_tmpa_tl { \tl_trim_spaces:n {#1} }
    \__chemmacros_load_module:V \l__chemmacros_tmpa_tl
  }

\cs_new_protected:Npn \__chemmacros_load_module:n #1
  {
    \chemmacros_if_module_loaded:nF {#1}
      {
        \chemmacros_if_module_exist:nTF {#1}
          {
            \__chemmacros_use_module_hook:nn {#1} {before}
            \msg_log:nnn {chemmacros} {loading-module} {#1}
            \@onefilewithoptions
              {\c__chemmacros_module_prefix_tl.#1}[][]
              \c__chemmacros_module_extension_tl
            \__chemmacros_use_module_hook:nn {#1} {after}
          }
          { \msg_error:nnn {chemmacros} {module-missing} {#1} }
      }
  }
\cs_generate_variant:Nn \__chemmacros_load_module:n { V }

\prg_new_conditional:Npnn \chemmacros_if_module_loaded:n #1 {p,T,F,TF}
  {
    \seq_if_in:NnTF \g__chemmacros_loaded_modules_seq {#1}
      { \prg_return_true: }
      { \prg_return_false: }
  }

\prg_new_conditional:Npnn \chemmacros_if_module_exist:n #1 {p,T,F,TF}
  {
    \file_if_exist:nTF
      {\c__chemmacros_module_prefix_tl.#1.\c__chemmacros_module_extension_tl}
      { \prg_return_true: }
      { \prg_return_false: }
  }

% --------------------------------------------------------------------------
\ChemCompatibilityFrom{5.1}
% module hooks:
% #1: module
% #2: code
\cs_new_protected:Npn \chemmacros_after_module:nn #1#2
  {
    \chemmacros_if_module_loaded:nTF {#1}
      {#2}
      { \__chemmacros_add_to_module_hook:nnn {#1} {after} {#2} }
  }

% #1: module
% #2: code
\cs_new_protected:Npn \chemmacros_before_module:nn #1#2
  {
    \chemmacros_if_module_loaded:nF {#1}
      { \__chemmacros_add_to_module_hook:nnn {#1} {before} {#2} }
  }
\EndChemCompatibility

% #1: module
% #2: hook name
% #3: code
\cs_new_protected:Npn \__chemmacros_add_to_module_hook:nnn #1#2#3
  {
    \chemmacros_if_module_loaded:nF {#1}
      {
        \tl_if_exist:cF {g__chemmacros_module_#1_#2_hook_tl}
          { \tl_new:c {g__chemmacros_module_#1_#2_hook_tl} }
        \tl_gput_right:cn {g__chemmacros_module_#1_#2_hook_tl} {#3}
      }
  }

% #1: module
% #2: hook name
\cs_new_protected:Npn \__chemmacros_use_module_hook:nn #1#2
  {
    \tl_if_exist:cT {g__chemmacros_module_#1_#2_hook_tl}
      {
        \tl_use:c {g__chemmacros_module_#1_#2_hook_tl}
        \tl_gclear:c {g__chemmacros_module_#1_#2_hook_tl}
      }
  }

% --------------------------------------------------------------------------
\cs_new_protected:Npn \__chemmacros_module:nnnn #1#2#3#4
  {
    \chemmacros_if_compatibility:nnF {>=} {#4}
      {
        \msg_warning:nnnn {chemmacros} {module-not-available} {#2} {#4}
        \file_input_stop:
      }
    \seq_gput_right:Nn \g__chemmacros_loaded_modules_seq {#2}
    \prop_gput:Nnn \g__chemmacros_loaded_modules_prop {#2} {#3}
    \ProvidesFile
      {\c__chemmacros_module_prefix_tl.#2.\c__chemmacros_module_extension_tl}
      [
        \c_chemmacros_date_tl
        \c_space_tl
        v \c_chemmacros_version_tl
        \c_space_tl
        chemmacros~ module~ `#2'~ #3
      ]
    \bool_if:nF {#1} { \ExplSyntaxOn }
  }
  
% define a chemmacros module:
% standard modules are written in the expl3 programming environment, the
% starred version only uses a 2e programming environment, i.e., with @ as a
% letter
% #1: boolean
% #2: name
% #3: description
\NewDocumentCommand \ChemModule {smmO{5.0}}
  { \__chemmacros_module:nnnn {#1} {#2} {#3} {#4} }

% --------------------------------------------------------------------------
% command for loading modules:
\NewDocumentCommand \usechemmodule {m} { \chemmacros_load_modules:n {#1} }

% --------------------------------------------------------------------------
% load default modules:
\chemmacros_load_modules:n
  {
    % required modules:
    base,
    errorcheck,
    lang, greek,
    chemformula,
    % preloaded modules:
    acid-base,
    symbols,
    charges,
    particles,
    phases ,
    nomenclature
  }

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

% --------------------------------------------------------------------------
Modules: (* = preloaded)
 - internal modules:
   - base *
   - errorcheck *
   - lang *
   - greek *
   - chemformula *
   - tikz
 - user modules:
   - acid-base *
   - all
   - charges *
   - isotopes
   - mechanisms
   - newman
   - nomenclature *
   - orbital
   - particles *
   - phases *
   - reactions
   - redox
   - scheme
   - spectroscopy
   - symbols *
   - thermodynamics
   - units
   - xfrac

% --------------------------------------------------------------------------
Version history
2015/08/29 - initial release v5.0
2015/09/23 - add module hooks `before' and `after'
           - allow to give minimal compatibility version to a module: this
             should be the first version when a module is published and
             shouldn't be changed any more; loading the corresponding module
             will abort when compatibility is too low
           - store loaded modules in a seq and in a prop
2015/10/14 - bug fix in the module hook mechanism
           - bug fix in \chemmacros_if_module_loaded:n
           - new `errorcheck' module
