%%%==============================================================================
%% Copyright 2025-present by Alceu Frigeri
%%
%% This work may be distributed and/or modified under the conditions of
%%
%% * The [LaTeX Project Public License](http://www.latex-project.org/lppl.txt),
%%   version 1.3c (or later), and/or
%% * The [GNU Affero General Public License](https://www.gnu.org/licenses/agpl-3.0.html),
%%   version 3 (or later)
%%
%% This work has the LPPL maintenance status *maintained*.
%%
%% The Current Maintainer of this work is Alceu Frigeri
%%
%% This is version {1.2a} {2026/01/03}
%%
%% The list of files that compose this work can be found in the README.md file at
%% https://ctan.org/pkg/pkginfograb
%%
%%%==============================================================================
\NeedsTeXFormat{LaTeX2e}[2022/06/01]

\ProvidesExplPackage
    {pkginfograb}
    {2026/01/03}
    {1.2a}
    {Collecting~ package's~ info~ in~ a~ regular~ way}

\seq_new:N \l__pkginfograb_sets_seq
\cs_new_protected:Npn \pkginfograb_set:nn #1
  {
    \seq_put_right:Nn \l__pkginfograb_sets_seq {#1}
    \prop_new_linked:c {l__pkginfograb_#1_prop}
    \prop_set_from_keyval:cn {l__pkginfograb_#1_prop}
  }

%%%%%%%
%%%
%%% Just an attempt at having package's info in a regular way
%%%   \pkginfograb_set:nn {<pkg-name>} { props} sets package info
%%%
%%%   \pkginfograbProvidesExplPackage {<pkg-name>} { props} sets package info
%%%     and calls \ProvidesExplPackage
%%%
%%%%%%%
%\RequirePackage{pkginfograb}
%\pkginfograbProvidesExplPackage
\pkginfograb_set:nn {pkginfograb}
  { 
    name         = {pkginfograb} ,
    prefix       = {pkginfograb} ,
    date         = {2026/01/03},
    version      = {1.2a} ,
    description  = {Collecting~ package's~ info~ in~ a~ regular~ way}
  }
%%%%%%%
%%% End of cut-n-paste
%%%%%%%

\cs_new:Npn \pkginfograbProvidesExplPackage #1#2
  {
    \pkginfograb_set:nn {#1}{#2}
    \__pkginfograb_provides_expl:cN { l__pkginfograb_ #1 _prop } \ProvidesExplPackage
  }

\cs_new:Npn \pkginfograbProvidesExplClass #1#2
  {
    \pkginfograb_set:nn {#1}{#2}
    \__pkginfograb_provides_expl:cN { l__pkginfograb_ #1 _prop } \ProvidesExplClass
  }

\cs_new:Npn \pkginfograbProvidesExplFile #1#2
  {
    \pkginfograb_set:nn {#1}{#2}
    \__pkginfograb_provides_expl:cN { l__pkginfograb_ #1 _prop } \ProvidesExplFile
  }


\seq_const_from_clist:Nn \c__pkginfograb_info_list_seq {name,date,version,description}
\cs_new:Npn \__pkginfograb_provides_expl:NN #1#2
  {
    \tl_clear:N \l__pkginfograb_tmpa_tl
    \seq_map_inline:Nn \c__pkginfograb_info_list_seq
      {
        \prop_get:NnNTF #1 { ##1 } \l__pkginfograb_tmpb_tl
          { 
            \tl_put_right:Ne \l__pkginfograb_tmpa_tl { {\l__pkginfograb_tmpb_tl} }
          }
          { 
            \tl_put_right:Nn \l__pkginfograb_tmpa_tl { { } }
          }
      }
    \exp_last_unbraced:NV #2 \l__pkginfograb_tmpa_tl
  }
\cs_generate_variant:Nn   \__pkginfograb_provides_expl:NN {c}

\cs_new_protected:Npn \pkginfograb_get:nn #1#2
  {
    \prop_if_exist:cT { l__pkginfograb_ #1 _prop }
      {
        \prop_item:cn 
          { l__pkginfograb_ #1 _prop } {#2}
      }
  }

\cs_new_protected:Npn \pkginfograb_get:nnN #1#2#3
  {
    \prop_if_exist:cTF { l__pkginfograb_ #1 _prop }
      {
        \prop_get:cnNF { l__pkginfograb_ #1 _prop } { #2 } #3
          { \tl_clear:N #3 }
      }
      { \tl_clear:N #3 }
  }

\cs_new_protected:Npn \pkginfograb_description:n #1
  { 
    \prop_if_exist:cTF { l__pkginfograb_ #1 _prop }
      {
        \par\noindent Package~ \textbf{\pkginfograb_get:nn{#1}{name}}~
        Version:~\pkginfograb_get:nn{#1}{version}~ -~ \pkginfograb_get:nn{#1}{date}
        \par 
        \emph{\pkginfograb_get:nn{#1}{description}}~\par 
      }
      {
        \par \textbf{#1}'s~info~not~defined.\par
      }
  } 

%%%%%%%%%%
%%%%%%%%%% Just to be complete
%%%%%%%%%%

\cs_new_protected:Npn \pkginfograb_if_set_p:n #1
  { \prop_if_exist_p:c { l__pkginfograb_ #1 _prop } }

\cs_new_protected:Npn \pkginfograb_if_set:nTF #1
  { \prop_if_exist:cTF { l__pkginfograb_ #1 _prop } }
\cs_new_protected:Npn \pkginfograb_if_set:nT #1
  { \prop_if_exist:cT { l__pkginfograb_ #1 _prop } }
\cs_new_protected:Npn \pkginfograb_if_set:nF #1
  { \prop_if_exist:cF { l__pkginfograb_ #1 _prop } }

\cs_new_protected:Npn \pkginfograb_map_inline:n
  { \seq_map_inline:Nn \l__pkginfograb_sets_seq }

%%%%%%%%%%
%%%%%%%%%% ARGH... below follows version testing...
%%%%%%%%%%


\msg_new:nnnn {pkginfograb} {requires}
  {
    #1~requires~ #2~ version ~ #3~ or~ newer
  }
  {
    Package~#1~ requires~ at~ least~ version ~#3 ~ from ~ package ~ #2.
  }

\msg_new:nnnn {pkginfograb} {version format}
  {
    Invalid~ version~ format:~ #1.~ Should~be~[v]digits[~.~digits[~.~digits]][letters]
  }
  {
    Invalid~ version~ format:~ #1.~ Should~be~[v]digits[~.~digits[~.~digits]][letters]
  }
  
\msg_new:nnnn {pkginfograb} {date format}
  {
    Invalid~ date~ format:~ #1.~ Should~be~YYYY/MM/DD~or~YYYY-MM-DD~or~YYYY.MM.DD
  }
  {
    Invalid~ date~ format:~ #1.~ Should~be~YYYY/MM/DD~or~YYYY-MM-DD~or~YYYY.MM.DD
  }


%\tl_new:N \l__pkginfograb_tmpa_tl
\tl_new:N \l__pkginfograb_tmpb_tl
\tl_new:N \l__pkginfograb_tmpc_tl
\tl_new:N \l__pkginfograb_tmpd_tl
\seq_new:N \l__pkginfograb_tmpa_seq
\seq_new:N \l__pkginfograb_tmpb_seq

\cs_new_protected:Npn \pkginfograb_req_version:nnn #1#2#3
  {
    \prop_if_exist:cTF { l__pkginfograb_ #2 _prop }
      {
        \pkginfograb_get:nnN {#2}{version}\l__pkginfograb_tmpa_tl
        
        \__pkginfograb_regex_split:VNTF \l__pkginfograb_tmpa_tl \l__pkginfograb_tmpa_seq
          {
            \__pkginfograb_regex_split:nNTF {#3} \l__pkginfograb_tmpb_seq
              {
                \__pkginfograb_req_version:TF
                  {} % OK, nothing to be done
                  {
                    \msg_error:nnnnn {pkginfograb}{requires}{#1}{#2}{#3}
                  }
              }
              {
                \msg_error:nnn {pkginfograb}{version format}{#3}
              }
          }
          {
            \msg_error:nnV {pkginfograb}{version format} \l__pkginfograb_tmpa_tl
          }            
      }
      {
        \msg_error:nnnnn {pkginfograb}{requires}{#1}{#2}{#3}
      }
  }
  
%%
%% This will match 
%% versionA: [v]{digit]}[letters]
%% versionB: [v]{digit.digit}[letters]
%% versionC: [v]{digit.digit.digit}[letters]
%% so that each regex has 5 capturing groups
%%
%%
\regex_const:Nn \l__pkginfograb_versionA_regex {\A(v?)(\d+)(\d*)(\d*)([a-zA-Z]*)\Z}
\regex_const:Nn \l__pkginfograb_versionB_regex {\A(v?)(\d+)\.(\d+)(\d*)([a-zA-Z]*)\Z}
\regex_const:Nn \l__pkginfograb_versionC_regex {\A(v?)(\d+)\.(\d+)\.(\d+)([a-zA-Z]*)\Z}

\prg_new_protected_conditional:Npnn \__pkginfograb_regex_split:nN #1#2 {TF}
  {
    \regex_split:NnNTF \l__pkginfograb_versionA_regex {#1} #2
      {
        \prg_return_true:
      }
      {
        \regex_split:NnNTF \l__pkginfograb_versionB_regex {#1} #2
          {
            \prg_return_true:
          }
          {
            \regex_split:NnNTF \l__pkginfograb_versionC_regex {#1} #2
              {
                \prg_return_true:
              }
              {
                \prg_return_false:
              }
          }
      }
  }
\prg_generate_conditional_variant:Nnn \__pkginfograb_regex_split:nN  {V} {TF}

\prg_generate_conditional_variant:Nnn \fp_compare:nNn {VNV}{TF}
\prg_generate_conditional_variant:Nnn \str_compare:nNn {VNV}{TF}

\prg_new_protected_conditional:Npnn \__pkginfograb_req_version: {TF}
  {
    \__pkginfograb_build_version:NNN
      \l__pkginfograb_tmpa_seq \l__pkginfograb_tmpc_tl \l__pkginfograb_tmpa_tl
    \__pkginfograb_build_version:NNN 
      \l__pkginfograb_tmpb_seq \l__pkginfograb_tmpd_tl \l__pkginfograb_tmpb_tl
    \fp_compare:VNVTF \l__pkginfograb_tmpc_tl < \l__pkginfograb_tmpd_tl 
      { \prg_return_false: }
      {
        \fp_compare:VNVTF \l__pkginfograb_tmpc_tl = \l__pkginfograb_tmpd_tl
          {
            \str_compare:VNVTF \l__pkginfograb_tmpa_tl < \l__pkginfograb_tmpb_tl
              { \prg_return_false: }
              { \prg_return_true: }
          }
          { \prg_return_true: }
      }
  }

\tl_new:N \l__pkginfograb_tmpx_tl
\cs_new_protected:Npn \__pkginfograb_build_version:NNN #1#2#3
  {
    \seq_pop_left:NN  #1 \l__pkginfograb_tmpx_tl
    \seq_pop_left:NN  #1 \l__pkginfograb_tmpx_tl
    \seq_pop_right:NN #1 \l__pkginfograb_tmpx_tl
    \seq_pop_right:NN #1 #3
    \tl_set:Ne #2 
      { \seq_format:Nn #1 {0>5} }
  }


\prg_new_protected_conditional:Npnn \__pkginfograb_req_date: {TF}
  {
    \__pkginfograb_build_date:NN
      \l__pkginfograb_tmpa_seq \l__pkginfograb_tmpc_tl
    \__pkginfograb_build_date:NN 
      \l__pkginfograb_tmpb_seq \l__pkginfograb_tmpd_tl
    \fp_compare:VNVTF \l__pkginfograb_tmpc_tl < \l__pkginfograb_tmpd_tl 
      { \prg_return_false: }
      { \prg_return_true: }
  }


\cs_new_protected:Npn \__pkginfograb_build_date:NN #1#2
  {
    \seq_pop_left:NN  #1 \l__pkginfograb_tmpx_tl
    \seq_pop_right:NN #1 \l__pkginfograb_tmpx_tl
    \tl_set:Ne #2 
      { \seq_format:Nn #1 {0>2} }
  }


\regex_const:Nn \l__pkginfograb_date_regex {\A(\d\d\d\d)[/\-\.](\d\d?)[/\-\.](\d\d?)\Z}

\cs_new_protected:Npn \pkginfograb_req_date:nnn #1#2#3
  {
    \prop_if_exist:cTF { l__pkginfograb_ #2 _prop }
      {
        \pkginfograb_get:nnN {#2}{date}\l__pkginfograb_tmpa_tl

        \regex_split:NVNTF \l__pkginfograb_date_regex \l__pkginfograb_tmpa_tl \l__pkginfograb_tmpa_seq        
          {
            \regex_split:NnNTF \l__pkginfograb_date_regex {#3} \l__pkginfograb_tmpb_seq        
              {              
                \__pkginfograb_build_date:NN
                  \l__pkginfograb_tmpa_seq \l__pkginfograb_tmpc_tl
                \__pkginfograb_build_date:NN 
                  \l__pkginfograb_tmpb_seq \l__pkginfograb_tmpd_tl
                \fp_compare:VNVTF \l__pkginfograb_tmpc_tl < \l__pkginfograb_tmpd_tl 
                  {
                    \msg_error:nnnnn {pkginfograb}{requires}{#1}{#2}{#3}
                  }
                  {} % OK, nothing to be done
              }
              {
                \msg_error:nnn {pkginfograb}{date format}{#3}
              }
          }
          {
            \msg_error:nnV {pkginfograb}{date format} \l__pkginfograb_tmpa_tl
          }            
      }
      {
        \msg_error:nnnnn {pkginfograb}{requires}{#1}{#2}{#3}
      }
  }



%% just in case one wishes to use this in a LaTeX2e context.  
\cs_new:Npn \pkginfograb_set_aliases:
  {
    \cs_set_eq:NN \PkgInfoSet         \pkginfograb_set:nn
    \cs_set_eq:NN \PkgInfoIfSet       \pkginfograb_if_set:nTF
    \cs_set_eq:NN \PkgInfo            \pkginfograb_get:nn
    \cs_set_eq:NN \PkgInfoGet         \pkginfograb_get:nnN
    \cs_set_eq:NN \PkgInfoDescription \pkginfograb_description:n
    \cs_set_eq:NN \PkgInfoReqVersion  \pkginfograb_req_version:nnn
    \cs_set_eq:NN \PkgInfoReqDate     \pkginfograb_req_date:nnn
    \cs_set_eq:NN \PkgInfoMapOver     \pkginfograb_map_inline:n
  }
  
\cs_new_eq:NN \PkgInfoSetAliases \pkginfograb_set_aliases:


