-- 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 NoRebindableSyntax #-}
{-# LANGUAGE OverloadedStrings #-}

module Duckling.Numeral.GA.Rules
  ( rules
  ) where

import Data.HashMap.Strict (HashMap)
import Data.String
import Data.Text (Text)
import Prelude
import qualified Data.HashMap.Strict as HashMap
import qualified Data.Text as Text

import Duckling.Dimensions.Types
import Duckling.Numeral.Helpers
import Duckling.Numeral.Types (NumeralData (..))
import Duckling.Regex.Types
import Duckling.Types
import qualified Duckling.Numeral.Types as TNumeral

ruleNumeralsPrefixWithNegativeOrMinus :: Rule
ruleNumeralsPrefixWithNegativeOrMinus :: Rule
ruleNumeralsPrefixWithNegativeOrMinus = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"numbers prefix with -, negative or minus"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"-|m(í|i)neas(\\sa)?"
    , Predicate -> PatternItem
Predicate Predicate
isPositive
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token
_:
       Token Dimension a
Numeral NumeralData{TNumeral.value = v}:
       [Token]
_) -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v Double -> Double -> Double
forall a. Num a => a -> a -> a
* (-Double
1)
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

oneToTenMap :: HashMap Text Integer
oneToTenMap :: HashMap Text Integer
oneToTenMap = [(Text, Integer)] -> HashMap Text Integer
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList
  [ (Text
"aon", Integer
1)
  , (Text
"dha", Integer
2)
  , (Text
"dhá", Integer
2)
  , (Text
"trí", Integer
3)
  , (Text
"tri", Integer
3)
  , (Text
"ceithre", Integer
4)
  , (Text
"cuig", Integer
5)
  , (Text
"cúig", Integer
5)
  , (Text
"sé", Integer
6)
  , (Text
"se", Integer
6)
  , (Text
"seacht", Integer
7)
  , (Text
"ocht", Integer
8)
  , (Text
"naoi", Integer
9)
  , (Text
"deich", Integer
10)
  ]

ruleNumerals2 :: Rule
ruleNumerals2 :: Rule
ruleNumerals2 = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"numbers, 1-10"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(aon|dh(á|a)|tr(í|i)|ceithre|c(ú|u)ig|seacht|s(é|e)|ocht|naoi|deich)"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
RegexMatch (GroupMatch (match:_)):[Token]
_) ->
        Text -> HashMap Text Integer -> Maybe Integer
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup (Text -> Text
Text.toLower Text
match) HashMap Text Integer
oneToTenMap Maybe Integer -> (Integer -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Integer -> Maybe Token
integer
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleDecimalWithThousandsSeparator :: Rule
ruleDecimalWithThousandsSeparator :: Rule
ruleDecimalWithThousandsSeparator = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"decimal with thousands separator"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(\\d+(,\\d\\d\\d)+\\.\\d+)"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
RegexMatch (GroupMatch (match:_)):[Token]
_) ->
        Text -> Maybe Double
parseDouble (Text -> Text -> Text -> Text
Text.replace Text
"," Text
Text.empty Text
match) Maybe Double -> (Double -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Double -> Maybe Token
double
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleDecimalNumeral :: Rule
ruleDecimalNumeral :: Rule
ruleDecimalNumeral = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"decimal number"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(\\d*\\.\\d+)"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
RegexMatch (GroupMatch (match:_)):[Token]
_) -> Bool -> Text -> Maybe Token
parseDecimal Bool
True Text
match
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleDag :: Rule
ruleDag :: Rule
ruleDag = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"déag"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"d(é|e)ag"
    ]
  , prod :: Production
prod = \[Token]
_ -> Integer -> Maybe Token
integer Integer
10
  }

ruleNumeralsSuffixesKMG :: Rule
ruleNumeralsSuffixesKMG :: Rule
ruleNumeralsSuffixesKMG = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"numbers suffixes (K, M, G)"
  , pattern :: Pattern
pattern =
    [ Dimension NumeralData -> PatternItem
forall a. Typeable a => Dimension a -> PatternItem
dimension Dimension NumeralData
Numeral
    , String -> PatternItem
regex String
"([kmg])(?=[\\W\\$€]|$)"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
Numeral NumeralData{TNumeral.value = v}:
       Token Dimension a
RegexMatch (GroupMatch (match:_)):
       [Token]
_) -> case Text -> Text
Text.toLower Text
match of
         Text
"k" -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
1e3
         Text
"m" -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
1e6
         Text
"g" -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
1e9
         Text
_   -> Maybe Token
forall a. Maybe a
Nothing
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

oldVigNumeralsSMap :: HashMap Text Integer
oldVigNumeralsSMap :: HashMap Text Integer
oldVigNumeralsSMap = [(Text, Integer)] -> HashMap Text Integer
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList
  [ (Text
"dá fhichead", Integer
40)
  , (Text
"da fhichead", Integer
40)
  , (Text
"dhá fhichead", Integer
40)
  , (Text
"dha fhichead", Integer
40)
  , (Text
"trí fichid", Integer
60)
  , (Text
"tri fichid", Integer
60)
  , (Text
"ceithre fichid", Integer
80)
  ]

ruleOldVigesimalNumeralsS :: Rule
ruleOldVigesimalNumeralsS :: Rule
ruleOldVigesimalNumeralsS = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"old vigesimal numbers, 20s"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(d[ée]ag )?is (dh?(á|a) fhichead|tr(í|i) fichid|ceithre fichid)"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
RegexMatch (GroupMatch (ten:match:_)):[Token]
_) -> do
        Integer
