{-# 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 s :: StaticString
s)     = ByteString -> Builder
B.copyByteString (ByteString -> Builder) -> ByteString -> Builder
forall a b. (a -> b) -> a -> b
$ StaticString -> ByteString
getUtf8ByteString StaticString
s
fromChoiceString (String s :: String
s)     = String -> Builder
B.fromHtmlEscapedString String
s
fromChoiceString (Text s :: Text
s)       = Text -> Builder
B.fromHtmlEscapedText Text
s
fromChoiceString (ByteString s :: ByteString
s) = ByteString -> Builder
B.fromByteString ByteString
s
fromChoiceString (PreEscaped x :: ChoiceString
x) = case ChoiceString
x of
    String s :: String
s -> String -> Builder
B.fromString String
s
    Text   s :: Text
s -> Text -> Builder
B.fromText Text
s
    s :: ChoiceString
s        -> ChoiceString -> Builder
fromChoiceString ChoiceString
s
fromChoiceString (External x :: ChoiceString
x) = case ChoiceString
x of
    -- Check that the sequence "</" is *not* in the external data.
    String s :: String
s     -> if "</" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf` String
s then Builder
forall a. Monoid a => a
mempty else String -> Builder
B.fromString String
s
    Text   s :: Text
s     -> if "</" Text -> Text -> Bool
`T.isInfixOf` Text
s then Builder
forall a. Monoid a => a
mempty else Text -> Builder
B.fromText Text
s
    ByteString s :: ByteString
s -> if "</" ByteString -> ByteString -> Bool
`S.isInfixOf` ByteString
s then Builder
forall a. Monoid a => a
mempty else ByteString -> Builder
B.fromByteString ByteString
s
    s :: ChoiceString
s            -> ChoiceString -> Builder
fromChoiceString ChoiceString
s
fromChoiceString (AppendChoiceString x :: ChoiceString
x y :: ChoiceString
y) =
    ChoiceString -> Builder
fromChoiceString ChoiceString
x Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` ChoiceString -> Builder
fromChoiceString ChoiceString
y
fromChoiceString 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 :: Builder -> MarkupM b -> Builder
go attrs :: Builder
attrs (Parent _ open :: StaticString
open close :: StaticString
close content :: 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 '>'
            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 attrs :: Builder
attrs (CustomParent tag :: ChoiceString
tag content :: MarkupM b
content) =
        Char -> Builder
B.fromChar '<'
            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 '>'
            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 "</"
            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 '>'
    go attrs :: Builder
attrs (Leaf _ begin :: StaticString
begin end :: StaticString
end _) =
        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 attrs :: Builder
attrs (CustomLeaf tag :: ChoiceString
tag close :: Bool
close _) =
        Char -> Builder
B.fromChar '<'
            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 " />" else Char -> Builder
B.fromChar '>')
    go attrs :: Builder
attrs (AddAttribute _ key :: StaticString
key value :: ChoiceString
value h :: 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 '"'
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Builder
attrs) MarkupM b
h
    go attrs :: Builder
attrs (AddCustomAttribute key :: ChoiceString
key value :: ChoiceString
value h :: MarkupM b
h) =
        Builder -> MarkupM b -> Builder
forall b. Builder -> MarkupM b -> Builder
go (Char -> Builder
B.fromChar ' '
            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 "=\""
            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 '"'
            Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Builder
attrs) MarkupM b
h
    go _ (Content content :: ChoiceString
content _) = ChoiceString -> Builder
fromChoiceString ChoiceString
content
    go _ (Comment comment :: ChoiceString
comment _) =
        ByteString -> Builder
B.fromByteString "<!-- "
            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 " -->"
    go attrs :: Builder
attrs (Append h1 :: MarkupM b
h1 h2 :: 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 _ (Empty _) = 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 io :: 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" #-}