% \iffalse meta-comment
%
% Copyright (C) 2008-2014 by Ulrich M. Schwarz
% Copyright (C) 2019      by Frank Mittelbach
% Copyright (C) 2020-     by Yukai Chou
%
% This file may be distributed and/or modified under the conditions of
% the LaTeX Project Public License, version 1.3c.
% The license can be obtained from
% http://www.latex-project.org/lppl/lppl-1-3c.txt
%
% \fi
%
%\iffalse (hide this from DocInput)
%<*kv>
%\fi
%
%\StopEventually{}
%    \begin{macrocode}

\let\@xa\expandafter
\let\@nx\noexpand

\DeclareOption{lowercase}{%
  \PackageInfo{thm-kv}{Theorem names will be lowercased}%
  \global\def\thmt@modifycase{\protect\MakeLowercase}}

\DeclareOption{uppercase}{%
  \PackageInfo{thm-kv}{Theorem names will be uppercased}%
  \global\def\thmt@modifycase{\protect\MakeUppercase}}

\DeclareOption{anycase}{%
  \PackageInfo{thm-kv}{Theorem names will be unchanged}%
  \global\def\thmt@modifycase{}}

\ExecuteOptions{uppercase}
\ProcessOptions\relax

\RequirePackage{keyval,kvsetkeys,thm-patch}

