    {- |
    New common report types, used by the BudgetReport for now, perhaps all reports later.
    -}
    {-# LANGUAGE DeriveAnyClass #-}
    {-# LANGUAGE DeriveFunctor  #-}
    {-# LANGUAGE DeriveGeneric  #-}
    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE NamedFieldPuns #-}

    module Hledger.Reports.ReportTypes
    ( PeriodicReport(..)
    , PeriodicReportRow(..)

    , Percentage
    , Change
    , Balance
    , Total
    , Average

    , periodicReportSpan
    , prMapName
    , prMapMaybeName

    , CompoundPeriodicReport(..)
    , CBCSubreportSpec(..)

    , DisplayName(..)
    , flatDisplayName
    , treeDisplayName

    , prrShowDebug
    , prrFullName
    , prrDisplayName
    , prrIndent
    , prrAdd
    ) where

    import Data.Aeson (ToJSON(..))
    import Data.Bifunctor (Bifunctor(..))
    import Data.Decimal (Decimal)
    import Data.Maybe (mapMaybe)
    import Data.Text (Text)
    import GHC.Generics (Generic)

    import Hledger.Data
    import Hledger.Query (Query)
    import Hledger.Reports.ReportOptions (ReportOpts)
    import Data.Text qualified as T
    import Data.List (intercalate)

    type Percentage = Decimal

    type Change  = MixedAmount  -- ^ A change in balance during a certain period.
    type Balance = MixedAmount  -- ^ An ending balance as of some date.
    type Total   = MixedAmount  -- ^ The sum of 'Change's in a report or a report row. Does not make sense for 'Balance's.
    type Average = MixedAmount  -- ^ The average of 'Change's or 'Balance's in a report or report row.

    -- | A periodic report is a generic tabular report, where each row corresponds
    -- to some label (usually an account name) and each column to a date period.
    -- The column periods are usually consecutive subperiods formed by splitting
    -- the overall report period by some report interval (daily, weekly, etc.).
    -- It has:
    --
    -- 1. a list of each column's period (date span)
    --
    -- 2. a list of rows, each containing:
    --
    --   * an account label
    --
    --   * the account's depth
    --
    --   * A list of amounts, one for each column. Depending on the value type,
    --     these can represent balance changes, ending balances, budget
    --     performance, etc. (for example, see 'BalanceAccumulation' and
    --     "Hledger.Cli.Commands.Balance").
    --
    --   * the total of the row's amounts for a periodic report,
    --     or zero for cumulative/historical reports (since summing
    --     end balances generally doesn't make sense).
    --
    --   * the average of the row's amounts
    --
    -- 3. the column totals, and the overall grand total (or zero for
    -- cumulative/historical reports) and grand average.

    data PeriodicReport a b =
      PeriodicReport
      { forall a b. PeriodicReport a b -> [DateSpan]
    prDates  :: [DateSpan]               -- The subperiods formed by splitting the overall
                                             -- report period by the report interval. For
                                             -- ending-balance reports, only the end date is
                                             -- significant. Usually displayed as report columns.
      , forall a b. PeriodicReport a b -> [PeriodicReportRow a b]
    prRows   :: [PeriodicReportRow a b]  -- One row per account in the report.
      , forall a b. PeriodicReport a b -> PeriodicReportRow () b
    prTotals :: PeriodicReportRow () b   -- The grand totals row.
      } deriving (Int -> PeriodicReport a b -> ShowS
    [PeriodicReport a b] -> ShowS
    PeriodicReport a b -> String
    (Int -> PeriodicReport a b -> ShowS)
    -> (PeriodicReport a b -> String)
    -> ([PeriodicReport a b] -> ShowS)
    -> Show (PeriodicReport a b)
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    forall a b. (Show a, Show b) => Int -> PeriodicReport a b -> ShowS
    forall a b. (Show a, Show b) => [PeriodicReport a b] -> ShowS
    forall a b. (Show a, Show b) => PeriodicReport a b -> String
    $cshowsPrec :: forall a b. (Show a, Show b) => Int -> PeriodicReport a b -> ShowS
    showsPrec :: Int -> PeriodicReport a b -> ShowS
    $cshow :: forall a b. (Show a, Show b) => PeriodicReport a b -> String
    show :: PeriodicReport a b -> String
    $cshowList :: forall a b. (Show a, Show b) => [PeriodicReport a b] -> ShowS
    showList :: [PeriodicReport a b] -> ShowS
    Show, (forall a b. (a -> b) -> PeriodicReport a a -> PeriodicReport a b)
    -> (forall a b. a -> PeriodicReport a b -> PeriodicReport a a)
    -> Functor (PeriodicReport a)
    forall a b. a -> PeriodicReport a b -> PeriodicReport a a
    forall a b. (a -> b) -> PeriodicReport a a -> PeriodicReport a b
    forall a a b. a -> PeriodicReport a b -> PeriodicReport a a
    forall a a b. (a -> b) -> PeriodicReport a a -> PeriodicReport a b
    forall (f :: * -> *).
    (forall a b. (a -> b) -> f a -> f b)
    -> (forall a b. a -> f b -> f a) -> Functor f
    $cfmap :: forall a a b. (a -> b) -> PeriodicReport a a -> PeriodicReport a b
    fmap :: forall a b. (a -> b) -> PeriodicReport a a -> PeriodicReport a b
    $c<$ :: forall a a b. a -> PeriodicReport a b -> PeriodicReport a a
    <$ :: forall a b. a -> PeriodicReport a b -> PeriodicReport a a
    Functor, (forall x. PeriodicReport a b -> Rep (PeriodicReport a b) x)
    -> (forall x. Rep (PeriodicReport a b) x -> PeriodicReport a b)
    -> Generic (PeriodicReport a b)
    forall x. Rep (PeriodicReport a b) x -> PeriodicReport a b
    forall x. PeriodicReport a b -> Rep (PeriodicReport a b) x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    forall a b x. Rep (PeriodicReport a b) x -> PeriodicReport a b
    forall a b x. PeriodicReport a b -> Rep (PeriodicReport a b) x
    $cfrom :: forall a b x. PeriodicReport a b -> Rep (PeriodicReport a b) x
    from :: forall x. PeriodicReport a b -> Rep (PeriodicReport a b) x
    $cto :: forall a b x. Rep (PeriodicReport a b) x -> PeriodicReport a b
    to :: forall x. Rep (PeriodicReport a b) x -> PeriodicReport a b
    Generic, [PeriodicReport a b] -> Value
    [PeriodicReport a b] -> Encoding
    PeriodicReport a b -> Bool
    PeriodicReport a b -> Value
    PeriodicReport a b -> Encoding
    (PeriodicReport a b -> Value)
    -> (PeriodicReport a b -> Encoding)
    -> ([PeriodicReport a b] -> Value)
    -> ([PeriodicReport a b] -> Encoding)
    -> (PeriodicReport a b -> Bool)
    -> ToJSON (PeriodicReport a b)
    forall a.
    (a -> Value)
    -> (a -> Encoding)
    -> ([a] -> Value)
    -> ([a] -> Encoding)
    -> (a -> Bool)
    -> ToJSON a
    forall a b. (ToJSON a, ToJSON b) => [PeriodicReport a b] -> Value
    forall a b.
    (ToJSON a, ToJSON b) =>
    [PeriodicReport a b] -> Encoding
    forall a b. (ToJSON a, ToJSON b) => PeriodicReport a b -> Bool
    forall a b. (ToJSON a, ToJSON b) => PeriodicReport a b -> Value
    forall a b. (ToJSON a, ToJSON b) => PeriodicReport a b -> Encoding
    $ctoJSON :: forall a b. (ToJSON a, ToJSON b) => PeriodicReport a b -> Value
    toJSON :: PeriodicReport a b -> Value
    $ctoEncoding :: forall a b. (ToJSON a, ToJSON b) => PeriodicReport a b -> Encoding
    toEncoding :: PeriodicReport a b -> Encoding
    $ctoJSONList :: forall a b. (ToJSON a, ToJSON b) => [PeriodicReport a b] -> Value
    toJSONList :: [PeriodicReport a b] -> Value
    $ctoEncodingList :: forall a b.
    (ToJSON a, ToJSON b) =>
    [PeriodicReport a b] -> Encoding
    toEncodingList :: [PeriodicReport a b] -> Encoding
    $comitField :: forall a b. (ToJSON a, ToJSON b) => PeriodicReport a b -> Bool
    omitField :: PeriodicReport a b -> Bool
    ToJSON)

    instance Bifunctor PeriodicReport where
      bimap :: forall a b c d.
    (a -> b) -> (c -> d) -> PeriodicReport a c -> PeriodicReport b d
    bimap a -> b
    f c -> d
    g PeriodicReport a c
    pr = PeriodicReport a c
    pr{prRows = map (bimap f g) $ prRows pr, prTotals = g <$> prTotals pr}

    instance HasAmounts b => HasAmounts (PeriodicReport a b) where
      styleAmounts :: Map CommoditySymbol AmountStyle
    -> PeriodicReport a b -> PeriodicReport a b
    styleAmounts Map CommoditySymbol AmountStyle
    styles r :: PeriodicReport a b
    r@PeriodicReport{[PeriodicReportRow a b]
    prRows :: forall a b. PeriodicReport a b -> [PeriodicReportRow a b]
    prRows :: [PeriodicReportRow a b]
    prRows,PeriodicReportRow () b
    prTotals :: forall a b. PeriodicReport a b -> PeriodicReportRow () b
    prTotals :: PeriodicReportRow () b
    prTotals} =
        PeriodicReport a b
    r{prRows=styleAmounts styles prRows, prTotals=styleAmounts styles prTotals}

    data PeriodicReportRow a b =
      PeriodicReportRow
      { forall a b. PeriodicReportRow a b -> a
    prrName    :: a    -- An account name.
      , forall a b. PeriodicReportRow a b -> [b]
    prrAmounts :: [b]  -- The data value for each subperiod.
      , forall a b. PeriodicReportRow a b -> b
    prrTotal   :: b    -- The total of this row's values.
      , forall a b. PeriodicReportRow a b -> b
    prrAverage :: b    -- The average of this row's values.
      } deriving (Int -> PeriodicReportRow a b -> ShowS
    [PeriodicReportRow a b] -> ShowS
    PeriodicReportRow a b -> String
    (Int -> PeriodicReportRow a b -> ShowS)
    -> (PeriodicReportRow a b -> String)
    -> ([PeriodicReportRow a b] -> ShowS)
    -> Show (PeriodicReportRow a b)
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    forall a b.
    (Show a, Show b) =>
    Int -> PeriodicReportRow a b -> ShowS
    forall a b. (Show a, Show b) => [PeriodicReportRow a b] -> ShowS
    forall a b. (Show a, Show b) => PeriodicReportRow a b -> String
    $cshowsPrec :: forall a b.
    (Show a, Show b) =>
    Int -> PeriodicReportRow a b -> ShowS
    showsPrec :: Int -> PeriodicReportRow a b -> ShowS
    $cshow :: forall a b. (Show a, Show b) => PeriodicReportRow a b -> String
    show :: PeriodicReportRow a b -> String
    $cshowList :: forall a b. (Show a, Show b) => [PeriodicReportRow a b] -> ShowS
    showList :: [PeriodicReportRow a b] -> ShowS
    Show, (forall a b.
     (a -> b) -> PeriodicReportRow a a -> PeriodicReportRow a b)
    -> (forall a b.
        a -> PeriodicReportRow a b -> PeriodicReportRow a a)
    -> Functor (PeriodicReportRow a)
    forall a b. a -> PeriodicReportRow a b -> PeriodicReportRow a a
    forall a b.
    (a -> b) -> PeriodicReportRow a a -> PeriodicReportRow a b
    forall a a b. a -> PeriodicReportRow a b -> PeriodicReportRow a a
    forall a a b.
    (a -> b) -> PeriodicReportRow a a -> PeriodicReportRow a b
    forall (f :: * -> *).
    (forall a b. (a -> b) -> f a -> f b)
    -> (forall a b. a -> f b -> f a) -> Functor f
    $cfmap :: forall a a b.
    (a -> b) -> PeriodicReportRow a a -> PeriodicReportRow a b
    fmap :: forall a b.
    (a -> b) -> PeriodicReportRow a a -> PeriodicReportRow a b
    $c<$ :: forall a a b. a -> PeriodicReportRow a b -> PeriodicReportRow a a
    <$ :: forall a b. a -> PeriodicReportRow a b -> PeriodicReportRow a a
    Functor, (forall x. PeriodicReportRow a b -> Rep (PeriodicReportRow a b) x)
    -> (forall x.
        Rep (PeriodicReportRow a b) x -> PeriodicReportRow a b)
    -> Generic (PeriodicReportRow a b)
    forall x. Rep (PeriodicReportRow a b) x -> PeriodicReportRow a b
    forall x. PeriodicReportRow a b -> Rep (PeriodicReportRow a b) x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    forall a b x.
    Rep (PeriodicReportRow a b) x -> PeriodicReportRow a b
    forall a b x.
    PeriodicReportRow a b -> Rep (PeriodicReportRow a b) x
    $cfrom :: forall a b x.
    PeriodicReportRow a b -> Rep (PeriodicReportRow a b) x
    from :: forall x. PeriodicReportRow a b -> Rep (PeriodicReportRow a b) x
    $cto :: forall a b x.
    Rep (PeriodicReportRow a b) x -> PeriodicReportRow a b
    to :: forall x. Rep (PeriodicReportRow a b) x -> PeriodicReportRow a b
    Generic, [PeriodicReportRow a b] -> Value
    [PeriodicReportRow a b] -> Encoding
    PeriodicReportRow a b -> Bool
    PeriodicReportRow a b -> Value
    PeriodicReportRow a b -> Encoding
    (PeriodicReportRow a b -> Value)
    -> (PeriodicReportRow a b -> Encoding)
    -> ([PeriodicReportRow a b] -> Value)
    -> ([PeriodicReportRow a b] -> Encoding)
    -> (PeriodicReportRow a b -> Bool)
    -> ToJSON (PeriodicReportRow a b)
    forall a.
    (a -> Value)
    -> (a -> Encoding)
    -> ([a] -> Value)
    -> ([a] -> Encoding)
    -> (a -> Bool)
    -> ToJSON a
    forall a b.
    (ToJSON b, ToJSON a) =>
    [PeriodicReportRow a b] -> Value
    forall a b.
    (ToJSON b, ToJSON a) =>
    [PeriodicReportRow a b] -> Encoding
    forall a b. (ToJSON b, ToJSON a) => PeriodicReportRow a b -> Bool
    forall a b. (ToJSON b, ToJSON a) => PeriodicReportRow a b -> Value
    forall a b.
    (ToJSON b, ToJSON a) =>
    PeriodicReportRow a b -> Encoding
    $ctoJSON :: forall a b. (ToJSON b, ToJSON a) => PeriodicReportRow a b -> Value
    toJSON :: PeriodicReportRow a b -> Value
    $ctoEncoding :: forall a b.
    (ToJSON b, ToJSON a) =>
    PeriodicReportRow a b -> Encoding
    toEncoding :: PeriodicReportRow a b -> Encoding
    $ctoJSONList :: forall a b.
    (ToJSON b, ToJSON a) =>
    [PeriodicReportRow a b] -> Value
    toJSONList :: [PeriodicReportRow a b] -> Value
    $ctoEncodingList :: forall a b.
    (ToJSON b, ToJSON a) =>
    [PeriodicReportRow a b] -> Encoding
    toEncodingList :: [PeriodicReportRow a b] -> Encoding
    $comitField :: forall a b. (ToJSON b, ToJSON a) => PeriodicReportRow a b -> Bool
    omitField :: PeriodicReportRow a b -> Bool
    ToJSON)

    instance Bifunctor PeriodicReportRow where
      first :: forall a b c.
    (a -> b) -> PeriodicReportRow a c -> PeriodicReportRow b c
    first a -> b
    f PeriodicReportRow a c
    prr = PeriodicReportRow a c
    prr{prrName = f $ prrName prr}
      second :: forall b c a.
    (b -> c) -> PeriodicReportRow a b -> PeriodicReportRow a c
    second = (b -> c) -> PeriodicReportRow a b -> PeriodicReportRow a c
    forall a b.
    (a -> b) -> PeriodicReportRow a a -> PeriodicReportRow a b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap

    instance Semigroup b => Semigroup (PeriodicReportRow a b) where
      <> :: PeriodicReportRow a b
    -> PeriodicReportRow a b -> PeriodicReportRow a b
    (<>) = PeriodicReportRow a b
    -> PeriodicReportRow a b -> PeriodicReportRow a b
    forall b a.
    Semigroup b =>
    PeriodicReportRow a b
    -> PeriodicReportRow a b -> PeriodicReportRow a b
    prrAdd

    instance HasAmounts b => HasAmounts (PeriodicReportRow a b) where
      styleAmounts :: Map CommoditySymbol AmountStyle
    -> PeriodicReportRow a b -> PeriodicReportRow a b
    styleAmounts Map CommoditySymbol AmountStyle
    styles PeriodicReportRow a b
    r =
        PeriodicReportRow a b
    r{prrAmounts=styleAmounts styles $ prrAmounts r
         ,prrTotal  =styleAmounts styles $ prrTotal r
         ,prrAverage=styleAmounts styles $ prrAverage r
         }

    prrShowDebug :: PeriodicReportRow DisplayName MixedAmount -> String
    prrShowDebug :: PeriodicReportRow DisplayName MixedAmount -> String
    prrShowDebug (PeriodicReportRow DisplayName
    dname [MixedAmount]
    amts MixedAmount
    _tot MixedAmount
    _avg) =
      [String] -> String
    unwords [
        CommoditySymbol -> String
    T.unpack (CommoditySymbol -> String) -> CommoditySymbol -> String
    forall a b. (a -> b) -> a -> b
    $ DisplayName -> CommoditySymbol
    displayFull DisplayName
    dname,
        String
    "",
        String -> [String] -> String
    forall a. [a] -> [[a]] -> [a]
    intercalate String
    " | " ([String] -> String) -> [String] -> String
    forall a b. (a -> b) -> a -> b
    $ (MixedAmount -> String) -> [MixedAmount] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map MixedAmount -> String
    showMixedAmount [MixedAmount]
    amts
        ]

    -- | Add two 'PeriodicReportRows', preserving the name of the first.
    prrAdd :: Semigroup b => PeriodicReportRow a b -> PeriodicReportRow a b -> PeriodicReportRow a b
    prrAdd :: forall b a.
    Semigroup b =>
    PeriodicReportRow a b
    -> PeriodicReportRow a b -> PeriodicReportRow a b
    prrAdd (PeriodicReportRow a
    n1 [b]
    amts1 b
    t1 b
    a1) (PeriodicReportRow a
    _ [b]
    amts2 b
    t2 b
    a2) =
        a -> [b] -> b -> b -> PeriodicReportRow a b
    forall a b. a -> [b] -> b -> b -> PeriodicReportRow a b
    PeriodicReportRow a
    n1 ((b -> b -> b) -> [b] -> [b] -> [b]
    forall a. (a -> a -> a) -> [a] -> [a] -> [a]
    zipWithPadded b -> b -> b
    forall a. Semigroup a => a -> a -> a
    (<>) [b]
    amts1 [b]
    amts2) (b
    t1 b -> b -> b
    forall a. Semigroup a => a -> a -> a
    <> b
    t2) (b
    a1 b -> b -> b
    forall a. Semigroup a => a -> a -> a
    <> b
    a2)

    -- | Version of 'zipWith' which will not end on the shortest list, but will copy the rest of the longer list.
    zipWithPadded :: (a -> a -> a) -> [a] -> [a] -> [a]
    zipWithPadded :: forall a. (a -> a -> a) -> [a] -> [a] -> [a]
    zipWithPadded a -> a -> a
    f (a
    a:[a]
    as) (a
    b:[a]
    bs) = a -> a -> a
    f a
    a a
    b a -> [a] -> [a]
    forall a. a -> [a] -> [a]
    : (a -> a -> a) -> [a] -> [a] -> [a]
    forall a. (a -> a -> a) -> [a] -> [a] -> [a]
    zipWithPadded a -> a -> a
    f [a]
    as [a]
    bs
    zipWithPadded a -> a -> a
    _ [a]
    as     []     = [a]
    as
    zipWithPadded a -> a -> a
    _ []     [a]
    bs     = [a]
    bs

    -- | Figure out the overall date span of a PeriodicReport
    periodicReportSpan :: PeriodicReport a b -> DateSpan
    periodicReportSpan :: forall a b. PeriodicReport a b -> DateSpan
    periodicReportSpan (PeriodicReport [DateSpan]
    colspans [PeriodicReportRow a b]
    _ PeriodicReportRow () b
    _) =
      case [DateSpan]
    colspans of
        []  -> Maybe EFDay -> Maybe EFDay -> DateSpan
    DateSpan Maybe EFDay
    forall a. Maybe a
    Nothing Maybe EFDay
    forall a. Maybe a
    Nothing
        DateSpan
    s:[DateSpan]
    _ -> Maybe EFDay -> Maybe EFDay -> DateSpan
    DateSpan (Day -> EFDay
    Exact (Day -> EFDay) -> Maybe Day -> Maybe EFDay
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> DateSpan -> Maybe Day
    spanStart DateSpan
    s) (Day -> EFDay
    Exact (Day -> EFDay) -> Maybe Day -> Maybe EFDay
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> DateSpan -> Maybe Day
    spanEnd ([DateSpan] -> DateSpan
    forall a. HasCallStack => [a] -> a
    last [DateSpan]
    colspans))

    -- | Map a function over the row names.
    prMapName :: (a -> b) -> PeriodicReport a c -> PeriodicReport b c
    prMapName :: forall a b c. (a -> b) -> PeriodicReport a c -> PeriodicReport b c
    prMapName a -> b
    f PeriodicReport a c
    report = PeriodicReport a c
    report{prRows = map (prrMapName f) $ prRows report}

    -- | Map a function over the row names, possibly discarding some.
    prMapMaybeName :: (a -> Maybe b) -> PeriodicReport a c -> PeriodicReport b c
    prMapMaybeName :: forall a b c.
    (a -> Maybe b) -> PeriodicReport a c -> PeriodicReport b c
    prMapMaybeName a -> Maybe b
    f PeriodicReport a c
    report = PeriodicReport a c
    report{prRows = mapMaybe (prrMapMaybeName f) $ prRows report}

    -- | Map a function over the row names of the PeriodicReportRow.
    prrMapName :: (a -> b) -> PeriodicReportRow a c -> PeriodicReportRow b c
    prrMapName :: forall a b c.
    (a -> b) -> PeriodicReportRow a c -> PeriodicReportRow b c
    prrMapName a -> b
    f PeriodicReportRow a c
    row = PeriodicReportRow a c
    row{prrName = f $ prrName row}

    -- | Map maybe a function over the row names of the PeriodicReportRow.
    prrMapMaybeName :: (a -> Maybe b) -> PeriodicReportRow a c -> Maybe (PeriodicReportRow b c)
    prrMapMaybeName :: forall a b c.
    (a -> Maybe b)
    -> PeriodicReportRow a c -> Maybe (PeriodicReportRow b c)
    prrMapMaybeName a -> Maybe b
    f PeriodicReportRow a c
    row = case a -> Maybe b
    f (a -> Maybe b) -> a -> Maybe b
    forall a b. (a -> b) -> a -> b
    $ PeriodicReportRow a c -> a
    forall a b. PeriodicReportRow a b -> a
    prrName PeriodicReportRow a c
    row of
        Maybe b
    Nothing -> Maybe (PeriodicReportRow b c)
    forall a. Maybe a
    Nothing
        Just b
    a  -> PeriodicReportRow b c -> Maybe (PeriodicReportRow b c)
    forall a. a -> Maybe a
    Just PeriodicReportRow a c
    row{prrName = a}

    -- | A compound balance report has:
    --
    -- * an overall title
    --
    -- * the period (date span) of each column
    --
    -- * one or more named, normal-positive multi balance reports,
    --   with columns corresponding to the above, and a flag indicating
    --   whether they increased or decreased the overall totals
    --
    -- * a list of overall totals for each column, and their grand total and average
    --
    -- It is used in compound balance report commands like balancesheet,
    -- cashflow and incomestatement.
    data CompoundPeriodicReport a b = CompoundPeriodicReport
      { forall a b. CompoundPeriodicReport a b -> CommoditySymbol
    cbrTitle      :: Text
      , forall a b. CompoundPeriodicReport a b -> [DateSpan]
    cbrDates      :: [DateSpan]
      , forall a b.
    CompoundPeriodicReport a b
    -> [(CommoditySymbol, PeriodicReport a b, Bool)]
    cbrSubreports :: [(Text, PeriodicReport a b, Bool)]
      , forall a b. CompoundPeriodicReport a b -> PeriodicReportRow () b
    cbrTotals     :: PeriodicReportRow () b
      } deriving (Int -> CompoundPeriodicReport a b -> ShowS
    [CompoundPeriodicReport a b] -> ShowS
    CompoundPeriodicReport a b -> String
    (Int -> CompoundPeriodicReport a b -> ShowS)
    -> (CompoundPeriodicReport a b -> String)
    -> ([CompoundPeriodicReport a b] -> ShowS)
    -> Show (CompoundPeriodicReport a b)
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    forall a b.
    (Show a, Show b) =>
    Int -> CompoundPeriodicReport a b -> ShowS
    forall a b.
    (Show a, Show b) =>
    [CompoundPeriodicReport a b] -> ShowS
    forall a b.
    (Show a, Show b) =>
    CompoundPeriodicReport a b -> String
    $cshowsPrec :: forall a b.
    (Show a, Show b) =>
    Int -> CompoundPeriodicReport a b -> ShowS
    showsPrec :: Int -> CompoundPeriodicReport a b -> ShowS
    $cshow :: forall a b.
    (Show a, Show b) =>
    CompoundPeriodicReport a b -> String
    show :: CompoundPeriodicReport a b -> String
    $cshowList :: forall a b.
    (Show a, Show b) =>
    [CompoundPeriodicReport a b] -> ShowS
    showList :: [CompoundPeriodicReport a b] -> ShowS
    Show, (forall a b.
     (a -> b)
     -> CompoundPeriodicReport a a -> CompoundPeriodicReport a b)
    -> (forall a b.
        a -> CompoundPeriodicReport a b -> CompoundPeriodicReport a a)
    -> Functor (CompoundPeriodicReport a)
    forall a b.
    a -> CompoundPeriodicReport a b -> CompoundPeriodicReport a a
    forall a b.
    (a -> b)
    -> CompoundPeriodicReport a a -> CompoundPeriodicReport a b
    forall a a b.
    a -> CompoundPeriodicReport a b -> CompoundPeriodicReport a a
    forall a a b.
    (a -> b)
    -> CompoundPeriodicReport a a -> CompoundPeriodicReport a b
    forall (f :: * -> *).
    (forall a b. (a -> b) -> f a -> f b)
    -> (forall a b. a -> f b -> f a) -> Functor f
    $cfmap :: forall a a b.
    (a -> b)
    -> CompoundPeriodicReport a a -> CompoundPeriodicReport a b
    fmap :: forall a b.
    (a -> b)
    -> CompoundPeriodicReport a a -> CompoundPeriodicReport a b
    $c<$ :: forall a a b.
    a -> CompoundPeriodicReport a b -> CompoundPeriodicReport a a
    <$ :: forall a b.
    a -> CompoundPeriodicReport a b -> CompoundPeriodicReport a a
    Functor, (forall x.
     CompoundPeriodicReport a b -> Rep (CompoundPeriodicReport a b) x)
    -> (forall x.
        Rep (CompoundPeriodicReport a b) x -> CompoundPeriodicReport a b)
    -> Generic (CompoundPeriodicReport a b)
    forall x.
    Rep (CompoundPeriodicReport a b) x -> CompoundPeriodicReport a b
    forall x.
    CompoundPeriodicReport a b -> Rep (CompoundPeriodicReport a b) x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    forall a b x.
    Rep (CompoundPeriodicReport a b) x -> CompoundPeriodicReport a b
    forall a b x.
    CompoundPeriodicReport a b -> Rep (CompoundPeriodicReport a b) x
    $cfrom :: forall a b x.
    CompoundPeriodicReport a b -> Rep (CompoundPeriodicReport a b) x
    from :: forall x.
    CompoundPeriodicReport a b -> Rep (CompoundPeriodicReport a b) x
    $cto :: forall a b x.
    Rep (CompoundPeriodicReport a b) x -> CompoundPeriodicReport a b
    to :: forall x.
    Rep (CompoundPeriodicReport a b) x -> CompoundPeriodicReport a b
    Generic, [CompoundPeriodicReport a b] -> Value
    [CompoundPeriodicReport a b] -> Encoding
    CompoundPeriodicReport a b -> Bool
    CompoundPeriodicReport a b -> Value
    CompoundPeriodicReport a b -> Encoding
    (CompoundPeriodicReport a b -> Value)
    -> (CompoundPeriodicReport a b -> Encoding)
    -> ([CompoundPeriodicReport a b] -> Value)
    -> ([CompoundPeriodicReport a b] -> Encoding)
    -> (CompoundPeriodicReport a b -> Bool)
    -> ToJSON (CompoundPeriodicReport a b)
    forall a.
    (a -> Value)
    -> (a -> Encoding)
    -> ([a] -> Value)
    -> ([a] -> Encoding)
    -> (a -> Bool)
    -> ToJSON a
    forall a b.
    (ToJSON b, ToJSON a) =>
    [CompoundPeriodicReport a b] -> Value
    forall a b.
    (ToJSON b, ToJSON a) =>
    [CompoundPeriodicReport a b] -> Encoding
    forall a b.
    (ToJSON b, ToJSON a) =>
    CompoundPeriodicReport a b -> Bool
    forall a b.
    (ToJSON b, ToJSON a) =>
    CompoundPeriodicReport a b -> Value
    forall a b.
    (ToJSON b, ToJSON a) =>
    CompoundPeriodicReport a b -> Encoding
    $ctoJSON :: forall a b.
    (ToJSON b, ToJSON a) =>
    CompoundPeriodicReport a b -> Value
    toJSON :: CompoundPeriodicReport a b -> Value
    $ctoEncoding :: forall a b.
    (ToJSON b, ToJSON a) =>
    CompoundPeriodicReport a b -> Encoding
    toEncoding :: CompoundPeriodicReport a b -> Encoding
    $ctoJSONList :: forall a b.
    (ToJSON b, ToJSON a) =>
    [CompoundPeriodicReport a b] -> Value
    toJSONList :: [CompoundPeriodicReport a b] -> Value
    $ctoEncodingList :: forall a b.
    (ToJSON b, ToJSON a) =>
    [CompoundPeriodicReport a b] -> Encoding
    toEncodingList :: [CompoundPeriodicReport a b] -> Encoding
    $comitField :: forall a b.
    (ToJSON b, ToJSON a) =>
    CompoundPeriodicReport a b -> Bool
    omitField :: CompoundPeriodicReport a b -> Bool
    ToJSON)

    instance HasAmounts b => HasAmounts (CompoundPeriodicReport a b) where
      styleAmounts :: Map CommoditySymbol AmountStyle
    -> CompoundPeriodicReport a b -> CompoundPeriodicReport a b
    styleAmounts Map CommoditySymbol AmountStyle
    styles cpr :: CompoundPeriodicReport a b
    cpr@CompoundPeriodicReport{[(CommoditySymbol, PeriodicReport a b, Bool)]
    cbrSubreports :: forall a b.
    CompoundPeriodicReport a b
    -> [(CommoditySymbol, PeriodicReport a b, Bool)]
    cbrSubreports :: [(CommoditySymbol, PeriodicReport a b, Bool)]
    cbrSubreports, PeriodicReportRow () b
    cbrTotals :: forall a b. CompoundPeriodicReport a b -> PeriodicReportRow () b
    cbrTotals :: PeriodicReportRow () b
    cbrTotals} =
        CompoundPeriodicReport a b
    cpr{
            cbrSubreports = styleAmounts styles cbrSubreports
          , cbrTotals     = styleAmounts styles cbrTotals
          }

    instance HasAmounts b => HasAmounts (Text, PeriodicReport a b, Bool) where
      styleAmounts :: Map CommoditySymbol AmountStyle
    -> (CommoditySymbol, PeriodicReport a b, Bool)
    -> (CommoditySymbol, PeriodicReport a b, Bool)
    styleAmounts Map CommoditySymbol AmountStyle
    styles (CommoditySymbol
    a,PeriodicReport a b
    b,Bool
    c) = (CommoditySymbol
    a,Map CommoditySymbol AmountStyle
    -> PeriodicReport a b -> PeriodicReport a b
    forall a. HasAmounts a => Map CommoditySymbol AmountStyle -> a -> a
    styleAmounts Map CommoditySymbol AmountStyle
    styles PeriodicReport a b
    b,Bool
    c)

    -- | Description of one subreport within a compound balance report.
    -- Part of a "CompoundBalanceCommandSpec", but also used in hledger-lib.
    data CBCSubreportSpec a = CBCSubreportSpec
      { forall a. CBCSubreportSpec a -> CommoditySymbol
    cbcsubreporttitle          :: Text                      -- ^ The title to use for the subreport
      , forall a. CBCSubreportSpec a -> Query
    cbcsubreportquery          :: Query                     -- ^ The Query to use for the subreport
      , forall a. CBCSubreportSpec a -> ReportOpts -> ReportOpts
    cbcsubreportoptions        :: ReportOpts -> ReportOpts  -- ^ A function to transform the ReportOpts used to produce the subreport
      , forall a.
    CBCSubreportSpec a
    -> PeriodicReport DisplayName MixedAmount
    -> PeriodicReport a MixedAmount
    cbcsubreporttransform      :: PeriodicReport DisplayName MixedAmount -> PeriodicReport a MixedAmount  -- ^ A function to transform the result of the subreport
      , forall a. CBCSubreportSpec a -> Bool
    cbcsubreportincreasestotal :: Bool                      -- ^ Whether the subreport and overall report total are of the same sign (e.g. Assets are normally
                                                                --   positive in a balance sheet report, as is the overall total. Liabilities are normally of the
                                                                --   opposite sign.)
      }

    -- | The number of indentation steps with which to display a report item.
    -- 0 means no indentation. 1 means one indent step, which is normally rendered
    -- as two spaces in text output, or two no-break spaces in csv/html output.
    type NumberOfIndents = Int

    -- | A full name, display name, and indent level for an account.
    data DisplayName = DisplayName
        { DisplayName -> CommoditySymbol
    displayFull   :: AccountName
        , DisplayName -> CommoditySymbol
    displayName   :: AccountName
        , DisplayName -> Int
    displayIndent :: NumberOfIndents
        } deriving (Int -> DisplayName -> ShowS
    [DisplayName] -> ShowS
    DisplayName -> String
    (Int -> DisplayName -> ShowS)
    -> (DisplayName -> String)
    -> ([DisplayName] -> ShowS)
    -> Show DisplayName
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> DisplayName -> ShowS
    showsPrec :: Int -> DisplayName -> ShowS
    $cshow :: DisplayName -> String
    show :: DisplayName -> String
    $cshowList :: [DisplayName] -> ShowS
    showList :: [DisplayName] -> ShowS
    Show, DisplayName -> DisplayName -> Bool
    (DisplayName -> DisplayName -> Bool)
    -> (DisplayName -> DisplayName -> Bool) -> Eq DisplayName
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: DisplayName -> DisplayName -> Bool
    == :: DisplayName -> DisplayName -> Bool
    $c/= :: DisplayName -> DisplayName -> Bool
    /= :: DisplayName -> DisplayName -> Bool
    Eq, Eq DisplayName
    Eq DisplayName =>
    (DisplayName -> DisplayName -> Ordering)
    -> (DisplayName -> DisplayName -> Bool)
    -> (DisplayName -> DisplayName -> Bool)
    -> (DisplayName -> DisplayName -> Bool)
    -> (DisplayName -> DisplayName -> Bool)
    -> (DisplayName -> DisplayName -> DisplayName)
    -> (DisplayName -> DisplayName -> DisplayName)
    -> Ord DisplayName
    DisplayName -> DisplayName -> Bool
    DisplayName -> DisplayName -> Ordering
    DisplayName -> DisplayName -> DisplayName
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: DisplayName -> DisplayName -> Ordering
    compare :: DisplayName -> DisplayName -> Ordering
    $c< :: DisplayName -> DisplayName -> Bool
    < :: DisplayName -> DisplayName -> Bool
    $c<= :: DisplayName -> DisplayName -> Bool
    <= :: DisplayName -> DisplayName -> Bool
    $c> :: DisplayName -> DisplayName -> Bool
    > :: DisplayName -> DisplayName -> Bool
    $c>= :: DisplayName -> DisplayName -> Bool
    >= :: DisplayName -> DisplayName -> Bool
    $cmax :: DisplayName -> DisplayName -> DisplayName
    max :: DisplayName -> DisplayName -> DisplayName
    $cmin :: DisplayName -> DisplayName -> DisplayName
    min :: DisplayName -> DisplayName -> DisplayName
    Ord)

    instance ToJSON DisplayName where
        toJSON :: DisplayName -> Value
    toJSON = CommoditySymbol -> Value
    forall a. ToJSON a => a -> Value
    toJSON (CommoditySymbol -> Value)
    -> (DisplayName -> CommoditySymbol) -> DisplayName -> Value
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . DisplayName -> CommoditySymbol
    displayFull
        toEncoding :: DisplayName -> Encoding
    toEncoding = CommoditySymbol -> Encoding
    forall a. ToJSON a => a -> Encoding
    toEncoding (CommoditySymbol -> Encoding)
    -> (DisplayName -> CommoditySymbol) -> DisplayName -> Encoding
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . DisplayName -> CommoditySymbol
    displayFull

    -- | Construct a display name for a list report, where full names are shown unindented.
    flatDisplayName :: AccountName -> DisplayName
    flatDisplayName :: CommoditySymbol -> DisplayName
    flatDisplayName CommoditySymbol
    a = CommoditySymbol -> CommoditySymbol -> Int -> DisplayName
    DisplayName CommoditySymbol
    a CommoditySymbol
    a Int
    0

    -- | Construct a display name for a tree report, where leaf names (possibly prefixed by
    -- boring parents) are shown indented).
    treeDisplayName :: AccountName -> DisplayName
    treeDisplayName :: CommoditySymbol -> DisplayName
    treeDisplayName CommoditySymbol
    a = CommoditySymbol -> CommoditySymbol -> Int -> DisplayName
    DisplayName CommoditySymbol
    a (CommoditySymbol -> CommoditySymbol
    accountLeafName CommoditySymbol
    a) (CommoditySymbol -> Int
    accountNameLevel CommoditySymbol
    a)

    -- | Get the full canonical account name from a PeriodicReportRow containing a DisplayName.
    prrFullName :: PeriodicReportRow DisplayName a -> AccountName
    prrFullName :: forall a. PeriodicReportRow DisplayName a -> CommoditySymbol
    prrFullName = DisplayName -> CommoditySymbol
    displayFull (DisplayName -> CommoditySymbol)
    -> (PeriodicReportRow DisplayName a -> DisplayName)
    -> PeriodicReportRow DisplayName a
    -> CommoditySymbol
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . PeriodicReportRow DisplayName a -> DisplayName
    forall a b. PeriodicReportRow a b -> a
    prrName

    -- | Get the account display name from a PeriodicReportRow containing a DisplayName.
    prrDisplayName :: PeriodicReportRow DisplayName a -> AccountName
    prrDisplayName :: forall a. PeriodicReportRow DisplayName a -> CommoditySymbol
    prrDisplayName = DisplayName -> CommoditySymbol
    displayName (DisplayName -> CommoditySymbol)
    -> (PeriodicReportRow DisplayName a -> DisplayName)
    -> PeriodicReportRow DisplayName a
    -> CommoditySymbol
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . PeriodicReportRow DisplayName a -> DisplayName
    forall a b. PeriodicReportRow a b -> a
    prrName

    -- | Get the indent level from a PeriodicReportRow containing a DisplayName.
    prrIndent :: PeriodicReportRow DisplayName a -> Int
    prrIndent :: forall a. PeriodicReportRow DisplayName a -> Int
    prrIndent = DisplayName -> Int
    displayIndent (DisplayName -> Int)
    -> (PeriodicReportRow DisplayName a -> DisplayName)
    -> PeriodicReportRow DisplayName a
    -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . PeriodicReportRow DisplayName a -> DisplayName
    forall a b. PeriodicReportRow a b -> a
    prrName