{-# LANGUAGE StandaloneDeriving
  #-}


module Text.JSONb.Encode where


import Data.Ratio
import Data.ByteString.Char8
import qualified Data.ByteString.Lazy as Lazy

import Data.Trie hiding (singleton)

import Text.JSONb.Simple
import Text.JSON.Escape




{-| Encode 'JSON' as a strict 'ByteString'. All strings are treated as UTF-8;
    ASCII control characters are escaped and UTF-8 multi-char sequences are
    simply passed through.
 -}
encode                      ::  Style -> JSON -> ByteString
encode style@Compact json    =  case json of
  Object trie               ->  '{' `cons` pairs trie `snoc` '}'
  Array elems               ->  '[' `cons` elements elems `snoc` ']'
  String s                  ->  stringify s
  Number r
    | denominator r == 1    ->  (pack . show . numerator) r
    | otherwise             ->  (pack . show) (fromRational r :: Double)
  Boolean True              ->  pack "true"
  Boolean False             ->  pack "false"
  Null                      ->  pack "null"
 where
  comcat                     =  intercalate (singleton ',')
  elements                   =  comcat . fmap (encode style)
  pairs                      =  comcat . toListBy pair
   where
    pair k v                 =  stringify k `snoc` ':' `append` encode style v


{-| Style of serialization. Compact is the only one that is implemented at
    present.
 -}
data Style                   =  Compact -- for later: LightSpaces | Indented
deriving instance Show Style
deriving instance Eq Style


{-| Escape a 'ByteString' representing a JSON string and wrap it in quote
    marks.
 -}
stringify                   ::  ByteString -> ByteString
stringify s                  =  '"' `cons` escape s `snoc` '"'