{-# LANGUAGE LambdaCase           #-}
{-# LANGUAGE OverloadedStrings    #-}
{-# LANGUAGE ScopedTypeVariables  #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{- |
   Module      : Text.Pandoc.Lua.Marshaling.ReaderOptions
   Copyright   : © 2012-2022 John MacFarlane
                 © 2017-2022 Albert Krewinkel
   License     : GNU GPL, version 2 or above

   Maintainer  : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
   Stability   : alpha

Marshal citeproc 'Reference' values.
-}
module Text.Pandoc.Lua.Marshal.Reference
  ( pushReference
  ) where

import Citeproc.Types
  ( Date (..), DateParts (..), ItemId (..), Name (..), Reference (..)
  , Val (..), Variable, fromVariable
  )
import Control.Monad (forM_)
import HsLua hiding (Name, Reference, pushName, peekName)
import Text.Pandoc.Builder (Inlines, toList)
import Text.Pandoc.Lua.Marshal.Inline (pushInlines)
import Text.Pandoc.Lua.Marshal.List (pushPandocList)

import qualified Data.Map as Map

-- | Pushes a ReaderOptions value as userdata object.
pushReference :: LuaError e => Pusher e (Reference Inlines)
pushReference :: forall e. LuaError e => Pusher e (Reference Inlines)
pushReference Reference Inlines
reference = do
  forall e a.
LuaError e =>
[(Name, a -> LuaE e ())] -> a -> LuaE e ()
pushAsTable [ (Name
"id", forall e. Pusher e ItemId
pushItemId forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Reference a -> ItemId
referenceId)
              , (Name
"type", forall e. Pusher e Text
pushText forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Reference a -> Text
referenceType)
              ]
              Reference Inlines
reference
  forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (forall k a. Map k a -> [(k, a)]
Map.toList forall a b. (a -> b) -> a -> b
$ forall a. Reference a -> Map Variable (Val a)
referenceVariables Reference Inlines
reference) forall a b. (a -> b) -> a -> b
$ \(Variable
var, Val Inlines
val) -> do
    forall e. Pusher e Variable
pushVariable Variable
var
    forall e. LuaError e => Pusher e (Val Inlines)
pushVal Val Inlines
val
    forall e. LuaError e => StackIndex -> LuaE e ()
rawset (CInt -> StackIndex
nth CInt
3)

-- | Pushes an 'ItemId' as a string.
pushItemId :: Pusher e ItemId
pushItemId :: forall e. Pusher e ItemId
pushItemId = forall e. Pusher e Text
pushText forall b c a. (b -> c) -> (a -> b) -> a -> c
. ItemId -> Text
unItemId

-- | Pushes a person's 'Name' as a table.
pushName :: LuaError e => Pusher e Name
pushName :: forall e. LuaError e => Pusher e Name
pushName = forall e a.
LuaError e =>
[(Name, a -> LuaE e ())] -> a -> LuaE e ()
pushAsTable
  [ (Name
"family"                , forall {e}. Maybe Text -> LuaE e ()
pushTextOrNil forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> Maybe Text
nameFamily)
  , (Name
"given"                 , forall {e}. Maybe Text -> LuaE e ()
pushTextOrNil forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> Maybe Text
nameGiven)
  , (Name
"dropping-particle"     , forall {e}. Maybe Text -> LuaE e ()
pushTextOrNil forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> Maybe Text
nameDroppingParticle)
  , (Name
"non-dropping-particle" , forall {e}. Maybe Text -> LuaE e ()
pushTextOrNil forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> Maybe Text
nameNonDroppingParticle)
  , (Name
"suffix"                , forall {e}. Maybe Text -> LuaE e ()
pushTextOrNil forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> Maybe Text
nameSuffix)
  , (Name
"literal"               , forall {e}. Maybe Text -> LuaE e ()
pushTextOrNil forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> Maybe Text
nameLiteral)
  , (Name
"comma-suffix"          , forall e. Pusher e Bool
pushBoolOrNil forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> Bool
nameCommaSuffix)
  , (Name
"static-ordering"       , forall e. Pusher e Bool
pushBoolOrNil forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> Bool
nameStaticOrdering)
  ]
  where
    pushTextOrNil :: Maybe Text -> LuaE e ()
pushTextOrNil = \case
      Maybe Text
Nothing -> forall e. LuaE e ()
pushnil
      Just Text
xs -> forall e. Pusher e Text
pushText Text
xs

-- | Pushes a boolean, but uses @nil@ instead of @false@; table fields
-- are not set unless the value is true.
pushBoolOrNil :: Pusher e Bool
pushBoolOrNil :: forall e. Pusher e Bool
pushBoolOrNil = \case
  Bool
False -> forall e. LuaE e ()
pushnil
  Bool
True  -> forall e. Pusher e Bool
pushBool Bool
True

-- | Pushes a 'Variable' as string.
pushVariable :: Pusher e Variable
pushVariable :: forall e. Pusher e Variable
pushVariable = forall e. Pusher e Text
pushText forall b c a. (b -> c) -> (a -> b) -> a -> c
. Variable -> Text
fromVariable

-- | Pushes a 'Val', i.e., a variable value.
pushVal :: LuaError e => Pusher e (Val Inlines)
pushVal :: forall e. LuaError e => Pusher e (Val Inlines)
pushVal = \case
  TextVal Text
t -> forall e. Pusher e Text
pushText Text
t
  FancyVal Inlines
inlns -> forall e. LuaError e => Pusher e [Inline]
pushInlines forall a b. (a -> b) -> a -> b
$ forall a. Many a -> [a]
toList Inlines
inlns
  NumVal Int
i       -> forall a e. (Integral a, Show a) => a -> LuaE e ()
pushIntegral Int
i
  NamesVal [Name]
names -> forall e a. LuaError e => Pusher e a -> Pusher e [a]
pushPandocList forall e. LuaError e => Pusher e Name
pushName [Name]
names
  DateVal Date
date   -> forall e. LuaError e => Pusher e Date
pushDate Date
date
  Val Inlines
_              -> forall e. Pusher e Text
pushText forall a. Monoid a => a
mempty

-- | Pushes a 'Date' as table.
pushDate :: LuaError e => Pusher e Date
pushDate :: forall e. LuaError e => Pusher e Date
pushDate = forall e a.
LuaError e =>
[(Name, a -> LuaE e ())] -> a -> LuaE e ()
pushAsTable
  [ (Name
"date-parts", forall e a. LuaError e => Pusher e a -> Pusher e [a]
pushPandocList forall {e}. LuaError e => DateParts -> LuaE e ()
pushDateParts forall b c a. (b -> c) -> (a -> b) -> a -> c
. Date -> [DateParts]
dateParts)
  , (Name
"circa", forall e. Pusher e Bool
pushBoolOrNil forall b c a. (b -> c) -> (a -> b) -> a -> c
. Date -> Bool
dateCirca)
  , (Name
"season", forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall e. LuaE e ()
pushnil forall a e. (Integral a, Show a) => a -> LuaE e ()
pushIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. Date -> Maybe Int
dateSeason)
  , (Name
"literal", forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall e. LuaE e ()
pushnil forall e. Pusher e Text
pushText forall b c a. (b -> c) -> (a -> b) -> a -> c
. Date -> Maybe Text
dateLiteral)
  ]
 where
   -- date parts are lists of Int values
   pushDateParts :: DateParts -> LuaE e ()
pushDateParts (DateParts [Int]
dp) = forall e a. LuaError e => Pusher e a -> Pusher e [a]
pushPandocList forall a e. (Integral a, Show a) => a -> LuaE e ()
pushIntegral [Int]
dp