module Data.ByteString.Pathological ( nonstandardRead
                                    , chunksOf
                                    , readLarge
                                    , readSmall
                                    , readRandom
                                    ) where

import           Control.Applicative
import           Control.Monad        ((<=<))
import qualified Data.ByteString      as BS
import qualified Data.ByteString.Lazy as BSL
import           System.Random        (randomRIO)

-- | Read a file into a 'BSL.ByteString' using varying chunk size.
nonstandardRead :: FilePath -> IO BSL.ByteString
nonstandardRead fp = do
    bStrict <- BS.readFile fp
    let (h, t) = BS.splitAt (64 * 1024) bStrict
    pure $ BSL.fromChunks [h, t]

-- | Read into a 'BSL.ByteString' of varying chunk sizes (non-lazily).
readRandom :: FilePath -> IO BSL.ByteString
readRandom = fmap BSL.fromChunks . (randomSplit <=< BS.readFile)

randomSplit :: BS.ByteString -> IO [BS.ByteString]
randomSplit b = do
    nextSz <- randomRIO (16 * 1024, 128 * 1024)
    if BS.length b <= nextSz
        then pure [b]
        else
            let (b', b'') = BS.splitAt nextSz b
            in (b' :) <$> randomSplit b''

-- | Read into @16k@ chunks (non-lazily)
readSmall :: FilePath -> IO BSL.ByteString
readSmall = fmap (BSL.fromChunks . chunksOf (16 * 1024)) . BS.readFile

-- | Read into @128k@ chunks (non-lazily)
readLarge :: FilePath -> IO BSL.ByteString
readLarge = fmap (BSL.fromChunks . chunksOf (128 * 1024)) . BS.readFile

chunksOf :: Int -> BS.ByteString -> [BS.ByteString]
chunksOf bSz b =
    if BS.length b <= bSz
        then [b]
        else
            let (b', b'') = BS.splitAt bSz b
            in b' : chunksOf bSz b''