    {-# LANGUAGE OverloadedStrings #-}
    {-# LANGUAGE TemplateHaskell #-}

    module Hledger.Cli.Commands.Import (
      importmode
     ,importcmd
    )
    where

    import Control.Monad
    import Data.List
    import Hledger
    import Hledger.Cli.CliOptions
    import Hledger.Cli.Commands.Add (journalAddTransaction)
    -- import Hledger.Cli.Commands.Print (print')
    import System.Console.CmdArgs.Explicit
    import Text.Printf

    importmode :: Mode RawOpts
    importmode = CommandDoc
    -> [Flag RawOpts]
    -> [(CommandDoc, [Flag RawOpts])]
    -> [Flag RawOpts]
    -> ([Arg RawOpts], Maybe (Arg RawOpts))
    -> Mode RawOpts
    hledgerCommandMode
      $(embedFileRelative "Hledger/Cli/Commands/Import.txt")
      [[CommandDoc] -> (RawOpts -> RawOpts) -> CommandDoc -> Flag RawOpts
    forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
    flagNone ["catchup"] (CommandDoc -> RawOpts -> RawOpts
    setboolopt "catchup") "just mark all transactions as already imported"
      ,[CommandDoc] -> (RawOpts -> RawOpts) -> CommandDoc -> Flag RawOpts
    forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
    flagNone ["dry-run"] (CommandDoc -> RawOpts -> RawOpts
    setboolopt "dry-run") "just show the transactions to be imported"
      ]
      [(CommandDoc, [Flag RawOpts])
    generalflagsgroup1]
      [Flag RawOpts]
    hiddenflags
      ([], Arg RawOpts -> Maybe (Arg RawOpts)
    forall a. a -> Maybe a
    Just (Arg RawOpts -> Maybe (Arg RawOpts))
    -> Arg RawOpts -> Maybe (Arg RawOpts)
    forall a b. (a -> b) -> a -> b
    $ CommandDoc -> Arg RawOpts
    argsFlag "FILE [...]")

    importcmd :: CliOpts -> Journal -> IO ()
    importcmd opts :: CliOpts
    opts@CliOpts{rawopts_ :: CliOpts -> RawOpts
    rawopts_=RawOpts
    rawopts,inputopts_ :: CliOpts -> InputOpts
    inputopts_=InputOpts
    iopts} j :: Journal
    j = do
      -- XXX could be helpful to show the last-seen date, and number of old transactions, too
      let
        inputfiles :: [CommandDoc]
    inputfiles = CommandDoc -> RawOpts -> [CommandDoc]
    listofstringopt "args" RawOpts
    rawopts
        inputstr :: CommandDoc
    inputstr = CommandDoc -> [CommandDoc] -> CommandDoc
    forall a. [a] -> [[a]] -> [a]
    intercalate ", " ([CommandDoc] -> CommandDoc) -> [CommandDoc] -> CommandDoc
    forall a b. (a -> b) -> a -> b
    $ (CommandDoc -> CommandDoc) -> [CommandDoc] -> [CommandDoc]
    forall a b. (a -> b) -> [a] -> [b]
    map CommandDoc -> CommandDoc
    quoteIfNeeded [CommandDoc]
    inputfiles
        catchup :: Bool
    catchup = CommandDoc -> RawOpts -> Bool
    boolopt "catchup" RawOpts
    rawopts
        dryrun :: Bool
    dryrun = CommandDoc -> RawOpts -> Bool
    boolopt "dry-run" RawOpts
    rawopts
        iopts' :: InputOpts
    iopts' = InputOpts
    iopts{new_ :: Bool
    new_=Bool
    True, new_save_ :: Bool
    new_save_=Bool -> Bool
    not Bool
    dryrun}
      case [CommandDoc]
    inputfiles of
        [] -> CommandDoc -> IO ()
    forall a. CommandDoc -> a
    error' "please provide one or more input files as arguments"  -- PARTIAL:
        fs :: [CommandDoc]
    fs -> do
          Either CommandDoc Journal
    enewj <- InputOpts -> [CommandDoc] -> IO (Either CommandDoc Journal)
    readJournalFiles InputOpts
    iopts' [CommandDoc]
    fs
          case Either CommandDoc Journal
    enewj of
            Left e :: CommandDoc
    e     -> CommandDoc -> IO ()
    forall a. CommandDoc -> a
    error' CommandDoc
    e
            Right newj :: Journal
    newj ->
              case (Transaction -> Day) -> [Transaction] -> [Transaction]
    forall b a. Ord b => (a -> b) -> [a] -> [a]
    sortOn Transaction -> Day
    tdate ([Transaction] -> [Transaction]) -> [Transaction] -> [Transaction]
    forall a b. (a -> b) -> a -> b
    $ Journal -> [Transaction]
    jtxns Journal
    newj of
                -- with --dry-run the output should be valid journal format, so messages have ; prepended
                [] -> do
                  -- in this case, we vary the output depending on --dry-run, which is a bit awkward
                  let semicolon :: CommandDoc
    semicolon = if Bool
    dryrun then "; " else "" :: String
                  CommandDoc -> CommandDoc -> CommandDoc -> IO ()
    forall r. PrintfType r => CommandDoc -> r
    printf "%sno new transactions found in %s\n\n" CommandDoc
    semicolon CommandDoc
    inputstr
                newts :: [Transaction]
    newts | Bool
    dryrun -> do
                  CommandDoc -> Int -> CommandDoc -> IO ()
    forall r. PrintfType r => CommandDoc -> r
    printf "; would import %d new transactions from %s:\n\n" ([Transaction] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [Transaction]
    newts) CommandDoc
    inputstr
                  -- TODO how to force output here ?
                  -- length (jtxns newj) `seq` print' opts{rawopts_=("explicit",""):rawopts} newj
                  (Transaction -> IO ()) -> [Transaction] -> IO ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ (CommandDoc -> IO ()
    putStr (CommandDoc -> IO ())
    -> (Transaction -> CommandDoc) -> Transaction -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Transaction -> CommandDoc
    showTransaction) [Transaction]
    newts
                newts :: [Transaction]
    newts | Bool
    catchup -> do
                  CommandDoc -> CommandDoc -> Int -> IO ()
    forall r. PrintfType r => CommandDoc -> r
    printf "marked %s as caught up, skipping %d unimported transactions\n\n" CommandDoc
    inputstr ([Transaction] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [Transaction]
    newts)
                newts :: [Transaction]
    newts -> do
                  -- XXX This writes unix line endings (\n), some at least,
                  -- even if the file uses dos line endings (\r\n), which could leave
                  -- mixed line endings in the file. See also writeFileWithBackupIfChanged.
                  (Journal -> Transaction -> IO Journal)
    -> Journal -> [Transaction] -> IO ()
    forall (t :: * -> *) (m :: * -> *) b a.
    (Foldable t, Monad m) =>
    (b -> a -> m b) -> b -> t a -> m ()
    foldM_ (Journal -> CliOpts -> Transaction -> IO Journal
    `journalAddTransaction` CliOpts
    opts) Journal
    j [Transaction]
    newts  -- gets forced somehow.. (how ?)
                  CommandDoc -> Int -> CommandDoc -> IO ()
    forall r. PrintfType r => CommandDoc -> r
    printf "imported %d new transactions from %s\n" ([Transaction] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [Transaction]
    newts) CommandDoc
    inputstr