{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Main
    where

import Control.Applicative ((<$>))
import Control.Monad (Monad((>>=), return), replicateM)
import Data.Function ((.), ($))
import Data.Int (Int)
import Data.String (String)
import Data.Tuple (uncurry)
import System.IO (IO)

import Data.ByteString (ByteString)

import Control.Monad.Random
import Criterion.Main (bench, defaultMain, nf)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as C8

import Data.Digest.ApacheMD5 (apacheMD5)
import Data.Digest.ApacheMD5.Internal (Salt(Salt), alpha64)


genSalt :: RandT StdGen IO Salt
genSalt = Salt . BS.pack
    <$> replicateM 8 (BS.index alpha64 <$> getRandomR (0, 63))
    -- We know, that salt will be correct since we generate it out of
    -- alpha64, therefore we don't use mkSalt to check it for us.

genPassword :: Int -> RandT StdGen IO String
genPassword len = replicateM len (getRandomR ('!', '~'))

genData :: Int -> RandT StdGen IO (ByteString, Salt)
genData len = do
    s <- genSalt
    p <- C8.pack <$> genPassword len
    return (p, s)

main :: IO ()
main = do
    (!inputData8, _) <- genData' 8
    (!inputData16, _) <- genData' 16
    (!inputData32, _) <- genData' 32
    (!inputData64, _) <- genData' 64
    (!inputData128, _) <- genData' 128
    (!inputData256, _) <- genData' 256
    (!inputData512, _) <- genData' 512

    defaultMain
        [ bench "Random passwords of length 8" $ test inputData8
        , bench "Random passwords of length 16" $ test inputData16
        , bench "Random passwords of length 32" $ test inputData32
        , bench "Random passwords of length 64" $ test inputData64
        , bench "Random passwords of length 128" $ test inputData128
        , bench "Random passwords of length 256" $ test inputData256
        , bench "Random passwords of length 512" $ test inputData512
        ]
  where
    test = nf $ uncurry apacheMD5
    genData' n = getStdGen >>= runRandT (genData n)