{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC
    -fno-warn-name-shadowing
    -fno-warn-unused-imports
    #-}
module Main where

import Shelly
import Filesystem.Path.CurrentOS (splitDirectories, encodeString, decodeString)
import qualified Filesystem as F

import qualified Data.Text as T
import qualified Data.ByteString as B

import Control.Monad.IO.Class
import System.Random.MWC
import Control.Monad.Primitive

import Control.Monad
import Control.Applicative
import Prelude hiding (FilePath)
import Data.String
import System.Environment

rands :: (PrimMonad m, Variate a) => Gen (PrimState m) -> Int -> m [a]
rands gen i = replicateM i (uniform gen)

randRs :: (PrimMonad m, Variate a) => Gen (PrimState m) -> Int -> (a, a) -> m [a]
randRs gen i z = replicateM i (uniformR z gen)

lastElemLength :: FilePath -> Int
lastElemLength fd = case splitDirectories fd of
    [] -> error $ "Empty filepath " ++ show fd
    g -> T.length $ toTextIgnore $ last g

randName :: Gen (PrimState IO) -> Int -> IO FilePath
randName gen l = decodeString . map toEnum <$> randRs gen l (fromEnum 'a', fromEnum 'z')

main :: IO ()
main = do
    g <- getArgs
    case g of
        [inDir, outDir] ->
            withSystemRandom . asGenIO $ \gen -> do
            shellyNoDir $ do
            escaping False $ do
            -- verbosely $ do
            out <- absPath (decodeString outDir)
            in' <- absPath (decodeString inDir)
            descent gen out in'
        _ -> putStrLn "Specify input directory and output directory"

descent :: Gen (PrimState IO) -> FilePath -> FilePath -> Sh ()
descent gen outDir fd = do
    isDir <- test_d fd
    if isDir
      then do
        n <- liftIO $ randName gen $ lastElemLength fd
        let newDir = outDir </> n
        mkdir_p newDir
        chdir fd $ do
            filesOrDirs <- ls "."
            mapM_ (descent gen newDir) filesOrDirs
      else do
        file <- absPath fd
        liftIO $ do
        size <- F.getSize file
        newFname <- randName gen $ lastElemLength file
        bs <- B.pack <$> rands gen (fromInteger size)
        B.writeFile (encodeString $ outDir </> newFname) bs
