module JSONEncoder.Builders where

import JSONEncoder.Prelude hiding (length)
import ByteString.TreeBuilder
import qualified Data.Text


{-# INLINABLE intercalate #-}
intercalate :: Foldable f => Builder -> f Builder -> Builder
intercalate incut =
  foldl' (appendWithIncut incut) mempty

{-# INLINABLE appendWithIncut #-}
appendWithIncut :: Builder -> Builder -> Builder -> Builder
appendWithIncut incut a b =
  if length a == 0
    then b
    else if length b == 0
      then a
      else a <> incut <> b

{-# INLINABLE stringEncodedChar #-}
stringEncodedChar :: Char -> Builder
stringEncodedChar =
  \case
    '\"' -> "\\\""
    '\\' -> "\\\\"
    '\n' -> "\\n"
    '\r' -> "\\r"
    '\t' -> "\\t"
    '\b' -> "\\b"
    '\f' -> "\\f"
    char -> encodedChar char

{-# INLINABLE encodedChar #-}
encodedChar :: Char -> Builder
encodedChar char =
  if char < '\x20'
    then 
      let
        hex =
          fromString (showHex (fromEnum char) "")
        in "\\u" <> mconcat (replicate (4 - length hex) (asciiChar '0')) <> hex
    else
      utf8Char char

{-# INLINABLE stringLiteral #-}
stringLiteral :: Text -> Builder
stringLiteral string =
  asciiChar '"' <> encoded string <> asciiChar '"'
  where
    encoded =
      Data.Text.foldl' (\builder -> mappend builder . stringEncodedChar) mempty