% Kale Ewasiuk (kalekje@gmail.com)
% 2024-08-17
% Copyright (C) 2021-2024 Kale Ewasiuk
%
% Permission is hereby granted, free of charge, to any person obtaining a copy
% of this software and associated documentation files (the "Software"), to deal
% in the Software without restriction, including without limitation the rights
% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
% copies of the Software, and to permit persons to whom the Software is
% furnished to do so, subject to the following conditions:
%
% The above copyright notice and this permission notice shall be included in
% all copies or substantial portions of the Software.
%
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
% ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
% TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
% PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
% SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
% ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
% ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
% OR OTHER DEALINGS IN THE SOFTWARE.

\ProvidesPackage{penlightplus}[2024-08-17]

\RequirePackage{luacode}
\RequirePackage{luakeys}
\RequirePackage[import]{penlight}
\RequirePackage{etoolbox}

\DeclareOption{globals}{\luadirect{__PL_GLOBALS__ = true}}
\DeclareOption{pl}{\directlua{pl = penlight}}
\ProcessOptions*\relax

\luadirect{require'penlightplus'}




\global\newcommand{\writePDFmetadata}{\luadirect{penlight.tex.writePDFmetadata()}}

\NewDocumentCommand{\writePDFmetadatakv}{ s m }{
\IfBooleanTF{#1}{% if *, overwrite everything
  \luadirect{
    __PDFmetadata__ = penlight.luakeys.parse(\luastring{#2})
      penlight.tex.writePDFmetadata()
  }}{
    \luadirect{
    __PDFmetadata__ = __PDFmetadata__ or {}
    penlight.tablex.update(__PDFmetadata__, penlight.luakeys.parse(\luastring{#2}))
    penlight.tex.writePDFmetadata()
  }}
}


\gdef\luastringT#1{\luastring{\unexpanded\expandafter\expandafter\expandafter{#1}}}  % expand luastring twice
\global\let\luastringF\luastring  % fully expanded luastring

% allow control over expansion of arguments to a latex function
\NewDocumentCommand{\MakeluastringCommands}{O{} m }{% #1 the desired commands #2 defaults
  \luadirect{penlight.tex.aliasluastring(\luastring{#2},\luastring{#1})}%
}

\NewDocumentCommand{\splittocomma}{ O{nn} m m }{%
  \MakeluastringCommands[nn]{#1}%
  \luadirect{penlight.tex.split2comma(\plluastringA{#2},\plluastringB{#3})}%
}

\NewDocumentCommand{\splittoitems}{ O{NN} m m }{%
  \MakeluastringCommands[nn]{#1}%
  \luadirect{penlight.tex.split2items(\plluastringA{#2},\plluastringB{#3})}%
}








%%%%

\newtoggle{luaexpr}\togglefalse{luaexpr}

\begin{luacode*}

\end{luacode*}

\NewDocumentCommand{\ifluax}{m m O{}}{% if lua expression is true do {m} if not [o]
  \luadirect{penlight.toggle_luaexpr(#1)}%
  \iftoggle{luaexpr}{#2}{#3}%
  \togglefalse{luaexpr}% safety set to false
}

\NewDocumentCommand{\ifluaxv}{m m O{}}{\ifluax{penlight.hasval(#1)}{#2}[#3]}% if lua expression is truthy do {m} else [o]






\NewDocumentCommand{\caseswitch}{s m +m}{\ignorespaces\luadirect{penlight.caseswitch(\luastring{#1},\luastring{#2},\luastringN{#3})}\unskip}
% argument 1 is star option, which throws an error if case is not found
% argument 2 is the case, fully expanded
% argument 3 is a luakeys table of options, not expanded





%%% tbls below

\NewDocumentCommand{\tblnew}{m}{\luadirect{% initialize a tbl and set blank
  penlight.tbls[\luastring{#1}] = {}
  penlight.rec_tbl = \luastring{#1}
}}

\NewDocumentCommand{\tblfrkv}{m +m O{}}{\luadirect{%
  penlight.rec_tbl_opts = penlight.luakeys.parse(\luastring{#3})
  penlight.tbls[\luastring{#1}] = penlight.luakeys.parse(string.subpar(\luastring{#2}), penlight.rec_tbl_opts)
  penlight.rec_tbl = \luastring{#1}
}}

\NewDocumentCommand{\tblfrkvCD}{m +m O{}}{\tblfrkv{#1}{#2}[#3]\tblkvundefcheck\tbldefall{}{}}
%% tbl from key-vals, then check defaults, then define all keys using default format
\NewDocumentCommand{\tblfrkvNCD}{m +m O{}}{\tblfrkvN{#1}{#2}[#3]\tblkvundefcheck\tbldefall{}{}}

\NewDocumentCommand{\tblfrkvN}{m +m O{}}{\luadirect{%
  penlight.rec_tbl_opts = penlight.luakeys.parse(\luastring{#3})
  penlight.tbls[\luastring{#1}] = penlight.luakeys.parse(string.subpar(\luastringN{#2}), penlight.rec_tbl_opts)
  penlight.rec_tbl = \luastring{#1}
}}

\NewDocumentCommand{\tblfrcsv}{m +m O{}}{\tblfrkv{#1}{#2}[naked_as_value=true,#3]}

\NewDocumentCommand{\tblfrcsvN}{m +m O{}}{\tblfrkvN{#1}{#2}[naked_as_value=true,#3]}


\NewDocumentCommand{\tblkvundefcheck}{}{\luadirect{penlight.check_recent_tbl_undefault()}}% check defaults list and throw error if foreign keys were used



\NewDocumentCommand{\tblapp}{m m}{\luadirect{% append to a table (ie using integer index)  with a value (second arg) # todo option for string or number
  __tbl__ = penlight.get_tbl_name(\luastring{#1})
  table.insert(penlight.tbls[__tbl__], \luastring{#2})
}}

\NewDocumentCommand{\tblcon}{m m}{\luadirect{% concatenate to a table (ie using integer index)  with a  list of comma separated values (second arg) #
  __tbl__ = penlight.get_tbl_name(\luastring{#1})
  for k, v in ipairs(penlight.luakeys.parse(string.subpar(\luastring{#2}), {naked_as_value=true})) do
    table.insert(penlight.tbls[__tbl__], v)
  end
}}

\NewDocumentCommand{\tbladd}{m m}{\luadirect{% add a kv pair to a table
  __tbl__, __key__ = penlight.get_tbl_index(\luastring{#1}, true)
  penlight.tbls[__tbl__][__key__] = \luastring{#2}
}}

\NewDocumentCommand{\tbladdN}{m m m}{\luadirect{% add a kv pair to a table
  __tbl__, __key__ = penlight.get_tbl_index(\luastring{#1}, true)
  penlight.tbls[__tbl__][__key__] = \luastringN{#2}
}}




\NewDocumentCommand{\tblchg}{ m }{\luadirect{% change recent table
  penlight.rec_tbl = \luastring{#1}
}}


\NewDocumentCommand{\tblget}{m}{\luadirect{% get an item
  penlight.get_tbl_item(\luastring{#1}, true)
}}

\NewDocumentCommand{\tblset}{m m}{\luadirect{% set item with {value}
  penlight.set_tbl_item(\luastring{#1}, \luastring{#2})
}}


\NewDocumentCommand{\tbldef}{ m m }{\luadirect{penlight.def_tbl(\luastring{#1}, \luastring{#2})}}

% define a table, use * to make global definition
\NewDocumentCommand{\tblgdef}{ m m }{\luadirect{penlight.def_tbl(\luastring{#1}, \luastring{#2}, 'global')}}

\NewDocumentCommand{\tbldefall}{ m m }{\luadirect{penlight.def_tbl_all(\luastring{#1}, \luastring{#2})}}

\NewDocumentCommand{\tbldefxy}{ m m }{\luadirect{penlight.def_tbl_coords(\luastring{#1}, \luastring{#2})}}% define #2x and #2y from a space delimited x-y pair

\NewDocumentCommand{\tblif}{m m O{}}{\ifluax{penlight.get_tbl_item(\luastring{#1})}{#2}[#3]}

\NewDocumentCommand{\tblifv}{m m O{}}{\ifluaxv{penlight.get_tbl_item(\luastring{#1})}{#2}[#3]}

\NewDocumentCommand{\tblprt}{m}{\luadirect{penlight.wrth(penlight.get_tbl(\luastring{#1}),'penlightplus table: '..\luastring{#1})}}




% legacy code, delete this
\let\kvtblundefcheck\tblkvundefcheck

\NewDocumentCommand{\tbladdo}{m m m}{\luadirect{% add a kv pair to a table
  __tbl__ = penlight.get_tbl_name(\luastring{#1})
  penlight.tbls[__tbl__][\luastring{#2}] = \luastring{#3}
}}

\NewDocumentCommand{\tbladdNo}{m m m}{\luadirect{% add a kv pair to a table
  __tbl__ = penlight.get_tbl_name(\luastring{#1})
  penlight.tbls[__tbl__][\luastring{#2}] = \luastringN{#3}
}}

\let\chgtbl\tblchg
\let\newtbl\tblnew
\let\gettbl\tblget
\let\settbl\tblset
\let\deftbl\tbldef
\let\gdeftbl\tblgdef
\let\iftbl\tblif
\let\iftblv\tblifv