module Data.Currency.Pretty
(
prettyPrint
, prettyPrintWith
, PrettyConfig(..)
, defaultConfig
, module Data.Currency.Amounts
) where
import Data.Currency.Amounts
import Data.Monoid ((<>))
import Text.Printf
prettyPrint :: (Currency c) => Amount c -> String
prettyPrint = prettyPrintWith defaultConfig
prettyPrintWith :: (Currency c) => PrettyConfig -> Amount c -> String
prettyPrintWith cnf (Amount currency amount) =
prefixSymbol currency cnf
$ prefixCode currency cnf
$ changeDecimalSep cnf
$ largeAmountSeparate cnf
$ toDecimalString currency cnf amount
prefixSymbol :: (Currency c) => c -> PrettyConfig -> String -> String
prefixSymbol currency cnf val
| useCurrencySymbol cnf = symbol currency <> " " <> val
| otherwise = val
prefixCode :: (Currency c) => c -> PrettyConfig -> String -> String
prefixCode currency cnf val
| useCurrencySymbol cnf = val
| suffixIsoCode cnf = val <> " " <> isoCode currency
| otherwise = isoCode currency <> " " <> val
changeDecimalSep :: PrettyConfig -> String -> String
changeDecimalSep cnf = replaceFst '.' (decimalSeparator cnf)
where
replaceFst :: Char -> Char -> String -> String
replaceFst _ _ [] = []
replaceFst c c' (s:ss)
| s == c = c' : ss
| otherwise = s : replaceFst c c' ss
largeAmountSeparate :: PrettyConfig -> String -> String
largeAmountSeparate cnf amount
| compactFourDigitAmounts cnf = if length integer <= 4
then sign mSign unsignedAmount
else separatedAmount
| otherwise = separatedAmount
where
(mSign, unsignedAmount) = unSign amount
(integer, decimal) = span (/= '.') unsignedAmount
separated = reverse $ intersperseN 3 (largeAmountSeparator cnf) $ reverse integer
separatedAmount = sign mSign $ separated ++ decimal
toDecimalString :: (Currency c) => c -> PrettyConfig -> Double -> String
toDecimalString currency cnf amount
| showDecimals cnf = printf format amount
| otherwise = takeWhile (/= '.') $ printf "%.1f" amount
where format = "%." <> show (decimalDigits currency) <> "f"
intersperseN :: Eq a => Int -> a -> [a] -> [a]
intersperseN n s ss
| null remainder = ss
| otherwise = (chunk ++ [s]) ++ intersperseN n s remainder
where (chunk, remainder) = splitAt n ss
sign :: Maybe Char -> String -> String
sign (Just s) a = s : a
sign Nothing a = a
unSign :: String -> (Maybe Char, String)
unSign ('-':s) = (Just '-', s)
unSign ('+':s) = (Just '+', s)
unSign s = (Nothing, s)
data PrettyConfig = PrettyConfig
{ showDecimals :: Bool
, compactFourDigitAmounts :: Bool
, useCurrencySymbol :: Bool
, suffixIsoCode :: Bool
, largeAmountSeparator :: Char
, decimalSeparator :: Char
} deriving (Show)
defaultConfig :: PrettyConfig
defaultConfig = PrettyConfig
{ showDecimals = True
, compactFourDigitAmounts = True
, useCurrencySymbol = False
, suffixIsoCode = False
, largeAmountSeparator = ','
, decimalSeparator = '.'
}