% --------------------------------------------------------------------------
%
% the CHEMMACROS package -- module: `base'
%
% --------------------------------------------------------------------------
% 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--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.
% --------------------------------------------------------------------------
\ChemModule{base}{2020/02/02 basic chemmacros module}

% for the document hooks
\ChemCompatibilityFrom{5.1}
\RequirePackage {etoolbox}
\EndChemCompatibility

% --------------------------------------------------------------------------
\msg_new:nnn {chemmacros} {command-deprecated}
  {
    The~ command~ \token_to_str:N #1 \c_space_tl is~ deprecated.~ Use~
    \token_to_str:N #2 \c_space_tl instead.
  }

% define a deprecated command with hints to the corresponding new one:
\cs_new_protected:Npn \chemmacros_define_deprecated:NN #1#2
  {
    \cs_set_protected:Npn #1
      {
        \msg_warning:nnnn {chemmacros} {command-deprecated} {#1} {#2}
        #2
      }
  }

\NewDocumentCommand \DeclareChemDeprecated {mm}
  { \chemmacros_define_deprecated:NN #1 #2 }

% --------------------------------------------------------------------------
% define a macro set:
% \NewChem... \RenewChem... \DeclareChem... \ProvideChem...
% #1: macro names
% #2: arg spec
% #3: internal command call
\cs_new_protected:Npn \chemmacros_new_macroset:nnn #1#2#3
  {
    \exp_args:Nc \NewDocumentCommand
      {
        NewChem
        \str_uppercase:f { \tl_head:n {#1} }
        \tl_tail:n {#1}
      }
      {#2}
      {
        \cs_if_free:NTF ##1
          { #3 }
          { \msg_error:nnn {chemmacros} {new-#1} {##1} }
      }
    \exp_args:Nc \NewDocumentCommand
      {
        RenewChem
        \str_uppercase:f { \tl_head:n {#1} }
        \tl_tail:n {#1}
      }
      {#2}
      {
        \cs_if_free:NTF ##1
          { \msg_error:nnn {chemmacros} {renew-#1} {##1} }
          { #3 }
      }
    \exp_args:Nc \NewDocumentCommand
      {
        DeclareChem
        \str_uppercase:f { \tl_head:n {#1} }
        \tl_tail:n {#1}
      }
      {#2}
      {#3}
    \exp_args:Nc \NewDocumentCommand
      {
        ProvideChem
        \str_uppercase:f { \tl_head:n {#1} }
        \tl_tail:n {#1}
      }
      {#2}
      { \cs_if_free:NT ##1 { #3 } }
    \msg_new:nnn {chemmacros} {new-#1}
      {
        You've~ tried~ to~ define~ a~ #1~ with~ \token_to_str:N
        \NewChem #1 ,~ but~ the~ command~ sequence~ \token_to_str:N ##1
        \c_space_tl already~ exists.~ Please~ choose~ another~ name.
      }
    \msg_new:nnn {chemmacros} {renew-#1}
      {
        You've~ tried~ to~ renew~ the~ #1~ \token_to_str:N ##1 ,~ but~
        it~ doesn't~ exist.
      }
  }

\cs_new_protected:Npn \chemmacros_new_environment_macroset:nnn #1#2#3
  {
    \exp_args:Nc \NewDocumentCommand {NewChem#1} {#2}
      {
        \bool_lazy_and:nnTF
          { \cs_if_free_p:c {##1} }
          { \cs_if_free_p:c {end##1} }
          {#3}
          { \msg_error:nnn {chemmacros} {new-#1} {##1} }
      }
    \exp_args:Nc \NewDocumentCommand {RenewChem#1} {#2}
      {
        \bool_lazy_or:nnTF
          { \cs_if_free_p:c {##1} }
          { \cs_if_free_p:c {end##1} }
          { \msg_error:nnn {chemmacros} {renew-#1} {##1} }
          {#3}
      }
    \exp_args:Nc \NewDocumentCommand {DeclareChem#1} {#2} {#3}
    \exp_args:Nc \NewDocumentCommand {ProvideChem#1} {#2}
      {
        \bool_lazy_and:nT
          { \cs_if_free_p:c {##1} }
          { \cs_if_free_p:c {end##1} }
          {#3}
      }
    \msg_new:nnn {chemmacros} {new-#1}
      {
        You've~ tried~ to~ define~ a~ #1~ with~ \token_to_str:N
        \NewChem #1 ,~ but~ the~ command~ sequence~ \exp_not:c {##1}
        \c_space_tl already~ exists.~ Please~ choose~ another~ name.
      }
    \msg_new:nnn {chemmacros} {renew-#1}
      { You've~ tried~ to~ renew~ the~ #1~ ##1,~ but~ it~ doesn't~ exist. }
  }

\NewDocumentCommand \NewChemMacroset {smmm}
  {
    \IfBooleanTF {#1}
      { \chemmacros_new_environment_macroset:nnn {#2} {#3} {#4} }
      { \chemmacros_new_macroset:nnn {#2} {#3} {#4} }
  }
  
% --------------------------------------------------------------------------
\cs_new_protected:Npn \chemmacros_define_keys:nn #1#2
  { \keys_define:nn {chemmacros/#1} {#2} }
\cs_generate_variant:Nn \chemmacros_define_keys:nn {x}

\cs_new_protected:Npn \chemmacros_set_keys:nn #1#2
  { \keys_set:nn {chemmacros/#1} {#2} }
\cs_generate_variant:Nn \chemmacros_set_keys:nn {x,nx}

\cs_new_protected:Npn \chemmacros_set_keys_groups:nnn #1#2#3
  { \keys_set_groups:nnn {chemmacros/#1} {#2} {#3} }

\cs_new_protected:Npn \chemmacros_set_keys_filter:nnn #1#2#3
  { \keys_set_filter:nnn {chemmacros/#1} {#2} {#3} }

\cs_new_protected:Npn \chemmacros_define_global_keys:n #1
  { \keys_define:nn {chemmacros} {#1} }

\cs_new_protected:Npn \chemmacros_set_global_keys:n #1
  { \keys_set:nn {chemmacros} {#1} }

% --------------------------------------------------------------------------
% basic tools:
\cs_new:Npn \chemmacros_remove_backslash:N #1
  { \exp_after:wN \use_none:n \token_to_str:N #1 }

\cs_new_eq:NN \chemmacros_ignore_spaces: \tex_ignorespaces:D

\cs_new_protected:Npn \chemmacros_nobreak:     { \tex_penalty:D 10000 \scan_stop: }
\cs_new_protected:Npn \chemmacros_allow_break: { \tex_penalty:D \c_zero_int }
\cs_new_protected:Npn \chemmacros_skip_nobreak:N #1
  {
    \chemmacros_nobreak:
    \skip_horizontal:N #1
    \chemmacros_nobreak:
  }

% this is used at least in the `isotope' module
\prg_new_conditional:Npnn \chemmacros_if_is_int:n #1 {p,T,F,TF}
  {
    \if_charcode:w ! \if_int_compare:w 9 < 1#1 ! \else: _ \fi:
      \prg_return_true:
    \else:
      \prg_return_false:
    \fi:
  }

