% \iffalse meta-comment
%
%% File: ltdocinit.dtx
%
% Copyright (C) 2018-2021 The LaTeX Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file
%
%    http://www.latex-project.org/lppl.txt
%
% This file is part of the "LaTeX PDF management testphase bundle" (The Work in LPPL)
% and all files in that bundle must be distributed together.
%
% -----------------------------------------------------------------------
%
% The development version of the bundle can be found at
%
%    https://github.com/latex3/pdfresources
%
% for those people who are interested.
%
%<*driver>
\RequirePackage{pdfmanagement-testphase}
\DeclareDocumentMetadata{pdfstandard=A-2b}
\makeatletter
\declare@file@substitution{doc.sty}{doc-v3beta.sty}
\makeatother
\documentclass[full]{l3doc}
\usepackage{array,booktabs,hyperxmp}
\hypersetup{pdfauthor=The LaTeX Project,pdftitle=ltdocinit (LaTeX PDF management testphase bundle)}

\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \pkg{ltdocinit} module
% }
%
% \author{^^A
%  The \LaTeX{} Project\thanks
%    {^^A
%      E-mail:
%        \href{mailto:latex-team@latex-project.org}
%          {latex-team@latex-project.org}^^A
%    }^^A
% }
%
% \date{Version 0.95a, released 2021-02-22}
%
% \maketitle
% \begin{documentation}
%
% \section{\pkg{ltdocinit} documentation}
% This small module defines \cs{DeclareDocumentMetadata} and the related keys.
% It also defines commands to store document properties in a global container.
%
% \subsection{\cs{DeclareDocumentMetadata}}
%
% \begin{function}{\DeclareDocumentMetadata}
% \begin{syntax}
%  \cs{DeclareDocumentMetadata}\Arg{key-value list}
% \end{syntax}
% \end{function}
%
% Currently there is no dedicated location to declare settings concerning
% a document as a whole. Settings are placed somewhere in the preamble or
% with the class options or even with some package options.
% For some settings this can be too late,
% for example the pdf version can no longer be changed if a
% package has used code which already opened the PDF.
%
% \cs{DeclareDocumentMetadata} as a new command
% should unify such settings in one place.
% It should be used before \cs{documentclass}, directly after
% loading \pkg{pdfmanagement-testphase}. \cs{DeclareDocumentMetadata}
% can be used more than once.
%
% The keys defined for \cs{DeclareDocumentMetadata}
% currently allows to set the PDF version, to set the PDF \texttt{/Lang},
% to uncompress a pdf, to set the language and to declare a few PDF standards
% and some colorprofiles.
%
% \cs{DeclareDocumentMetadata} is also used to
% activate the new PDF management code and it loads
% a number of required files for the PDF management code.
% As this forces the loading of the backend files, a backend
% which can't be detected automatically like |dvipdfmx|,
% must be set in the first \cs{DeclareDocumentMetadata}.
%
% Currently the following keys are implemented
%
% \begin{description}
%    \item[\texttt{backend}] passes the backend name to expl3.
%    This will probably be extended to  pass the value also to packages.
%    \item[\texttt{pdfversion}] e.g. \texttt{pdfversion=1.7}
%    \item[\texttt{uncompress}] no value. Forces an uncompressed pdf.
%    \item[\texttt{lang}] to set the Lang entry in the Catalog.
%    E.g. \texttt{lang=de-DE}. The initial value is |en-US|
%    \item[\texttt{pdfstandard}] Choice key to set the pdf standard.
%      Currently |A-1b|, |A-2b| and |A-3b| are accepted as
%      values. The underlying code to ensure the requirements (as far as they
%      can be ensured) is incomplete, but a color profile is included and the
%      /OutputIntent is set. More information can be found in the documentation
%      of \pkg{l3pdfmeta}.
%    \item[\texttt{colorprofiles}] This allows to load icc-colorprofiles. Details
%    are described in the documentation of \pkg{l3pdfmeta}.
%    \item[\texttt{pdfmanagement}] Boolean. This activates/deactivates
%      the core management code. By default the value is true.
%    \item[firstaidoff] This accepts a comma lists of keysword and disable the patches
%    related to them. More information can be found in the documentation of
%    \pkg{pdfmanagement-firstaid}.
% \end{description}
%
% \subsection{Container for document properties}
%
% The module provides a container where classes, packages and users can store
% properties of the document which are perhaps of interest
% or use for other packages or the author.
%
% The properties are stored with a key |label/property|. The values can be
% retrieved expandably.
%
% \begin{function}{\AddToDocumentProperties}
% \begin{syntax}
%  \cs{AddToDocumentProperties}\oarg{label}\Arg{property}\Arg{value}
% \end{syntax}
% This stores \meta{value} under the key \meta{label}/\meta{property}.
% By default \meta{label} is the current package name |\@currname|. If another
% label is choosen, it should be one which avoids clashes with other packages
% using the container. The label |document| is reserved.
% \end{function}
%
% \begin{function}{\GetDocumentProperties}
% \begin{syntax}
%  \cs{AddToDocumentProperties}\Arg{label/property}
% \end{syntax}
% Expands to the \meta{value} corresponding to \meta{label/property}
% in the container. If \meta{label/property} is missing,
% this has an empty expansion.
% The result is returned within \cs{exp_not:n}, which means
% that the \meta{value} does not expand further
% when appearing in an x-type argument expansion.
% \end{function}
%
% \begin{function}{\ShowDocumentProperties}
% \begin{syntax}
%  \cs{ShowDocumentProperties}
% \end{syntax}
% This show the current content of the container.
% \end{function}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{ltdocinit} implementation}
% \subsection{\cs{DeclareDocumentMetadata}}
%    \begin{macrocode}
%<@@=pdfmanagement>
%<*header>
\ProvidesExplPackage {ltdocinit} {2021-02-22} {0.95a}
  {Initialize document metadata}
