module Argo.Internal.Type.Encoder where

import qualified Argo.Internal.Literal as Literal
import qualified Argo.Internal.Type.Config as Config
import qualified Argo.Internal.Type.Indent as Indent
import qualified Argo.Vendor.Builder as Builder
import qualified Argo.Vendor.Transformers as Trans
import qualified Control.Monad as Monad
import qualified Data.Functor.Identity as Identity
import qualified Data.Semigroup as Semigroup

type Encoder
    = Trans.ReaderT
          Config.Config
          (Trans.WriterT Builder.Builder Identity.Identity)

unwrap :: Config.Config -> Encoder a -> (a, Builder.Builder)
unwrap :: forall a. Config -> Encoder a -> (a, Builder)
unwrap Config
c = forall a. Identity a -> a
Identity.runIdentity forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall w (m :: * -> *) a. WriterT w m a -> m (a, w)
Trans.runWriterT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b c. (a -> b -> c) -> b -> a -> c
flip forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
Trans.runReaderT Config
c

run :: Config.Config -> Encoder a -> Builder.Builder
run :: forall a. Config -> Encoder a -> Builder
run Config
c = forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Config -> Encoder a -> (a, Builder)
unwrap Config
c

list
    :: Encoder ()
    -> Encoder ()
    -> Encoder ()
    -> (a -> Encoder ())
    -> [a]
    -> Encoder ()
list :: forall a.
Encoder ()
-> Encoder ()
-> Encoder ()
-> (a -> Encoder ())
-> [a]
-> Encoder ()
list Encoder ()
left Encoder ()
right Encoder ()
separator a -> Encoder ()
encode [a]
xs = do
    Encoder ()
left
    case [a]
xs of
        [] -> forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
        a
x : [a]
ys -> do
            forall r (m :: * -> *) a.
(r -> r) -> ReaderT r m a -> ReaderT r m a
Trans.local Config -> Config
Config.increaseLevel forall a b. (a -> b) -> a -> b
$ do
                Maybe Builder
maybeIndent <- Config -> Maybe Builder
makeIndent forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) r. Monad m => ReaderT r m r
Trans.ask
                Maybe Builder -> Encoder ()
withNewLine Maybe Builder
maybeIndent
                a -> Encoder ()
encode a
x
                forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
Monad.forM_ [a]
ys forall a b. (a -> b) -> a -> b
$ \a
y -> do
                    Encoder ()
separator
                    Maybe Builder -> Encoder ()
withNewLine Maybe Builder
maybeIndent
                    a -> Encoder ()
encode a
y
            Maybe Builder
maybeIndent <- Config -> Maybe Builder
makeIndent forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) r. Monad m => ReaderT r m r
Trans.ask
            Maybe Builder -> Encoder ()
withNewLine Maybe Builder
maybeIndent
    Encoder ()
right

makeIndent :: Config.Config -> Maybe Builder.Builder
makeIndent :: Config -> Maybe Builder
makeIndent Config
config = case Config -> Indent
Config.indent Config
config of
    Indent.Spaces Int
spaces -> if Int
spaces forall a. Ord a => a -> a -> Bool
<= Int
0
        then forall a. Maybe a
Nothing
        else
            forall a. a -> Maybe a
Just
            forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b a. (Integral b, Monoid a) => b -> a -> a
Semigroup.stimesMonoid (Config -> Int
Config.level Config
config forall a. Num a => a -> a -> a
* Int
spaces)
            forall a b. (a -> b) -> a -> b
$ Word8 -> Builder
Builder.word8 Word8
Literal.space
    Indent
Indent.Tab ->
        forall a. a -> Maybe a
Just forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b a. (Integral b, Monoid a) => b -> a -> a
Semigroup.stimesMonoid (Config -> Int
Config.level Config
config) forall a b. (a -> b) -> a -> b
$ Word8 -> Builder
Builder.word8
            Word8
Literal.horizontalTabulation

withNewLine :: Maybe Builder.Builder -> Encoder ()
withNewLine :: Maybe Builder -> Encoder ()
withNewLine = forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall (f :: * -> *) a. Applicative f => a -> f a
pure ()) forall a b. (a -> b) -> a -> b
$ forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
Trans.lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) w. Monad m => w -> WriterT w m ()
Trans.tell forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Monoid a => a -> a -> a
mappend
    (Word8 -> Builder
Builder.word8 Word8
Literal.newLine)