{-|

A 'Commodity' is a symbol representing a currency or some other kind of
thing we are tracking, and some display preferences that tell how to
display 'Amount's of the commodity - is the symbol on the left or right,
are thousands separated by comma, significant decimal places and so on.

-}

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE CPP #-}

module Hledger.Data.Commodity
where
import Data.Char (isDigit)
import Data.List
import Data.Maybe (fromMaybe)
#if !(MIN_VERSION_base(4,11,0))
import Data.Monoid
#endif
import qualified Data.Text as T
-- import qualified Data.Map as M

import Hledger.Data.Types
import Hledger.Utils


-- characters that may not be used in a non-quoted commodity symbol
nonsimplecommoditychars :: String
nonsimplecommoditychars = "0123456789-+.@*;\n \"{}=" :: String

isNonsimpleCommodityChar :: Char -> Bool
isNonsimpleCommodityChar :: Char -> Bool
isNonsimpleCommodityChar c :: Char
c = Char -> Bool
isDigit Char
c Bool -> Bool -> Bool
|| Char
c Char -> Text -> Bool
`textElem` Text
otherChars
 where
   otherChars :: Text
otherChars = "-+.@*;\n \"{}=" :: T.Text
   textElem :: Char -> Text -> Bool
textElem = (Char -> Bool) -> Text -> Bool
T.any ((Char -> Bool) -> Text -> Bool)
-> (Char -> Char -> Bool) -> Char -> Text -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
(==)

quoteCommoditySymbolIfNeeded :: Text -> Text
quoteCommoditySymbolIfNeeded s :: Text
s | (Char -> Bool) -> Text -> Bool
T.any (Char -> Bool
isNonsimpleCommodityChar) Text
s = "\"" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
s Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "\""
                               | Bool
otherwise = Text
s

commodity :: String
commodity = ""

-- handy constructors for tests
-- unknown = commodity
-- usd     = "$"
-- eur     = "€"
-- gbp     = "£"
-- hour    = "h"

-- Some sample commodity' names and symbols, for use in tests..
commoditysymbols :: [(String, Text)]
commoditysymbols =
  [("unknown","")
  ,("usd","$")
  ,("eur","€")
  ,("gbp","£")
  ,("hour","h")
  ]

-- | Look up one of the sample commodities' symbol by name.
comm :: String -> CommoditySymbol
comm :: String -> Text
comm name :: String
name = (String, Text) -> Text
forall a b. (a, b) -> b
snd ((String, Text) -> Text) -> (String, Text) -> Text
forall a b. (a -> b) -> a -> b
$ (String, Text) -> Maybe (String, Text) -> (String, Text)
forall a. a -> Maybe a -> a
fromMaybe
              (String -> (String, Text)
forall a. String -> a
error' "commodity lookup failed")
              (((String, Text) -> Bool)
-> [(String, Text)] -> Maybe (String, Text)
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find (\n :: (String, Text)
n -> (String, Text) -> String
forall a b. (a, b) -> a
fst (String, Text)
n String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
name) [(String, Text)]
commoditysymbols)

-- | Find the conversion rate between two commodities. Currently returns 1.
conversionRate :: CommoditySymbol -> CommoditySymbol -> Double
conversionRate :: Text -> Text -> Double
conversionRate _ _ = 1

-- -- | Convert a list of commodities to a map from commodity symbols to
-- -- unique, display-preference-canonicalised commodities.
-- canonicaliseCommodities :: [CommoditySymbol] -> Map.Map String CommoditySymbol
-- canonicaliseCommodities cs =
--     Map.fromList [(s,firstc{precision=maxp}) | s <- symbols,
--                   let cs = commoditymap ! s,
--                   let firstc = head cs,
--                   let maxp = maximum $ map precision cs
--                  ]
--   where
--     commoditymap = Map.fromList [(s, commoditieswithsymbol s) | s <- symbols]
--     commoditieswithsymbol s = filter ((s==) . symbol) cs
--     symbols = nub $ map symbol cs