{-# OPTIONS -Wall #-}
{-# OPTIONS -Werror #-}

module DFINITY.RadixTree.Utilities
   ( createPrefix
   , createRoot
   , createRootFromNonce
   , defaultRoot
   , ignoreIOErrors
   ) where

import Codec.Serialise (serialise)
import Control.Exception (handle)
import Crypto.Hash.BLAKE2.BLAKE2s (finalize, hash, initialize, update)
import Data.ByteString as Strict (ByteString)
import Data.ByteString.Builder (toLazyByteString, wordDec)
import Data.ByteString.Lazy as Lazy (ByteString, foldlChunks, toStrict)
import Data.ByteString.Short (toShort)
import Data.Default.Class (def)
import System.IO.Error (IOError)

import DFINITY.RadixTree.Bits
import DFINITY.RadixTree.Types

createPrefix :: [Bool] -> Maybe RadixPrefix
createPrefix bits =
   if null bits
   then Nothing
   else Just $ fromBits bits

createRoot :: RadixNode -> RadixRoot
createRoot = toShort . hashLazy 20 . serialise

createRootFromNonce :: Word -> RadixRoot
createRootFromNonce = toShort . hash 20 mempty . toStrict . toLazyByteString . wordDec

defaultRoot :: RadixRoot
defaultRoot = createRoot def

hashLazy :: Int -> Lazy.ByteString -> Strict.ByteString
hashLazy size = finalize size . fold
   where fold = foldlChunks step $ initialize size
         step = flip update

ignoreIOErrors :: IO () -> IO ()
ignoreIOErrors = handle $ (const $ pure () :: IOError -> IO ())