{-
pandoc-crossref is a pandoc filter for numbering figures,
equations, tables and cross-references to them.
Copyright (C) 2015  Nikolay Yakimov <root@livid.pp.ru>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-}

{-# LANGUAGE FlexibleContexts, Rank2Types #-}
module Text.Pandoc.CrossRef.Util.Meta (
    getMetaList
  , getMetaBool
  , getMetaInlines
  , getMetaBlock
  , getMetaString
  , getList
  , toString
  , toInlines
  , tryCapitalizeM
  ) where

import Data.Default
import qualified Data.Text as T
import Text.Pandoc.Builder
import Text.Pandoc.CrossRef.Util.Util
import Text.Pandoc.Shared hiding (capitalize)
import Text.Pandoc.Walk

getMetaList :: (Default a) => (MetaValue -> a) -> T.Text -> Meta -> Int -> a
getMetaList :: forall a. Default a => (MetaValue -> a) -> Text -> Meta -> Int -> a
getMetaList MetaValue -> a
f Text
name Meta
meta Int
i = forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall a. Default a => a
def MetaValue -> a
f forall a b. (a -> b) -> a -> b
$ Text -> Meta -> Maybe MetaValue
lookupMeta Text
name Meta
meta forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> MetaValue -> Maybe MetaValue
getList Int
i

getMetaBool :: T.Text -> Meta -> Bool
getMetaBool :: Text -> Meta -> Bool
getMetaBool = forall b. Def b => (Text -> MetaValue -> b) -> Text -> Meta -> b
getScalar Text -> MetaValue -> Bool
toBool

getMetaInlines :: T.Text -> Meta -> [Inline]
getMetaInlines :: Text -> Meta -> [Inline]
getMetaInlines = forall b. Def b => (Text -> MetaValue -> b) -> Text -> Meta -> b
getScalar Text -> MetaValue -> [Inline]
toInlines

getMetaBlock :: T.Text -> Meta -> [Block]
getMetaBlock :: Text -> Meta -> [Block]
getMetaBlock = forall b. Def b => (Text -> MetaValue -> b) -> Text -> Meta -> b
getScalar Text -> MetaValue -> [Block]
toBlocks

getMetaString :: T.Text -> Meta -> T.Text
getMetaString :: Text -> Meta -> Text
getMetaString = forall b. Def b => (Text -> MetaValue -> b) -> Text -> Meta -> b
getScalar Text -> MetaValue -> Text
toString

getScalar :: Def b => (T.Text -> MetaValue -> b) -> T.Text -> Meta -> b
getScalar :: forall b. Def b => (Text -> MetaValue -> b) -> Text -> Meta -> b
getScalar Text -> MetaValue -> b
conv Text
name Meta
meta = forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall a. Def a => a
def' (Text -> MetaValue -> b
conv Text
name) forall a b. (a -> b) -> a -> b
$ Text -> Meta -> Maybe MetaValue
lookupMeta Text
name Meta
meta

class Def a where
  def' :: a

instance Def Bool where
  def' :: Bool
def' = Bool
False

instance Def [a] where
  def' :: [a]
def' = []

instance Def T.Text where
  def' :: Text
def' = Text
T.empty

unexpectedError :: forall a. String -> T.Text -> MetaValue -> a
unexpectedError :: forall a. String -> Text -> MetaValue -> a
unexpectedError String
e Text
n MetaValue
x = forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ String
"Expected " forall a. Semigroup a => a -> a -> a
<> String
e forall a. Semigroup a => a -> a -> a
<> String
" in metadata field " forall a. Semigroup a => a -> a -> a
<> Text -> String
T.unpack Text
n forall a. Semigroup a => a -> a -> a
<> String
" but got " forall a. Semigroup a => a -> a -> a
<> MetaValue -> String
g MetaValue
x
  where
    g :: MetaValue -> String
g (MetaBlocks [Block]
_) = String
"blocks"
    g (MetaString Text
_) = String
"string"
    g (MetaInlines [Inline]
_) = String
"inlines"
    g (MetaBool Bool
_) = String
"bool"
    g (MetaMap Map Text MetaValue
_) = String
"map"
    g (MetaList [MetaValue]
_) = String
"list"

