-- | This module is used by the push and put commands to apply the a bundle to a
-- remote repository. By remote I do not necessarily mean a repository on another
-- machine, it is just not the repository we're located in.
module Darcs.RemoteApply ( remoteApply, applyAs ) where

import System.Exit ( ExitCode )

import Darcs.Flags ( DarcsFlag( ApplyAs, Debug ), remoteDarcs )
import Darcs.Utils ( breakCommand )
import Darcs.URL ( isHttpUrl, isSshUrl, splitSshUrl, SshFilePath(..) )
import Darcs.External ( darcsProgram, pipeDoc, pipeDocSSH, maybeURLCmd )
import qualified Darcs.Ssh as Ssh ( remoteDarcs )
import Printer ( Doc )

remoteApply :: [DarcsFlag] -> String -> Doc -> IO ExitCode
remoteApply opts repodir bundle
    = case applyAs opts of
        Nothing -> if isSshUrl repodir
                   then applyViaSsh opts (splitSshUrl repodir) bundle
                   else if isHttpUrl repodir
                        then applyViaUrl opts repodir bundle
                        else applyViaLocal opts repodir bundle
        Just un -> if isSshUrl repodir
                   then applyViaSshAndSudo opts (splitSshUrl repodir) un bundle
                   else applyViaSudo un repodir bundle

applyAs :: [DarcsFlag] -> Maybe String
applyAs (ApplyAs user:_) = Just user
applyAs (_:fs) = applyAs fs
applyAs [] = Nothing
applyViaSudo :: String -> String -> Doc -> IO ExitCode
applyViaSudo user repo bundle =
    darcsProgram >>= \darcs ->
    pipeDoc "sudo" ["-u",user,darcs,"apply","--all","--repodir",repo] bundle
applyViaLocal :: [DarcsFlag] -> String -> Doc -> IO ExitCode
applyViaLocal opts repo bundle =
    darcsProgram >>= \darcs ->
    pipeDoc darcs ("apply":"--all":"--repodir":repo:applyopts opts) bundle

applyViaUrl :: [DarcsFlag] -> String -> Doc -> IO ExitCode
applyViaUrl opts repo bundle =
    do maybeapply <- maybeURLCmd "APPLY" repo
       case maybeapply of
         Nothing -> applyViaLocal opts repo bundle
         Just apply ->
           do let (cmd, args) = breakCommand apply
              pipeDoc cmd (args ++ [repo]) bundle

applyViaSsh :: [DarcsFlag] -> SshFilePath -> Doc -> IO ExitCode
applyViaSsh opts repo bundle =
    pipeDocSSH repo [Ssh.remoteDarcs (remoteDarcs opts) ++" apply --all "++unwords (applyopts opts)++
                     " --repodir '"++(sshRepo repo)++"'"] bundle

applyViaSshAndSudo :: [DarcsFlag] -> SshFilePath -> String -> Doc -> IO ExitCode
applyViaSshAndSudo opts repo username bundle =
    pipeDocSSH repo ["sudo -u "++username++" "++Ssh.remoteDarcs (remoteDarcs opts)++
                     " apply --all --repodir '"++(sshRepo repo)++"'"] bundle

applyopts :: [DarcsFlag] -> [String]
applyopts opts = if Debug `elem` opts then ["--debug"] else []