content: module Network.PublicSuffixList.Serialize (getDataStructure, putDataStructure) where
  
  import           Blaze.ByteString.Builder           (Builder, fromWord8,
                                                       toByteString)
  import           Blaze.ByteString.Builder.Char.Utf8 (fromText)
  import qualified Data.ByteString                    as BS
  import           Data.Foldable                      (foldMap)
  import           Data.Map                           (Map)
  import qualified Data.Map                           as Map
  import           Data.Monoid                        (mappend)
  import qualified Data.Text                          as T
  import qualified Data.Text.Encoding                 as TE
  
  import           Network.PublicSuffixList.Types
  
  getTree :: BS.ByteString -> (Tree T.Text, BS.ByteString)
  getTree =
      loop Map.empty
    where
      loop m bs
          | BS.null bs = (Node m, bs)
          | BS.head bs == 0 = (Node m, BS.drop 1 bs)
          | otherwise =
              let (k, v, bs') = getPair bs
               in loop (Map.insert k v m) bs'
  
  getPair :: BS.ByteString -> (T.Text, Tree T.Text, BS.ByteString)
  getPair bs0 =
      (k, v, bs2)
    where
      (k, bs1) = getText bs0
      (v, bs2) = getTree bs1
  
  getText :: BS.ByteString -> (T.Text, BS.ByteString)
  getText bs0 =
      (TE.decodeUtf8 v, BS.drop 1 bs1)
    where
      (v, bs1) = BS.break (== 0) bs0
  
  getDataStructure :: BS.ByteString -> DataStructure
  getDataStructure bs0 =
      (x, y)
    where
      (x, bs1) = getTree bs0
      (y, _) = getTree bs1
  
  putTree :: Tree T.Text -> Builder
  putTree = putMap . children
  
  putMap :: Map T.Text (Tree T.Text) -> Builder
  putMap m = Data.Foldable.foldMap putPair (Map.toList m) `mappend` fromWord8 0
  
  putPair :: (T.Text, Tree T.Text) -> Builder
  putPair (x, y) = putText x `mappend` putTree y
  
  putText :: T.Text -> Builder
  putText t = fromText t `Data.Monoid.mappend` fromWord8 0
  
  putDataStructure :: DataStructure -> BS.ByteString
  putDataStructure (x, y) = toByteString $ putTree x `mappend` putTree y
  
  