\long\def\thmt@kv@processor@default#1#2#3{%
 \def\kvsu@fam{#1}% new
 \@onelevel@sanitize\kvsu@fam% new
 \def\kvsu@key{#2}% new
 \@onelevel@sanitize\kvsu@key% new
 \unless\ifcsname KV@#1@\kvsu@key\endcsname
   \unless\ifcsname KVS@#1@handler\endcsname
     \kv@error@unknownkey{#1}{\kvsu@key}%
   \else
     \csname KVS@#1@handler\endcsname{#2}{#3}%
   % still using #2 #3 here is intentional: handler might
   % be used for strange stuff like implementing key names
   % that contain strange characters or other strange things.
     \relax
   \fi
 \else
   \ifx\kv@value\relax
     \unless\ifcsname KV@#1@\kvsu@key @default\endcsname
       \kv@error@novalue{#1}{\kvsu@key}%
     \else
       \csname KV@#1@\kvsu@key @default\endcsname
       \relax
     \fi
   \else
     \csname KV@#1@\kvsu@key\endcsname{#3}%
   \fi
 \fi
}

\@ifpackagelater{kvsetkeys}{2012/04/23}{%
  \PackageInfo{thm-kv}{kvsetkeys patch (v1.16 or later)}%
  \long\def\tmp@KVS@PD#1#2#3{%
    \def \kv@fam {#1}%
    \unless \ifcsname KV@#1@#2\endcsname 
      \unless \ifcsname KVS@#1@handler\endcsname 
        \kv@error@unknownkey {#1}{#2}%
      \else 
       \kv@handled@true 
        \csname KVS@#1@handler\endcsname {#2}{#3}\relax 
        \ifkv@handled@ \else 
          \kv@error@unknownkey {#1}{#2}%
        \fi 
      \fi 
    \else 
      \ifx \kv@value \relax 
        \unless \ifcsname KV@#1@#2@default\endcsname 
          \kv@error@novalue {#1}{#2}%
        \else
          \csname KV@#1@#2@default\endcsname \relax 
        \fi
      \else 
        \csname KV@#1@#2\endcsname {#3}%
      \fi 
    \fi
  }%
  \ifx\tmp@KVS@PD\KVS@ProcessorDefault
    \let\KVS@ProcessorDefault\thmt@kv@processor@default
    \def\kv@processor@default#1#2{%
      \begingroup
        \csname @safe@activestrue\endcsname
        \@xa\let\csname ifincsname\@xa\endcsname\csname iftrue\endcsname
        \edef\KVS@temp{\endgroup
% 2019/12/22 removed dependency on etexcmds package
          \noexpand\KVS@ProcessorDefault{#1}{\unexpanded{#2}}%
        }%
        \KVS@temp
    }%
  \else
    \PackageError{thm-kv}{kvsetkeys patch failed}{Try kvsetkeys v1.16 or earlier}
  \fi
}{\@ifpackagelater{kvsetkeys}{2011/04/06}{%
  % Patch has disappeared somewhere... thanksalot.
  \PackageInfo{thm-kv}{kvsetkeys patch (v1.13 or later)}
  \long\def\tmp@KVS@PD#1#2#3{% no non-etex-support here...
    \unless\ifcsname KV@#1@#2\endcsname
     \unless\ifcsname KVS@#1@handler\endcsname
        \kv@error@unknownkey{#1}{#2}%
      \else
        \csname KVS@#1@handler\endcsname{#2}{#3}%
        \relax
      \fi
    \else
      \ifx\kv@value\relax
       \unless\ifcsname KV@#1@#2@default\endcsname
          \kv@error@novalue{#1}{#2}%
        \else
          \csname KV@#1@#2@default\endcsname
          \relax
        \fi
      \else
        \csname KV@#1@#2\endcsname{#3}%
      \fi
    \fi
  }%
  \ifx\tmp@KVS@PD\KVS@ProcessorDefault
    \let\KVS@ProcessorDefault\thmt@kv@processor@default  
    \def\kv@processor@default#1#2{%
      \begingroup
        \csname @safe@activestrue\endcsname
        \let\ifincsname\iftrue
        \edef\KVS@temp{\endgroup
        \noexpand\KVS@ProcessorDefault{#1}{\unexpanded{#2}}%
      }%
    \KVS@temp
  }
  \else
    \PackageError{thm-kv}{kvsetkeys patch failed, try kvsetkeys v1.13 or earlier}
  \fi
}{%
  \RequirePackage{etex}
  \PackageInfo{thm-kv}{kvsetkeys patch applied (pre-1.13)}%
  \let\kv@processor@default\thmt@kv@processor@default
}}

% useful key handler defaults.
\newcommand\thmt@mkignoringkeyhandler[1]{%
  \kv@set@family@handler{#1}{%
    \thmt@debug{Key `##1' with value `##2' ignored by #1.}%
  }%
}
\newcommand\thmt@mkextendingkeyhandler[3]{%
% #1: family
% #2: prefix for file
% #3: key hint for error
  \kv@set@family@handler{#1}{%
    \thmt@selfextendingkeyhandler{#1}{#2}{#3}%
      {##1}{##2}%
  }%
}

\newcommand\thmt@selfextendingkeyhandler[5]{%
  % #1: family
  % #2: prefix for file
  % #3: key hint for error
  % #4: actual key
  % #5: actual value
  \IfFileExists{#2-#4.sty}{%
    \PackageInfo{thmtools}%
      {Automatically pulling in `#2-#4'}%
    \RequirePackage{#2-#4}%
    \ifcsname KV@#1@#4\endcsname
      \csname KV@#1@#4\endcsname{#5}%
    \else
      \PackageError{thmtools}%
      {#3 `#4' not known}
      {I don't know what that key does.\MessageBreak
       I've even loaded the file `#2-#4.sty', but that didn't help.
      }%
    \fi
  }{%
    \PackageError{thmtools}%
    {#3 `#4' not known}
    {I don't know what that key does by myself,\MessageBreak
     and no file `#2-#4.sty' to tell me seems to exist.
    }%
  }%
}


\newif\if@thmt@firstkeyset

% many keys are evaluated twice, because we don't know 
% if they make sense before or after, or both.
\def\thmt@trytwice{%
  \if@thmt@firstkeyset
    \@xa\@firstoftwo
  \else
    \@xa\@secondoftwo
  \fi
}

\@for\tmp@keyname:=parent,numberwithin,within\do{%
  \define@key{thmdef}{\tmp@keyname}{%
    \thmt@trytwice{%
      \thmt@setparent{#1}
      \thmt@setsibling{}%
    }{}%
  }%
}
\newcommand\thmt@setparent{%
  \def\thmt@parent
}

\@for\tmp@keyname:=sibling,numberlike,sharenumber\do{%
  \define@key{thmdef}{\tmp@keyname}{%
    \thmt@trytwice{%
      \thmt@setsibling{#1}%
      \thmt@setparent{}%
    }{}%
  }%
}
\newcommand\thmt@setsibling{%
  \def\thmt@sibling
}

\@for\tmp@keyname:=title,name,heading\do{%
  \define@key{thmdef}{\tmp@keyname}{\thmt@trytwice{\thmt@setthmname{#1}}{}}%
}
\newcommand\thmt@setthmname{%
  \def\thmt@thmname
}

\@for\tmp@keyname:=unnumbered,starred\do{%
  \define@key{thmdef}{\tmp@keyname}[]{\thmt@trytwice{\thmt@isnumberedfalse}{}}%
}

\def\thmt@YES{yes}
\def\thmt@NO{no}
\def\thmt@UNIQUE{unless unique}
\newif\ifthmt@isnumbered
\newif\ifthmt@isunlessunique

\define@key{thmdef}{numbered}[yes]{
  \def\thmt@tmp{#1}%
  \thmt@trytwice{%
    \ifx\thmt@tmp\thmt@YES
      \thmt@isnumberedtrue
    \else\ifx\thmt@tmp\thmt@NO
      \thmt@isnumberedfalse
    \else\ifx\thmt@tmp\thmt@UNIQUE
      \RequirePackage[unq]{unique}
      \thmt@isunlessuniquetrue
    \else
      \PackageError{thmtools}{Unknown value `#1' to key numbered}{}%
    \fi\fi\fi
  }{% trytwice: after definition
    \ifx\thmt@tmp\thmt@UNIQUE
      \ifx\thmt@parent\@empty
        \addtotheorempreheadhook[\thmt@envname]{\setuniqmark{\thmt@envname}}%
      \else
        \protected@edef\thmt@tmp{%
          % expand \thmt@envname and \thmt@parent
          \@nx\addtotheorempreheadhook[\thmt@envname @unique]{%
            \@nx\setuniqmark{\thmt@envname.\@nx\@nameuse{the\thmt@parent}}}%
          \@nx\addtotheorempreheadhook[\thmt@envname @numbered]{%
            \@nx\setuniqmark{\thmt@envname.\@nx\@nameuse{the\thmt@parent}}}%
          \@nx\addtotheorempreheadhook[\thmt@envname @unique]{%
            \def\@nx\thmt@dummyctrautorefname{\thmt@thmname\@nx\@gobble}}%
          \@nx\addtotheorempreheadhook[\thmt@envname @numbered]{%
            \def\@nx\thmt@dummyctrautorefname{\thmt@thmname\@nx\@gobble}}%
        }%
        \thmt@tmp
      \fi
      % \addtotheorempreheadhook[\thmt@envname]{%
      %   \def\thmt@dummyctrautorefname{\thmt@thmname\@gobble}}%
    \fi
  }%
}


\define@key{thmdef}{preheadhook}{%
  \thmt@trytwice{}{\addtotheorempreheadhook[\thmt@envname]{#1}}}
\define@key{thmdef}{postheadhook}{%
  \thmt@trytwice{}{\addtotheorempostheadhook[\thmt@envname]{#1}}}
\define@key{thmdef}{prefoothook}{%
  \thmt@trytwice{}{\addtotheoremprefoothook[\thmt@envname]{#1}}}
\define@key{thmdef}{postfoothook}{%
  \thmt@trytwice{}{\addtotheorempostfoothook[\thmt@envname]{#1}}}

\define@key{thmdef}{style}{\thmt@trytwice{\thmt@setstyle{#1}}{}}

% ugly hack: style needs to be evaluated first so its keys
% are not overridden by explicit other settings
\define@key{thmdef0}{style}{%
  \ifcsname thmt@style #1@defaultkeys\endcsname
    \thmt@toks{\kvsetkeys{thmdef}}%
    \@xa\@xa\@xa\the\@xa\@xa\@xa\thmt@toks\@xa\@xa\@xa{%
      \csname thmt@style #1@defaultkeys\endcsname}%
  \fi
}
\thmt@mkignoringkeyhandler{thmdef0}

% fallback definition.
% actually, only the kernel does not provide \theoremstyle.
% is this one worth having glue code for the theorem package?
\def\thmt@setstyle#1{%
  \PackageWarning{thm-kv}{%
    Your backend doesn't have a `\string\theoremstyle' command.
  }%
}

\ifcsname theoremstyle\endcsname 
  \let\thmt@originalthmstyle\theoremstyle
  \def\thmt@outerstyle{plain}
  \renewcommand\theoremstyle[1]{%
    \def\thmt@outerstyle{#1}%
    \thmt@originalthmstyle{#1}%
  }
  \def\thmt@setstyle#1{%
    \thmt@originalthmstyle{#1}%
  }
  \g@addto@macro\thmt@newtheorem@postdefinition{%
    \thmt@originalthmstyle{\thmt@outerstyle}%
  }
\fi


\thmt@mkextendingkeyhandler{thmdef}{thmdef}{\string\declaretheorem\space key}

\let\thmt@newtheorem\newtheorem

% \declaretheorem[option list 1]{thmname list}[option list 1]
% #1 = option list 1
% #2 = thmname list
\newcommand\declaretheorem[2][]{%
  % TODO: use \NewDocumentCommand from xparse? 
  % xparse will be part of latex2e format from latex2e 2020 Oct.
  \@ifnextchar[%
    {\declaretheorem@i{#1}{#2}}
    {\declaretheorem@i{#1}{#2}[]}%
}
\@onlypreamble\declaretheorem

% #1 = option list 1
% #2 = thmname list
% #3 = option list 2
\def\declaretheorem@i#1#2[#3]{%
  \@for\thmt@tmp:=#2\do{%
    % strip spaces, \KV@@sp@def is defined in keyval.sty
    \@xa\KV@@sp@def\@xa\thmt@tmp\@xa{\thmt@tmp}%
    \@xa\declaretheorem@ii\@xa{\thmt@tmp}{#1,#3}%
  }%
}

% #1 = single thmname (#1 and #2 are exchanged)
% #2 = option list
\def\declaretheorem@ii#1#2{%
  % why was that here?
  %\let\thmt@theoremdefiner\thmt@original@newtheorem
  % init options
  \thmt@setparent{}%
  \thmt@setsibling{}%
  \thmt@isnumberedtrue
  \thmt@isunlessuniquefalse
  \def\thmt@envname{#1}%
  \thmt@setthmname{\thmt@modifycase #1}%
  % use true code in \thmt@trytwice{<true>}{<false>}
  \@thmt@firstkeysettrue
  % parse options
  \kvsetkeys{thmdef0}{#2}% parse option "style" first
  \kvsetkeys{thmdef}{#2}%
  % call patched \newtheorem
  \ifthmt@isunlessunique
    \ifx\thmt@parent\@empty
    % define normal "unless unique" thm env
    \ifuniq{#1}{\thmt@isnumberedfalse}{\thmt@isnumberedtrue}%
    \declaretheorem@iii{#1}%
    \else
      % define special "unless unique" thm env, 
      % when "numbered=unless unique" and "numberwithin=<counter>" are both used
      \declaretheorem@iv{#1}%
      \thmt@isnumberedtrue
      \declaretheorem@iii{#1@numbered}%
      \thmt@isnumberedfalse
      \declaretheorem@iii{#1@unique}%
    \fi
  \else
    % define normal thm env
    \declaretheorem@iii{#1}%
  \fi
  % use false code in \thmt@trytwice{<true>}{<false>}
  \def\thmt@envname{#1}%
  \@thmt@firstkeysetfalse
  % uniquely ugly kludge: some keys make only sense afterwards.
  % and it gets kludgier: again, the default-inherited 
  % keys need to have a go at it.
  \kvsetkeys{thmdef0}{#2}%
  \kvsetkeys{thmdef}{#2}%
}

% define normal thm env, call \thmt@newtheorem
\def\declaretheorem@iii#1{%
  \protected@edef\thmt@tmp{%
    \@nx\thmt@newtheorem
    \ifthmt@isnumbered
      {#1}%
      \ifx\thmt@sibling\@empty\else [\thmt@sibling]\fi
      {\thmt@thmname}%
      \ifx\thmt@parent\@empty\else [\thmt@parent]\fi
    \else
      *{#1}{\thmt@thmname}%
    \fi
    \relax% added so we can delimited-read everything later
  }%
  \thmt@debug{Define theorem `#1' by ^^J\meaning\thmt@tmp}%
  \thmt@tmp
}

% define special thm env
\def\declaretheorem@iv#1{%
  \protected@edef\thmt@tmp{%
    % expand \thmt@envname and \thmt@parent
    \@nx\newenvironment{#1}{%
      \@nx\ifuniq{\thmt@envname.\@nx\@nameuse{the\thmt@parent}}{%
        \def\@nx\thmt@rawenvname{#1@unique}%
      }{%
        \def\@nx\thmt@rawenvname{#1@numbered}%
      }%
      \begin{\@nx\thmt@rawenvname}%
    }{%
      \end{\@nx\thmt@rawenvname}%
    }%
  }%
  \thmt@debug{Define special theorem `#1' by ^^J\meaning\thmt@tmp}%
  \thmt@tmp
}

\providecommand\thmt@quark{\thmt@quark}

% in-document keyval, i.e. \begin{theorem}[key=val,key=val]

\thmt@mkextendingkeyhandler{thmuse}{thmuse}{\thmt@envname\space optarg key}

\addtotheorempreheadhook{%
  \ifx\thmt@optarg\@empty\else
    \@xa\thmt@garbleoptarg\@xa{\thmt@optarg}\fi
}%

\newif\ifthmt@thmuse@iskv

\providecommand\thmt@garbleoptarg[1]{%
  \thmt@thmuse@iskvfalse
  \def\thmt@newoptarg{\@gobble}%
  \def\thmt@newoptargextra{}%
  \let\thmt@shortoptarg\@empty
  \def\thmt@warn@unusedkeys{}%
  \@for\thmt@fam:=\thmt@thmuse@families\do{%
    \kvsetkeys{\thmt@fam}{#1}%
  }%
  \ifthmt@thmuse@iskv
    \protected@edef\thmt@optarg{%
      \@xa\thmt@newoptarg
      \thmt@newoptargextra\@empty
    }%
    \ifx\thmt@shortoptarg\@empty
      \protected@edef\thmt@shortoptarg{\thmt@newoptarg\@empty}%
    \fi
    \thmt@warn@unusedkeys
  \else
    \def\thmt@optarg{#1}%
    \def\thmt@shortoptarg{#1}%
  \fi
}
% FIXME: not used?
% \def\thmt@splitopt#1=#2\thmt@quark{%
%   \def\thmt@tmpkey{#1}%
%   \ifx\thmt@tmpkey\@empty
%     \def\thmt@tmpkey{\thmt@quark}%
%   \fi
%   \@onelevel@sanitize\thmt@tmpkey
% }

\def\thmt@thmuse@families{thm@track@keys}

\kv@set@family@handler{thm@track@keys}{%
  \@onelevel@sanitize\kv@key
  \@namedef{thmt@unusedkey@\kv@key}{%
    \PackageWarning{thmtools}{Unused key `#1'}%
  }%
  \@xa\g@addto@macro\@xa\thmt@warn@unusedkeys\@xa{%
    \csname thmt@unusedkey@\kv@key\endcsname
  }
}

% key, code.
\def\thmt@define@thmuse@key#1#2{%
  \g@addto@macro\thmt@thmuse@families{,#1}%
  \define@key{#1}{#1}{\thmt@thmuse@iskvtrue
    \@namedef{thmt@unusedkey@#1}{}%
    #2}%
  \thmt@mkignoringkeyhandler{#1}%
}

\thmt@define@thmuse@key{label}{%
  \addtotheorempostheadhook[local]{\label{#1}}%
}
\thmt@define@thmuse@key{name}{%
  \thmt@setnewoptarg #1\@iden%
}
\newcommand\thmt@setnewoptarg[1][]{%
  \def\thmt@shortoptarg{#1}\thmt@setnewlongoptarg
}
\def\thmt@setnewlongoptarg #1\@iden{%
  \def\thmt@newoptarg{#1\@iden}}

\providecommand\thmt@suspendcounter[2]{%
  \@xa\protected@edef\csname the#1\endcsname{#2}%
  \@xa\let\csname c@#1\endcsname\c@thmt@dummyctr
}

\providecommand\thmcontinues[1]{%
  \ifcsname hyperref\endcsname
    \hyperref[#1]{continuing} 
  \else
    continuing
  \fi
  from p.\,\pageref{#1}%
}

\thmt@define@thmuse@key{continues}{%
  \thmt@suspendcounter{\thmt@envname}{\thmt@trivialref{#1}{??}}%
  \g@addto@macro\thmt@newoptarg{{, }%
    \thmcontinues{#1}%
    \@iden}%
}


%    \end{macrocode}
%
% Defining new theorem styles; keys are in opt-arg
% even though not having any doesn't make much sense.
% It doesn't do anything exciting here, it's up to 
% the glue layer to provide keys.
%
%    \begin{macrocode}
\def\thmt@declaretheoremstyle@setup{}
\def\thmt@declaretheoremstyle#1{%
  \PackageWarning{thmtools}{Your backend doesn't allow styling theorems}{}
}
\newcommand\declaretheoremstyle[2][]{%
  \def\thmt@style{#2}%
  \@xa\def\csname thmt@style \thmt@style @defaultkeys\endcsname{}%
  \thmt@declaretheoremstyle@setup
  \kvsetkeys{thmstyle}{#1}%
  \thmt@declaretheoremstyle{#2}%
}
\@onlypreamble\declaretheoremstyle

\kv@set@family@handler{thmstyle}{%
  \@onelevel@sanitize\kv@value
  \@onelevel@sanitize\kv@key
  \PackageInfo{thmtools}{%
    Key `\kv@key' (with value `\kv@value')\MessageBreak 
    is not a known style key.\MessageBreak
    Will pass this to every \string\declaretheorem\MessageBreak
    that uses `style=\thmt@style'%
  }%
  \ifx\kv@value\relax% no value given, don't pass on {}!
    \@xa\g@addto@macro\csname thmt@style \thmt@style @defaultkeys\endcsname{%
      #1,%
    }%
  \else
    \@xa\g@addto@macro\csname thmt@style \thmt@style @defaultkeys\endcsname{%
      #1={#2},%
    }%
  \fi
}
%    \end{macrocode}
%
%\iffalse
%</kv>
%\fi
