---LaTeXTableShortCapts – enable `.unlisted` and `short-caption=""` properties
--                        for Pandoc conversion to LaTeX

--[[
Copyright (c) 2019 Blake Riley

Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
]]
local List = require 'pandoc.List'

-- don't do anything unless we target latex
if FORMAT ~= "latex" then
  return {}
end

--- Code for injection into the LaTeX header,
--  to overwrite a macro in longtable captions.
longtable_caption_mod = [[
% -- begin:latex-table-short-captions --
\makeatletter\AtBeginDocument{%
\def\LT@c@ption#1[#2]#3{%                 % Overwrite the workhorse macro used in formatting a longtable caption.
  \LT@makecaption#1\fnum@table{#3}%
  \@ifundefined{pandoctableshortcapt}
     {\def\@tempa{#2}}                    % Use default behaviour: argument in square brackets
     {\let\@tempa\pandoctableshortcapt}   % If defined (even if blank), use to override
  \ifx\@tempa\@empty\else                 % If @tempa is blank, no lot entry! Otherwise, @tempa becomes the lot title.
     {\let\\\space
     \addcontentsline{lot}{table}{\protect\numberline{\thetable}{\@tempa}}}%
  \fi}
}\makeatother
% -- end:latex-table-short-captions --
]]

--- Creates a def shortcaption block to be placed before the table
-- @tparam ?string sc : The short-caption property value
-- @treturn Plain : The def shortcaption block
local function defshortcapt(sc)
  local scblock = List:new{}
  scblock:extend {pandoc.RawInline('tex', "\\def\\pandoctableshortcapt{")}
  if sc then
    scblock:extend (pandoc.read(sc).blocks[1].c)
  end
  scblock:extend {pandoc.RawInline('tex', "}")}
  if not sc then
    scblock:extend {pandoc.RawInline('tex', "  % .unlisted")}
  end
  return pandoc.Plain(scblock)
end

--- The undef shortcaption block to be placed after the table
local undefshortcapt = pandoc.RawBlock('tex', "\\let\\pandoctableshortcapt\\relax")

--- Parses a mock "Table Attr".
-- We use the Attr of an empty Span as if it were Table Attr.
-- This function extracts what is needed to build a short-caption.
-- @tparam Attr attr : The Attr of the property Span in the table caption
-- @treturn ?string : The identifier
-- @treturn ?string : The "short-caption" property, if present.
-- @treturn bool : Whether ".unlisted" appeared in the classes
local function parse_table_attrs(attr)
  -- Find label
  local label = nil
  if attr.identifier and (#attr.identifier > 0) then
    label = attr.identifier
  end

  -- Look for ".unlisted" in classes
  local unlisted = false
  if attr.classes:includes("unlisted") then
    unlisted = true
  end

  -- If not unlisted, then find the property short-caption.
  local short_caption = nil
  if not unlisted then
    if (attr.attributes["short-caption"]) and
       (#attr.attributes["short-caption"] > 0) then
      short_caption = attr.attributes['short-caption']
    end
  end

  return label, short_caption, unlisted
end

--- Wraps a table with shortcaption code
-- @tparam Table tbl : The table with {}-wrapped properties in the caption
-- @treturn List[Blocks] : The table with {label} in the caption,
--                         optionally wrapped in shortcaption code
function rewrite_longtable_caption(tbl)
  -- Escape if there is no caption present.
  if not tbl.caption then
    return nil
  end

  -- Try find the properties block
  local is_properties_span = function (inl)
    return (inl.t) and (inl.t == "Span")                      -- is span
                   and (inl.content) and (#inl.content == 0)  -- is empty span
  end
  local propspan, idx = tbl.caption:find_if(is_properties_span)

  -- If we couldn't find properties, escape.
  if not propspan then
    return nil
  end

  -- Otherwise, parse it all
  local label, short_caption, unlisted = parse_table_attrs(propspan.attr)

  -- Excise the span from the caption
  tbl.caption[idx] = nil

  -- Put label back into caption for pandoc-crossref
  if label then
    tbl.caption:extend {pandoc.Str("{#"..label.."}")}
  end

  -- Place new table
  local result = List:new{}
  if short_caption or unlisted then
    result:extend {defshortcapt(short_caption)}
  end
  result:extend {tbl}
  if short_caption or unlisted then
    result:extend {undefshortcapt}
  end
  return result
end

--- Inserts longtable_caption_mod into the header_includes
-- @tparam Meta meta : The document metadata
-- @treturn Meta : The document metadata, with replacement LaTeX macro
--                 in header_includes
function add_longtable_caption_mod(meta)
  local header_includes = -- test ? a : b
    (meta['header-includes'] and meta['header-includes'].t == 'MetaList')
    and meta['header-includes']
    or pandoc.MetaList{meta['header-includes']}
  header_includes[#header_includes + 1] =
    pandoc.MetaBlocks{pandoc.RawBlock('tex', longtable_caption_mod)}
  meta['header-includes'] = header_includes
  return meta
end

return {
  {
    Meta = add_longtable_caption_mod,
    Table = rewrite_longtable_caption,
  }
}
