content: -- Copyright (c) 2016-present, Facebook, Inc.
  -- All rights reserved.
  --
  -- This source code is licensed under the BSD-style license found in the
  -- LICENSE file in the root directory of this source tree.
  
  
  {-# LANGUAGE GADTs #-}
  {-# LANGUAGE OverloadedStrings #-}
  
  module Duckling.AmountOfMoney.Rules
    ( rules
    ) where
  
  import Data.HashMap.Strict (HashMap)
  import Data.Maybe
  import Data.String
  import Data.Text (Text)
  import Prelude
  import qualified Data.HashMap.Strict as HashMap
  import qualified Data.Text as Text
  
  import Duckling.AmountOfMoney.Helpers
  import Duckling.AmountOfMoney.Types (Currency(..), AmountOfMoneyData (..))
  import Duckling.Dimensions.Types
  import Duckling.Numeral.Helpers (isPositive)
  import Duckling.Numeral.Types (NumeralData (..))
  import Duckling.Regex.Types
  import Duckling.Types
  import qualified Duckling.AmountOfMoney.Types as TAmountOfMoney
  import qualified Duckling.Numeral.Types as TNumeral
  
  currencies :: HashMap Text Currency
  currencies = HashMap.fromList
    [ ("aed", AED)
    , ("aud", AUD)
    , ("bgn", BGN)
    , ("brl", BRL)
    , ("byn", BYN)
    , ("cad", CAD)
    , ("¢", Cent)
    , ("c", Cent)
    , ("chf", CHF)
    , ("cny", CNY)
    , ("czk", CZK)
    , ("rmb", CNY)
    , ("yuan", CNY)
    , ("$", Dollar)
    , ("dinar", Dinar)
    , ("dinars", Dinar)
    , ("dkk", DKK)
    , ("dollar", Dollar)
    , ("dollars", Dollar)
    , ("egp", EGP)
    , ("€", EUR)
    , ("eur", EUR)
    , ("euro", EUR)
    , ("euros", EUR)
    , ("eurs", EUR)
    , ("€ur", EUR)
    , ("€uro", EUR)
    , ("€uros", EUR)
    , ("€urs", EUR)
    , ("gbp", GBP)
    , ("gel", GEL)
    , ("hkd", HKD)
    , ("hrk", HRK)
    , ("idr", IDR)
    , ("ils", ILS)
    , ("₪", ILS)
    , ("nis", ILS)
    , ("inr", INR)
    , ("iqd", IQD)
    , ("rs", INR)
    , ("rs.", INR)
    , ("rupee", INR)
    , ("rupees", INR)
    , ("jmd", JMD)
    , ("jod", JOD)
    , ("¥", JPY)
    , ("jpy", JPY)
    , ("lari", GEL)
    , ("\x20BE", GEL)
    , ("yen", JPY)
    , ("krw", KRW)
    , ("kwd", KWD)
    , ("lbp", LBP)
    , ("mad", MAD)
    , ("mnt", MNT)
    , ("myr", MYR)
    , ("rm", MYR)
    , ("₮", MNT)
    , ("tugrik", MNT)
    , ("tugriks", MNT)
    , ("nok", NOK)
    , ("nzd", NZD)
    , ("pkr", PKR)
    , ("pln", PLN)
    , ("£", Pound)
    , ("pt", PTS)
    , ("pta", PTS)
    , ("ptas", PTS)
    , ("pts", PTS)
    , ("qar", QAR)
    , ("₽", RUB)
    , ("rial", Rial)
    , ("rials", Rial)
    , ("riyal", Riyal)
    , ("riyals", Riyal)
    , ("ron", RON)
    , ("rub", RUB)
    , ("sar", SAR)
    , ("sek", SEK)
    , ("sgd", SGD)
    , ("shekel", ILS)
    , ("shekels", ILS)
    , ("thb", THB)
    , ("ttd", TTD)
    , ("₴", UAH)
    , ("uah", UAH)
    , ("usd", USD)
    , ("us$", USD)
    , ("vnd", VND)
    , ("zar", ZAR)
    , ("tl", TRY)
    , ("lira", TRY)
    , ("₺", TRY)
    ]
  
  ruleCurrencies :: Rule
  ruleCurrencies = Rule
    { name = "currencies"
    , pattern =
      [ regex "(aed|aud|bgn|brl|byn|¢|cad|chf|cny|c|\\$|dinars?|dkk|dollars?|egp|(e|€)uro?s?|€|gbp|gel|\x20BE|hkd|hrk|idr|ils|₪|inr|iqd|jmd|jod|¥|jpy|lari|krw|kwd|lbp|mad|₮|mnt|tugriks?|myr|rm|nis|nok|nzd|£|pkr|pln|pta?s?|qar|₽|rs\\.?|riy?als?|ron|rub|rupees?|sar|sek|sgb|shekels?|thb|ttd|₴|uah|us(d|\\$)|vnd|yen|yuan|zar|tl|lira|₺)"
      ]
    , prod = \tokens -> case tokens of
        (Token RegexMatch (GroupMatch (match:_)):_) -> do
          c <- HashMap.lookup (Text.toLower match) currencies
          Just . Token AmountOfMoney $ currencyOnly c
        _ -> Nothing
    }
  
  ruleAmountUnit :: Rule
  ruleAmountUnit = Rule
    { name = "<amount> <unit>"
    , pattern =
      [ Predicate isPositive
      , Predicate isCurrencyOnly
      ]
    , prod = \tokens -> case tokens of
        (Token Numeral NumeralData{TNumeral.value = v}:
         Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.currency = c}:
         _) -> Just . Token AmountOfMoney . withValue v $ currencyOnly c
        _ -> Nothing
    }
  
  ruleAmountLatent :: Rule
  ruleAmountLatent = Rule
    { name = "<amount> (latent)"
    , pattern =
      [ Predicate isPositive
      ]
    , prod = \tokens -> case tokens of
        (Token Numeral NumeralData{TNumeral.value = v}:_) ->
          Just . Token AmountOfMoney . mkLatent $ valueOnly v
        _ -> Nothing
    }
  
  rules :: [Rule]
  rules =
    [ ruleAmountUnit
    , ruleAmountLatent
    , ruleCurrencies
    ]
  