\prg_new_conditional:Npnn \chemmacros_if_loaded:nn #1#2 {p,T,F,TF}
  {
    \use:c {chemmacros_if_#1_loaded:nTF} {#2}
      { \prg_return_true: }
      { \prg_return_false: }
  }
  
\prg_new_conditional:Npnn \chemmacros_if_package_loaded:n #1 {p,T,F,TF}
  {
    \cs_if_exist:cTF {ver@#1.sty}
      { \prg_return_true: }
      { \prg_return_false: }
  }

\prg_new_conditional:Npnn \chemmacros_if_class_loaded:n #1 {p,T,F,TF}
  {
    \cs_if_exist:cTF {ver@#1.cls}
      { \prg_return_true: }
      { \prg_return_false: }
  }

\ChemCompatibilityFrom{5.2}
% this is still true \AtBeginDocument:
\prg_new_conditional:Npnn \chemmacros_if_preamble: {p,T,F,TF}
  {
    \cs_if_eq:NNTF \@onlypreamble \@notprerr
      { \prg_return_false: }
      { \prg_return_true: }
  }

% this is still false \AtBeginDocument:
\prg_new_conditional:Npnn \chemmacros_if_document: {p,T,F,TF}
  {
    \bool_if:NTF \l__chemmacros_in_document_bool
      { \prg_return_true: }
      { \prg_return_false: }
  }
\EndChemCompatibility

\ChemCompatibilityFrom{5.6}
\cs_new_protected:Npn \chemmacros_cs_if_free_new:Npn #1
  {
    \cs_if_exist:NF #1
      { \cs_new:Npn #1 }
  }
\cs_generate_variant:Nn \chemmacros_cs_if_free_new:Npn {c}

\cs_new_protected:Npn \chemmacros_cs_if_free_new_protected:Npn #1
  {
    \cs_if_exist:NF #1
      { \cs_new_protected:Npn #1 }
  }
\cs_generate_variant:Nn \chemmacros_cs_if_free_new_protected:Npn {c}

\RequirePackage{scrlfile}

% #1: counter
% #2: singular
% #3: plural
% #4: Singular
% #5: Plural
\cs_new_protected:Npn \chemmacros_add_cleveref_support:nnnnn #1#2#3#4#5
  {
    \AfterPackage* {cleveref}
      {
        \cs_if_exist:cF {cref@#1@name}
          {
            \legacy_if:nTF {@cref@capitalise}
              { \crefname {#1} {#4} {#5} }
              { \crefname {#1} {#2} {#3} }
            \Crefname {#1} {#4} {#5}
          }
      }
  }
\cs_generate_variant:Nn \chemmacros_add_cleveref_support:nnnnn {nnnx , nnnxx , nnnnx }
  
% #1: counter
% #2: singular
% #3: Singular (optional)
% #4: plural
% #5: Plural (optional)
\NewDocumentCommand \ChemCleverefSupport {mmomo}
  {
    \IfNoValueTF {#3}
      {
        \IfNoValueTF {#5}
          {
            \chemmacros_add_cleveref_support:nnnnn
              {#1}
              {#2}
              {#4}
              { \tl_mixed_case:n {#2} }
              { \tl_mixed_case:n {#4} }
          }
          {
            \chemmacros_add_cleveref_support:nnnnn
              {#1}
              {#2}
              {#4}
              { \tl_mixed_case:n {#2} }
              {#5}
          }
      }
      {
        \IfNoValueTF {#5}
          {
            \chemmacros_add_cleveref_support:nnnnn
              {#1}
              {#2}
              {#4}
              {#3}
              { \tl_mixed_case:n {#4} }
          }
          { \chemmacros_add_cleveref_support:nnnnn {#1} {#2} {#4} {#3} {#5} }
      }
  }
\@onlypreamble\ChemCleverefSupport

% #1: id
% #2: mid sentence
% #3: begin sentence
\cs_new_protected:Npn \chemmacros_add_fancyref_support:nnn #1#2#3
  {
    \AfterPackage* {fancyref}
      {
        \chemmacros_cs_if_free_new:cpn {fancyref#1labelprefix} {#1}
        \chemmacros_cs_if_free_new:cpn {fref#1name} {#2}
        \chemmacros_cs_if_free_new:cpn {Fref#1name} {#3}
        \exp_args:Nnx \frefformat {vario} { \exp_not:c {fancyref#1labelprefix} }
          { \use:c {fref#1name} \fancyrefdefaultspacing ##1##3 }
        \exp_args:Nnx \Frefformat {vario} { \exp_not:c {fancyref#1labelprefix} }
          { \use:c {Fref#1name} \fancyrefdefaultspacing ##1##3 }
        \exp_args:Nnx \frefformat {plain} { \exp_not:c {fancyref#1labelprefix} }
          { \use:c {fref#1name} \fancyrefdefaultspacing ##1 }
        \exp_args:Nnx \Frefformat {plain} { \exp_not:c {fancyref#1labelprefix} }
          { \use:c {Fref#1name} \fancyrefdefaultspacing ##1 }
      }
  }
\cs_generate_variant:Nn \chemmacros_add_fancyref_support:nnn {nnx}

% #1: id
% #2: mid sentence
% #3: begin sentence (optional)
\NewDocumentCommand \ChemFancyrefSupport {mmo}
  {
    \IfNoValueTF {#3}
      { \chemmacros_add_fancyref_support:nnn {#1} {#2} { \tl_mixed_case:n {#3} } }
      { \chemmacros_add_fancyref_support:nnn {#1} {#2} {#3} }
  }
\@onlypreamble\ChemFancyrefSupport
\EndChemCompatibility

% --------------------------------------------------------------------------
% some checks at begin document:
\bool_new:N \l__chemmacros_in_document_bool
\bool_new:N \l__chemmacros_chemstyle_bool

\chemmacros_if_compatibility:nnTF {>=} {5.2}
  { \AfterEndPreamble }
  { \AtBeginDocument }
  { \bool_set_true:N \l__chemmacros_in_document_bool }

\AtBeginDocument
  {
    \@ifpackageloaded { chemstyle }
      { \bool_set_true:N \l__chemmacros_chemstyle_bool }
      { \bool_set_false:N \l__chemmacros_chemstyle_bool }
  }

% --------------------------------------------------------------------------
% detection and handling of bold face:
\RequirePackage{bm}

\prg_new_protected_conditional:Npnn \chemmacros_if_bold: {T,F,TF}
  {
    \seq_if_in:NVTF \l__chemmacros_if_bf_seq \f@series
      { \prg_return_true: }
      { \prg_return_false: }
  }

\seq_new:N  \l__chemmacros_if_bf_seq

\seq_set_split:Nnn \l__chemmacros_if_bf_seq { , }
  {
    b , bc , bm , bx , bux ,
    eb , ebc , ebx , mb ,
    sb , sbc , sbx ,
    ub , ubc , ubx
  }

\cs_new_protected:Npn \chemmacros_bold:n #1
  {
    \chemmacros_if_bold:TF
      {
        \mode_if_math:TF
          { \bm {#1} }
          { \textbf {#1} }
      }
      {#1}
  }

\cs_new_protected:Npn \chemmacros_detect_bold:n
  { \error \chemmacros_bold:n }

% --------------------------------------------------------------------------
\RequirePackage{amstext}

\cs_new_protected:Npn \chemmacros_text:n #1
  { \mode_if_math:TF { \text {#1} } {#1} }
\cs_generate_variant:Nn \chemmacros_text:n { V }

\cs_new_protected:Npn \chemmacros_math:n #1
  { \chemmacros_text:n { \c_math_toggle_token #1 \c_math_toggle_token } }
\cs_generate_variant:Nn \chemmacros_math:n { V }

% --------------------------------------------------------------------------
% a setup command:
\NewDocumentCommand \chemsetup {om}
  {
    \IfNoValueTF {#1}
      { \keys_set:nn {chemmacros}    {#2} }
      { \keys_set:nn {chemmacros/#1} {#2} }
  }

\chemmacros_define_global_keys:n
  { modules .code:n = \chemmacros_load_modules:n {#1} }

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

% load package #1 and add its options to chemmacros
%   this requires that package #1 defines its options with l3keys using its
%   name as module
\cs_new_protected:Npn \chemmacros_integrate_package:nnn #1#2#3
  {
    \tl_if_blank:nTF {#3}
      {
        \tl_if_blank:nTF {#1}
          { \RequirePackage {#2} }
          { \RequirePackage [#1] {#2} }
      }
      {
        \tl_if_blank:nTF {#1}
          { \RequirePackage {#2} [#3] }
          { \RequirePackage [#1] {#2} [#3] }
      }
    \chemmacros_define_global_keys:n
      {
        #2 .choice: ,
        #2 / unknown .code:n =
          \keys_set:no {#2} { \l_keys_key_tl = ##1 }
      }
  }

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

\chemmacros_if_compatibility:nnT {>=} {5.2}
  { \chemmacros_load_module:n {errorcheck} }

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

\bool_new:N \l__chemmacros_hyperref_bool

\AtEndPreamble
  {
    \chemmacros_if_package_loaded:nT {hyperref}
      { \bool_set_true:N \l__chemmacros_hyperref_bool }
  }

\file_input_stop:

2015/09/23 - new conditionals \chemmacros_if_preamble:TF and
             \chemmacros_if_document:TF
2015/10/14 - load `errorcheck' module
2016/02/09 - starred version of \NewChemMacroset
2016/03/07 - \chemmacros_define_keys:nn and friends
2016/04/25 - macros for cleveref and fancyref support, \ChemCleverefSupport
             \ChemFancyrefSupport
2016/05/04 - fix \ChemCleverefSupport
2017/08/28 - add missing hyperref check
2020/01/16 - adapt to renaming of string case changing functions
2020/02/02 - lazy boolean evaluation
