{-# LANGUAGE LambdaCase           #-}
{-# LANGUAGE OverloadedStrings    #-}
{- |
Copyright               : © 2021-2023 Albert Krewinkel
SPDX-License-Identifier : MIT
Maintainer              : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>

Marshaling/unmarshaling functions of types that are used exclusively
with tables.
-}
module Text.Pandoc.Lua.Marshal.TableParts
  ( peekCaption
  , peekCaptionFuzzy
  , pushCaption
  , peekColSpec
  , pushColSpec
  , peekRow
  , peekRowFuzzy
  , pushRow
  , peekTableBody
  , pushTableBody
  , peekTableFoot
  , pushTableFoot
  , peekTableHead
  , pushTableHead
    -- * Constructors
  , mkRow
  , mkTableFoot
  , mkTableHead
  ) where

import Control.Applicative ((<|>), optional)
import Control.Monad ((<$!>))
import HsLua
import Text.Pandoc.Lua.Marshal.Alignment (peekAlignment, pushAlignment)
import Text.Pandoc.Lua.Marshal.Attr (peekAttr, pushAttr)
import {-# SOURCE #-} Text.Pandoc.Lua.Marshal.Block
  ( peekBlocksFuzzy, pushBlocks )
import {-# SOURCE #-} Text.Pandoc.Lua.Marshal.Inline
  ( peekInlinesFuzzy, pushInlines )
import Text.Pandoc.Lua.Marshal.List (pushPandocList)
import Text.Pandoc.Lua.Marshal.Row
import Text.Pandoc.Lua.Marshal.TableFoot
import Text.Pandoc.Lua.Marshal.TableHead
import Text.Pandoc.Definition

-- | Push Caption element
pushCaption :: LuaError e => Caption -> LuaE e ()
pushCaption :: forall e. LuaError e => Caption -> LuaE e ()
pushCaption (Caption Maybe ShortCaption
shortCaption [Block]
longCaption) = do
  forall e. LuaE e ()
newtable
  forall e. LuaError e => Name -> LuaE e () -> LuaE e ()
addField Name
"short" (forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall e. LuaE e ()
pushnil forall e. LuaError e => Pusher e ShortCaption
pushInlines Maybe ShortCaption
shortCaption)
  forall e. LuaError e => Name -> LuaE e () -> LuaE e ()
addField Name
"long" (forall e. LuaError e => Pusher e [Block]
pushBlocks [Block]
longCaption)

-- | Peek Caption element
peekCaption :: LuaError e => Peeker e Caption
peekCaption :: forall e. LuaError e => Peeker e Caption
peekCaption StackIndex
idx = do
  Maybe ShortCaption
short <- forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional forall a b. (a -> b) -> a -> b
$ forall e a. LuaError e => Peeker e a -> Name -> Peeker e a
peekFieldRaw forall e. LuaError e => Peeker e ShortCaption
peekInlinesFuzzy Name
"short" StackIndex
idx
  [Block]
long <- forall e a. LuaError e => Peeker e a -> Name -> Peeker e a
peekFieldRaw forall e. LuaError e => Peeker e [Block]
peekBlocksFuzzy Name
"long" StackIndex
idx
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$! Maybe ShortCaption -> [Block] -> Caption
Caption Maybe ShortCaption
short [Block]
long

peekCaptionFuzzy :: LuaError e => Peeker e Caption
peekCaptionFuzzy :: forall e. LuaError e => Peeker e Caption
peekCaptionFuzzy = forall e a. Name -> Peek e a -> Peek e a
retrieving Name
"Caption" forall b c a. (b -> c) -> (a -> b) -> a -> c
. \StackIndex
idx -> do
      forall e. LuaError e => Peeker e Caption
peekCaption StackIndex
idx
  forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Maybe ShortCaption -> [Block] -> Caption
Caption forall a. Maybe a
Nothing forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
<$!> forall e. LuaError e => Peeker e [Block]
peekBlocksFuzzy StackIndex
idx)
  forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (forall a e. ByteString -> Peek e a
failPeek forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<
       forall e. Name -> StackIndex -> Peek e ByteString
typeMismatchMessage Name
"Caption, list of Blocks, or compatible element" StackIndex
idx)

-- | Push a ColSpec value as a pair of Alignment and ColWidth.
pushColSpec :: LuaError e => Pusher e ColSpec
pushColSpec :: forall e. LuaError e => Pusher e ColSpec
pushColSpec = forall e a b.
LuaError e =>
Pusher e a -> Pusher e b -> (a, b) -> LuaE e ()
pushPair forall e. Pusher e Alignment
pushAlignment forall e. LuaError e => Pusher e ColWidth
pushColWidth

-- | Peek a ColSpec value as a pair of Alignment and ColWidth.
peekColSpec :: LuaError e => Peeker e ColSpec
peekColSpec :: forall e. LuaError e => Peeker e ColSpec
peekColSpec = forall e a b.
LuaError e =>
Peeker e a -> Peeker e b -> Peeker e (a, b)
peekPair forall e. Peeker e Alignment
peekAlignment forall e. Peeker e ColWidth
peekColWidth

peekColWidth :: Peeker e ColWidth
peekColWidth :: forall e. Peeker e ColWidth
peekColWidth = forall e a. Name -> Peek e a -> Peek e a
retrieving Name
"ColWidth" forall b c a. (b -> c) -> (a -> b) -> a -> c
. \StackIndex
idx -> do
  forall b a. b -> (a -> b) -> Maybe a -> b
maybe ColWidth
ColWidthDefault Double -> ColWidth
ColWidth forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
<$!> forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (forall a e. (RealFloat a, Read a) => Peeker e a
peekRealFloat StackIndex
idx)

-- | Push a ColWidth value by pushing the width as a plain number, or
-- @nil@ for ColWidthDefault.
pushColWidth :: LuaError e => Pusher e ColWidth
pushColWidth :: forall e. LuaError e => Pusher e ColWidth
pushColWidth = \case
  (ColWidth Double
w)    -> forall a e. (Pushable a, LuaError e) => a -> LuaE e ()
push Double
w
  ColWidth
ColWidthDefault -> forall e. LuaE e ()
pushnil

-- | Pushes a 'TableBody' value as a Lua table with fields @attr@,
-- @row_head_columns@, @head@, and @body@.
pushTableBody :: LuaError e => Pusher e TableBody
pushTableBody :: forall e. LuaError e => Pusher e TableBody
pushTableBody (TableBody Attr
attr (RowHeadColumns Int
rowHeadColumns) [Row]
head' [Row]
body) = do
    forall e. LuaE e ()
newtable
    forall e. LuaError e => Name -> LuaE e () -> LuaE e ()
addField Name
"attr" (forall e. LuaError e => Pusher e Attr
pushAttr Attr
attr)
    forall e. LuaError e => Name -> LuaE e () -> LuaE e ()
addField Name
"row_head_columns" (forall a e. (Integral a, Show a) => a -> LuaE e ()
pushIntegral Int
rowHeadColumns)
    forall e. LuaError e => Name -> LuaE e () -> LuaE e ()
addField Name
"head" (forall e a. LuaError e => Pusher e a -> Pusher e [a]
pushPandocList forall e. LuaError e => Row -> LuaE e ()
pushRow [Row]
head')
    forall e. LuaError e => Name -> LuaE e () -> LuaE e ()
addField Name
"body" (forall e a. LuaError e => Pusher e a -> Pusher e [a]
pushPandocList forall e. LuaError e => Row -> LuaE e ()
pushRow [Row]
body)

-- | Retrieves a 'TableBody' value from a Lua table with fields @attr@,
-- @row_head_columns@, @head@, and @body@.
peekTableBody :: LuaError e => Peeker e TableBody
peekTableBody :: forall e. LuaError e => Peeker e TableBody
peekTableBody = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall e a. Name -> Peek e a -> Peek e a
retrieving Name
"TableBody")
  forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e a.
Name -> (StackIndex -> LuaE e Bool) -> Peeker e a -> Peeker e a
typeChecked Name
"table" forall e. StackIndex -> LuaE e Bool
istable
  forall a b. (a -> b) -> a -> b
$ \StackIndex
idx -> Attr -> RowHeadColumns -> [Row] -> [Row] -> TableBody
TableBody
  forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
<$!> forall e a. LuaError e => Peeker e a -> Name -> Peeker e a
peekFieldRaw forall e. LuaError e => Peeker e Attr
peekAttr Name
"attr" StackIndex
idx
  forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*>  forall e a. LuaError e => Peeker e a -> Name -> Peeker e a
peekFieldRaw (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Int -> RowHeadColumns
RowHeadColumns forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a e. (Integral a, Read a) => Peeker e a
peekIntegral) Name
"row_head_columns" StackIndex
idx
  forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*>  forall e a. LuaError e => Peeker e a -> Name -> Peeker e a
peekFieldRaw (forall a e. LuaError e => Peeker e a -> Peeker e [a]
peekList forall e. LuaError e => Peeker e Row
peekRowFuzzy) Name
"head" StackIndex
idx
  forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*>  forall e a. LuaError e => Peeker e a -> Name -> Peeker e a
peekFieldRaw (forall a e. LuaError e => Peeker e a -> Peeker e [a]
peekList forall e. LuaError e => Peeker e Row
peekRowFuzzy) Name
"body" StackIndex
idx

-- | Add a value to the table at the top of the stack at a string-index.
addField :: LuaError e => Name -> LuaE e () -> LuaE e ()
addField :: forall e. LuaError e => Name -> LuaE e () -> LuaE e ()
addField Name
key LuaE e ()
pushFieldValue = do
  forall e. Name -> LuaE e ()
pushName Name
key
  LuaE e ()
pushFieldValue
  forall e. LuaError e => StackIndex -> LuaE e ()
rawset (CInt -> StackIndex
nth CInt
3)