content: {-# LANGUAGE OverloadedStrings #-}
  {- |
     Module      : Text.Pandoc.Writers.BibTeX
     Copyright   : Copyright (C) 2021-2024 John MacFarlane
     License     : GNU GPL, version 2 or above
  
     Maintainer  : John MacFarlane <jgm@berkeley.edu>
     Stability   : alpha
     Portability : portable
  
  Writes a BibTeX or BibLaTeX bibliographies based on the
  'references' metadata in a Pandoc document.
  -}
  module Text.Pandoc.Writers.BibTeX
    ( writeBibTeX
    , writeBibLaTeX
    )
  where
  
  import Text.Pandoc.Options
  import Text.Pandoc.Definition
  import Data.Text (Text)
  import Data.Maybe (mapMaybe)
  import Citeproc (parseLang)
  import Text.Pandoc.Class (PandocMonad)
  import Text.Pandoc.Citeproc.BibTeX as BibTeX
  import Text.Pandoc.Citeproc.MetaValue (metaValueToReference)
  import Text.Pandoc.Writers.Shared (lookupMetaString, defField,
                                      addVariablesToContext)
  import Text.DocLayout (render, vcat)
  import Text.DocTemplates (Context(..))
  import Text.Pandoc.Templates (renderTemplate)
  
  -- | Write BibTeX based on the references metadata from a Pandoc document.
  writeBibTeX :: PandocMonad m => WriterOptions -> Pandoc -> m Text
  writeBibTeX = writeBibTeX' BibTeX.Bibtex
  
  -- | Write BibLaTeX based on the references metadata from a Pandoc document.
  writeBibLaTeX :: PandocMonad m => WriterOptions -> Pandoc -> m Text
  writeBibLaTeX = writeBibTeX' BibTeX.Biblatex
  
  writeBibTeX' :: PandocMonad m => Variant -> WriterOptions -> Pandoc -> m Text
  writeBibTeX' variant opts (Pandoc meta _) = do
    let mblang = case lookupMetaString "lang" meta of
                   "" -> Nothing
                   t  -> either (const Nothing) Just $ parseLang t
    let refs = case lookupMeta "references" meta of
                 Just (MetaList xs) -> mapMaybe metaValueToReference xs
                 _ -> []
    let main = vcat $ map (BibTeX.writeBibtexString opts variant mblang) refs
    let context  = defField "body" main
                   $ addVariablesToContext opts (mempty :: Context Text)
    let colwidth = if writerWrapText opts == WrapAuto
                      then Just $ writerColumns opts
                      else Nothing
    return $ render colwidth $
      case writerTemplate opts of
        Nothing  -> main
        Just tpl -> renderTemplate tpl context
  