x <- Text -> HashMap Text Integer -> Maybe Integer
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup (Text -> Text
Text.toLower Text
match) HashMap Text Integer
oldVigNumeralsSMap
        Integer -> Maybe Token
integer (Integer -> Maybe Token) -> Integer -> Maybe Token
forall a b. (a -> b) -> a -> b
$ if Text -> Bool
Text.null Text
ten then Integer
x else Integer
x Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
10
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleOldVigesimalFiche :: Rule
ruleOldVigesimalFiche :: Rule
ruleOldVigesimalFiche = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"old vigesimal 20 + 10"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"d[ée]ag is fiche"
    ]
  , prod :: Production
prod = Maybe Token -> Production
forall a b. a -> b -> a
const (Maybe Token -> Production) -> Maybe Token -> Production
forall a b. (a -> b) -> a -> b
$ Integer -> Maybe Token
integer Integer
30
  }

ruleAmhin :: Rule
ruleAmhin :: Rule
ruleAmhin = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"amháin"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"amh(á|a)in"
    ]
  , prod :: Production
prod = \[Token]
_ -> Integer -> Maybe Token
integer Integer
1
  }

twentyToNinetyMap :: HashMap Text Integer
twentyToNinetyMap :: HashMap Text Integer
twentyToNinetyMap = [(Text, Integer)] -> HashMap Text Integer
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList
 [ (Text
"fiche", Integer
20)
 , (Text
"triocha", Integer
30)
 , (Text
"tríocha", Integer
30)
 , (Text
"daichead", Integer
40)
 , (Text
"caoga", Integer
50)
 , (Text
"seasca", Integer
60)
 , (Text
"seachto", Integer
70)
 , (Text
"seachtó", Integer
70)
 , (Text
"ochto", Integer
80)
 , (Text
"ochtó", Integer
80)
 , (Text
"nócha", Integer
90)
 , (Text
"nocha", Integer
90)
 ]

ruleNumerals :: Rule
ruleNumerals :: Rule
ruleNumerals = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"numbers, 20-90"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(fiche|tr(í|i)ocha|daichead|caoga|seasca|seacht(ó|o)|ocht(ó|o)|n(ó|o)cha)"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
RegexMatch (GroupMatch (match:_)):[Token]
_) ->
        Text -> HashMap Text Integer -> Maybe Integer
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup (Text -> Text
Text.toLower Text
match) HashMap Text Integer
twentyToNinetyMap Maybe Integer -> (Integer -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Integer -> Maybe Token
integer
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleIntegerWithThousandsSeparator :: Rule
ruleIntegerWithThousandsSeparator :: Rule
ruleIntegerWithThousandsSeparator = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer with thousands separator ,"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(\\d{1,3}(,\\d\\d\\d){1,5})"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
RegexMatch (GroupMatch (match:_)):[Token]
_) ->
        Text -> Maybe Double
parseDouble (Text -> Text -> Text -> Text
Text.replace Text
"," Text
Text.empty Text
match) Maybe Double -> (Double -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Double -> Maybe Token
double
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

countNumeralsMap :: HashMap Text Integer
countNumeralsMap :: HashMap Text Integer
countNumeralsMap = [(Text, Integer)] -> HashMap Text Integer
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList
  [ (Text
"naid", Integer
0)
  , (Text
"náid", Integer
0)
  , (Text
"haon", Integer
1)
  , (Text
"dó", Integer
2)
  , (Text
"do", Integer
2)
  , (Text
"trí", Integer
3)
  , (Text
"tri", Integer
3)
  , (Text
"ceathair", Integer
4)
  , (Text
"cuig", Integer
5)
  , (Text
"cúig", Integer
5)
  , (Text
"sé", Integer
6)
  , (Text
"se", Integer
6)
  , (Text
"seacht", Integer
7)
  , (Text
"hocht", Integer
8)
  , (Text
"naoi", Integer
9)
  , (Text
"deich", Integer
10)
  ]

ruleCountNumerals :: Rule
ruleCountNumerals :: Rule
ruleCountNumerals = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"count numbers"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"a (n(á|a)id|haon|d(ó|o)|tr(í|i)|ceathair|c(ú|u)ig|s(é|e)|seacht|hocht|naoi|deich)"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
RegexMatch (GroupMatch (match:_)):[Token]
_) ->
        Text -> HashMap Text Integer -> Maybe Integer
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup (Text -> Text
Text.toLower Text
match) HashMap Text Integer
countNumeralsMap Maybe Integer -> (Integer -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Integer -> Maybe Token
integer
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

rules :: [Rule]
rules :: [Rule]
rules =
  [ Rule
ruleAmhin
  , Rule
ruleCountNumerals
  , Rule
ruleDag
  , Rule
ruleDecimalNumeral
  , Rule
ruleDecimalWithThousandsSeparator
  , Rule
ruleIntegerWithThousandsSeparator
  , Rule
ruleNumerals
  , Rule
ruleNumerals2
  , Rule
ruleNumeralsPrefixWithNegativeOrMinus
  , Rule
ruleNumeralsSuffixesKMG
  , Rule
ruleOldVigesimalNumeralsS
  , Rule
ruleOldVigesimalFiche
  ]