{-|

The @commodities@ command lists commodity/currency symbols.

-}

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

module Hledger.Cli.Commands.Commodities (
  commoditiesmode
 ,commodities
) where

import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.Text.IO as T
import System.Console.CmdArgs.Explicit

import Hledger
import Hledger.Cli.CliOptions
import Data.List.Extra (nubSort)
import Data.List ((\\))


-- | Command line options for this command.
commoditiesmode :: Mode RawOpts
commoditiesmode = CommandHelpStr
-> [Flag RawOpts]
-> [(CommandHelpStr, [Flag RawOpts])]
-> [Flag RawOpts]
-> ([Arg RawOpts], Maybe (Arg RawOpts))
-> Mode RawOpts
hledgerCommandMode
  $(embedFileRelative "Hledger/Cli/Commands/Commodities.txt")
  [[CommandHelpStr]
-> (RawOpts -> RawOpts) -> CommandHelpStr -> Flag RawOpts
forall a. [CommandHelpStr] -> (a -> a) -> CommandHelpStr -> Flag a
flagNone [CommandHelpStr
"used"]         (CommandHelpStr -> RawOpts -> RawOpts
setboolopt CommandHelpStr
"used")       CommandHelpStr
"list commodities used"
  ,[CommandHelpStr]
-> (RawOpts -> RawOpts) -> CommandHelpStr -> Flag RawOpts
forall a. [CommandHelpStr] -> (a -> a) -> CommandHelpStr -> Flag a
flagNone [CommandHelpStr
"declared"]     (CommandHelpStr -> RawOpts -> RawOpts
setboolopt CommandHelpStr
"declared")   CommandHelpStr
"list commodities declared"
  ,[CommandHelpStr]
-> (RawOpts -> RawOpts) -> CommandHelpStr -> Flag RawOpts
forall a. [CommandHelpStr] -> (a -> a) -> CommandHelpStr -> Flag a
flagNone [CommandHelpStr
"undeclared"]   (CommandHelpStr -> RawOpts -> RawOpts
setboolopt CommandHelpStr
"undeclared") CommandHelpStr
"list commodities used but not declared"
  ,[CommandHelpStr]
-> (RawOpts -> RawOpts) -> CommandHelpStr -> Flag RawOpts
forall a. [CommandHelpStr] -> (a -> a) -> CommandHelpStr -> Flag a
flagNone [CommandHelpStr
"unused"]       (CommandHelpStr -> RawOpts -> RawOpts
setboolopt CommandHelpStr
"unused")     CommandHelpStr
"list commodities declared but not used"
  ]
  [(CommandHelpStr, [Flag RawOpts])
generalflagsgroup2]
  [Flag RawOpts]
confflags
  ([], 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
$ CommandHelpStr -> Arg RawOpts
argsFlag CommandHelpStr
"[QUERY..]")

commodities :: CliOpts -> Journal -> IO ()
commodities :: CliOpts -> Journal -> IO ()
commodities opts :: CliOpts
opts@CliOpts{reportspec_ :: CliOpts -> ReportSpec
reportspec_ = ReportSpec{_rsQuery :: ReportSpec -> Query
_rsQuery = Query
query}} Journal
j = do
  let
    used :: [CommoditySymbol]
used       = CommandHelpStr -> [CommoditySymbol] -> [CommoditySymbol]
forall a. Show a => CommandHelpStr -> a -> a
dbg5 CommandHelpStr
"used"       ([CommoditySymbol] -> [CommoditySymbol])
-> [CommoditySymbol] -> [CommoditySymbol]
forall a b. (a -> b) -> a -> b
$
      Set CommoditySymbol -> [CommoditySymbol]
forall a. Set a -> [a]
S.toList (Set CommoditySymbol -> [CommoditySymbol])
-> Set CommoditySymbol -> [CommoditySymbol]
forall a b. (a -> b) -> a -> b
$ Journal -> Set CommoditySymbol
journalCommoditiesFromPriceDirectives Journal
j Set CommoditySymbol -> Set CommoditySymbol -> Set CommoditySymbol
forall a. Semigroup a => a -> a -> a
<> Journal -> Set CommoditySymbol
journalCommoditiesFromTransactions Journal
j
    declared' :: [CommoditySymbol]
declared'  = CommandHelpStr -> [CommoditySymbol] -> [CommoditySymbol]
forall a. Show a => CommandHelpStr -> a -> a
dbg5 CommandHelpStr
"declared"   ([CommoditySymbol] -> [CommoditySymbol])
-> [CommoditySymbol] -> [CommoditySymbol]
forall a b. (a -> b) -> a -> b
$ Map CommoditySymbol Commodity -> [CommoditySymbol]
forall k a. Map k a -> [k]
M.keys (Map CommoditySymbol Commodity -> [CommoditySymbol])
-> Map CommoditySymbol Commodity -> [CommoditySymbol]
forall a b. (a -> b) -> a -> b
$ Journal -> Map CommoditySymbol Commodity
jdeclaredcommodities Journal
j
    unused :: [CommoditySymbol]
