    {-# LANGUAGE LambdaCase           #-}
    {-# LANGUAGE OverloadedStrings    #-}
    {- |
    Copyright               : © 2021-2025 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
      ( 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 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 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 = Pusher e Alignment -> Pusher e ColWidth -> ColSpec -> LuaE e ()
    forall e a b.
    LuaError e =>
    Pusher e a -> Pusher e b -> (a, b) -> LuaE e ()
    pushPair Pusher e Alignment
    forall e. Pusher e Alignment
    pushAlignment Pusher e ColWidth
    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 = Peeker e Alignment -> Peeker e ColWidth -> Peeker e ColSpec
    forall e a b.
    LuaError e =>
    Peeker e a -> Peeker e b -> Peeker e (a, b)
    peekPair Peeker e Alignment
    forall e. Peeker e Alignment
    peekAlignment Peeker e ColWidth
    forall e. Peeker e ColWidth
    peekColWidth

    peekColWidth :: Peeker e ColWidth
    peekColWidth :: forall e. Peeker e ColWidth
    peekColWidth = Name -> Peek e ColWidth -> Peek e ColWidth
    forall e a. Name -> Peek e a -> Peek e a
    retrieving Name
    "ColWidth" (Peek e ColWidth -> Peek e ColWidth)
    -> (StackIndex -> Peek e ColWidth) -> StackIndex -> Peek e ColWidth
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . \StackIndex
    idx -> do
      ColWidth -> (Double -> ColWidth) -> Maybe Double -> ColWidth
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe ColWidth
    ColWidthDefault Double -> ColWidth
    ColWidth (Maybe Double -> ColWidth)
    -> Peek e (Maybe Double) -> Peek e ColWidth
    forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
    <$!> Peek e Double -> Peek e (Maybe Double)
    forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
    optional (Peeker e Double
    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)    -> Double -> LuaE e ()
    forall a e. (Pushable a, LuaError e) => a -> LuaE e ()
    forall e. LuaError e => Double -> LuaE e ()
    push Double
    w
      ColWidth
    ColWidthDefault -> LuaE e ()
    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
        LuaE e ()
    forall e. LuaE e ()
    newtable
        Name -> LuaE e () -> LuaE e ()
    forall e. LuaError e => Name -> LuaE e () -> LuaE e ()
    addField Name
    "attr" (Pusher e Attr
    forall e. LuaError e => Pusher e Attr
    pushAttr Attr
    attr)
        Name -> LuaE e () -> LuaE e ()
    forall e. LuaError e => Name -> LuaE e () -> LuaE e ()
    addField Name
    "row_head_columns" (Int -> LuaE e ()
    forall a e. (Integral a, Show a) => a -> LuaE e ()
    pushIntegral Int
    rowHeadColumns)
        Name -> LuaE e () -> LuaE e ()
    forall e. LuaError e => Name -> LuaE e () -> LuaE e ()
    addField Name
    "head" (Pusher e Row -> Pusher e [Row]
    forall e a. LuaError e => Pusher e a -> Pusher e [a]
    pushPandocList Pusher e Row
    forall e. LuaError e => Row -> LuaE e ()
    pushRow [Row]
    head')
        Name -> LuaE e () -> LuaE e ()
    forall e. LuaError e => Name -> LuaE e () -> LuaE e ()
    addField Name
    "body" (Pusher e Row -> Pusher e [Row]
    forall e a. LuaError e => Pusher e a -> Pusher e [a]
    pushPandocList Pusher e Row
    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 = (Peek e TableBody -> Peek e TableBody)
    -> (StackIndex -> Peek e TableBody)
    -> StackIndex
    -> Peek e TableBody
    forall a b. (a -> b) -> (StackIndex -> a) -> StackIndex -> b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (Name -> Peek e TableBody -> Peek e TableBody
    forall e a. Name -> Peek e a -> Peek e a
    retrieving Name
    "TableBody")
      ((StackIndex -> Peek e TableBody)
     -> StackIndex -> Peek e TableBody)
    -> ((StackIndex -> Peek e TableBody)
        -> StackIndex -> Peek e TableBody)
    -> (StackIndex -> Peek e TableBody)
    -> StackIndex
    -> Peek e TableBody
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Name
    -> (StackIndex -> LuaE e Bool)
    -> (StackIndex -> Peek e TableBody)
    -> StackIndex
    -> Peek e TableBody
    forall e a.
    Name -> (StackIndex -> LuaE e Bool) -> Peeker e a -> Peeker e a
    typeChecked Name
    "table" StackIndex -> LuaE e Bool
    forall e. StackIndex -> LuaE e Bool
    istable
      ((StackIndex -> Peek e TableBody)
     -> StackIndex -> Peek e TableBody)
    -> (StackIndex -> Peek e TableBody)
    -> StackIndex
    -> Peek e TableBody
    forall a b. (a -> b) -> a -> b
    $ \StackIndex
    idx -> Attr -> RowHeadColumns -> [Row] -> [Row] -> TableBody
    TableBody
      (Attr -> RowHeadColumns -> [Row] -> [Row] -> TableBody)
    -> Peek e Attr
    -> Peek e (RowHeadColumns -> [Row] -> [Row] -> TableBody)
    forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
    <$!> Peeker e Attr -> Name -> Peeker e Attr
    forall e a. LuaError e => Peeker e a -> Name -> Peeker e a
    peekFieldRaw Peeker e Attr
    forall e. LuaError e => Peeker e Attr
    peekAttr Name
    "attr" StackIndex
    idx
      Peek e (RowHeadColumns -> [Row] -> [Row] -> TableBody)
    -> Peek e RowHeadColumns -> Peek e ([Row] -> [Row] -> TableBody)
    forall a b. Peek e (a -> b) -> Peek e a -> Peek e b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*>  Peeker e RowHeadColumns -> Name -> Peeker e RowHeadColumns
    forall e a. LuaError e => Peeker e a -> Name -> Peeker e a
    peekFieldRaw ((Int -> RowHeadColumns) -> Peek e Int -> Peek e RowHeadColumns
    forall a b. (a -> b) -> Peek e a -> Peek e b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Int -> RowHeadColumns
    RowHeadColumns (Peek e Int -> Peek e RowHeadColumns)
    -> (StackIndex -> Peek e Int) -> Peeker e RowHeadColumns
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . StackIndex -> Peek e Int
    forall a e. (Integral a, Read a) => Peeker e a
    peekIntegral) Name
    "row_head_columns" StackIndex
    idx
      Peek e ([Row] -> [Row] -> TableBody)
    -> Peek e [Row] -> Peek e ([Row] -> TableBody)
    forall a b. Peek e (a -> b) -> Peek e a -> Peek e b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*>  Peeker e [Row] -> Name -> Peeker e [Row]
    forall e a. LuaError e => Peeker e a -> Name -> Peeker e a
    peekFieldRaw (Peeker e Row -> Peeker e [Row]
    forall a e. LuaError e => Peeker e a -> Peeker e [a]
    peekList Peeker e Row
    forall e. LuaError e => Peeker e Row
    peekRowFuzzy) Name
    "head" StackIndex
    idx
      Peek e ([Row] -> TableBody) -> Peek e [Row] -> Peek e TableBody
    forall a b. Peek e (a -> b) -> Peek e a -> Peek e b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*>  Peeker e [Row] -> Name -> Peeker e [Row]
    forall e a. LuaError e => Peeker e a -> Name -> Peeker e a
    peekFieldRaw (Peeker e Row -> Peeker e [Row]
    forall a e. LuaError e => Peeker e a -> Peeker e [a]
    peekList Peeker e Row
    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
      Name -> LuaE e ()
    forall e. Name -> LuaE e ()
    pushName Name
    key
      LuaE e ()
    pushFieldValue
      StackIndex -> LuaE e ()
    forall e. LuaError e => StackIndex -> LuaE e ()
    rawset (CInt -> StackIndex
    nth CInt
    3)