%  Copyright (C) 2005 David Roundy
%
%  This program is free software; you can redistribute it and/or modify
%  it under the terms of the GNU General Public License as published by
%  the Free Software Foundation; either version 2, or (at your option)
%  any later version.
%
%  This program is distributed in the hope that it will be useful,
%  but WITHOUT ANY WARRANTY; without even the implied warranty of
%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%  GNU General Public License for more details.
%
%  You should have received a copy of the GNU General Public License
%  along with this program; see the file COPYING.  If not, write to
%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
%  Boston, MA 02110-1301, USA.


\begin{code}
module MainGui where
#ifdef HAVEWX
-- base haskell
import Control.Exception ( catch, Exception(ExitException), throw )
import Control.Monad ( liftM )
import Data.Maybe ( fromJust )
import System.Directory ( setCurrentDirectory )
import System.Exit ( exitWith, ExitCode(ExitSuccess) )

-- wxhaskell
import Graphics.UI.WX hiding ( when, text )
import qualified Graphics.UI.WX as WX ( text )
import Graphics.UI.WXCore hiding ( when )

-- darcs
import DarcsCommands ( DarcsCommand(command_argdefaults, command_command) )
import DarcsFlags ( DarcsFlag(Gui, SubGui) )
import GuiUtils ( patchViewer, updatePatchViewer )
import Patch ( flatten, )
import Repository ( get_unrecorded, withRepoLock, withRepoGuiLockCanFail,
                    read_repo, )
import Pull
import Push
import Record
import Revert
import Send
import Unrecord
\end{code}

Darcs includes an experimental graphical interface.  You should note
that this interface may not have all the functionality of the
command-line equivalent.

\begin{code}
repositoryGui :: Maybe FilePath -- ^ repository
              -> IO ()