toInlines :: T.Text -> MetaValue -> [Inline]
toInlines :: Text -> MetaValue -> [Inline]
toInlines Text
_ (MetaBlocks [Block]
s) = [Block] -> [Inline]
blocksToInlines [Block]
s
toInlines Text
_ (MetaInlines [Inline]
s) = [Inline]
s
toInlines Text
_ (MetaString Text
s) = forall a. Many a -> [a]
toList forall a b. (a -> b) -> a -> b
$ Text -> Inlines
text Text
s
toInlines Text
n MetaValue
x = forall a. String -> Text -> MetaValue -> a
unexpectedError String
"inlines" Text
n MetaValue
x

toBool :: T.Text -> MetaValue -> Bool
toBool :: Text -> MetaValue -> Bool
toBool Text
_ (MetaBool Bool
b) = Bool
b
toBool Text
n MetaValue
x = forall a. String -> Text -> MetaValue -> a
unexpectedError String
"bool" Text
n MetaValue
x

toBlocks :: T.Text -> MetaValue -> [Block]
toBlocks :: Text -> MetaValue -> [Block]
toBlocks Text
_ (MetaBlocks [Block]
bs) = [Block]
bs
toBlocks Text
_ (MetaInlines [Inline]
ils) = [[Inline] -> Block
Plain [Inline]
ils]
toBlocks Text
_ (MetaString Text
s) = forall a. Many a -> [a]
toList forall a b. (a -> b) -> a -> b
$ Inlines -> Blocks
plain forall a b. (a -> b) -> a -> b
$ Text -> Inlines
text Text
s
toBlocks Text
n MetaValue
x = forall a. String -> Text -> MetaValue -> a
unexpectedError String
"blocks" Text
n MetaValue
x

toString :: T.Text -> MetaValue -> T.Text
toString :: Text -> MetaValue -> Text
toString Text
_ (MetaString Text
s) = Text
s
toString Text
_ (MetaBlocks [Block]
b) = forall a. Walkable Inline a => a -> Text
stringify [Block]
b
toString Text
_ (MetaInlines [Inline]
i) = forall a. Walkable Inline a => a -> Text
stringify [Inline]
i
toString Text
n MetaValue
x = forall a. String -> Text -> MetaValue -> a
unexpectedError String
"string" Text
n MetaValue
x

getList :: Int -> MetaValue -> Maybe MetaValue
getList :: Int -> MetaValue -> Maybe MetaValue
getList Int
i (MetaList [MetaValue]
l) = [MetaValue]
l forall {a}. [a] -> Int -> Maybe a
!!? Int
i
  where
    [a]
list !!? :: [a] -> Int -> Maybe a
!!? Int
index | Int
index forall a. Ord a => a -> a -> Bool
>= Int
0 Bool -> Bool -> Bool
&& Int
index forall a. Ord a => a -> a -> Bool
< forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
list = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ [a]
list forall a. [a] -> Int -> a
!! Int
index
                   | Bool -> Bool
not forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => t a -> Bool
null [a]
list = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. [a] -> a
last [a]
list
                   | Bool
otherwise = forall a. Maybe a
Nothing
getList Int
_ MetaValue
x = forall a. a -> Maybe a
Just MetaValue
x

tryCapitalizeM :: (Functor m, Monad m, Walkable Inline a, Default a, Eq a) =>
        (T.Text -> m a) -> T.Text -> Bool -> m a
tryCapitalizeM :: forall (m :: * -> *) a.
(Functor m, Monad m, Walkable Inline a, Default a, Eq a) =>
(Text -> m a) -> Text -> Bool -> m a
tryCapitalizeM Text -> m a
f Text
varname Bool
capitalize
  | Bool
capitalize = do
    a
res <- Text -> m a
f (Text -> Text
capitalizeFirst Text
varname)
    case a
res of
      a
xs | a
xs forall a. Eq a => a -> a -> Bool
== forall a. Default a => a
def -> Text -> m a
f Text
varname forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall a b (m :: * -> *).
(Walkable a b, Monad m, Applicative m, Functor m) =>
(a -> m a) -> b -> m b
walkM forall {m :: * -> *}. Monad m => Inline -> m Inline
capStrFst
         | Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return a
xs
  | Bool
otherwise  = Text -> m a
f Text
varname
  where
    capStrFst :: Inline -> m Inline
capStrFst (Str Text
s) = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Text -> Inline
Str forall a b. (a -> b) -> a -> b
$ Text -> Text
capitalizeFirst Text
s
    capStrFst Inline
x = forall (m :: * -> *) a. Monad m => a -> m a
return Inline
x