module Text.Pandoc.Lua.Marshaling.MediaBag (pushIterator) where
import Foreign.Ptr (Ptr)
import Foreign.StablePtr (StablePtr, deRefStablePtr, newStablePtr)
import Foreign.Lua (Lua, NumResults, Peekable, Pushable, StackIndex)
import Foreign.Lua.Types.Peekable (reportValueOnFailure)
import Foreign.Lua.Userdata (ensureUserdataMetatable, pushAnyWithMetatable,
                             toAnyWithName)
import Text.Pandoc.MediaBag (MediaBag, mediaItems)
import Text.Pandoc.MIME (MimeType)
import Text.Pandoc.Lua.Marshaling.AnyValue (AnyValue (..))
import qualified Data.ByteString.Lazy as BL
import qualified Foreign.Lua as Lua
import qualified Foreign.Storable as Storable
newtype MediaItems = MediaItems [(String, MimeType, BL.ByteString)]
instance Pushable MediaItems where
  push = pushMediaItems
instance Peekable MediaItems where
  peek = peekMediaItems
pushIterator :: MediaBag -> Lua NumResults
pushIterator mb = do
  Lua.pushHaskellFunction nextItem
  Lua.push (MediaItems $ mediaItems mb)
  Lua.pushnil
  return 3
mediaItemsTypeName :: String
mediaItemsTypeName = "pandoc MediaItems"
pushMediaItems :: MediaItems -> Lua ()
pushMediaItems xs = pushAnyWithMetatable pushMT xs
 where
  pushMT = ensureUserdataMetatable mediaItemsTypeName (return ())
peekMediaItems :: StackIndex -> Lua MediaItems
peekMediaItems = reportValueOnFailure mediaItemsTypeName
                 (`toAnyWithName` mediaItemsTypeName)
nextItem :: Ptr (StablePtr MediaItems) -> AnyValue -> Lua NumResults
nextItem ptr _ = do
  (MediaItems items) <- Lua.liftIO $ deRefStablePtr =<< Storable.peek ptr
  case items of
    [] -> 2 <$ (Lua.pushnil *> Lua.pushnil)
    (key, mt, content):xs -> do
      Lua.liftIO $ Storable.poke ptr =<< newStablePtr (MediaItems xs)
      Lua.push key
      Lua.push mt
      Lua.push content
      return 3