%  Copyright (C) 2002-2004 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.

\subsection{darcs whatsnew}
\label{whatsnew}
\begin{code}
module WhatsNew ( whatsnew ) where
import System ( ExitCode(..), exitWith )
import List ( sort )
import Monad ( liftM, when, unless )

import DarcsCommands ( DarcsCommand(..), nodefaults )
import DarcsArguments ( DarcsFlag(..), working_repo_dir, lookforadds,
                        ignoretimes, verbose, noskip_boring,
#ifdef HAVEWX
                        gui_interactive,
#endif
                        summary, unified,
                        fix_filepaths_wrt,
                        list_registered_files,
                      )
import TouchesFiles ( choose_touching )
import Repository ( identifyRepository,
                    slurp_recorded, get_unrecorded, amInRepository )
import RepoPrefs ( filetype_function )
import Diff ( smart_diff )
import Patch ( patch_summary, join_patches, apply_to_slurpy, is_hunk, flatten,
               is_null_patch,
             )
import PrintPatch ( printPatch, contextualPrintPatch )
import Patch ( invert, apply_to_filepaths, null_patch )
import Printer ( putDocLn, renderString, vcat, text )
#ifdef HAVEWX
import GuiUtils ( patchViewer, updatePatchViewer )
import Patch ( Patch )
import Graphics.UI.WX hiding ( when, text )
import qualified Graphics.UI.WX ( text )
import Graphics.UI.WXCore hiding ( when )
#endif
\end{code}

\options{whatsnew}

\haskell{whatsnew_description}
\begin{code}
whatsnew_description :: String
whatsnew_description = "Display unrecorded changes in the working copy."
\end{code}
\haskell{whatsnew_help} \verb!darcs whatsnew! will return a non-zero value if
there are no changes, which can be useful if you just want to see in a
script if anything has been modified.  If you want to see some context
around your changes, you can use the \verb!-u! option, to get output
similar to the unidiff format.

\begin{code}
whatsnew_help :: String
whatsnew_help =
 "whatsnew gives you a view of what changes you've made in your working\n"++
 "copy that haven't yet been recorded.  The changes are displayed in\n"++
 "darcs patch format. Note that --look-for-adds implies --summary usage.\n"
\end{code}

\begin{code}
whatsnew :: DarcsCommand
whatsnew = DarcsCommand {command_name = "whatsnew",
                         command_help = whatsnew_help,
                         command_description = whatsnew_description,
                         command_extra_args = -1,
                         command_extra_arg_help = ["[FILE or DIRECTORY]..."],
                         command_command = whatsnew_cmd,
                         command_prereq = amInRepository,
                         command_get_arg_possibilities = list_registered_files,
                         command_argdefaults = nodefaults,
                         command_darcsoptions = [verbose,
#ifdef HAVEWX
                                                 gui_interactive,
#endif
                                                 summary, unified, ignoretimes,
                                                 lookforadds, noskip_boring,
                                                 working_repo_dir]}
\end{code}

\begin{code}
whatsnew_cmd :: [DarcsFlag] -> [String] -> IO ()
whatsnew_cmd opts' args 
  | LookForAdds `elem` opts' && NoSummary `notElem` opts' = do
    -- add Summary to the opts since 'darcs whatsnew --look-for-adds'
    -- implies summary
    let opts = Summary : opts'
    repository <- identifyRepository "."
    files <- fix_filepaths_wrt "." opts args
    when (concat files /= "") $
         putStrLn $ "What's new in "++unwords (map show files)++":\n"
    maybe_all_changes <- get_unrecorded repository opts
    maybe_old_changes <- get_unrecorded repository $
                         filter (/= LookForAdds) opts
    s <- slurp_recorded repository
    ftf <- filetype_function
    let chold = case maybe_old_changes of Nothing -> null_patch
                                          Just p -> p
        pre_changed_files = apply_to_filepaths (invert chold) files
        select_adds = join_patches . filter (not . is_hunk) . flatten
        select_files = choose_touching pre_changed_files
        cho = select_files chold
        all_changes = case maybe_all_changes of Nothing -> join_patches []
                                                Just p -> p
        cha = select_adds $ select_files all_changes
        maybe_new_changes = do so <- apply_to_slurpy (select_adds cho) s
                               sn <- apply_to_slurpy cha s
                               smart_diff [LookForAdds,Summary] ftf so sn
        chn = case maybe_new_changes of Nothing -> join_patches []
                                        Just nc -> nc
    if is_null_patch chn && is_null_patch cho
       then do putStrLn "No changes!"
               exitWith $ ExitFailure 1
       else do putDocLn $ patch_summary cho
               unless (is_null_patch chn) $
                      putDocLn $ lower_as $ renderString $ patch_summary chn
           where lower_as s = vcat $ map (text . l_as) $ lines s
                 l_as ('A':s) = 'a':s
                 l_as s = s

whatsnew_cmd opts args = do
    files <- sort `liftM` fix_filepaths_wrt "." opts args
    when (concat files /= "") $
         putStrLn $ "What's new in "++unwords (map show files)++":\n"
    repository <- identifyRepository "."
    maybe_changes <- get_unrecorded repository opts
    case maybe_changes of
      Nothing -> do putStrLn "No changes!"
                    exitWith $ ExitFailure 1
      Just changes ->
          let pre_changed_files = apply_to_filepaths (invert changes) files
              ch =  choose_touching pre_changed_files changes
                    in
              if is_null_patch ch
              then do putStrLn "No changes!"
                      exitWith $ ExitFailure 1
              else
#ifdef HAVEWX
                 if Gui `elem` opts
                 then do s <- slurp_recorded repository
                         guiShowPatch ch s
                 else
#endif
                       if Summary `elem` opts
                       then putDocLn $ patch_summary ch
                       else if Unified `elem` opts
                            then do s <- slurp_recorded repository
                                    contextualPrintPatch s ch
                            else printPatch ch

#ifdef HAVEWX
guiShowPatch :: Patch -> a -> IO ()
guiShowPatch p _ = start $ hello p
hello :: Patch -> IO ()
hello p = do f <- frame [Graphics.UI.WX.text := "Whats New!"]
             t <- patchViewer f 
             updatePatchViewer t (flatten p)
             (ms,mclose) <- default_menubar
             quit <- button f [Graphics.UI.WX.text := "Quit", on command := close f]
             set f [layout := column 0 [fill $ widget t,
                                        centre $ hstretch $ margin 5 $ widget quit],
                    menuBar := ms, on (menu mclose) := close f,
                    clientSize := sz 600 400 -- this is window actual size
                   ]

default_menubar :: IO ([Menu ()], MenuItem ())
default_menubar = do
  file <- menuPane [Graphics.UI.WX.text := "&File"]
  mclose <- menuItem file [Graphics.UI.WX.text := "&Quit\tCtrl+Q", help := "Quit darcs"]
  return ([file],mclose)
#endif
\end{code}

If you give one or more file or directory names as an argument to
\verb!whatsnew!, darcs will output only changes to those files or to files in
those directories.
