{-# LANGUAGE ScopedTypeVariables, ForeignFunctionInterface #-}

module Scion.PersistentBrowser.FileUtil where

import qualified Codec.Archive.Tar as Tar
import qualified Codec.Compression.GZip as GZip
import Control.Exception (bracket)
import qualified Data.ByteString as SBS
import qualified Data.ByteString.Char8 as SBS8
import qualified Data.ByteString.Lazy as LBS
import qualified Data.ByteString.Lazy.Char8 as LBS8
import Data.List (isPrefixOf)
import Network.Browser
import Network.HTTP
import Network.HTTP.Proxy
import System.Directory
import System.FilePath
import Scion.PersistentBrowser.TempFile
import Scion.PersistentBrowser.Util (logToStdout)

-- |Takes out the "." and ".." special directory
-- entries from a list of file paths.
filterDots :: [FilePath] -> [FilePath]
filterDots = filter (\d -> d /= "." && d /= "..")

-- |Downloads a file from the internet.
downloadFileLazy :: String -> IO (Maybe LBS.ByteString)
downloadFileLazy url = do 
                        response <- fetchURL url
                        return $ Just (LBS8.pack response)

-- |Downloads a file from the internet.
downloadFileStrict :: String -> IO (Maybe SBS.ByteString)
downloadFileStrict url = do 
                        response <- fetchURL url
                        return $ Just (SBS8.pack response)

-- |Downloads a file from the internet and check it's a Hoogle file.
downloadHoogleFile :: String -> IO (Maybe SBS.ByteString)
downloadHoogleFile url = do 
                            response <- fetchURL url
                            return $ getHoogleFile response

downloadHoogleFile' :: String -> BrowserAction (HandleStream String) (Maybe SBS.ByteString)
downloadHoogleFile' url = do 
                            (_,res) <- request $ getRequest url
                            return $ getHoogleFile $ rspBody res

getHoogleFile :: String -> Maybe SBS.ByteString
getHoogleFile response=if "-- Hoogle documentation" `isPrefixOf` response
                                               then Just (SBS8.pack response)
                                               else Nothing

-- |Downloads a file from the internet, using the system proxy
fetchURL :: String -> IO (String)
fetchURL url=do
            pr<-fetchProxy False
            (_,res) <- browse $ do 
                setErrHandler logToStdout
                setOutHandler logToStdout
                setProxy pr 
                request $ getRequest url
            return $ rspBody res
                            
-- |Un-gzip and un-tar a file into a folder.
unTarGzip :: LBS.ByteString -> FilePath -> IO ()
unTarGzip cnts folder = let ungzip  = GZip.decompress cnts
                            entries = Tar.read ungzip
                        in  do createDirectories entries
                               Tar.unpack folder entries
                        where createDirectories Tar.Done     = return ()
                              createDirectories (Tar.Fail _) = return ()
                              createDirectories (Tar.Next e es) =
                                case Tar.entryContent e of
                                  Tar.NormalFile _ _ -> do let dir = folder </> takeDirectory (Tar.entryPath e)
                                                           createDirectoryIfMissing True dir
                                                           createDirectories es
                                  Tar.Directory      -> do let dir = folder </> Tar.entryPath e
                                                           createDirectoryIfMissing True dir
                                                           createDirectories es
                                  _                  -> createDirectories es

-- HACK: Taken from Unixutils.
-- The version in Hackage conflicts with some of our packages.

-- |temporarily change the working directory to |dir| while running |action|
withWorkingDirectory :: FilePath -> IO a -> IO a
withWorkingDirectory dir action = 
    bracket getCurrentDirectory setCurrentDirectory (\ _ -> setCurrentDirectory dir >> action)

-- |create a temporary directory, run the action, remove the temporary directory
-- the directory will be created inside the system temporary directory (cf bug 3413186)
-- the temporary directory will be automatically removed afterwards.
-- your working directory is not altered
withTemporaryDirectory :: (FilePath -> IO a) -> IO a
withTemporaryDirectory f =
     do home <- getTemporaryDirectory 
        bracket (createTempDirectory home ".scion")
                removeDirectoryRecursive
                f