% !TEX encoding = UTF-8 Unicode
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{okithm}[2021/11/11 v0.9 by <NAME>I]

% ======== Options ========
\RequirePackage{kvoptions}
\DeclareBoolOption[true]{theorems}
\DeclareComplementaryOption{notheorem}{theorems}
\DeclareBoolOption[true]{algorithms}
\DeclareComplementaryOption{noalgorithm}{algorithms}
\DeclareStringOption[section]{numberwithin}
\DeclareStringOption[long]{optstyle}
\DeclareBoolOption[true]{enumitem}
\DeclareComplementaryOption{noenumitem}{enumitem}
\ProcessKeyvalOptions*

% ======== Theorems ========
\ifokithm@theorems
  \RequirePackage{amsthm}
  \RequirePackage{thmtools}
  \RequirePackage{translations}

  \ProvideTranslation{English}{theorem}{Theorem}
  \ProvideTranslation{English}{definition}{Definition}
  \ProvideTranslation{English}{lemma}{Lemma}
  \ProvideTranslation{English}{proposition}{Proposition}
  \ProvideTranslation{English}{corollary}{Corollary}
  \ProvideTranslation{English}{example}{Example}
  \ProvideTranslation{English}{remark}{Remark}
  \ProvideTranslation{English}{proof}{Proof}

  \ProvideTranslation{Japanese}{theorem}{定理}
  \ProvideTranslation{Japanese}{definition}{定義}
  \ProvideTranslation{Japanese}{lemma}{補題}
  \ProvideTranslation{Japanese}{proposition}{命題}
  \ProvideTranslation{Japanese}{corollary}{系}
  \ProvideTranslation{Japanese}{example}{例}
  \ProvideTranslation{Japanese}{proof}{証明}

  \declaretheoremstyle{okithm@defstyle}
  \declaretheoremstyle[qed=\qedsymbol]{okicmd@exstyle}

  \ifcurrentlanguage{Japanese}{%
    \declaretheoremstyle{okicmd@thmstyle}
    \declaretheoremstyle[qed=\qedsymbol]{okicmd@proofstyle}
  }{%
    \declaretheoremstyle[bodyfont=\normalfont\itshape]{okicmd@thmstyle}
    \declaretheoremstyle[headfont=\normalfont\itshape,qed=\qedsymbol]{okicmd@proofstyle}
  }

  \declaretheorem[%
    name=\protect\GetTranslation{theorem},%
    style=okicmd@thmstyle,%
    numberwithin=\okithm@numberwithin%
  ]{theorem}
  \declaretheorem[%
    name=\protect\GetTranslation{definition},%
    style=okithm@defstyle,%
    sibling=theorem%
  ]{definition}
  \declaretheorem[%
    name=\protect\GetTranslation{lemma},%
    style=okicmd@thmstyle,%
    sibling=theorem%
  ]{lemma}
  \declaretheorem[%
    name=\protect\GetTranslation{proposition},%
    style=okicmd@thmstyle,%
    sibling=theorem%
  ]{proposition}
  \declaretheorem[%
    name=\protect\GetTranslation{corollary},%
    style=okicmd@thmstyle,%
    sibling=theorem%
  ]{corollary}
  \declaretheorem[%
    name=\protect\GetTranslation{example},%
    style=okicmd@exstyle,%
    sibling=theorem%
  ]{example}
  \declaretheorem[%
    name=\protect\GetTranslation{remark},%
    style=okithm@defstyle,%
    sibling=theorem%
  ]{remark}

  \let\proof\@undefined
  \let\endproof\@undefined
  \declaretheorem[%
    name=\protect\GetTranslation{proof},%
    style=okicmd@proofstyle,%
    numbered=no%
  ]{proof}
\fi

% ======== Algorithms ========
\ifokithm@algorithms
  \let\Return\relax
  \RequirePackage{algorithm}
  \RequirePackage[noend]{algpseudocode}

  \algnewcommand{\algorithmicinput}{\makebox[\widthof{\textbf{Output}}][l]{\textbf{Input}}\textbf{:}}
  \algnewcommand{\Input}{\item[\algorithmicinput]}
  \algnewcommand{\algorithmicoutput}{\textbf{Output:}}
  \algnewcommand{\Output}{\item[\algorithmicoutput]}

  \algnewcommand{\algorithmicto}{\textbf{to}}
  \algdef{SE}[FOR]{ForTo}{EndFor}[2]{\algorithmicfor\ #1 \algorithmicto\ #2 \algorithmicdo}{\algorithmicend\ \algorithmicfor}\algtext*{EndFor}
\fi

% ======== Optimization Problems ========
\RequirePackage{array}
\RequirePackage{xkeyval}

\define@cmdkeys{Minimizekey}[optprob@]{label,name,variable}
\define@choicekey*{Minimizekey}{style}[\val]{short,long}{\def\optprob@style{\val}}

% https://tex.stackexchange.com/questions/271062/labeling-a-text-and-referencing-it-later
\MakeRobust{\ref}% avoid expanding it when in a textual label
\newcommand{\labeltext}[2]{%
  \@bsphack
  \csname phantomsection\endcsname% in case hyperref is used
  \def\@currentlabel{#1}{\label{#2}}%
  \@esphack
}

\newcommand{\okithm@makeoptprob}[5]{%
  % #1 : options
  % #2 : minimize
  % #3 : object function
  % #4 : subject to
  % #5 : constraints
  \setkeys{Minimizekey}{#1}%
  \ifdefined\optprob@label
    \labeltext{\optprob@name}{\optprob@label}%
  \fi
  \begin{align}%
    \ifdefined\optprob@name%
      (\text{\optprob@name})\quad%
  	\fi%
    \begin{array}{|cl}%
      \ifdefined\optprob@variable%
        \underset{\optprob@variable}{\mathrm{#2}}%
      \else%
        \text{#2}%
      \fi%
      &$\begin{array}[t]{l}\displaystyle#3\end{array}$ \\
      \text{#4}%
      &$\begin{array}[t]{>{\displaystyle}l<{}>{\displaystyle}l<{}}#5\end{array}$%
    \end{array}%
  \end{align}%
  \let\optprob@label\undefined%
  \let\optprob@name\undefined%
  \let\optprob@variable\undefined%
  \let\optprob@style\undefined%
}

\newcommand{\okithm@DeclareOptProb}[5]{%
  % #1 : name of the command
  % #2 : minimize
  % #3 : min
  % #4 : subject to
  % #5 : s.t.
  \newcommand#1[3][]{%
    \setkeys{Minimizekey}{##1}%
    \ifdefined\optprob@style\else%
      \def\optprob@style{\okithm@optstyle}%
    \fi%
    \ifthenelse{\equal{\optprob@style}{long}}{%
      \okithm@makeoptprob{##1}{#2}{##2}{#4}{##3}%
    }{%
      \okithm@makeoptprob{##1}{#3}{##2}{#5}{##3}%
    }\ignorespaces%
  }%
}%

\okithm@DeclareOptProb{\Minimize}{minimize}{min}{subject to}{s.t.}
\okithm@DeclareOptProb{\Maximize}{maximize}{max}{subject to}{s.t.}

% ======== Enumeration ========
\ifokithm@enumitem
  \RequirePackage{enumitem}

  \setlist{font=\upshape,leftmargin=*}
  \setlist[1]{labelindent=\parindent}
  \setlist[enumerate,1]{label={(\arabic*)}}
  \setlist[enumerate,2]{label={(\arabic{enumi}-\arabic*)}}
  \setlist[enumerate,3]{label={(\arabic{enumi}-\arabic{enumii}-\arabic*)}}
\fi