%</header>
%    \end{macrocode}
% \cs{DeclareDocumentMetadata} should for now not be used after
% \cs{documentclass} so we error in this case. It can be used more than once
% but follow-up calls should not do the initialization code.
%    \begin{macrocode}
%<*package>
\msg_new:nnn  { document } { setup-after-documentclass }
              {
                \token_to_str:N \DeclareDocumentMetadata \c_space_tl
                should~be~used~only~before~\token_to_str:N\documentclass
              }
%    \end{macrocode}
% \begin{macro}{\DeclareDocumentMetadata}
%    \begin{macrocode}
\NewDocumentCommand\DeclareDocumentMetadata { m }
  {
    \cs_if_eq:NNTF \documentclass \@twoclasseserror
      { \msg_error:nn { document }{ setup-after-documentclass } }
      {
%    \end{macrocode}
% The wanted backend must be detected first, we read the init key and then
% force the loading by either loading l3pdf (+ expl3) or only expl3.
%    \begin{macrocode}
        \keys_set_groups:nnn { document / metadata} {init}{ #1 }
        %should be loaded after the backend is set, and only if not in the kernel
        \cs_if_free:NTF \pdf_uncompress:
         {\RequirePackage{l3pdf}}{\RequirePackage{expl3}}
%    \end{macrocode}
% Now we load the extra backend code and set the boolean to true
%    \begin{macrocode}
        \ExplSyntaxOn\makeatletter
          \file_input:n {l3backend-testphase-\c_sys_backend_str.def}
        \ExplSyntaxOff\makeatother
        \bool_gset_true:N \g_@@_active_bool
%    \end{macrocode}
% set the default language, process the rest of the keys,
% and setup the generic driver
%    \begin{macrocode}
        \keys_set_filter:nnn  { document / metadata } { init } { lang=en-US, #1 }
        \bool_if:NT \g_@@_active_bool
          {
            \PassOptionsToPackage{customdriver=hgeneric-testphase}{hyperref}
          }
%    \end{macrocode}
% \cs{pdfmanagement_add:nnn} has collected values in this hook.
%    \begin{macrocode}
        \hook_use_once:n {pdfmanagement/add}
%    \end{macrocode}
% Redefine \cs{DeclareDocumentMetadata} so that it only process the keys.
% We need to update the hyperref option if the active status changes.
%    \begin{macrocode}
        \RenewDocumentCommand\DeclareDocumentMetadata { m }
          {
            \keys_set_filter:nnn  { document / metadata } { init } { ##1 }
            \bool_if:NTF \g_@@_active_bool
             {
               \str_remove_all:cn {opt@hyperref.sty}{customdriver=hgeneric-testphase}
               \PassOptionsToPackage{customdriver=hgeneric-testphase}{hyperref}
             }
             {
               \str_remove_all:cn {opt@hyperref.sty}{customdriver=hgeneric-testphase}
             }
          }
%    \end{macrocode}
% Load more modules and the firstaid code.
%    \begin{macrocode}
        \RequirePackage{pdfmanagement-firstaid}
      }
  }
%    \end{macrocode}
% \end{macro}
% \subsection{Container for document Properties}
% The container for the document properties is a prop
% \begin{variable}{\g_@@_documentproperties_prop}
%    \begin{macrocode}
\prop_new:N \g_@@_documentproperties_prop %
%    \end{macrocode}
% \end{variable}
% \begin{macro}{\AddToDocumentProperties}
%    \begin{macrocode}
\NewDocumentCommand\AddToDocumentProperties{O{\@currname}mm}
  {
    \exp_args:NNx
      \prop_gput:Nnn \g_@@_documentproperties_prop
        {
          \tl_if_blank:eTF {#1}{top-level/}{#1/} #2
        }
        { #3}
  }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\GetDocumentProperties}
%    \begin{macrocode}
\NewExpandableDocumentCommand\GetDocumentProperties{m}
  {
    \prop_item:Nn \g_@@_documentproperties_prop {#1}
  }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\ShowDocumentProperties}
%    \begin{macrocode}
\msg_new:nnn  { pdfmanagement } { show-properties }
  {
    The~following~document~properties~have~been~stored:
    #1
  }
\NewDocumentCommand\ShowDocumentProperties {}
  {
    \msg_show:nnx {pdfmanagement}{show-properties}
      {
        \prop_map_function:NN \g_@@_documentproperties_prop \msg_show_item:nn
      }
  }
%    \end{macrocode}
% \end{macro}
%  \subsection{The keys for \cs{DeclareDocumentMetadata}}
%  As they use \cs{AddToDocumentProperties} they have to come after
%  it has been defined.
%
%  \begin{variable}{\g_@@_firstaidoff_clist}
%  A list to store the firstaid code which should be disabled
%    \begin{macrocode}
\clist_new:N \g_@@_firstaidoff_clist
%    \end{macrocode}
% \end{variable}
%    \begin{macrocode}
\keys_define:nn { document / metadata }
  {
    backend .code:n =
      {
        \PassOptionsToPackage { driver=#1 } {expl3}
        \AddToDocumentProperties[document]{backend}{#1}
      },
    backend .groups:n = { init } ,
  }

\keys_define:nn { document / metadata }
  {
    ,pdfversion .code:n =
      {
        \pdf_version_gset:n { #1 }
        \AddToDocumentProperties[document]{pdfversion}{#1}
      }
    ,uncompress .code:n =
      {
        \pdf_uncompress:
      }
    ,uncompress .value_forbidden:n = true
    ,lang .code:n =
      {
        \pdfmanagement_add:nnn {Catalog} {Lang}{(#1)}
        \AddToDocumentProperties[document]{lang}{#1}
      }
    %,xmpmeta .bool_gset:N = \g_pdfmeta_xmp_bool %see pdfmeta unused and undefined for now!
    % this uses internal command from pdfmeta, it should probably move there ...
    ,pdfstandard .code:n =
      {
        \exp_args:Nnx
        \keys_set:nn {document / metadata} {_pdfstandard=\str_uppercase:n{#1}}
      }
    ,_pdfstandard .choices:nn =
      {A-1B,A-2B,A-3B}
      {
        \prop_if_exist:cT { g__pdfmeta_standard_pdf/#1_prop }
          {
            \prop_gset_eq:Nc \g__pdfmeta_standard_prop { g__pdfmeta_standard_pdf/#1 _prop }
          }
        \AddToDocumentProperties [document]{pdfstandard}{#1}
      }
    ,_pdfstandard / unknown .code:n =
      {
        \msg_warning:nnn{pdf}{unknown-standard}{#1}
      }
    ,pdfmanagement .bool_gset:N = \g_@@_active_bool
    ,pdfmanagement .initial:n =  {true}
    ,firstaidoff .clist_gset:N = \g_@@_firstaidoff_clist
  }
%    \end{macrocode}
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
