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 :: ByteString -> (Tree Text, ByteString)
getTree =
    Map Text (Tree Text) -> ByteString -> (Tree Text, ByteString)
loop Map Text (Tree Text)
forall k a. Map k a
Map.empty
  where
    loop :: Map Text (Tree Text) -> ByteString -> (Tree Text, ByteString)
loop Map Text (Tree Text)
m ByteString
bs
        | ByteString -> Bool
BS.null ByteString
bs = (Map Text (Tree Text) -> Tree Text
forall e. Map e (Tree e) -> Tree e
Node Map Text (Tree Text)
m, ByteString
bs)
        | ByteString -> Word8
BS.head ByteString
bs Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0 = (Map Text (Tree Text) -> Tree Text
forall e. Map e (Tree e) -> Tree e
Node Map Text (Tree Text)
m, Int -> ByteString -> ByteString
BS.drop Int
1 ByteString
bs)
        | Bool
otherwise =
            let (Text
k, Tree Text
v, ByteString
bs') = ByteString -> (Text, Tree Text, ByteString)
getPair ByteString
bs
             in Map Text (Tree Text) -> ByteString -> (Tree Text, ByteString)
loop (Text -> Tree Text -> Map Text (Tree Text) -> Map Text (Tree Text)
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Text
k Tree Text
v Map Text (Tree Text)
m) ByteString
bs'

getPair :: BS.ByteString -> (T.Text, Tree T.Text, BS.ByteString)
getPair :: ByteString -> (Text, Tree Text, ByteString)
getPair ByteString
bs0 =
    (Text
k, Tree Text
v, ByteString
bs2)
  where
    (Text
k, ByteString
bs1) = ByteString -> (Text, ByteString)
getText ByteString
bs0
    (Tree Text
v, ByteString
bs2) = ByteString -> (Tree Text, ByteString)
getTree ByteString
bs1

getText :: BS.ByteString -> (T.Text, BS.ByteString)
getText :: ByteString -> (Text, ByteString)
getText ByteString
bs0 =
    (ByteString -> Text
TE.decodeUtf8 ByteString
v, Int -> ByteString -> ByteString
BS.drop Int
1 ByteString
bs1)
  where
    (ByteString
v, ByteString
bs1) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
BS.break (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0) ByteString
bs0

getDataStructure :: BS.ByteString -> DataStructure
getDataStructure :: ByteString -> DataStructure
getDataStructure ByteString
bs0 =
    (Tree Text
x, Tree Text
y)
  where
    (Tree Text
x, ByteString
bs1) = ByteString -> (Tree Text, ByteString)
getTree ByteString
bs0
    (Tree Text
y, ByteString
_) = ByteString -> (Tree Text, ByteString)
getTree ByteString
bs1

putTree :: Tree T.Text -> Builder
putTree :: Tree Text -> Builder
putTree = Map Text (Tree Text) -> Builder
putMap (Map Text (Tree Text) -> Builder)
-> (Tree Text -> Map Text (Tree Text)) -> Tree Text -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Tree Text -> Map Text (Tree Text)
forall e. Tree e -> Map e (Tree e)
children

putMap :: Map T.Text (Tree T.Text) -> Builder
putMap :: Map Text (Tree Text) -> Builder
putMap Map Text (Tree Text)
m = ((Text, Tree Text) -> Builder) -> [(Text, Tree Text)] -> Builder
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
Data.Foldable.foldMap (Text, Tree Text) -> Builder
putPair (Map Text (Tree Text) -> [(Text, Tree Text)]
forall k a. Map k a -> [(k, a)]
Map.toList Map Text (Tree Text)
m) Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Word8 -> Builder
fromWord8 Word8
0

putPair :: (T.Text, Tree T.Text) -> Builder
putPair :: (Text, Tree Text) -> Builder
putPair (Text
x, Tree Text
y) = Text -> Builder
putText Text
x Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Tree Text -> Builder
putTree Tree Text
y

putText :: T.Text -> Builder
putText :: Text -> Builder
putText Text
t = Text -> Builder
fromText Text
t Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`Data.Monoid.mappend` Word8 -> Builder
fromWord8 Word8
0

putDataStructure :: DataStructure -> BS.ByteString
putDataStructure :: DataStructure -> ByteString
putDataStructure (Tree Text
x, Tree Text
y) = Builder -> ByteString
toByteString (Builder -> ByteString) -> Builder -> ByteString
forall a b. (a -> b) -> a -> b
$ Tree Text -> Builder
putTree Tree Text
x Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Tree Text -> Builder
putTree Tree Text
y