------------------------------------------------------------------------
-- Zip.hs
-- Copyright (c) 2008 John MacFarlane
-- License     : BSD3 (see LICENSE)
--
-- This is a demonstration of the use of the 'Codec.Archive.Zip' library.
-- It duplicates some of the functionality of the 'zip' command-line
-- program.
------------------------------------------------------------------------

import Codec.Archive.Zip
import System.IO
import qualified Data.ByteString.Lazy as B
import System.Exit
import System.Environment
import System.Directory
import System.Console.GetOpt
import Control.Monad ( when )
import Control.Applicative ( (<$>) )

data Flag 
  = Quiet 
  | Version
  | Decompress
  | Recursive
  | Remove
  | List
  | Help
  deriving (Eq, Show, Read)

options :: [OptDescr Flag]
options =
   [ Option ['d']   ["decompress"] (NoArg Decompress)    "decompress (unzip)"
   , Option ['r']   ["recursive"]  (NoArg Recursive)     "recursive"
   , Option ['R']   ["remove"]     (NoArg Remove)        "remove"
   , Option ['l']   ["list"]       (NoArg List)          "list"
   , Option ['v']   ["version"]    (NoArg Version)       "version"
   , Option ['q']   ["quiet"]      (NoArg Quiet)         "quiet"
   , Option ['h']   ["help"]       (NoArg Help)          "help"
   ]

main :: IO ()
main = do
  argv <- getArgs
  progname <- getProgName
  let header = "Usage: " ++ progname ++ " [OPTION...] archive files..."
  (opts, args) <- case getOpt Permute options argv of
      (o, _, _)      | Version `elem` o -> putStrLn "version 0.1.1.4" >> exitWith ExitSuccess
      (o, _, _)      | Help `elem` o    -> error $ usageInfo header options
      (o, (a:as), [])                   -> return (o, a:as)
      (_, _, errs)                      -> error $ concat errs ++ "\n" ++ usageInfo header options
  let verbosity = if Quiet `elem` opts then [] else [OptVerbose]
  let cmd = take 1 $ filter (`notElem` [Quiet, Help, Version]) opts
  let cmd' = if null cmd
                then Recursive
                else head cmd
  let (archivePath : files) = args
  exists <- doesFileExist archivePath
  archive <- if exists
                then toArchive <$> B.readFile archivePath
                else return emptyArchive
  case cmd' of
       Decompress  -> extractFilesFromArchive verbosity archive  
       Remove      -> do tempDir <- getTemporaryDirectory
                         (tempArchivePath, tempArchive) <- openTempFile tempDir "zip" 
                         B.hPut tempArchive $ fromArchive $ 
                                              foldr deleteEntryFromArchive archive files
                         hClose tempArchive
                         copyFile tempArchivePath archivePath
                         removeFile tempArchivePath
       List        -> mapM_ putStrLn $ filesInArchive archive
       Recursive   -> do when (null files) $ error "No files specified."
                         tempDir <- getTemporaryDirectory
                         (tempArchivePath, tempArchive) <- openTempFile tempDir "zip" 
                         addFilesToArchive (verbosity ++ [OptRecursive]) archive files >>= 
                            B.hPut tempArchive . fromArchive
                         hClose tempArchive
                         copyFile tempArchivePath archivePath
                         removeFile tempArchivePath
       _           -> error "Unknown command"