unused     = CommandHelpStr -> [CommoditySymbol] -> [CommoditySymbol]
forall a. Show a => CommandHelpStr -> a -> a
dbg5 CommandHelpStr
"unused"     ([CommoditySymbol] -> [CommoditySymbol])
-> [CommoditySymbol] -> [CommoditySymbol]
forall a b. (a -> b) -> a -> b
$ [CommoditySymbol]
declared' [CommoditySymbol] -> [CommoditySymbol] -> [CommoditySymbol]
forall a. Eq a => [a] -> [a] -> [a]
\\ [CommoditySymbol]
used
    undeclared :: [CommoditySymbol]
undeclared = CommandHelpStr -> [CommoditySymbol] -> [CommoditySymbol]
forall a. Show a => CommandHelpStr -> a -> a
dbg5 CommandHelpStr
"undeclared" ([CommoditySymbol] -> [CommoditySymbol])
-> [CommoditySymbol] -> [CommoditySymbol]
forall a b. (a -> b) -> a -> b
$ [CommoditySymbol]
used     [CommoditySymbol] -> [CommoditySymbol] -> [CommoditySymbol]
forall a. Eq a => [a] -> [a] -> [a]
\\ [CommoditySymbol]
declared'
    all' :: [CommoditySymbol]
all'       = CommandHelpStr -> [CommoditySymbol] -> [CommoditySymbol]
forall a. Show a => CommandHelpStr -> a -> a
dbg5 CommandHelpStr
"all"        ([CommoditySymbol] -> [CommoditySymbol])
-> [CommoditySymbol] -> [CommoditySymbol]
forall a b. (a -> b) -> a -> b
$ [CommoditySymbol] -> [CommoditySymbol]
forall a. Ord a => [a] -> [a]
nubSort ([CommoditySymbol] -> [CommoditySymbol])
-> [CommoditySymbol] -> [CommoditySymbol]
forall a b. (a -> b) -> a -> b
$ [[CommoditySymbol]] -> [CommoditySymbol]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [
       Journal -> [CommoditySymbol]
journalCommoditiesDeclared Journal
j
      ,(PriceDirective -> CommoditySymbol)
-> [PriceDirective] -> [CommoditySymbol]
forall a b. (a -> b) -> [a] -> [b]
map PriceDirective -> CommoditySymbol
pdcommodity ([PriceDirective] -> [CommoditySymbol])
-> [PriceDirective] -> [CommoditySymbol]
forall a b. (a -> b) -> a -> b
$ Journal -> [PriceDirective]
jpricedirectives Journal
j          -- gets the first symbol from P directives
      ,(Amount -> CommoditySymbol) -> [Amount] -> [CommoditySymbol]
forall a b. (a -> b) -> [a] -> [b]
map Amount -> CommoditySymbol
acommodity (Set Amount -> [Amount]
forall a. Set a -> [a]
S.toList (Set Amount -> [Amount]) -> Set Amount -> [Amount]
forall a b. (a -> b) -> a -> b
$ Journal -> Set Amount
journalAmounts Journal
j)  -- includes the second symbol from P directives
      ]

  (CommoditySymbol -> IO ()) -> [CommoditySymbol] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ CommoditySymbol -> IO ()
T.putStrLn ([CommoditySymbol] -> IO ()) -> [CommoditySymbol] -> IO ()
forall a b. (a -> b) -> a -> b
$ (CommoditySymbol -> Bool) -> [CommoditySymbol] -> [CommoditySymbol]
forall a. (a -> Bool) -> [a] -> [a]
filter (Query -> CommoditySymbol -> Bool
matchesCommodity Query
query) ([CommoditySymbol] -> [CommoditySymbol])
-> [CommoditySymbol] -> [CommoditySymbol]
forall a b. (a -> b) -> a -> b
$
    case CliOpts -> Maybe UsedOrDeclared
usedOrDeclaredFromOpts CliOpts
opts of
      Maybe UsedOrDeclared
Nothing         -> [CommoditySymbol]
all'
      Just UsedOrDeclared
Used       -> [CommoditySymbol]
used
      Just UsedOrDeclared
Declared   -> [CommoditySymbol]
declared'
      Just UsedOrDeclared
Undeclared -> [CommoditySymbol]
undeclared
      Just UsedOrDeclared
Unused     -> [CommoditySymbol]
unused