repositoryGui mRepoPath =
 do f <- frame [ WX.text := "wxDarcs" ]
    --
    fileMenu <- menuPane [WX.text := "&File"]
    mclose   <- menuQuit fileMenu [help := "Quit darcs"]
    -- --------------------------------
    -- repository view
    -- --------------------------------
    sp   <- panel f []
    spp  <- panel sp []
    splt <- splitterWindow spp []
    -- unrecorded patches
    wp    <- panel splt []
    wView <- patchViewer wp
    -- recorded patches
    cp    <- panel splt []
    cView <- patchViewer cp
    --
    textlog <- textCtrl sp [enabled := False, wrap := WrapNone]
    textCtrlMakeLogActiveTarget textlog
    -- repo layout
    let repoLay = container sp $ fill $ column 1
         [ fill $ container spp $ fill $ hsplit splt 5 100
           (container wp $ fill $ column 1
             [ hfill $ label "What's new", fill  $ widget wView ])
           (container cp $ fill $ column 1
             [ hfill $ label "Changes", fill  $ widget cView ])
         , hfill $ vspace 3
         , hfill $ label "Log", hfill $ widget textlog ]
    -- --------------------------------
    -- button bar
    -- --------------------------------
    mp <- panel f []
    addBt    <- button_ mp [ WX.text := "Add" ]
    mvBt     <- button_ mp [ WX.text := "Move" ]
    pushBt   <- button mp [ WX.text := "Push" ]
    pullBt   <- button mp [ WX.text := "Pull" ]
    sendBt   <- button mp [ WX.text := "Send" ]
    applyBt  <- button_ mp [ WX.text := "Apply" ]
    oblBt    <- button mp [ WX.text := "Obliterate" ]
    amdBt    <- button_ mp [ WX.text := "Amend" ]
    unrecBt  <- button mp [ WX.text := "Unrecord" ]
    recBt    <- button mp [ WX.text := "Record" ]
    revBt    <- button mp [ WX.text := "Revert" ]
    --
    openBt   <- button mp [ WX.text := "Open", on command := openRepo f ]
    quitBt <- button mp [ WX.text := "Quit", on command := exitWith ExitSuccess ]
    --
    let btnLay = column 3 $ map hfill
                 [ widget openBt
                 , vspace 2, alignCentre $ label "Files"
                 , widget addBt, widget mvBt
                 , vspace 2, alignCentre $ label "Changes"
                 , widget recBt, widget revBt
                 , vspace 2, alignCentre $ label "Local"
                 , widget oblBt, widget amdBt, widget unrecBt
                 , vspace 2, alignCentre $ label "Remote"
                 , widget pushBt, widget pullBt
                 , vspace 3
                 , widget sendBt, widget applyBt ]
        totalBtnLay = margin 2 $ container mp $ vfill $ column 0 $
                      [ vfill btnLay
                      , vspace 5
                      , hfill $ widget quitBt
                      , vspace 5 ]
    -- --------------------------------
    -- commands
    -- --------------------------------
    let updateRepoViewHere = updateRepoView (wView, cView)
        btnLst = -- widgets to activate/disactivate
           [ addBt, mvBt, pullBt, pushBt, sendBt, applyBt
           , oblBt, amdBt, unrecBt, recBt, revBt ]
        enableButtons t =
          mapM (\b -> set b [ enabled := t ] ) btnLst
        activateMainIfPossible True  =
          do withRepoGuiLockCanFail $ \repository ->
               do enableButtons True
                  updateRepoViewHere repository
                  set f [ on activate := \_ -> return () ]
             return ()
        activateMainIfPossible False = return ()
        --
        ignoreExit (ExitException _) = return ()
        ignoreExit x = throw x
        runDarcsCmd cmd =
          do enableButtons False
             set f [ on activate := activateMainIfPossible ]
             args <- command_argdefaults cmd "" []
             command_command cmd [Gui, SubGui] args `Control.Exception.catch` ignoreExit
    --
    set pullBt   [ on command := runDarcsCmd pull ]
    set pushBt   [ on command := runDarcsCmd push ]
    set sendBt   [ on command := runDarcsCmd send ]
    set oblBt    [ on command := runDarcsCmd obliterate ]
    set unrecBt  [ on command := runDarcsCmd unrecord ]
    set recBt    [ on command := runDarcsCmd record ]
    set revBt    [ on command := runDarcsCmd revert ]
    -- activate the gui if possible
    case mRepoPath of
      Nothing ->
        do enableButtons False
           set wView [ enabled := False ]
           set cView [ enabled := False ]
      Just repoPath  ->
        do setCurrentDirectory repoPath
           -- FIX ME -- pass the right opts -- jch
           withRepoLock [] updateRepoViewHere
           set wView [ enabled := True ]
           set cView [ enabled := True ]
    -- --------------------------------
    -- global layout
    -- --------------------------------
    set f [ layout := fill $ row 1 [ vfill totalBtnLay, fill repoLay ]
          , menuBar := [fileMenu]
          , on (menu mclose) := close f
          , clientSize := sz 600 400 -- this is window actual size
          ]
 where
 -- local repository selector
 openRepo f =
  do mchosen <- dirOpenDialog f False "Choose a repository..." "."
     case mchosen of
       Nothing     -> return ()
       Just chosen -> close f >> repositoryGui (Just chosen)
 --
 updateRepoView (wView,cView) repository =
  do -- FIXME: I don't know if this is actually the correct way to retrieve the patches
     n' <- get_unrecorded repository []
     o' <- head `liftM` read_repo repository
     let n = case n' of
             Nothing  -> []
             Just n'' -> flatten n''
         o = map (fromJust . snd) $ reverse o'
     updatePatchViewer wView n
     updatePatchViewer cView o
\end{code}

\begin{code}
notYetImplTip, notYetImplMsg :: String
notYetImplTip = "not yet implemented"
notYetImplMsg = "This GUI feature has not been implemented yet"

-- | Dummy button for features not yet implemented
button_ :: Window a -> [Prop (Button ())] -> IO (Button ())
button_ f l = button f $
 l ++ [ tooltip := notYetImplTip
      , on command := errorDialog f "Sorry!" notYetImplMsg ]
#endif
\end{code}
