{-# LANGUAGE OverloadedStrings #-}
module Text.Blaze.Renderer.Utf8
    ( renderMarkupBuilder
    , renderMarkup
    , renderMarkupToByteStringIO
    , renderHtmlBuilder
    , renderHtml
    , renderHtmlToByteStringIO
    ) where

import Data.Monoid (mappend, mempty)
import Data.List (isInfixOf)

import qualified Data.ByteString.Lazy as L
import qualified Data.Text as T (isInfixOf)
import qualified Data.ByteString as S (ByteString, isInfixOf)

import Text.Blaze.Internal
import Blaze.ByteString.Builder (Builder)
import qualified Blaze.ByteString.Builder           as B
import qualified Blaze.ByteString.Builder.Html.Utf8 as B

-- | Render a 'ChoiceString'.
--
fromChoiceString :: ChoiceString  -- ^ String to render
                 -> Builder       -- ^ Resulting builder
fromChoiceString :: ChoiceString -> Builder
fromChoiceString (Static StaticString
s)     = ByteString -> Builder
B.copyByteString (ByteString -> Builder) -> ByteString -> Builder
forall a b. (a -> b) -> a -> b
$ StaticString -> ByteString
getUtf8ByteString StaticString
s
fromChoiceString (String [Char]
s)     = [Char] -> Builder
B.fromHtmlEscapedString [Char]
s
fromChoiceString (Text Text
s)       = Text -> Builder
B.fromHtmlEscapedText Text
s
fromChoiceString (ByteString ByteString
s) = ByteString -> Builder
B.fromByteString ByteString
s
fromChoiceString (PreEscaped ChoiceString
x) = case ChoiceString
x of
    String [Char]
s -> [Char] -> Builder
B.fromString [Char]
s
    Text   Text
s -> Text -> Builder
B.fromText Text
s
    ChoiceString
s        -> ChoiceString -> Builder
fromChoiceString ChoiceString
s
fromChoiceString (External ChoiceString
x) = case ChoiceString
x of
    -- Check that the sequence "</" is *not* in the external data.
    String [Char]
s     -> if [Char]
"</" [Char] -> [Char] -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf` [Char]
s then Builder
forall a. Monoid a => a
mempty else [Char] -> Builder
B.fromString [Char]
s
    Text   Text
s     -> if Text
"</" Text -> Text -> Bool
`T.isInfixOf` Text
s then Builder
forall a. Monoid a => a
mempty else Text -> Builder
B.fromText Text
s
    ByteString ByteString
s -> if ByteString
"</" ByteString -> ByteString -> Bool
`S.isInfixOf` ByteString
s then Builder
forall a. Monoid a => a
mempty else ByteString -> Builder
B.fromByteString ByteString
s
    ChoiceString
s            -> ChoiceString -> Builder
fromChoiceString ChoiceString
s
fromChoiceString (AppendChoiceString ChoiceString
x ChoiceString
y) =
    ChoiceString -> Builder
fromChoiceString ChoiceString
x Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` ChoiceString -> Builder
fromChoiceString ChoiceString
y
fromChoiceString ChoiceString
EmptyChoiceString = Builder
forall a. Monoid a => a
mempty
{-# INLINE fromChoiceString #-}

-- | Render some 'Markup' to a 'Builder'.
--
renderMarkupBuilder, renderHtmlBuilder :: Markup     -- ^ Markup to render
                  -> Builder  -- ^ Resulting builder
renderMarkupBuilder :: Markup -> Builder
renderMarkupBuilder = Builder -> Markup -> Builder
forall b. Builder -> MarkupM b -> Builder
go Builder
forall a. Monoid a => a
mempty
  where
    go :: Builder -> MarkupM b -> Builder
    go :: forall b. Builder -> MarkupM b -> Builder
go Builder
attrs (Parent StaticString
_ StaticString
open StaticString
close MarkupM b
content) =
        ByteString -> Builder
B.copyByteString (StaticString -> ByteString
getUtf8ByteString StaticString
open)
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Builder
attrs
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Char -> Builder
B.fromChar Char
'>'
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Builder -> MarkupM b -> Builder
forall b. Builder -> MarkupM b -> Builder
go Builder
forall a. Monoid a => a
mempty MarkupM b
content
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` ByteString -> Builder
B.copyByteString (StaticString -> ByteString
getUtf8ByteString StaticString
close)
    go Builder
attrs (CustomParent ChoiceString
tag MarkupM b
content) =
        Char -> Builder
B.fromChar Char
'<'
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` ChoiceString -> Builder
fromChoiceString ChoiceString
tag
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Builder
attrs
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Char -> Builder
B.fromChar Char
'>'
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Builder -> MarkupM b -> Builder
forall b. Builder -> MarkupM b -> Builder
go Builder
forall a. Monoid a => a
mempty MarkupM b
content
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` ByteString -> Builder
B.fromByteString ByteString
"</"
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` ChoiceString -> Builder
fromChoiceString ChoiceString
tag
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Char -> Builder
B.fromChar Char
'>'
    go Builder
attrs (Leaf StaticString
_ StaticString
begin StaticString
end b
_) =
        ByteString -> Builder
B.copyByteString (StaticString -> ByteString
getUtf8ByteString StaticString
begin)
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Builder
attrs
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` ByteString -> Builder
B.copyByteString (StaticString -> ByteString
getUtf8ByteString StaticString
end)
    go Builder
attrs (CustomLeaf ChoiceString
tag Bool
close b
_) =
        Char -> Builder
B.fromChar Char
'<'
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` ChoiceString -> Builder
fromChoiceString ChoiceString
tag
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Builder
attrs
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` (if Bool
close then ByteString -> Builder
B.fromByteString ByteString
" />" else Char -> Builder
B.fromChar Char
'>')
    go Builder
attrs (AddAttribute StaticString
_ StaticString
key ChoiceString
value MarkupM b
h) =
        Builder -> MarkupM b -> Builder
forall b. Builder -> MarkupM b -> Builder
go (ByteString -> Builder
B.copyByteString (StaticString -> ByteString
getUtf8ByteString StaticString
key)
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` ChoiceString -> Builder
fromChoiceString ChoiceString
value
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Char -> Builder
B.fromChar Char
'"'
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Builder
attrs) MarkupM b
h
    go Builder
attrs (AddCustomAttribute ChoiceString
key ChoiceString
value MarkupM b
h) =
        Builder -> MarkupM b -> Builder
forall b. Builder -> MarkupM b -> Builder
go (Char -> Builder
B.fromChar Char
' '
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` ChoiceString -> Builder
fromChoiceString ChoiceString
key
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` ByteString -> Builder
B.fromByteString ByteString
"=\""
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` ChoiceString -> Builder
fromChoiceString ChoiceString
value
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Char -> Builder
B.fromChar Char
'"'
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Builder
attrs) MarkupM b
h
    go Builder
_ (Content ChoiceString
content b
_) = ChoiceString -> Builder
fromChoiceString ChoiceString
content
    go Builder
_ (Comment ChoiceString
comment b
_) =
        ByteString -> Builder
B.fromByteString ByteString
"<!-- "
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` ChoiceString -> Builder
fromChoiceString ChoiceString
comment
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` ByteString -> Builder
B.fromByteString ByteString
" -->"
    go Builder
attrs (Append MarkupM b
h1 MarkupM b
h2) = Builder -> MarkupM b -> Builder
forall b. Builder -> MarkupM b -> Builder
go Builder
attrs MarkupM b
h1 Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Builder -> MarkupM b -> Builder
forall b. Builder -> MarkupM b -> Builder
go Builder
attrs MarkupM b
h2
    go Builder
_ (Empty b
_) = Builder
forall a. Monoid a => a
mempty
    {-# NOINLINE go #-}
{-# INLINE renderMarkupBuilder #-}

renderHtmlBuilder :: Markup -> Builder
renderHtmlBuilder = Markup -> Builder
renderMarkupBuilder
{-# INLINE renderHtmlBuilder #-}
{-# DEPRECATED renderHtmlBuilder
    "Use renderHtmlBuilder from Text.Blaze.Html.Renderer.Utf8 instead" #-}

-- | Render HTML to a lazy UTF-8 encoded 'L.ByteString.'
--
renderMarkup, renderHtml :: Markup          -- ^ Markup to render
                         -> L.ByteString  -- ^ Resulting 'L.ByteString'
renderMarkup :: Markup -> ByteString
renderMarkup = Builder -> ByteString
B.toLazyByteString (Builder -> ByteString)
-> (Markup -> Builder) -> Markup -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Markup -> Builder
renderMarkupBuilder
{-# INLINE renderMarkup #-}

renderHtml :: Markup -> ByteString
renderHtml = Markup -> ByteString
renderMarkup
{-# INLINE renderHtml #-}
{-# DEPRECATED renderHtml
    "Use renderHtml from Text.Blaze.Html.Renderer.Utf8 instead" #-}


-- | Repeatedly render HTML to a buffer and process this buffer using the given
-- IO action.
--
renderMarkupToByteStringIO, renderHtmlToByteStringIO :: (S.ByteString -> IO ())
                                                        -- ^ IO action to execute per rendered buffer
                                                     -> Markup          -- ^ Markup to render
                                                     -> IO ()         -- ^ Resulting IO action
renderMarkupToByteStringIO :: (ByteString -> IO ()) -> Markup -> IO ()
renderMarkupToByteStringIO ByteString -> IO ()
io = (ByteString -> IO ()) -> Builder -> IO ()
B.toByteStringIO ByteString -> IO ()
io (Builder -> IO ()) -> (Markup -> Builder) -> Markup -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Markup -> Builder
renderMarkupBuilder
{-# INLINE renderMarkupToByteStringIO #-}

renderHtmlToByteStringIO :: (ByteString -> IO ()) -> Markup -> IO ()
renderHtmlToByteStringIO = (ByteString -> IO ()) -> Markup -> IO ()
renderMarkupToByteStringIO
{-# INLINE renderHtmlToByteStringIO #-}
{-# DEPRECATED renderHtmlToByteStringIO
    "Use renderMarkupToByteStringIO from Text.Blaze.Html.Renderer.Utf8 instead" #-}