-- 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.Numeral.PL.Rules
  ( rules
  ) where

import Data.Maybe
import Data.String
import Prelude
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

ruleSixteen :: Rule
ruleSixteen = Rule
  { name = "sixteen"
  , pattern =
    [ regex "szesna(s|Å›)(tu|cie|toma)"
    ]
  , prod = \_ -> integer 16
  }

ruleFourteen :: Rule
ruleFourteen = Rule
  { name = "fourteen"
  , pattern =
    [ regex "czterna(s|Å›)(tu|cie|toma)"
    ]
  , prod = \_ -> integer 14
  }

ruleTwo :: Rule
ruleTwo = Rule
  { name = "two"
  , pattern =
    [ regex "dw(a|(o|Ã³)(ch|m)|oma|iema|ie)"
    ]
  , prod = \_ -> integer 2
  }

ruleSixty :: Rule
ruleSixty = Rule
  { name = "sixty"
  , pattern =
    [ regex "sze(Å›Ä‡)dziesi(Ä…)t|sze(Å›Ä‡)dziesi(Ä™)ci(u|oma)"
    ]
  , prod = \_ -> integer 60
  }

ruleSeventy :: Rule
ruleSeventy = Rule
  { name = "seventy"
  , pattern =
    [ regex "siedemdziesi((a|Ä…)t|(e|Ä™)ci(u|oma))"
    ]
  , prod = \_ -> integer 70
  }

ruleEighty :: Rule
ruleEighty = Rule
  { name = "eighty"
  , pattern =
    [ regex "osiemdziesi((a|Ä…)t|(e|Ä™)ci(u|oma))"
    ]
  , prod = \_ -> integer 80
  }

ruleNinety :: Rule
ruleNinety = Rule
  { name = "ninety"
  , pattern =
    [ regex "dziewi(e|Ä™)(c|Ä‡)dziesi((a|Ä…)|(e|Ä™))(t|ci(u|oma))"
    ]
  , prod = \_ -> integer 90
  }

ruleIntersectWithAnd :: Rule
ruleIntersectWithAnd = Rule
  { name = "intersect (with and)"
  , pattern =
    [ Predicate hasGrain
    , regex "i|a"
    , Predicate $ and . sequence [not . isMultipliable, isPositive]
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:
       _:
       Token Numeral NumeralData{TNumeral.value = val2}:
       _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2
      _ -> Nothing
  }

ruleNumeralsPrefixWithNegativeOrMinus :: Rule
ruleNumeralsPrefixWithNegativeOrMinus = Rule
  { name = "numbers prefix with -, negative or minus"
  , pattern =
    [ regex "-|minus|negative"
    , Predicate isPositive
    ]
  , prod = \tokens -> case tokens of
      (_:Token Numeral nd:_) -> double (TNumeral.value nd * (-1))
      _ -> Nothing
  }

ruleOne :: Rule
ruleOne = Rule
  { name = "one"
  , pattern =
    [ regex "jed(en|nego|nemu|nym|nej|n(a|Ä…))"
    ]
  , prod = \_ -> integer 1
  }

ruleTen :: Rule
ruleTen = Rule
  { name = "ten"
  , pattern =
    [ regex "dzisi(e|Ä™)(Ä‡|c)(iu|ioma)?"
    ]
  , prod = \_ -> integer 10
  }

ruleSpecialCompositionForMissingHundredsLikeInOneTwentyTwo :: Rule
ruleSpecialCompositionForMissingHundredsLikeInOneTwentyTwo = Rule
  { name = "special composition for missing hundreds like in one twenty two"
  , pattern =
    [ Predicate $ numberBetween 1 10
    , Predicate $ numberBetween 10 100
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = v1}:
       Token Numeral NumeralData{TNumeral.value = v2}:
       _) -> double (v1 * 100 + v2)
      _ -> Nothing
  }

ruleDecimalWithThousandsSeparator :: Rule
ruleDecimalWithThousandsSeparator = Rule
  { name = "decimal with thousands separator"
  , pattern =
    [ regex "(\\d+(,\\d\\d\\d)+\\.\\d+)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        parseDouble (Text.replace "," Text.empty match) >>= double
      _ -> Nothing
  }

ruleNine :: Rule
ruleNine = Rule
  { name = "nine"
  , pattern =
    [ regex "dziewi(e|Ä™)(Ä‡|c)(iu|ioma)?"
    ]
  , prod = \_ -> integer 9
  }

ruleNumeral8 :: Rule
ruleNumeral8 = Rule
  { name = "number 800"
  , pattern =
    [ regex "(osiem(set| setek))"
    ]
  , prod = \_ -> integer 800 >>= withGrain 2
  }

ruleTwelve :: Rule
ruleTwelve = Rule
  { name = "twelve"
  , pattern =
    [ regex "dwunast(u|oma)|dwana(Å›|s)cie"
    ]
  , prod = \_ -> integer 12
  }

ruleDecimalNumeral :: Rule
ruleDecimalNumeral = Rule
  { name = "decimal number"
  , pattern =
    [ regex "(\\d*\\.\\d+)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) -> parseDecimal True match
      _ -> Nothing
  }

ruleFifteen :: Rule
ruleFifteen = Rule
  { name = "fifteen"
  , pattern =
    [ regex "pi(Ä™)tna(s|Å›)(ta|tu|cie|toma)"
    ]
  , prod = \_ -> integer 15
  }

ruleEleven :: Rule
ruleEleven = Rule
  { name = "eleven"
  , pattern =
    [ regex "jedena(stu|(s|Å›)cie|stoma)"
    ]
  , prod = \_ -> integer 11
  }

ruleThirteen :: Rule
ruleThirteen = Rule
  { name = "thirteen"
  , pattern =
    [ regex "trzyna(Å›|s)(tu|cie|toma)"
    ]
  , prod = \_ -> integer 13
  }

ruleThirty :: Rule
ruleThirty = Rule
  { name = "thirty"
  , pattern =
    [ regex "trzydzie(Å›)ci|trzydziest(u|oma)"
    ]
  , prod = \_ -> integer 30
  }

ruleNumeral2 :: Rule
ruleNumeral2 = Rule
  { name = "number 200"
  , pattern =
    [ regex "dwie((Å›)cie| setki)"
    ]
  , prod = \_ -> integer 200 >>= withGrain 2
  }

ruleSeventeen :: Rule
ruleSeventeen = Rule
  { name = "seventeen"
  , pattern =
    [ regex "siedemna(s|Å›)(tu|cie|toma)"
    ]
  , prod = \_ -> integer 17
  }

ruleNumeral :: Rule
ruleNumeral = Rule
  { name = "number 100"
  , pattern =
    [ regex "(sto|setki)"
    ]
  , prod = \_ -> integer 100 >>= withGrain 2
  }

ruleNumeral9 :: Rule
ruleNumeral9 = Rule
  { name = "number 900"
  , pattern =
    [ regex "dziewi(Ä™Ä‡)(set| setek)"
    ]
  , prod = \_ -> integer 900 >>= withGrain 2
  }

ruleSingle :: Rule
ruleSingle = Rule
  { name = "single"
  , pattern =
    [ regex "pojedynczy"
    ]
  , prod = \_ -> integer 1
  }

ruleTwenty :: Rule
ruleTwenty = Rule
  { name = "twenty"
  , pattern =
    [ regex "dwadzie(Å›|s)cia|dwudziest(u|oma)"
    ]
  , prod = \_ -> integer 20
  }

ruleAFew :: Rule
ruleAFew = Rule
  { name = "a few"
  , pattern =
    [ regex "kilk(a|u)"
    ]
  , prod = \_ -> integer 3
  }

ruleEight :: Rule
ruleEight = Rule
  { name = "eight"
  , pattern =
    [ regex "o(s|Å›)(iem|miu|mioma)"
    ]
  , prod = \_ -> integer 8
  }

ruleNumeral5 :: Rule
ruleNumeral5 = Rule
  { name = "number 500"
  , pattern =
    [ regex "pi(Ä™Ä‡)(set| setek)"
    ]
  , prod = \_ -> integer 500 >>= withGrain 2
  }

ruleNumeral3 :: Rule
ruleNumeral3 = Rule
  { name = "number 300"
  , pattern =
    [ regex "(trzy(sta| setki))"
    ]
  , prod = \_ -> integer 300 >>= withGrain 2
  }

ruleZero :: Rule
ruleZero = Rule
  { name = "zero"
  , pattern =
    [ regex "(zero|nic)"
    ]
  , prod = \_ -> integer 0
  }

ruleThousand :: Rule
ruleThousand = Rule
  { name = "thousand"
  , pattern =
    [ regex "ty(s|Å›)i(a|Ä…|Ä™)c(e|y)?"
    ]
  , prod = \_ -> integer 1000 >>= withGrain 3 >>= withMultipliable
  }

ruleMillion :: Rule
ruleMillion = Rule
  { name = "million"
  , pattern =
    [ regex "milion(y|(Ã³)w)?"
    ]
  , prod = \_ -> integer 1000000 >>= withGrain 6 >>= withMultipliable
  }

ruleIntersect :: Rule
ruleIntersect = Rule
  { name = "intersect"
  , pattern =
    [ Predicate hasGrain
    , Predicate $ and . sequence [not . isMultipliable, isPositive]
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:
       Token Numeral NumeralData{TNumeral.value = val2}:
       _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2
      _ -> Nothing
  }

ruleMultiply :: Rule
ruleMultiply = Rule
  { name = "compose by multiplication"
  , pattern =
    [ dimension Numeral
    , Predicate isMultipliable
    ]
  , prod = \tokens -> case tokens of
      (token1:token2:_) -> multiply token1 token2
      _ -> Nothing
  }

ruleThree :: Rule
ruleThree = Rule
  { name = "three"
  , pattern =
    [ regex "trz(y|ema|ech)"
    ]
  , prod = \_ -> integer 3
  }

ruleFour :: Rule
ruleFour = Rule
  { name = "four"
  , pattern =
    [ regex "czter(ej|y|ech|em|ema)"
    ]
  , prod = \_ -> integer 4
  }

ruleNumeralsSuffixesKMG :: Rule
ruleNumeralsSuffixesKMG = Rule
  { name = "numbers suffixes (K, M, G)"
  , pattern =
    [ dimension Numeral
    , regex "([kmg])(?=[\\W\\$â‚¬]|$)"
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = v}:
       Token RegexMatch (GroupMatch (match:_)):
       _) -> case Text.toLower match of
         "k" -> double $ v * 1e3
         "m" -> double $ v * 1e6
         "g" -> double $ v * 1e9
         _   -> Nothing
      _ -> Nothing
  }

ruleNumeral7 :: Rule
ruleNumeral7 = Rule
  { name = "number 700"
  , pattern =
    [ regex "(siedem(set| setek))"
    ]
  , prod = \_ -> integer 700 >>= withGrain 2
  }

ruleAPair :: Rule
ruleAPair = Rule
  { name = "a pair"
  , pattern =
    [ regex "para?"
    ]
  , prod = \_ -> integer 2
  }

ruleCouple :: Rule
ruleCouple = Rule
  { name = "couple"
  , pattern =
    [ regex "pare"
    ]
  , prod = \_ -> integer 2
  }

ruleSix :: Rule
ruleSix = Rule
  { name = "six"
  , pattern =
    [ regex "sze(s|Å›)(c|Ä‡)(iu|oma|u)?"
    ]
  , prod = \_ -> integer 6
  }

ruleNumeral6 :: Rule
ruleNumeral6 = Rule
  { name = "number 600"
  , pattern =
    [ regex "(szeÅ›Ä‡(set| setek))"
    ]
  , prod = \_ -> integer 600 >>= withGrain 2
  }

ruleNumeral4 :: Rule
ruleNumeral4 = Rule
  { name = "number 400"
  , pattern =
    [ regex "(cztery(sta| setki))"
    ]
  , prod = \_ -> integer 400 >>= withGrain 2
  }

ruleFive :: Rule
ruleFive = Rule
  { name = "five"
  , pattern =
    [ regex "pi(e|Ä™)(c|Ä‡)(iu|oma|u)?"
    ]
  , prod = \_ -> integer 5
  }

ruleFourty :: Rule
ruleFourty = Rule
  { name = "fou?rty"
  , pattern =
    [ regex "czterdzie(Å›)ci|czterdziest(u|oma)"
    ]
  , prod = \_ -> integer 40
  }

ruleDozen :: Rule
ruleDozen = Rule
  { name = "dozen"
  , pattern =
    [ regex "tuzin"
    ]
  , prod = \_ -> integer 12 >>= withMultipliable
  }

ruleSeven :: Rule
ruleSeven = Rule
  { name = "seven"
  , pattern =
    [ regex "sied(miu|em|mioma)"
    ]
  , prod = \_ -> integer 7
  }

ruleNineteen :: Rule
ruleNineteen = Rule
  { name = "nineteen"
  , pattern =
    [ regex "dziewietna(s|Å›)(tu|cie|toma)"
    ]
  , prod = \_ -> integer 19
  }

ruleInteger2 :: Rule
ruleInteger2 = Rule
  { name = "integer 21..99"
  , pattern =
    [ oneOf [20, 30 .. 90]
    , Predicate $ numberBetween 1 10
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = v1}:
       Token Numeral NumeralData{TNumeral.value = v2}:
       _) -> double $ v1 + v2
      _ -> Nothing
  }

ruleEighteen :: Rule
ruleEighteen = Rule
  { name = "eighteen"
  , pattern =
    [ regex "osiemna(s|Å›)(tu|cie|toma)"
    ]
  , prod = \_ -> integer 18
  }

ruleNumeralDotNumeral :: Rule
ruleNumeralDotNumeral = Rule
  { name = "number dot number"
  , pattern =
    [ dimension Numeral
    , regex "dot|point"
    , Predicate $ not . hasGrain
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral nd1:_:Token Numeral nd2:_) ->
        double $ TNumeral.value nd1 + decimalsToDouble (TNumeral.value nd2)
      _ -> Nothing
  }

ruleIntegerWithThousandsSeparator :: Rule
ruleIntegerWithThousandsSeparator = Rule
  { name = "integer with thousands separator ,"
  , pattern =
    [ regex "(\\d{1,3}(,\\d\\d\\d){1,5})"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        parseDouble (Text.replace "," Text.empty match) >>= double
      _ -> Nothing
  }

ruleFifty :: Rule
ruleFifty = Rule
  { name = "fifty"
  , pattern =
    [ regex "pi(Ä™Ä‡)dziesi(Ä…)t|pi(Ä™Ä‡)dziesi(Ä™)ci(u|oma)"
    ]
  , prod = \_ -> integer 50
  }

rules :: [Rule]
rules =
  [ ruleAFew
  , ruleAPair
  , ruleCouple
  , ruleDecimalNumeral
  , ruleDecimalWithThousandsSeparator
  , ruleDozen
  , ruleEight
  , ruleEighteen
  , ruleEighty
  , ruleEleven
  , ruleFifteen
  , ruleFifty
  , ruleFive
  , ruleFour
  , ruleFourteen
  , ruleFourty
  , ruleInteger2
  , ruleIntegerWithThousandsSeparator
  , ruleIntersect
  , ruleIntersectWithAnd
  , ruleMillion
  , ruleMultiply
  , ruleNine
  , ruleNineteen
  , ruleNinety
  , ruleNumeral
  , ruleNumeral2
  , ruleNumeral3
  , ruleNumeral4
  , ruleNumeral5
  , ruleNumeral6
  , ruleNumeral7
  , ruleNumeral8
  , ruleNumeral9
  , ruleNumeralDotNumeral
  , ruleNumeralsPrefixWithNegativeOrMinus
  , ruleNumeralsSuffixesKMG
  , ruleOne
  , ruleSeven
  , ruleSeventeen
  , ruleSeventy
  , ruleSingle
  , ruleSix
  , ruleSixteen
  , ruleSixty
  , ruleSpecialCompositionForMissingHundredsLikeInOneTwentyTwo
  , ruleTen
  , ruleThirteen
  , ruleThirty
  , ruleThousand
  , ruleThree
  , ruleTwelve
  , ruleTwenty
  , ruleTwo
  , ruleZero
  ]


-- 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 OverloadedStrings #-}

module Duckling.Numeral.PT.Corpus
  ( corpus
  ) where

import Data.String
import Prelude

import Duckling.Locale
import Duckling.Numeral.Types
import Duckling.Resolve
import Duckling.Testing.Types

corpus :: Corpus
corpus = (testContext {locale = makeLocale PT Nothing}, testOptions, allExamples)

allExamples :: [Example]
allExamples = concat
  [ examples (NumeralValue 1)
             [ "1"
             , "um"
             , "Uma"
             ]
  , examples (NumeralValue 2)
             [ "2"
             , "dois"
             , "duas"
             , "pares de"
             , "um par de"
             ]
  , examples (NumeralValue 3)
             [ "3"
             , "trÃªs"
             , "tres"
             ]
  , examples (NumeralValue 6)
             [ "6"
             , "seis"
             ]
  , examples (NumeralValue 11)
             [ "11"
             , "onze"
             ]
  , examples (NumeralValue 12)
             [ "12"
             , "doze"
             , "uma dÃºzia"
             , "uma duzia"
             , "uma duzias de"
             ]
  , examples (NumeralValue 14)
             [ "14"
             , "Catorze"
             , "quatorze"
             ]
  , examples (NumeralValue 16)
             [ "16"
             , "dezesseis"
             , "dezasseis"
             ]
  , examples (NumeralValue 17)
             [ "17"
             , "dezessete"
             , "dezassete"
             ]
  , examples (NumeralValue 18)
             [ "18"
             , "dezoito"
             ]
  , examples (NumeralValue 19)
             [ "19"
             , "dezenove"
             , "dezanove"
             ]
  , examples (NumeralValue 21)
             [ "21"
             , "vinte e um"
             ]
  , examples (NumeralValue 23)
             [ "23"
             , "vinte e tres"
             , "vinte e trÃªs"
             ]
  , examples (NumeralValue 24)
             [ "24"
             , "vinte e quatro"
             , "duas dÃºzias"
             , "duas duzias"
             ]
  , examples (NumeralValue 50)
             [ "50"
             , "cinquenta"
             , "cinqÃ¼enta"
             , "cincoenta"
             ]
  , examples (NumeralValue 70)
             [ "setenta"
             ]
  , examples (NumeralValue 78)
             [ "setenta e oito"
             ]
  , examples (NumeralValue 80)
             [ "oitenta"
             ]
  , examples (NumeralValue 33)
             [ "33"
             , "trinta e trÃªs"
             , "trinta e tres"
             ]
  , examples (NumeralValue 1.1)
             [ "1,1"
             , "1,10"
             , "01,10"
             ]
  , examples (NumeralValue 0.77)
             [ "0,77"
             , ",77"
             , "ponto setenta e sete"
             ]
  , examples (NumeralValue 1000)
             [ "mil"
             ]
  , examples (NumeralValue 100000)
             [ "100.000"
             , "100000"
             , "100K"
             , "100k"
             , "100.000,00"
             ]
  , examples (NumeralValue 100)
             [ "100"
             , "Cem"
             ]
  , examples (NumeralValue 104)
             [ "104"
             , "cento e quatro"
             ]
  , examples (NumeralValue 243)
             [ "243"
             ,"duzentos e quarenta e tres"
             ]
  , examples (NumeralValue 300)
             [ "trezentos"
             ]
  , examples (NumeralValue 343)
             [ "trezentos e quarenta e tres"
             , "343"
             ]
  , examples (NumeralValue 891)
             [ "oitocentos e noventa e um"
             , "891"
             ]
  , examples (NumeralValue 2200)
             [ "dois mil e duzentos"
             ]
  , examples (NumeralValue 3000000)
             [ "3M"
             , "3000K"
             , "3000000"
             , "3.000.000"
             ]
  , examples (NumeralValue 1200000)
             [ "1.200.000"
             , "1200000"
             , "1,2M"
             , "1200K"
             , ",0012G"
             ]
  , examples (NumeralValue (-1200000))
             [ "- 1.200.000"
             , "-1200000"
             , "menos 1.200.000"
             , "-1,2M"
             , "-1200K"
             , "-,0012G"
             , "negativo 1,2M"
             ]
  , examples (NumeralValue 1.5)
             [ "1 ponto cinco"
             , "um ponto cinco"
             , "1,5"
             ]
  , examples (NumeralValue 1200000.42)
             [ "1.200.000,42"
             ]
  , examples (NumeralValue 0.2)
             [ "1/5"
             , "2/10"
             , "3/15"
             , "20/100"
             ]
  ]


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

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

import Control.Applicative ((<|>))
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.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

ruleDozen :: Rule
ruleDozen = Rule
  { name = "a dozen of"
  , pattern =
    [ regex "(uma )?d(u|Ãº)zias?( de)?"
    ]
  , prod = \_ -> integer 12 >>= withMultipliable >>= notOkForAnyTime
  }

zeroNineteenMap :: HashMap Text Integer
zeroNineteenMap = HashMap.fromList
  [ ( "zero"        , 0 )
  , ( "um"          , 1 )
  , ( "uma"         , 1 )
  , ( "dois"        , 2 )
  , ( "duas"        , 2 )
  , ( "tres"        , 3 )
  , ( "trÃªs"        , 3 )
  , ( "quatro"      , 4 )
  , ( "cinco"       , 5 )
  , ( "seis"        , 6 )
  , ( "sete"        , 7 )
  , ( "oito"        , 8 )
  , ( "nove"        , 9 )
  , ( "dez"         , 10 )
  , ( "onze"        , 11 )
  , ( "doze"        , 12 )
  , ( "treze"       , 13 )
  , ( "catorze"     , 14 )
  , ( "quatorze"    , 14 )
  , ( "quinze"      , 15 )
  , ( "dezesseis"   , 16 )
  , ( "dezasseis"   , 16 )
  , ( "dezessete"   , 17 )
  , ( "dezassete"   , 17 )
  , ( "dezoito"     , 18 )
  , ( "dezenove"    , 19 )
  , ( "dezanove"    , 19 )
  ]

informalMap :: HashMap Text Integer
informalMap = HashMap.fromList
  [ ( "um par"      , 2 )
  , ( "um par de"   , 2 )
  , ( "par"         , 2 )
  , ( "pares"       , 2 )
  , ( "par de"      , 2 )
  , ( "pares de"    , 2 )
  , ( "um pouco"    , 3 )
  , ( "pouco"       , 3 )
  ]

ruleToNineteen :: Rule
ruleToNineteen = Rule
  { name = "integer (0..19)"
  , pattern =
    [ regex "(zero|d(oi|ua)s|(uma? )?par(es)?( de)?|tr(e|Ãª)s|(um )?pouco|uma?|(c|qu)atorze|quatro|quinze|cinco|dez[ea]sseis|seis|dez[ea]ssete|sete|dezoito|oito|dez[ea]nove|nove|dez|onze|doze|treze)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        let x = Text.toLower match in
        (HashMap.lookup x zeroNineteenMap >>= integer) <|>
        (HashMap.lookup x informalMap >>= integer >>= notOkForAnyTime)
      _ -> Nothing
  }

tensMap :: HashMap Text Integer
tensMap = HashMap.fromList
  [ ( "vinte"     , 20 )
  , ( "trinta"    , 30 )
  , ( "quarenta"  , 40 )
  , ( "cincoenta" , 50 )
  , ( "cinquenta" , 50 )
  , ( "cinqÃ¼enta" , 50 )
  , ( "sessenta"  , 60 )
  , ( "setenta"   , 70 )
  , ( "oitenta"   , 80 )
  , ( "noventa"   , 90 )
  ]

ruleTens :: Rule
ruleTens = Rule
  { name = "tens (20..90)"
  , pattern =
    [ regex "(vinte|trinta|quarenta|cin(co|q[uÃ¼])enta|sessenta|setenta|oitenta|noventa)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) tensMap >>= integer
      _ -> Nothing
  }

centsMap :: HashMap Text Integer
centsMap = HashMap.fromList
  [ ( "cem"           , 100 )
  , ( "cento"         , 100 )
  , ( "duzentos"      , 200 )
  , ( "trezentos"     , 300 )
  , ( "quatrocentos"  , 400 )
  , ( "quinhetos"     , 500 )
  , ( "seiscentos"    , 600 )
  , ( "setecentos"    , 700 )
  , ( "oitocentos"    , 800 )
  , ( "novecentos"    , 900 )
  ]

ruleCent :: Rule
ruleCent = Rule
  { name = "hundreds (100..900)"
  , pattern =
    [ regex "(cem|cento|duzentos|trezentos|quatrocentos|quinhetos|seiscentos|setecentos|oitocentos|novecentos)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) centsMap >>= integer
      _ -> Nothing
  }

rulePowersOfTen :: Rule
rulePowersOfTen = Rule
  { name = "powers of tens"
  , pattern =
    [ regex "(milhao|milhÃ£o|milhÃµes|milhoes|bilhao|bilhÃ£o|bilhÃµes|bilhoes|mil)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of
        "mil"      -> double 1e3 >>= withGrain 3 >>= withMultipliable
        "milhao"   -> double 1e6 >>= withGrain 6 >>= withMultipliable
        "milhÃ£o"   -> double 1e6 >>= withGrain 6 >>= withMultipliable
        "milhÃµes"  -> double 1e6 >>= withGrain 6 >>= withMultipliable
        "milhoes"  -> double 1e6 >>= withGrain 6 >>= withMultipliable
        "bilhao"   -> double 1e9 >>= withGrain 9 >>= withMultipliable
        "bilhÃ£o"   -> double 1e9 >>= withGrain 9 >>= withMultipliable
        "bilhÃµes"  -> double 1e9 >>= withGrain 9 >>= withMultipliable
        "bilhoes"  -> double 1e9 >>= withGrain 9 >>= withMultipliable
        _          -> Nothing
      _ -> Nothing
  }

ruleCompositeTens :: Rule
ruleCompositeTens = Rule
  { name = "integer 21..99"
  , pattern =
    [ oneOf [20,30..90]
    , Predicate $ numberBetween 1 10
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = tens}:
       Token Numeral NumeralData{TNumeral.value = units}:
       _) -> double $ tens + units
      _ -> Nothing
  }

ruleDecsAnd :: Rule
ruleDecsAnd = Rule
  { name = "number (21..29 31..39 .. 91..99)"
  , pattern =
    [ oneOf [20, 30..90]
    , regex "e"
    , Predicate $ numberBetween 1 10
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = v1}:
       _:
       Token Numeral NumeralData{TNumeral.value = v2}:
       _) -> double $ v1 + v2
      _ -> Nothing
  }

ruleCompositeCents :: Rule
ruleCompositeCents = Rule
  { name = "integer 101..999"
  , pattern =
    [ oneOf [100, 200..900]
    , Predicate $ numberBetween 1 100
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = hundreds}:
       Token Numeral NumeralData{TNumeral.value = units}:
       _) -> double $ hundreds + units
      _ -> Nothing
  }

ruleCentsAnd :: Rule
ruleCentsAnd = Rule
  { name = "number (101..199 201..299 .. 901..999)"
  , pattern =
    [ oneOf [100, 200..900]
    , regex "e"
    , Predicate $ numberBetween 1 100
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = v1}:
       _:
       Token Numeral NumeralData{TNumeral.value = v2}:
       _) -> double $ v1 + v2
      _ -> Nothing
  }

ruleSkipHundreds :: Rule
ruleSkipHundreds = Rule
  { name = "one twenty two"
  , pattern =
    [ Predicate $ numberBetween 1 10
    , Predicate $ numberBetween 10 100
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = hundreds}:
       Token Numeral NumeralData{TNumeral.value = rest}:
       _) -> double $ hundreds*100 + rest
      _ -> Nothing
  }

ruleDotSpelledOut :: Rule
ruleDotSpelledOut = Rule
  { name = "one point 2"
  , pattern =
    [ dimension Numeral
    , regex "ponto"
    , Predicate $ not . hasGrain
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral nd1:_:Token Numeral nd2:_) ->
        double $ TNumeral.value nd1 + decimalsToDouble (TNumeral.value nd2)
      _ -> Nothing
  }

ruleLeadingDotSpelledOut :: Rule
ruleLeadingDotSpelledOut = Rule
  { name = "point 77"
  , pattern =
    [ regex "ponto"
    , Predicate $ not . hasGrain
    ]
  , prod = \tokens -> case tokens of
      (_:Token Numeral nd:_) -> double . decimalsToDouble $ TNumeral.value nd
      _ -> Nothing
  }

ruleDecimals :: Rule
ruleDecimals = Rule
  { name = "decimal number"
  , pattern =
    [ regex "(\\d*\\,\\d+)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) -> parseDecimal False match
      _ -> Nothing
  }

ruleCommas :: Rule
ruleCommas = Rule
  { name = "dot-separated numbers"
  , pattern =
    [ regex "(\\d+(\\.\\d\\d\\d)+(\\,\\d+)?)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        parseDecimal False $ Text.replace "." Text.empty match
      _ -> Nothing
  }

ruleSuffixes :: Rule
ruleSuffixes = Rule
  { name = "suffixes (K,M,G))"
  , pattern =
    [ dimension Numeral
    , regex "(k|m|g)(?=[\\W$â‚¬Â¢Â£]|$)"
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = v}:
       Token RegexMatch (GroupMatch (match:_)):
       _) -> case Text.toLower match of
        "k" -> double $ v * 1e3
        "m" -> double $ v * 1e6
        "g" -> double $ v * 1e9
        _   -> Nothing
      _ -> Nothing
  }

ruleNegative :: Rule
ruleNegative = Rule
  { name = "negative numbers"
  , pattern =
    [ regex "(-|menos|negativo)(?!\\s*\\-)"
    , Predicate isPositive
    ]
  , prod = \tokens -> case tokens of
      (_:Token Numeral nd:_) -> double $ TNumeral.value nd * (-1)
      _ -> Nothing
  }

ruleSum :: Rule
ruleSum = Rule
  { name = "intersect 2 numbers"
  , pattern =
    [ Predicate hasGrain
    , Predicate $ and . sequence [not . isMultipliable, isPositive]
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:
       Token Numeral NumeralData{TNumeral.value = val2}:
       _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2
      _ -> Nothing
  }

ruleSumAnd :: Rule
ruleSumAnd = Rule
  { name = "intersect 2 numbers (with and)"
  , pattern =
    [ Predicate hasGrain
    , regex "e"
    , Predicate $ and . sequence [not . isMultipliable, isPositive]
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:
       _:
       Token Numeral NumeralData{TNumeral.value = val2}:
       _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2
      _ -> Nothing
  }

ruleMultiply :: Rule
ruleMultiply = Rule
  { name = "compose by multiplication"
  , pattern =
    [ dimension Numeral
    , Predicate isMultipliable
    ]
  , prod = \tokens -> case tokens of
      (token1:token2:_) -> multiply token1 token2
      _ -> Nothing
  }

rules :: [Rule]
rules =
  [ ruleToNineteen
  , ruleTens
  , ruleCent
  , rulePowersOfTen
  , ruleCompositeTens
  , ruleCompositeCents
  , ruleSkipHundreds
  , ruleDotSpelledOut
  , ruleLeadingDotSpelledOut
  , ruleDecimals
  , ruleCommas
  , ruleSuffixes
  , ruleNegative
  , ruleSum
  , ruleDecsAnd
  , ruleCentsAnd
  , ruleSumAnd
  , ruleMultiply
  , ruleDozen
  ]


-- 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 OverloadedStrings #-}

module Duckling.Numeral.RO.Corpus
  ( corpus
  ) where

import Data.String
import Prelude

import Duckling.Locale
import Duckling.Numeral.Types
import Duckling.Resolve
import Duckling.Testing.Types

context :: Context
context = testContext {locale = makeLocale RO Nothing}

corpus :: Corpus
corpus = (context, testOptions, allExamples)

allExamples :: [Example]
allExamples = concat
  [ examples (NumeralValue 0)
             [ "0"
             , "zero"
             , "nici unul"
             , "nici unu"
             , "nici una"
             , "nici o"
             , "nicio"
             , "nimic"
             ]
  , examples (NumeralValue 1)
             [ "1"
             , "unu"
             , "unul"
             , "un"
             , "o"
             , "intai"
             , "Ã®ntÃ¢i"
             ]
  , examples (NumeralValue 2)
             [ "2"
             , "doi"
             , "doua"
             , "douÄƒ"
             ]
  , examples (NumeralValue 3)
             [ "3"
             , "trei"
             ]
  , examples (NumeralValue 4)
             [ "4"
             , "patru"
             ]
  , examples (NumeralValue 5)
             [ "5"
             , "cinci"
             ]
  , examples (NumeralValue 6)
             [ "6"
             , "sase"
             , "È™ase"
             ]
  , examples (NumeralValue 7)
             [ "7"
             , "sapte"
             , "È™apte"
             ]
  , examples (NumeralValue 8)
             [ "8"
             , "opt"
             ]
  , examples (NumeralValue 9)
             [ "9"
             , "noua"
             , "nouÄƒ"
             ]
  , examples (NumeralValue 10)
             [ "10"
             , "zece"
             , "zeci"
             ]
  , examples (NumeralValue 10)
             [ "10"
             , "zece"
             ]
  , examples (NumeralValue 11)
             [ "11"
             , "unsprezece"
             , "unspe"
             , "unÈ™pe"
             ]
  , examples (NumeralValue 19)
             [ "19"
             , "nouasprezece"
             , "nouaspe"
             , "nouÄƒsprezece"
             , "nouÄƒÈ™pe"
             ]
  , examples (NumeralValue 70)
             [ "70"
             , "sapte zeci"
             , "È™apte zeci"
             ]
  , examples (NumeralValue 1.1)
             [ "1,1"
             , "1,10"
             , "01,10"
             ]
  , examples (NumeralValue 0.77)
             [ "0,77"
             , ",77"
             ]
  , examples (NumeralValue 100000)
             [ "100.000"
             , "100000"
             ]
  , examples (NumeralValue 3000000)
             [ "3000000"
             , "3.000.000"
             ]
  , examples (NumeralValue 1200000)
             [ "1.200.000"
             , "1200000"
             ]
  , examples (NumeralValue (-1200000))
             [ "-1.200.000"
             , "-1200000"
             , "minus 1.200.000"
             ]
  , examples (NumeralValue (-3))
             [ "-3"
             , "3 negativ"
             ]
  , examples (NumeralValue 5000)
             [ "5 mii"
             , "cinci mii"
             ]
  , examples (NumeralValue 1000)
             [ "o mie"
             , "1 mie"
             ]
  , examples (NumeralValue 100)
             [ "o suta"
             , "o sutÄƒ"
             , "1 suta"
             , "1 sutÄƒ"
             ]
  , examples (NumeralValue 300)
             [ "3 sute"
             , "trei sute"
             ]
  , examples (NumeralValue 1000000)
             [ "un milion"
             , "1 milion"
             ]
  , examples (NumeralValue 7000000)
             [ "7 milioane"
             , "sapte milioane"
             , "È™apte milioane"
             ]
  , examples (NumeralValue 21000000)
             [ "21 de milioane"
             , "douazeci si unu de milioane"
             ]
  , examples (NumeralValue 1000000000)
             [ "un miliard"
             , "1 miliard"
             ]
  , examples (NumeralValue 9000000000)
             [ "9 miliarde"
             , "noua miliarde"
             , "nouÄƒ miliarde"
             ]
  , examples (NumeralValue 20)
             [ "20"
             , "douazeci"
             , "doua zeci"
             , "douÄƒzeci"
             , "douÄƒ zeci"
             ]
  , examples (NumeralValue 23)
             [ "23"
             , "20 3"
             , "douazeci 3"
             , "douÄƒzeci 3"
             , "douÄƒzeci trei"
             , "douazeci si trei"
             , "douÄƒzeci È™i trei"
             ]
  ]


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

module Duckling.Numeral.RO.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.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

ruleNumeralsPrefixWithOrMinus :: Rule
ruleNumeralsPrefixWithOrMinus = Rule
  { name = "numbers prefix with - or minus"
  , pattern =
    [ regex "-|minus"
    , Predicate isPositive
    ]
  , prod = \case
      (_:Token Numeral nd:_) -> double (TNumeral.value nd * (-1))
      _ -> Nothing
  }

ruleDecimalWithThousandsSeparator :: Rule
ruleDecimalWithThousandsSeparator = Rule
  { name = "decimal with thousands separator"
  , pattern =
    [ regex "(\\d+(\\.\\d\\d\\d)+,\\d+)"
    ]
  , prod = \case
      (Token RegexMatch (GroupMatch (match:_)):
       _) -> let fmt = Text.replace "," "." $ Text.replace "." Text.empty match
        in parseDouble fmt >>= double
      _ -> Nothing
  }

ruleDecimalNumeral :: Rule
ruleDecimalNumeral = Rule
  { name = "decimal number"
  , pattern =
    [ regex "(\\d*,\\d+)"
    ]
  , prod = \case
      (Token RegexMatch (GroupMatch (match:_)):_) -> parseDecimal False match
      _ -> Nothing
  }

ruleInteger3 :: Rule
ruleInteger3 = Rule
  { name = "integer 21..99"
  , pattern =
    [ oneOf [20, 30 .. 90]
    , Predicate $ numberBetween 1 10
    ]
  , prod = \case
      (Token Numeral NumeralData{TNumeral.value = v1}:
       Token Numeral NumeralData{TNumeral.value = v2}:
       _) -> double $ v1 + v2
      _ -> Nothing
  }

ruleMultiply :: Rule
ruleMultiply = Rule
  { name = "compose by multiplication"
  , pattern =
    [ dimension Numeral
    , Predicate isMultipliable
    ]
  , prod = \case
      (token1:token2:_) -> multiply token1 token2
      _ -> Nothing
  }

ruleMultiplyDe :: Rule
ruleMultiplyDe = Rule
  { name = "compose by multiplication"
  , pattern =
    [ numberWith TNumeral.value (>= 20)
    , regex "de"
    , Predicate isMultipliable
    ]
  , prod = \case
      (token1:_:token2:_) -> multiply token1 token2
      _ -> Nothing
  }

ruleIntersect :: Rule
ruleIntersect = Rule
  { name = "intersect"
  , pattern =
    [ Predicate hasGrain
    , Predicate $ and . sequence [not . isMultipliable, isPositive]
    ]
  , prod = \case
      (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:
       Token Numeral NumeralData{TNumeral.value = val2}:
       _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2
      _ -> Nothing
  }

ruleIntersectCuI :: Rule
ruleIntersectCuI = Rule
  { name = "intersect (cu È™i)"
  , pattern =
    [ Predicate hasGrain
    , regex "[sÈ™]i"
    , Predicate $ and . sequence [not . isMultipliable, isPositive]
    ]
  , prod = \case
      (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:
       _:
       Token Numeral NumeralData{TNumeral.value = val2}:
       _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2
      _ -> Nothing
  }

ruleNumeralsSuffixesWithNegativ :: Rule
ruleNumeralsSuffixesWithNegativ = Rule
  { name = "numbers suffixes with (negativ)"
  , pattern =
    [ Predicate isPositive
    , regex "neg(ativ)?"
    ]
  , prod = \case
      (Token Numeral NumeralData{TNumeral.value = v}:
       _) -> double $ v * (-1)
      _ -> Nothing
  }

rulePowersOfTen :: Rule
rulePowersOfTen = Rule
  { name = "powers of tens"
  , pattern =
    [ regex "(sut(a|e|Äƒ)?|milio(n|ane)?|miliar(de?)?|mi[ei]?)"
    ]
  , prod = \case
      (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of
        "suta"      -> double 1e2 >>= withGrain 2 >>= withMultipliable
        "sute"      -> double 1e2 >>= withGrain 2 >>= withMultipliable
        "sutÄƒ" -> double 1e2 >>= withGrain 2 >>= withMultipliable
        "mi"        -> double 1e3 >>= withGrain 3 >>= withMultipliable
        "mie"       -> double 1e3 >>= withGrain 3 >>= withMultipliable
        "mii"       -> double 1e3 >>= withGrain 3 >>= withMultipliable
        "milio"     -> double 1e6 >>= withGrain 6 >>= withMultipliable
        "milion"    -> double 1e6 >>= withGrain 6 >>= withMultipliable
        "milioane"  -> double 1e6 >>= withGrain 6 >>= withMultipliable
        "miliar"    -> double 1e9 >>= withGrain 9 >>= withMultipliable
        "miliard"   -> double 1e9 >>= withGrain 9 >>= withMultipliable
        "miliarde"  -> double 1e9 >>= withGrain 9 >>= withMultipliable
        _           -> Nothing
      _ -> Nothing
  }

zeroTenMap :: HashMap Text Integer
zeroTenMap = HashMap.fromList
  [ ("zero", 0)
  , ("nimic", 0)
  , ("nicio", 0)
  , ("nici o", 0)
  , ("nici una", 0)
  , ("nici unu", 0)
  , ("nici unul", 0)
  , ("un", 1)
  , ("una", 1)
  , ("unu", 1)
  , ("unul", 1)
  , ("intai", 1)
  , ("Ã®ntai", 1)
  , ("intÃ¢i", 1)
  , ("Ã®ntÃ¢i", 1)
  , ("o", 1)
  , ("doi", 2)
  , ("doua", 2)
  , ("douÄƒ", 2)
  , ("trei", 3)
  , ("patru", 4)
  , ("cinci", 5)
  , ("sase", 6)
  , ("\537ase", 6)
  , ("sapte", 7)
  , ("\537apte", 7)
  , ("opt", 8)
  , ("noua", 9)
  , ("nouÄƒ", 9)
  , ("zece", 10)
  , ("zeci", 10)
  ]

ruleIntegerZeroTen :: Rule
ruleIntegerZeroTen = Rule
  { name = "integer (0..10)"
  , pattern =
    [ regex "(zero|nimic|nici(\\s?o|\\sun(a|ul?))|una|unul?|doi|dou(a|Äƒ)|trei|patru|cinci|(s|È™)ase|(s|È™)apte|opt|nou(a|Äƒ)|zec[ei]|(i|Ã®)nt(a|Ã¢)i|un|o)"
    ]
  , prod = \case
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) zeroTenMap >>= integer
      _ -> Nothing
  }

elevenNineteenMap :: HashMap Text Integer
elevenNineteenMap = HashMap.fromList
  [ ("un", 11)
  , ("doi", 12)
  , ("trei", 13)
  , ("pai", 14)
  , ("cin", 15)
  , ("cinci", 15)
  , ("sai", 16)
  , ("\537ai", 16)
  , ("sapti", 17)
  , ("\537apti", 17)
  , ("sapte", 17)
  , ("\537apte", 17)
  , ("opti", 18)
  , ("opt", 18)
  , ("noua", 19)
  , ("nouÄƒ", 19)
  ]

ruleInteger :: Rule
ruleInteger = Rule
  { name = "integer (11..19)"
  , pattern =
    [ regex "(cin|sapti|opti)(s|È™)pe|(cinci|(s|È™)apte|opt)sprezece|(un|doi|trei|pai|(s|È™)ai|nou(a|Äƒ))((s|È™)pe|sprezece)"
    ]
  , prod = \case
      (Token RegexMatch (GroupMatch (e1:_:e2:_:r:_)):_) -> do
        match <- case () of
          _ | not $ Text.null e1 -> Just e1
            | not $ Text.null e2 -> Just e2
            | not $ Text.null r  -> Just r
            | otherwise          -> Nothing
        HashMap.lookup (Text.toLower match) elevenNineteenMap >>= integer
      _ -> Nothing
  }

ruleInteger2 :: Rule
ruleInteger2 = Rule
  { name = "integer (20..90)"
  , pattern =
    [ regex "(dou[aÄƒ]|trei|patru|cinci|[sÈ™]ai|[sÈ™]apte|opt|nou[aÄƒ])\\s?zeci"
    ]
  , prod = \case
      (Token RegexMatch (GroupMatch (match:_)):_) -> do
        unit <- HashMap.lookup (Text.toLower match) zeroTenMap
        integer (unit * 10) >>= withGrain 2 >>= withMultipliable
      _ -> Nothing
  }

ruleIntegerCuSeparatorDeMiiDot :: Rule
ruleIntegerCuSeparatorDeMiiDot = Rule
  { name = "integer cu separator de mii dot"
  , pattern =
    [ regex "(\\d{1,3}(\\.\\d\\d\\d){1,5})"
    ]
  , prod = \case
      (Token RegexMatch (GroupMatch (match:_)):
       _) -> let fmt = Text.replace "." Text.empty match
        in parseDouble fmt >>= double
      _ -> Nothing
  }

rules :: [Rule]
rules =
  [ ruleDecimalNumeral
  , ruleDecimalWithThousandsSeparator
  , ruleInteger
  , ruleIntegerZeroTen
  , ruleInteger2
  , ruleInteger3
  , ruleIntegerCuSeparatorDeMiiDot
  , ruleIntersect
  , ruleIntersectCuI
  , ruleMultiply
  , ruleMultiplyDe
  , ruleNumeralsPrefixWithOrMinus
  , ruleNumeralsSuffixesWithNegativ
  , rulePowersOfTen
  ]


-- 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. An additional grant
-- of patent rights can be found in the PATENTS file in the same directory.

{-# LANGUAGE OverloadedStrings #-}

module Duckling.Numeral.SK.Corpus
  ( corpus
  ) where

import Data.String
import Prelude

import Duckling.Locale
import Duckling.Numeral.Types
import Duckling.Resolve
import Duckling.Testing.Types

corpus :: Corpus
corpus =
  ( testContext {locale = makeLocale SK Nothing}
  , testOptions
  , allExamples
  )

allExamples :: [Example]
allExamples = concat
  [ examples (NumeralValue 0)
             [ "0"
             , "nula"
             ]
  , examples (NumeralValue 1)
             [ "1"
             , "jeden"
             , "jedna"
             ]
  , examples (NumeralValue 2)
             [ "2"
             , "dva"
             , "dve"
             ]
  , examples (NumeralValue 7)
             [ "7"
             , "sedem"
             ]
  , examples (NumeralValue 14)
             [ "14"
             , "Å¡trnÃ¡sÅ¥"
             ]
  , examples (NumeralValue 16)
             [ "16"
             , "Å¡estnÃ¡sÅ¥"
             ]
  , examples (NumeralValue 17)
             [ "17"
             , "sedemnÃ¡sÅ¥"
             ]
  , examples (NumeralValue 18)
             [ "18"
             , "osemnÃ¡sÅ¥"
             ]
  , examples (NumeralValue 20)
             [ "20"
             , "dvadsaÅ¥"
             ]
  , examples (NumeralValue 1.1)
             [ "1,1"
             , "1,10"
             , "01,10"
             ]
  , examples (NumeralValue 0.77)
             [ "0,77"
             , ",77"
             ]
  , examples (NumeralValue 100000)
             [ "100.000"
             , "100000"
             , "100K"
             , "100k"
             ]
  , examples (NumeralValue 3000000)
             [ "3M"
             , "3000K"
             , "3000000"
             , "3.000.000"
             ]
  , examples (NumeralValue 1200000)
             [ "1.200.000"
             , "1200000"
             , "1,2M"
             , "1200K"
             , ",0012G"
             ]
  , examples (NumeralValue (-1200000))
             [ "- 1.200.000"
             , "-1200000"
             , "mÃnus 1.200.000"
             , "-1,2M"
             , "-1200K"
             , "-,0012G"
             ]
  , examples (NumeralValue 5000)
             [ "5 tisÃc"
             , "pÃ¤Å¥ tisÃc"
             ]
  ]


-- 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. An additional grant
-- of patent rights can be found in the PATENTS file in the same directory.

{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}

module Duckling.Numeral.SK.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.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

ruleIntersectWithAnd :: Rule
ruleIntersectWithAnd = Rule
  { name = "intersect (with and)"
  , pattern =
    [ Predicate hasGrain
    , regex "a"
    , Predicate $ and . sequence [not . isMultipliable, isPositive]
    ]
  , prod = \case
      (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:
       _:
       Token Numeral NumeralData{TNumeral.value = val2}:
       _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2
      _ -> Nothing
  }

ruleNumeralsPrefixWithNegativeOrMinus :: Rule
ruleNumeralsPrefixWithNegativeOrMinus = Rule
  { name = "numbers prefix with -, negative or minus"
  , pattern =
    [ regex "-|mÃnus|zÃ¡pornÃ©"
    , Predicate isPositive
    ]
  , prod = \case
      (_:
       Token Numeral NumeralData{TNumeral.value = v}:
       _) -> double $ v * (-1)
      _ -> Nothing
  }

ruleFew :: Rule
ruleFew = Rule
  { name = "few"
  , pattern =
    [ regex "(zo)?pÃ¡r"
    ]
  , prod = \_ -> integer 3
  }

ruleDecimalWithThousandsSeparator :: Rule
ruleDecimalWithThousandsSeparator = Rule
  { name = "decimal with thousands separator"
  , pattern =
    [ regex "(\\d+(\\.\\d\\d\\d)+\\,\\d+)"
    ]
  , prod = \case
      (Token RegexMatch (GroupMatch (match:_)):
       _) -> let fmt = Text.replace "," "." $ Text.replace "." Text.empty match
        in parseDouble fmt >>= double
      _ -> Nothing
  }

ruleDecimalNumeral :: Rule
ruleDecimalNumeral = Rule
  { name = "decimal number"
  , pattern =
    [ regex "(\\d*,\\d+)"
    ]
  , prod = \case
      (Token RegexMatch (GroupMatch (match:_)):
       _) -> parseDecimal False match
      _ -> Nothing
  }

ruleIntegerCompositeTens :: Rule
ruleIntegerCompositeTens = Rule
  { name = "integer 21..99"
  , pattern =
    [ oneOf [20, 30..90]
    , Predicate $ numberBetween 1 10
    ]
  , prod = \case
      (Token Numeral NumeralData{TNumeral.value = tens}:
       Token Numeral NumeralData{TNumeral.value = units}:
       _) -> double $ tens + units
      _ -> Nothing
  }

ruleSingle :: Rule
ruleSingle = Rule
  { name = "single"
  , pattern =
    [ regex "jed(en|no|na)"
    ]
  , prod = \_ -> integer 1 >>= withGrain 1
  }

ruleSum :: Rule
ruleSum = Rule
  { name = "intersect"
  , pattern =
    [ Predicate hasGrain
    , Predicate $ and . sequence [not . isMultipliable, isPositive]
    ]
  , prod = \case
      (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:
       Token Numeral NumeralData{TNumeral.value = val2}:
       _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2
      _ -> Nothing
  }

ruleMultiply :: Rule
ruleMultiply = Rule
  { name = "compose by multiplication"
  , pattern =
    [ dimension Numeral
    , Predicate isMultipliable
    ]
  , prod = \case
      (token1:token2:_) -> multiply token1 token2
      _ -> Nothing
  }

ruleNumeralsSuffixesKMG :: Rule
ruleNumeralsSuffixesKMG = Rule
  { name = "numbers suffixes (K, M, G)"
  , pattern =
    [ dimension Numeral
    , regex "([kmg])(?=[\\W\\$â‚¬]|$)"
    ]
  , prod = \case
      (Token Numeral NumeralData{TNumeral.value = v}:
       Token RegexMatch (GroupMatch (match:_)):
       _) -> case Text.toLower match of
         "k" -> double $ v * 1e3
         "m" -> double $ v * 1e6
         "g" -> double $ v * 1e9
         _   -> Nothing
      _ -> Nothing
  }

rulePowersOfTen :: Rule
rulePowersOfTen = Rule
  { name = "powers of tens"
  , pattern =
    [ regex "(sto(vky)?|tisÃce?|miliÃ³ny?)"
    ]
  , prod = \case
      (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of
        "sto"     -> double 1e2 >>= withGrain 2 >>= withMultipliable
        "stovky"  -> double 1e2 >>= withGrain 2 >>= withMultipliable
        "tisÃc"   -> double 1e3 >>= withGrain 3 >>= withMultipliable
        "tisÃce"  -> double 1e3 >>= withGrain 3 >>= withMultipliable
        "miliÃ³n"  -> double 1e6 >>= withGrain 6 >>= withMultipliable
        "miliÃ³ny" -> double 1e6 >>= withGrain 6 >>= withMultipliable
        _         -> Nothing
      _ -> Nothing
  }

ruleCouple :: Rule
ruleCouple = Rule
  { name = "couple, a pair"
  , pattern =
    [ regex "pÃ¡ry?"
    ]
  , prod = \_ -> integer 2
  }

ruleDozen :: Rule
ruleDozen = Rule
  { name = "dozen"
  , pattern =
    [ regex "tucet"
    ]
  , prod = \_ -> integer 12 >>= withGrain 1 >>= withMultipliable
  }

zeroToNineteenMap :: HashMap Text Integer
zeroToNineteenMap = HashMap.fromList
  [ ( "nula"    , 0 )
  , ( "jeden"   , 1 )
  , ( "jedna"   , 1 )
  , ( "jedno"   , 1 )
  , ( "dva"     , 2 )
  , ( "dve"     , 2 )
  , ( "tri"     , 3 )
  , ( "Å¡tyri"   , 4 )
  , ( "pÃ¤Å¥"     , 5 )
  , ( "Å¡esÅ¥"    , 6 )
  , ( "sedem"   , 7 )
  , ( "osem"    , 8 )
  , ( "devÃ¤Å¥"   , 9 )
  , ( "desaÅ¥"   , 10 )
  , ( "jedenÃ¡sÅ¥", 11 )
  , ( "dvanÃ¡sÅ¥" , 12 )
  , ( "trinÃ¡sÅ¥" , 13 )
  , ( "Å¡trnÃ¡sÅ¥" , 14 )
  , ( "pÃ¤tnÃ¡sÅ¥" , 15 )
  , ( "Å¡estnÃ¡sÅ¥", 16 )
  , ( "sedemnÃ¡sÅ¥", 17 )
  , ( "osemnÃ¡sÅ¥" , 18 )
  , ( "devÃ¤tnÃ¡sÅ¥", 19 )
  ]

ruleInteger :: Rule
ruleInteger = Rule
  { name = "integer (0..19)"
  -- e.g. jedenÃ¡sÅ¥ must be before jeden, otherwise jeden will always shadow jedenÃ¡sÅ¥
  , pattern =
    [ regex "(nula|jed(enÃ¡sÅ¥|en|na|no)|dv(anÃ¡sÅ¥|a|e)|trinÃ¡sÅ¥|tri|Å¡trnÃ¡sÅ¥|Å¡tyri|pÃ¤tnÃ¡sÅ¥|pÃ¤Å¥|Å¡estnÃ¡sÅ¥|Å¡esÅ¥|sedemnÃ¡sÅ¥|sedem|osemnÃ¡sÅ¥|osem|devÃ¤tnÃ¡sÅ¥|devÃ¤Å¥|desaÅ¥)"
    ]
  , prod = \case
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) zeroToNineteenMap >>= integer
      _ -> Nothing
  }

dozenMap :: HashMap Text Integer
dozenMap = HashMap.fromList
  [ ( "dvadsaÅ¥"        , 20)
  , ( "tridsaÅ¥"        , 30)
  , ( "Å¡tyridsaÅ¥"      , 40)
  , ( "pÃ¤Å¥desiat"      , 50)
  , ( "Å¡esÅ¥desiat"     , 60)
  , ( "sedemdesiat"    , 70)
  , ( "osemdesiat"     , 80)
  , ( "devÃ¤tdesiat"    , 90)
  ]

ruleInteger2 :: Rule
ruleInteger2 = Rule
  { name = "integer (20..90)"
  , pattern =
    [ regex "((dva|tri|Å¡tyri)dsaÅ¥|(pÃ¤Å¥|Å¡esÅ¥|sedem|osem|devÃ¤t)desiat)"
    ]
  , prod = \case
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) dozenMap >>= integer
      _ -> Nothing
  }

ruleNumeralDotNumeral :: Rule
ruleNumeralDotNumeral = Rule
  { name = "number dot number"
  , pattern =
    [ dimension Numeral
    , regex "celÃ¡|celÃ½ch|celÃ©"
    , Predicate $ not . hasGrain
    ]
  , prod = \case
      (Token Numeral nd1:_:Token Numeral nd2:_) ->
        double $ TNumeral.value nd1 + decimalsToDouble (TNumeral.value nd2)
      _ -> Nothing
  }

ruleIntegerWithThousandsSeparator :: Rule
ruleIntegerWithThousandsSeparator = Rule
  { name = "integer with thousands separator ."
  , pattern =
    [ regex "(\\d{1,3}(\\.\\d\\d\\d){1,5})"
    ]
  , prod = \case
      (Token RegexMatch (GroupMatch (match:_)):
       _) -> let fmt = Text.replace "." Text.empty match
        in parseDouble fmt >>= double
      _ -> Nothing
  }

rules :: [Rule]
rules =
  [ ruleCouple
  , ruleDecimalNumeral
  , ruleDecimalWithThousandsSeparator
  , ruleDozen
  , ruleFew
  , ruleInteger
  , ruleInteger2
  , ruleIntegerCompositeTens
  , ruleIntegerWithThousandsSeparator
  , ruleSum
  , ruleIntersectWithAnd
  , ruleMultiply
  , ruleNumeralDotNumeral
  , ruleNumeralsPrefixWithNegativeOrMinus
  , ruleNumeralsSuffixesKMG
  , rulePowersOfTen
  , ruleSingle
  ]


-- 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 OverloadedStrings #-}

module Duckling.Numeral.SV.Corpus
  ( corpus ) where

import Prelude
import Data.String

import Duckling.Locale
import Duckling.Numeral.Types
import Duckling.Resolve
import Duckling.Testing.Types

corpus :: Corpus
corpus = (testContext {locale = makeLocale SV Nothing}, testOptions, allExamples)

allExamples :: [Example]
allExamples = concat
  [ examples (NumeralValue 0)
             [ "0"
             , "noll"
             ]
  , examples (NumeralValue 1)
             [ "1"
             , "en"
             , "ett"
             ]
  , examples (NumeralValue 2)
             [ "2"
             , "tvÃ¥"
             , "ett par"
             ]
  , examples (NumeralValue 7)
             [ "7"
             , "sju"
             ]
  , examples (NumeralValue 14)
             [ "14"
             , "Fjorton"
             ]
  , examples (NumeralValue 16)
             [ "16"
             , "sexton"
             ]
  , examples (NumeralValue 17)
             [ "17"
             , "sjutton"
             ]
  , examples (NumeralValue 18)
             [ "18"
             , "arton"
             ]
  , examples (NumeralValue 20)
             [ "20"
             , "tjugo"
             ]
  , examples (NumeralValue 1.1)
             [ "1,1"
             , "1,10"
             , "01,10"
             ]
  , examples (NumeralValue 0.77)
             [ "0,77"
             , ",77"
             ]
  , examples (NumeralValue 100000)
             [ "100.000"
             , "100000"
             , "100K"
             , "100k"
             ]
  , examples (NumeralValue 3000000)
             [ "3M"
             , "3000K"
             , "3000000"
             , "3.000.000"
             ]
  , examples (NumeralValue 1200000)
             [ "1.200.000"
             , "1200000"
             , "1,2M"
             , "1200K"
             , ",0012G"
             ]
  , examples (NumeralValue (-1200000))
             [ "- 1.200.000"
             , "-1200000"
             , "minus 1.200.000"
             , "negativ 1200000"
             , "-1,2M"
             , "-1200K"
             , "-,0012G"
             ]
  , examples (NumeralValue 5000)
             [ "5 tusen"
             , "fem tusen"
             ]
  ]


-- 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.Numeral.SV.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.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

ruleIntersectWithAnd :: Rule
ruleIntersectWithAnd = Rule
  { name = "intersect (with and)"
  , pattern =
    [ Predicate hasGrain
    , regex "och"
    , Predicate $ and . sequence [not . isMultipliable, isPositive]
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:
       _:
       Token Numeral NumeralData{TNumeral.value = val2}:
       _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2
      _ -> Nothing
  }

ruleNumeralsPrefixWithNegativeOrMinus :: Rule
ruleNumeralsPrefixWithNegativeOrMinus = Rule
  { name = "numbers prefix with -, negative or minus"
  , pattern =
    [ regex "-|minus|negativ"
    , Predicate isPositive
    ]
  , prod = \tokens -> case tokens of
      (_:
       Token Numeral NumeralData{TNumeral.value = v}:
       _) -> double $ v * (-1)
      _ -> Nothing
  }

ruleFew :: Rule
ruleFew = Rule
  { name = "few"
  , pattern =
    [ regex "(nÃ¥gra )?fÃ¥"
    ]
  , prod = \_ -> integer 3
  }

ruleDecimalWithThousandsSeparator :: Rule
ruleDecimalWithThousandsSeparator = Rule
  { name = "decimal with thousands separator"
  , pattern =
    [ regex "(\\d+(\\.\\d\\d\\d)+\\,\\d+)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):
       _) -> let fmt = Text.replace "," "." $ Text.replace "." Text.empty match
        in parseDouble fmt >>= double
      _ -> Nothing
  }

ruleDecimalNumeral :: Rule
ruleDecimalNumeral = Rule
  { name = "decimal number"
  , pattern =
    [ regex "(\\d*,\\d+)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):
       _) -> parseDecimal False match
      _ -> Nothing
  }

ruleInteger3 :: Rule
ruleInteger3 = Rule
  { name = "integer 21..99"
  , pattern =
    [ oneOf [70, 20, 60, 50, 40, 90, 30, 80]
    , Predicate $ numberBetween 1 10
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = v1}:
       Token Numeral NumeralData{TNumeral.value = v2}:
       _) -> double $ v1 + v2
      _ -> Nothing
  }

ruleSingle :: Rule
ruleSingle = Rule
  { name = "single"
  , pattern =
    [ regex "enkel"
    ]
  , prod = \_ -> integer 1 >>= withGrain 1
  }

ruleIntersect :: Rule
ruleIntersect = Rule
  { name = "intersect"
  , pattern =
    [ Predicate hasGrain
    , Predicate $ and . sequence [not . isMultipliable, isPositive]
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:
       Token Numeral NumeralData{TNumeral.value = val2}:
       _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2
      _ -> Nothing
  }

ruleMultiply :: Rule
ruleMultiply = Rule
  { name = "compose by multiplication"
  , pattern =
    [ dimension Numeral
    , Predicate isMultipliable
    ]
  , prod = \tokens -> case tokens of
      (token1:token2:_) -> multiply token1 token2
      _ -> Nothing
  }

ruleNumeralsSuffixesKMG :: Rule
ruleNumeralsSuffixesKMG = Rule
  { name = "numbers suffixes (K, M, G)"
  , pattern =
    [ dimension Numeral
    , regex "([kmg])(?=[\\W\\$â‚¬]|$)"
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = v}:
       Token RegexMatch (GroupMatch (match:_)):
       _) -> case Text.toLower match of
         "k" -> double $ v * 1e3
         "m" -> double $ v * 1e6
         "g" -> double $ v * 1e9
         _   -> Nothing
      _ -> Nothing
  }

rulePowersOfTen :: Rule
rulePowersOfTen = Rule
  { name = "powers of tens"
  , pattern =
    [ regex "(hundra?|tusen?|miljon(er)?)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of
        "hundr"    -> double 1e2 >>= withGrain 2 >>= withMultipliable
        "hundra"   -> double 1e2 >>= withGrain 2 >>= withMultipliable
        "tuse"     -> double 1e3 >>= withGrain 3 >>= withMultipliable
        "tusen"    -> double 1e3 >>= withGrain 3 >>= withMultipliable
        "miljon"   -> double 1e6 >>= withGrain 6 >>= withMultipliable
        "miljoner" -> double 1e6 >>= withGrain 6 >>= withMultipliable
        _          -> Nothing
      _ -> Nothing
  }

ruleCouple :: Rule
ruleCouple = Rule
  { name = "couple, a pair"
  , pattern =
    [ regex "ett par"
    ]
  , prod = \_ -> integer 2
  }

ruleDozen :: Rule
ruleDozen = Rule
  { name = "dozen"
  , pattern =
    [ regex "dussin"
    ]
  , prod = \_ -> integer 12 >>= withGrain 1 >>= withMultipliable
  }

zeroToNineteenMap :: HashMap Text Integer
zeroToNineteenMap = HashMap.fromList
  [ ( "inget"    , 0 )
  , ( "ingen"    , 0 )
  , ( "noll"     , 0 )
  , ( "en"       , 1 )
  , ( "ett"      , 1 )
  , ( "tvÃ¥" , 2 )
  , ( "tre"      , 3 )
  , ( "fyra"     , 4 )
  , ( "fem"      , 5 )
  , ( "sex"      , 6 )
  , ( "sju"      , 7 )
  , ( "Ã¥tta", 8 )
  , ( "nio"      , 9 )
  , ( "tio"      , 10 )
  , ( "elva"     , 11 )
  , ( "tolv"     , 12 )
  , ( "tretton"  , 13 )
  , ( "fjorton"  , 14 )
  , ( "femton"   , 15 )
  , ( "sexton"   , 16 )
  , ( "sjutton"  , 17 )
  , ( "arton"    , 18 )
  , ( "nitton"   , 19 )
  ]

ruleInteger :: Rule
ruleInteger = Rule
  { name = "integer (0..19)"
  , pattern =
    [ regex "(inget|ingen|noll|en|ett|tvÃ¥|tretton|tre|fyra|femton|fem|sexton|sex|sjutton|sju|Ã¥tta|nio|tio|elva|tolv|fjorton|arton|nitton)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) zeroToNineteenMap >>= integer
      _ -> Nothing
  }

dozenMap :: HashMap Text Integer
dozenMap = HashMap.fromList
  [ ( "tjugo"      , 20)
  , ( "trettio"    , 30)
  , ( "fyrtio"     , 40)
  , ( "femtio"     , 50)
  , ( "sextio"     , 60)
  , ( "sjuttio"    , 70)
  , ( "Ã¥ttio" , 80)
  , ( "nittio"     , 90)
  ]

ruleInteger2 :: Rule
ruleInteger2 = Rule
  { name = "integer (20..90)"
  , pattern =
    [ regex "(tjugo|trettio|fyrtio|femtio|sextio|sjuttio|Ã¥ttio|nittio)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) dozenMap >>= integer
      _ -> Nothing
  }

ruleNumeralDotNumeral :: Rule
ruleNumeralDotNumeral = Rule
  { name = "number dot number"
  , pattern =
    [ dimension Numeral
    , regex "komma"
    , Predicate $ not . hasGrain
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral nd1:_:Token Numeral nd2:_) ->
        double $ TNumeral.value nd1 + decimalsToDouble (TNumeral.value nd2)
      _ -> Nothing
  }

ruleIntegerWithThousandsSeparator :: Rule
ruleIntegerWithThousandsSeparator = Rule
  { name = "integer with thousands separator ."
  , pattern =
    [ regex "(\\d{1,3}(\\.\\d\\d\\d){1,5})"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):
       _) -> let fmt = Text.replace "." Text.empty match
        in parseDouble fmt >>= double
      _ -> Nothing
  }

rules :: [Rule]
rules =
  [ ruleCouple
  , ruleDecimalNumeral
  , ruleDecimalWithThousandsSeparator
  , ruleDozen
  , ruleFew
  , ruleInteger
  , ruleInteger2
  , ruleInteger3
  , ruleIntegerWithThousandsSeparator
  , ruleIntersect
  , ruleIntersectWithAnd
  , ruleMultiply
  , ruleNumeralDotNumeral
  , ruleNumeralsPrefixWithNegativeOrMinus
  , ruleNumeralsSuffixesKMG
  , rulePowersOfTen
  , ruleSingle
  ]


-- 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 OverloadedStrings #-}

module Duckling.Numeral.SW.Corpus
  ( corpus ) where

import Data.String
import Prelude

import Duckling.Locale
import Duckling.Numeral.Types
import Duckling.Resolve
import Duckling.Testing.Types

corpus :: Corpus
corpus = (testContext {locale = makeLocale SW Nothing}, testOptions, allExamples)

allExamples :: [Example]
allExamples = concat
  [ examples (NumeralValue 0)
             [ "0"
             , "sufuri"
             , "zero"
             ]
  , examples (NumeralValue 1)
             [ "moja"
             ]
  , examples (NumeralValue 2)
             [ "mbili"
             ]
  , examples (NumeralValue 3)
             [ "tatu"
             ]
  , examples (NumeralValue 4)
             [ "nne"
             ]
  , examples (NumeralValue 5)
             [ "tano"
             ]
  , examples (NumeralValue 6)
             [ "sita"
             ]
  , examples (NumeralValue 7)
             [ "saba"
             ]
  , examples (NumeralValue 8)
             [ "nane"
             ]
  , examples (NumeralValue 9)
             [ "tisa"
             ]
  , examples (NumeralValue 10)
             [ "kumi"
             ]
  , examples (NumeralValue 20)
             [ "ishirini"
             ]
  , examples (NumeralValue 30)
             [ "thelathini"
             ]
  , examples (NumeralValue 40)
             [ "arubaini"
             , "arobaini"
             ]
  , examples (NumeralValue 50)
             [ "hamsini"
             ]
  , examples (NumeralValue 60)
             [ "sitini"
             ]
  , examples (NumeralValue 70)
             [ "sabini"
             ]
  , examples (NumeralValue 80)
             [ "themanini"
             ]
  , examples (NumeralValue 90)
             [ "tisini"
             ]
  ]


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

module Duckling.Numeral.SW.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.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

ruleNumeralMap :: HashMap Text Integer
ruleNumeralMap = HashMap.fromList
  [ ( "sufuri", 0 )
  , ( "zero", 0 )
  , ( "moja", 1 )
  , ( "mbili", 2 )
  , ( "tatu", 3 )
  , ( "nne", 4 )
  , ( "tano", 5)
  , ( "sita", 6)
  , ( "saba", 7)
  , ( "nane", 8)
  , ( "tisa", 9)
  , ( "kumi", 10)
  ]

ruleNumeral :: Rule
ruleNumeral = Rule
  { name = "number (0..10)"
  , pattern =
    [ regex "(sufuri|zero|moja|mbili|tatu|nne|tano|sita|saba|nane|tisa|kumi)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) ruleNumeralMap >>= integer
      _ -> Nothing
  }

tensMap :: HashMap Text Integer
tensMap = HashMap.fromList
  [ ( "ishirini", 20 )
  , ( "thelathini", 30 )
  , ( "arubaini", 40 )
  , ( "arobaini", 40 )
  , ( "hamsini", 50 )
  , ( "sitini", 60 )
  , ( "sabini", 70 )
  , ( "themanini", 80 )
  , ( "tisini", 90 )
  ]

ruleTens :: Rule
ruleTens = Rule
  { name = "integer (20,30..90)"
  , pattern =
    [ regex "(ishirini|thelathini|arubaini|arobaini|hamsini|sitini|sabini|themanini|tisini)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) tensMap >>= integer
      _ -> Nothing
  }

ruleCompositeTens :: Rule
ruleCompositeTens = Rule
  { name = "integer 11..19 21..29 .. 91..99"
  , pattern = [oneOf [20,30..90]
  , regex "-?na-?"
  , Predicate $ numberBetween 1 10]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = v1}:
       Token Numeral NumeralData{TNumeral.value = v2}:
       _) -> double $ v1 + v2
      _ -> Nothing
  }

rules :: [Rule]
rules =
  [ ruleNumeral
  , ruleTens
  , ruleCompositeTens
  ]


-- 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 OverloadedStrings #-}

module Duckling.Numeral.TR.Corpus
  ( corpus ) where

import Prelude
import Data.String

import Duckling.Locale
import Duckling.Numeral.Types
import Duckling.Resolve
import Duckling.Testing.Types

corpus :: Corpus
corpus = (testContext {locale = makeLocale TR Nothing}, testOptions, allExamples)

allExamples :: [Example]
allExamples = concat
  [ examples (NumeralValue 0)
             [ "0"
             , "yok"
             , "hiÃ§"
             , "sÄ±fÄ±r"
             ]
  , examples (NumeralValue 1)
             [ "1"
             , "bir"
             , "tek"
             , "yek"
             ]
  , examples (NumeralValue 2)
             [ "2"
             , "iki"
             , "Ã§ift"
             ]
  , examples (NumeralValue 33)
             [ "33"
             , "otuzÃ¼Ã§"
             , "otuz Ã¼Ã§"
             , "0033"
             ]
  , examples (NumeralValue 14)
             [ "14"
             , "ondÃ¶rt"
             , "on dÃ¶rt"
             ]
  , examples (NumeralValue 16)
             [ "16"
             , "onaltÄ±"
             , "on altÄ±"
             ]
  , examples (NumeralValue 17)
             [ "17"
             , "onyedi"
             , "on yedi"
             ]
  , examples (NumeralValue 18)
             [ "18"
             , "onsekiz"
             , "on sekiz"
             ]
  , examples (NumeralValue 1.1)
             [ "1,1"
             , "1,10"
             , "01,10"
             , "bir virgÃ¼l bir"
             , "bir nokta bir"
             ]
  , examples (NumeralValue 0.77)
             [ "0,77"
             , ",77"
             , "sÄ±fÄ±r virgÃ¼l yetmiÅŸyedi"
             , "sÄ±fÄ±r virgÃ¼l yetmiÅŸ yedi"
             ]
  , examples (NumeralValue 100000)
             [ "100.000"
             , "100000"
             , "100K"
             , "100k"
             , "100b"
             ]
  , examples (NumeralValue 3000000)
             [ "3M"
             , "3000K"
             , "3000000"
             , "3.000.000"
             ]
  , examples (NumeralValue 1200000)
             [ "1.200.000"
             , "1200000"
             , "1,2M"
             , "1200K"
             , ",0012G"
             , "1200B"
             ]
  , examples (NumeralValue (-1200000))
             [ "- 1.200.000"
             , "-1200000"
             , "eksi 1.200.000"
             , "negatif 1200000"
             , "-1,2M"
             , "-1200K"
             , "-,0012G"
             , "-1200B"
             ]
  , examples (NumeralValue 5000)
             [ "5 bin"
             , "beÅŸ bin"
             ]
  , examples (NumeralValue 50)
             [ "5 deste"
             , "beÅŸ deste"
             ]
  , examples (NumeralValue 200000)
             [ "iki yÃ¼z bin"
             , "ikiyÃ¼zbin"
             ]
  , examples (NumeralValue 21011)
             [ "yirmi bir bin on bir"
             , "yirmibir bin onbir"
             ]
  , examples (NumeralValue 721012)
             [ "yedi yÃ¼z yirmibir bin on iki"
             , "yedi yÃ¼z yirmi bir bin on iki"
             , "yediyÃ¼z yirmibir bin oniki"
             ]
  , examples (NumeralValue 300341)
             [ "Ã¼Ã§yÃ¼zbin Ã¼Ã§yÃ¼z kÄ±rkbir"
             , "Ã¼Ã§ yÃ¼z bin Ã¼Ã§ yÃ¼z kÄ±rk bir"
             ]
  , examples (NumeralValue 40348)
             [ "kÄ±rkbin Ã¼Ã§yÃ¼z kÄ±rksekiz"
             , "kÄ±rk bin Ã¼Ã§ yÃ¼z kÄ±rk sekiz"
             ]
  , examples (NumeralValue 31256721)
             [ "otuz bir milyon iki yÃ¼z elli altÄ± bin yedi yÃ¼z yirmi bir"
             ]
  , examples (NumeralValue 107)
             [ "107"
             , "yÃ¼z yedi"
             ]
  , examples (NumeralValue 5.5)
             [ "beÅŸ buÃ§uk"
             , "beÅŸbuÃ§uk"
             , "5 buÃ§uk"
             , "5,5"
             ]
  , examples (NumeralValue 3500000)
             [ "3,5 milyon"
             , "3500000"
             , "Ã¼Ã§ buÃ§uk milyon"
             , "Ã¼Ã§buÃ§uk milyon"
             , "3,5M"
             ]
  , examples (NumeralValue 0.5)
             [ "yarÄ±m"
             , "0,5"
             ]
  , examples (NumeralValue 2500)
             [ "2,5 bin"
             , "2500"
             , "iki bin beÅŸ yÃ¼z"
             , "ikibin beÅŸyÃ¼z"
             ]
  , examples (NumeralValue 2200000)
             [ "2,2 milyon"
             , "iki nokta iki milyon"
             , "iki virgÃ¼l iki milyon"
             ]
  , examples (NumeralValue 72.5)
             [ "yetmiÅŸikibuÃ§uk"
             , "yetmiÅŸiki buÃ§uk"
             , "yetmiÅŸ iki buÃ§uk"
             , "72,5"
             ]
  ]


-- 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.Numeral.TR.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.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

hundredsMap :: HashMap Text Integer
hundredsMap = HashMap.fromList
  [ ( "yÃ¼z", 100)
  , ( "ikiyÃ¼z", 200)
  , ( "Ã¼Ã§yÃ¼z", 300)
  , ( "dÃ¶rtyÃ¼z", 400)
  , ( "beÅŸyÃ¼z", 500)
  , ( "altÄ±yÃ¼z", 600)
  , ( "yediyÃ¼z", 700)
  , ( "sekizyÃ¼z", 800)
  , ( "dokuzyÃ¼z", 900)
  ]

ruleInteger5 :: Rule
ruleInteger5 = Rule
  { name = "integer 100..900"
  , pattern =
    [ regex "(yÃ¼z|ikiyÃ¼z|Ã¼Ã§yÃ¼z|dÃ¶rtyÃ¼z|beÅŸyÃ¼z|altÄ±yÃ¼z|yediyÃ¼z|sekizyÃ¼z|dokuzyÃ¼z)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) hundredsMap >>= integer >>= withGrain 2
      _ -> Nothing
  }

ruleNumeralsPrefixWithNegativeOrMinus :: Rule
ruleNumeralsPrefixWithNegativeOrMinus = Rule
  { name = "numbers prefix with -, negative or minus"
  , pattern =
    [ regex "-|eksi|negatif"
    , Predicate isPositive
    ]
  , prod = \tokens -> case tokens of
      (_:Token Numeral NumeralData{TNumeral.value = v}:_) ->
        double (v * (- 1))
      _ -> Nothing
  }

ruleACoupleOf :: Rule
ruleACoupleOf = Rule
  { name = "a couple (of)"
  , pattern =
    [ regex "(bir )?Ã§ift"
    ]
  , prod = \_ -> integer 2 >>= withGrain 1
  }

ruleFew :: Rule
ruleFew = Rule
  { name = "few"
  , pattern =
    [ regex "(bir)?az"
    ]
  , prod = \_ -> integer 3
  }

ruleTen :: Rule
ruleTen = Rule
  { name = "ten"
  , pattern =
    [ regex "on"
    ]
  , prod = \_ -> integer 10 >>= withGrain 1 >>= withMultipliable
  }

ruleDecimalWithThousandsSeparator :: Rule
ruleDecimalWithThousandsSeparator = Rule
  { name = "decimal with thousands separator"
  , pattern =
    [ regex "(\\d+(\\.\\d\\d\\d)+,\\d+)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):
       _) -> let fmt = Text.replace "," "." $ Text.replace "." Text.empty match
        in parseDouble fmt >>= double
      _ -> Nothing
  }

ruleMultiply :: Rule
ruleMultiply = Rule
  { name = "compose by multiplication"
  , pattern =
    [ dimension Numeral
    , Predicate isMultipliable
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = val1}:
       Token Numeral NumeralData{TNumeral.value = val2, TNumeral.grain = g2}:
       _) | isNothing g2 || (isJust g2 && val2 > val1) -> case g2 of
         Nothing -> double $ val1 * val2
         Just g  -> double (val1 * val2) >>= withGrain g
      _ -> Nothing
  }

ruleDecimalNumeral :: Rule
ruleDecimalNumeral = Rule
  { name = "decimal number"
  , pattern =
    [ regex "(\\d*,\\d+)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        parseDecimal False match
      _ -> Nothing
  }

numeralSuffixesHalfsuffixTextMap :: HashMap Text Double
numeralSuffixesHalfsuffixTextMap = HashMap.fromList
  [ ( "birbuÃ§uk", 1.5)
  , ( "bibuÃ§uk", 1.5)
  , ( "ikibuÃ§uk", 2.5)
  , ( "Ã¼\231buÃ§uk", 3.5)
  , ( "dÃ¶rtbuÃ§uk", 4.5)
  , ( "be\351buÃ§uk", 5.5)
  , ( "altÄ±buÃ§uk", 6.5)
  , ( "yedibuÃ§uk", 7.5)
  , ( "sekizbuÃ§uk", 8.5)
  , ( "dokuzbuÃ§uk", 9.5)
  ]

ruleNumeralSuffixesHalfsuffixText :: Rule
ruleNumeralSuffixesHalfsuffixText = Rule
  { name = "number suffixes (half-suffix text) (1..9)"
  , pattern =
    [ regex "((bir?|iki|Ã¼Ã§Ã¼?|dÃ¶rt|beÅŸ|altÄ±|yedi|sekiz|dokuz)(buÃ§uk))"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) numeralSuffixesHalfsuffixTextMap >>= double
      _ -> Nothing
  }

tenToNintynineMap :: HashMap Text Integer
tenToNintynineMap = HashMap.fromList
  [ ( "onbi", 11)
  , ( "onbir", 11)
  , ( "oniki", 12)
  , ( "onÃ¼Ã§", 13)
  , ( "ondÃ¶rt", 14)
  , ( "onbeÅŸ", 15)
  , ( "onaltÄ±", 16)
  , ( "onyedi", 17)
  , ( "onsekiz", 18)
  , ( "ondokuz", 19)
  , ( "yirmibi", 21)
  , ( "yirmibir", 21)
  , ( "yirmiiki", 22)
  , ( "yirmiÃ¼Ã§", 23)
  , ( "yirmidÃ¶rt", 24)
  , ( "yirmibeÅŸ", 25)
  , ( "yirmialtÄ±", 26)
  , ( "yirmiyedi", 27)
  , ( "yirmisekiz", 28)
  , ( "yirmidokuz", 29)
  , ( "otuzbi", 31)
  , ( "otuzbir", 31)
  , ( "otuziki", 32)
  , ( "otuzÃ¼Ã§", 33)
  , ( "otuzdÃ¶rt", 34)
  , ( "otuzbeÅŸ", 35)
  , ( "otuzaltÄ±", 36)
  , ( "otuzyedi", 37)
  , ( "otuzsekiz", 38)
  , ( "otuzdokuz", 39)
  , ( "kÄ±rkbir", 41)
  , ( "kÄ±rkbi", 41)
  , ( "kÄ±rkiki", 42)
  , ( "kÄ±rkÃ¼Ã§", 43)
  , ( "kÄ±rkdÃ¶rt", 44)
  , ( "kÄ±rkbeÅŸ", 45)
  , ( "kÄ±rkaltÄ±", 46)
  , ( "kÄ±rkyedi", 47)
  , ( "kÄ±rksekiz", 48)
  , ( "kÄ±rkdokuz", 49)
  , ( "ellibi", 51)
  , ( "ellibir", 51)
  , ( "elliiki", 52)
  , ( "elliÃ¼Ã§", 53)
  , ( "ellidÃ¶rt", 54)
  , ( "ellibeÅŸ", 55)
  , ( "ellialtÄ±", 56)
  , ( "elliyedi", 57)
  , ( "ellisekiz", 58)
  , ( "ellidokuz", 59)
  , ( "altmÄ±ÅŸbir", 61)
  , ( "atmÄ±ÅŸbir", 61)
  , ( "atmÄ±ÅŸiki", 62)
  , ( "altmÄ±ÅŸiki", 62)
  , ( "atmÄ±ÅŸÃ¼Ã§", 63)
  , ( "altmÄ±ÅŸÃ¼Ã§", 63)
  , ( "atmÄ±ÅŸdÃ¶rt", 64)
  , ( "altmÄ±ÅŸdÃ¶rt", 64)
  , ( "atmÄ±ÅŸbeÅŸ", 65)
  , ( "altmÄ±ÅŸbeÅŸ", 65)
  , ( "atmÄ±ÅŸaltÄ±", 66)
  , ( "altmÄ±ÅŸaltÄ±", 66)
  , ( "altmÄ±ÅŸyedi", 67)
  , ( "atmÄ±ÅŸyedi", 67)
  , ( "altmÄ±ÅŸsekiz", 68)
  , ( "atmÄ±ÅŸsekiz", 68)
  , ( "atmÄ±ÅŸdokuz", 69)
  , ( "altmÄ±ÅŸdokuz", 69)
  , ( "yetmiÅŸbir", 71)
  , ( "yetmiÅŸbi", 71)
  , ( "yetmiÅŸiki", 72)
  , ( "yetmiÅŸÃ¼Ã§", 73)
  , ( "yetmiÅŸdÃ¶rt", 74)
  , ( "yetmiÅŸbeÅŸ", 75)
  , ( "yetmiÅŸaltÄ±", 76)
  , ( "yetmiÅŸyedi", 77)
  , ( "yetmiÅŸsekiz", 78)
  , ( "yetmiÅŸdokuz", 79)
  , ( "seksenbir", 81)
  , ( "seksenbi", 81)
  , ( "sekseniki", 82)
  , ( "seksenÃ¼Ã§", 83)
  , ( "seksendÃ¶rt", 84)
  , ( "seksenbeÅŸ", 85)
  , ( "seksenaltÄ±", 86)
  , ( "seksenyedi", 87)
  , ( "seksensekiz", 88)
  , ( "seksendokuz", 89)
  , ( "doksanbi", 91)
  , ( "doksanbir", 91)
  , ( "doksaniki", 92)
  , ( "doksanÃ¼Ã§", 93)
  , ( "doksandÃ¶rt", 94)
  , ( "doksanbeÅŸ", 95)
  , ( "doksanaltÄ±", 96)
  , ( "doksanyedi", 97)
  , ( "doksansekiz", 98)
  , ( "doksandokuz", 99)
  ]

ruleInteger3 :: Rule
ruleInteger3 = Rule
  { name = "integer 11..19 21..29 31..39 41..49 51..59 61..69 71..79 81..89 91..99"
  , pattern =
    [ regex "((on|yirmi|otuz|kÄ±rk|elli|atmÄ±ÅŸ|altmÄ±ÅŸ|yetmiÅŸ|seksen|doksan)(bir|bi|iki|Ã¼Ã§|dÃ¶rt|beÅŸ|altÄ±|yedi|sekiz|dokuz))"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) tenToNintynineMap >>= integer
      _ -> Nothing
  }

thousandsMap :: HashMap Text Integer
thousandsMap = HashMap.fromList
  [ ( "bin", 1000)
  , ( "ikibin", 2000)
  , ( "Ã¼Ã§bin", 3000)
  , ( "dÃ¶rtbin", 4000)
  , ( "beÅŸbin", 5000)
  , ( "altÄ±bin", 6000)
  , ( "yedibin", 7000)
  , ( "sekizbin", 8000)
  , ( "dokuzbin", 9000)
  ]

ruleInteger6 :: Rule
ruleInteger6 = Rule
  { name = "integer 1000..9000"
  , pattern =
    [ regex "(bin|ikibin|Ã¼Ã§bin|dÃ¶rtbin|beÅŸbin|altÄ±bin|yedibin|sekizbin|dokuzbin)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) thousandsMap >>= integer >>= withGrain 3
      _ -> Nothing
  }

ruleIntersect :: Rule
ruleIntersect = Rule
  { name = "intersect"
  , pattern =
    [ Predicate hasGrain
    , Predicate $ and . sequence [not . isMultipliable, isPositive]
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:
       Token Numeral NumeralData{TNumeral.value = val2}:
       _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2
      _ -> Nothing
  }

ruleNumeralsSuffixesKMG :: Rule
ruleNumeralsSuffixesKMG = Rule
  { name = "numbers suffixes (K, M, G)"
  , pattern =
    [ dimension Numeral
    , regex "([kmgb])(?=[\\W\\$â‚¬]|$)"
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = v}:
       Token RegexMatch (GroupMatch (match:_)):
       _) -> case Text.toLower match of
          "k" -> double $ v * 1e3
          "b" -> double $ v * 1e3
          "m" -> double $ v * 1e6
          "g" -> double $ v * 1e9
          _ -> Nothing
      _ -> Nothing
  }

rulePowersOfTen :: Rule
rulePowersOfTen = Rule
  { name = "powers of tens"
  , pattern =
    [ regex "(y(Ã¼)z|bin|milyon)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of
        "yÃ¼z" -> double 1e2 >>= withGrain 2 >>= withMultipliable
        "bin"      -> double 1e3 >>= withGrain 3 >>= withMultipliable
        "milyon"   -> double 1e6 >>= withGrain 6 >>= withMultipliable
        _          -> Nothing
      _ -> Nothing
  }

tenThousandsMap :: HashMap Text Integer
tenThousandsMap = HashMap.fromList
  [  ( "onbin", 10000)
   , ( "yirmibin", 20000)
   , ( "otuzbin", 30000)
   , ( "kÄ±rkbin", 40000)
   , ( "ellibin", 50000)
   , ( "altmÄ±ÅŸbin", 60000)
   , ( "atmÄ±ÅŸbin", 60000)
   , ( "yetmiÅŸbin", 70000)
   , ( "seksenbin", 80000)
   , ( "doksanbin", 90000)
  ]

ruleInteger7 :: Rule
ruleInteger7 = Rule
  { name = "integer 10000..90000"
  , pattern =
    [ regex "(onbin|yirmibin|otuzbin|kÄ±rkbin|ellibin|atmÄ±ÅŸbin|altmÄ±ÅŸbin|yetmiÅŸbin|seksenbin|doksanbin)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) tenThousandsMap >>= integer >>= withGrain 4
      _ -> Nothing
  }

hundredThousandsMap :: HashMap Text Integer
hundredThousandsMap = HashMap.fromList
  [ ( "yÃ¼zbin", 100000)
  , ( "ikiyÃ¼zbin", 200000)
  , ( "Ã¼Ã§yÃ¼zbin", 300000)
  , ( "dÃ¶rtyÃ¼zbin", 400000)
  , ( "beÅŸyÃ¼zbin", 500000)
  , ( "altÄ±yÃ¼zbin", 600000)
  , ( "yediyÃ¼zbin", 700000)
  , ( "sekizyÃ¼zbin", 800000)
  , ( "dokuzyÃ¼zbin", 900000)
  ]

ruleInteger8 :: Rule
ruleInteger8 = Rule
  { name = "integer 100000..900000"
  , pattern =
    [ regex "(yÃ¼zbin|ikiyÃ¼zbin|Ã¼Ã§yÃ¼zbin|dÃ¶rtyÃ¼zbin|beÅŸyÃ¼zbin|altÄ±yÃ¼zbin|yediyÃ¼zbin|sekizyÃ¼zbin|dokuzyÃ¼zbin)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) hundredThousandsMap >>= integer >>= withGrain 5
      _ -> Nothing
  }

ruleHalf :: Rule
ruleHalf = Rule
  { name = "half"
  , pattern =
    [ regex "(yarÄ±m)"
    ]
  , prod = \_ -> double 0.5
  }

integer9Map :: HashMap Text Double
integer9Map = HashMap.fromList
  [ ( "onbirbuÃ§uk", 11.5)
  , ( "onbibuÃ§uk", 11.5)
  , ( "onikibuÃ§uk", 12.5)
  , ( "onÃ¼Ã§buÃ§uk", 13.5)
  , ( "ondÃ¶rtbuÃ§uk", 14.5)
  , ( "onbeÅŸbuÃ§uk", 15.5)
  , ( "onaltÄ±buÃ§uk", 16.5)
  , ( "onyedibuÃ§uk", 17.5)
  , ( "onsekizbuÃ§uk", 18.5)
  , ( "ondokuzbuÃ§uk", 19.5)
  , ( "yirmibibuÃ§uk", 21.5)
  , ( "yirmibirbuÃ§uk", 21.5)
  , ( "yirmiikibuÃ§uk", 22.5)
  , ( "yirmiÃ¼Ã§buÃ§uk", 23.5)
  , ( "yirmidÃ¶rtbuÃ§uk", 24.5)
  , ( "yirmibeÅŸbuÃ§uk", 25.5)
  , ( "yirmialtÄ±buÃ§uk", 26.5)
  , ( "yirmiyedibuÃ§uk", 27.5)
  , ( "yirmisekizbuÃ§uk", 28.5)
  , ( "yirmidokuzbuÃ§uk", 29.5)
  , ( "otuzbibuÃ§uk", 31.5)
  , ( "otuzbirbuÃ§uk", 31.5)
  , ( "otuzikibuÃ§uk", 32.5)
  , ( "otuzÃ¼Ã§buÃ§uk", 33.5)
  , ( "otuzdÃ¶rtbuÃ§uk", 34.5)
  , ( "otuzbeÅŸbuÃ§uk", 35.5)
  , ( "otuzaltÄ±buÃ§uk", 36.5)
  , ( "otuzyedibuÃ§uk", 37.5)
  , ( "otuzsekizbuÃ§uk", 38.5)
  , ( "otuzdokuzbuÃ§uk", 39.5)
  , ( "kÄ±rkbirbuÃ§uk", 41.5)
  , ( "kÄ±rkbibuÃ§uk", 41.5)
  , ( "kÄ±rkikibuÃ§uk", 42.5)
  , ( "kÄ±rkÃ¼Ã§buÃ§uk", 43.5)
  , ( "kÄ±rkdÃ¶rtbuÃ§uk", 44.5)
  , ( "kÄ±rkbeÅŸbuÃ§uk", 45.5)
  , ( "kÄ±rkaltÄ±buÃ§uk", 46.5)
  , ( "kÄ±rkyedibuÃ§uk", 47.5)
  , ( "kÄ±rksekizbuÃ§uk", 48.5)
  , ( "kÄ±rkdokuzbuÃ§uk", 49.5)
  , ( "ellibibuÃ§uk", 51.5)
  , ( "ellibirbuÃ§uk", 51.5)
  , ( "elliikibuÃ§uk", 52.5)
  , ( "elliÃ¼Ã§buÃ§uk", 53.5)
  , ( "ellidÃ¶rtbuÃ§uk", 54.5)
  , ( "ellibeÅŸbuÃ§uk", 55.5)
  , ( "ellialtÄ±buÃ§uk", 56.5)
  , ( "elliyedibuÃ§uk", 57.5)
  , ( "ellisekizbuÃ§uk", 58.5)
  , ( "ellidokuzbuÃ§uk", 59.5)
  , ( "altmÄ±ÅŸbirbuÃ§uk", 61.5)
  , ( "atmÄ±ÅŸbirbuÃ§uk", 61.5)
  , ( "altmÄ±ÅŸikibuÃ§uk", 62.5)
  , ( "atmÄ±ÅŸikibuÃ§uk", 62.5)
  , ( "atmÄ±ÅŸÃ¼Ã§buÃ§uk", 63.5)
  , ( "altmÄ±ÅŸÃ¼Ã§buÃ§uk", 63.5)
  , ( "altmÄ±ÅŸdÃ¶rtbuÃ§uk", 64.5)
  , ( "atmÄ±ÅŸdÃ¶rtbuÃ§uk", 64.5)
  , ( "altmÄ±ÅŸbeÅŸbuÃ§uk", 65.5)
  , ( "atmÄ±ÅŸbeÅŸbuÃ§uk", 65.5)
  , ( "altmÄ±ÅŸaltÄ±buÃ§uk", 66.5)
  , ( "atmÄ±ÅŸaltÄ±buÃ§uk", 66.5)
  , ( "atmÄ±ÅŸyedibuÃ§uk", 67.5)
  , ( "altmÄ±ÅŸyedibuÃ§uk", 67.5)
  , ( "altmÄ±ÅŸsekizbuÃ§uk", 68.5)
  , ( "atmÄ±ÅŸsekizbuÃ§uk", 68.5)
  , ( "altmÄ±ÅŸdokuzbuÃ§uk", 69.5)
  , ( "atmÄ±ÅŸdokuzbuÃ§uk", 69.5)
  , ( "yetmiÅŸbibuÃ§uk", 71.5)
  , ( "yetmiÅŸbirbuÃ§uk", 71.5)
  , ( "yetmiÅŸikibuÃ§uk", 72.5)
  , ( "yetmiÅŸÃ¼Ã§buÃ§uk", 73.5)
  , ( "yetmiÅŸdÃ¶rtbuÃ§uk", 74.5)
  , ( "yetmiÅŸbeÅŸbuÃ§uk", 75.5)
  , ( "yetmiÅŸaltÄ±buÃ§uk", 76.5)
  , ( "yetmiÅŸyedibuÃ§uk", 77.5)
  , ( "yetmiÅŸsekizbuÃ§uk", 78.5)
  , ( "yetmiÅŸdokuzbuÃ§uk", 79.5)
  , ( "seksenbibuÃ§uk", 81.5)
  , ( "seksenbirbuÃ§uk", 81.5)
  , ( "seksenikibuÃ§uk", 82.5)
  , ( "seksenÃ¼Ã§buÃ§uk", 83.5)
  , ( "seksendÃ¶rtbuÃ§uk", 84.5)
  , ( "seksenbeÅŸbuÃ§uk", 85.5)
  , ( "seksenaltÄ±buÃ§uk", 86.5)
  , ( "seksenyedibuÃ§uk", 87.5)
  , ( "seksensekizbuÃ§uk", 88.5)
  , ( "seksendokuzbuÃ§uk", 89.5)
  , ( "doksanbirbuÃ§uk", 91.5)
  , ( "doksanbibuÃ§uk", 91.5)
  , ( "doksanikibuÃ§uk", 92.5)
  , ( "doksanÃ¼Ã§buÃ§uk", 93.5)
  , ( "doksandÃ¶rtbuÃ§uk", 94.5)
  , ( "doksanbeÅŸbuÃ§uk", 95.5)
  , ( "doksanaltÄ±buÃ§uk", 96.5)
  , ( "doksanyedibuÃ§uk", 97.5)
  , ( "doksansekizbuÃ§uk", 98.5)
  , ( "doksandokuzbuÃ§uk", 99.5)
  ]

ruleInteger9 :: Rule
ruleInteger9 = Rule
  { name = "integer 11..19 21..29 31..39 41..49 51..59 61..69 71..79 81..89 91..99"
  , pattern =
    [ regex "((on|yirmi|otuz|kÄ±rk|elli|atmÄ±ÅŸ|altmÄ±ÅŸ|yetmiÅŸ|seksen|doksan)(bir|bi|iki|Ã¼Ã§Ã¼?|dÃ¶rt|beÅŸ|altÄ±|yedi|sekiz|dokuz)(buÃ§uk))"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) integer9Map >>= double
      _ -> Nothing
  }

ruleDozen :: Rule
ruleDozen = Rule
  { name = "dozen"
  , pattern =
    [ regex "dÃ¼zine"
    ]
  , prod = \_ -> integer 12 >>= withGrain 1 >>= withMultipliable
  }

oneToNineMap :: HashMap Text Integer
oneToNineMap = HashMap.fromList
  [ ( "s\305f\305r", 0)
  , ( "yok", 0)
  , ( "hiÃ§", 0)
  , ( "bir", 1)
  , ( "bi", 1)
  , ( "yek", 1)
  , ( "tek", 1)
  , ( "iki", 2)
  , ( "Ã¼Ã§", 3)
  , ( "Ã¼Ã§Ã¼", 3)
  , ( "dÃ¶rt", 4)
  , ( "beÅŸ", 5)
  , ( "altÄ±", 6)
  , ( "yedi", 7)
  , ( "sekiz", 8)
  , ( "dokuz", 9)
  ]

ruleInteger :: Rule
ruleInteger = Rule
  { name = "integer (0..9)"
  , pattern =
    [ regex "(yok|hi(Ã§)|s(Ä±)f(Ä±)r|bir?|[ty]ek|iki|(Ã¼)(Ã§)(Ã¼)?|d(Ã¶)rt|be(ÅŸ)|alt(Ä±)|yedi|sekiz|dokuz)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) oneToNineMap >>= integer
      _ -> Nothing
  }

numeralSuffixesHalfsuffixText2Map :: HashMap Text Double
numeralSuffixesHalfsuffixText2Map = HashMap.fromList
  [ ( "onbuÃ§uk", 10.5)
  , ( "yirmibuÃ§uk", 20.5)
  , ( "otuzbuÃ§uk", 30.5)
  , ( "kÄ±rkbuÃ§uk", 40.5)
  , ( "ellibuÃ§uk", 50.5)
  , ( "atmÄ±ÅŸbuÃ§uk", 60.5)
  , ( "altmÄ±ÅŸbuÃ§uk", 60.5)
  , ( "yetmiÅŸbuÃ§uk", 70.5)
  , ( "seksenbuÃ§uk", 80.5)
  , ( "doksanbuÃ§uk", 90.5)
  ]

ruleNumeralSuffixesHalfsuffixText2 :: Rule
ruleNumeralSuffixesHalfsuffixText2 = Rule
  { name = "number suffixes (half-suffix text) (10..90)"
  , pattern =
    [ regex "((on|yirmi|otuz|kÄ±rk|elli|atmÄ±ÅŸ|altmÄ±ÅŸ|yetmiÅŸ|seksen|doksan)(buÃ§uk))"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) numeralSuffixesHalfsuffixText2Map
        >>= double
      _ -> Nothing
  }

ruleNumeralSuffixesHalfSuffix :: Rule
ruleNumeralSuffixesHalfSuffix = Rule
  { name = "number suffixes (half-suffix)"
  , pattern =
    [ dimension Numeral
    , regex "(buÃ§uk)(?=[\\W\\$â‚¬]|$)"
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = v}:_) -> double $ v + 0.5
      _ -> Nothing
  }

ruleInteger4 :: Rule
ruleInteger4 = Rule
  { name = "integer 11..99"
  , pattern =
    [ oneOf [70, 20, 60, 50, 40, 90, 30, 10, 80]
    , Predicate $ numberBetween 1 10
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = v1}:
       Token Numeral NumeralData{TNumeral.value = v2}:
       _) -> double $ v1 + v2
      _ -> Nothing
  }

ruleGroupOfTens :: Rule
ruleGroupOfTens = Rule
  { name = "group of ten(s)"
  , pattern =
    [ regex "deste"
    ]
  , prod = \_ -> integer 10 >>= withGrain 1 >>= withMultipliable
  }

tensMap :: HashMap Text Integer
tensMap = HashMap.fromList
  [ ( "on", 10)
  , ( "yirmi", 20)
  , ( "otuz", 30)
  , ( "kÄ±rk", 40)
  , ( "elli", 50)
  , ( "altmÄ±ÅŸ", 60)
  , ( "atmÄ±ÅŸ", 60)
  , ( "yetmiÅŸ", 70)
  , ( "seksen", 80)
  , ( "doksan", 90)
  ]

ruleInteger2 :: Rule
ruleInteger2 = Rule
  { name = "integer (10..90)"
  , pattern =
    [ regex "(on|yirmi|otuz|kÄ±rk|elli|atmÄ±ÅŸ|altmÄ±ÅŸ|yetmiÅŸ|seksen|doksan)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        HashMap.lookup (Text.toLower match) tensMap >>= integer
      _ -> Nothing
  }

ruleQuarter :: Rule
ruleQuarter = Rule
  { name = "quarter"
  , pattern =
    [ regex "(Ã§eyrek)"
    ]
  , prod = \_ -> double 0.25
  }

ruleNumeralDotNumeral :: Rule
ruleNumeralDotNumeral = Rule
  { name = "number dot number"
  , pattern =
    [ dimension Numeral
    , regex "nokta|virgÃ¼l"
    , Predicate $ not . hasGrain
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = v1}:
       _:
       Token Numeral NumeralData{TNumeral.value = v2}:
       _) -> double $ v1 + decimalsToDouble v2
      _ -> Nothing
  }

ruleIntegerWithThousandsSeparator :: Rule
ruleIntegerWithThousandsSeparator = Rule
  { name = "integer with thousands separator ."
  , pattern =
    [ regex "(\\d{1,3}(\\.\\d\\d\\d){1,5})"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):_) ->
        parseDouble (Text.replace "." Text.empty match) >>= double
      _ -> Nothing
  }

rules :: [Rule]
rules =
  [ ruleACoupleOf
  , ruleDecimalNumeral
  , ruleDecimalWithThousandsSeparator
  , ruleDozen
  , ruleFew
  , ruleGroupOfTens
  , ruleHalf
  , ruleInteger
  , ruleInteger2
  , ruleInteger3
  , ruleInteger4
  , ruleInteger5
  , ruleInteger6
  , ruleInteger7
  , ruleInteger8
  , ruleInteger9
  , ruleIntegerWithThousandsSeparator
  , ruleIntersect
  , ruleNumeralDotNumeral
  , ruleNumeralSuffixesHalfSuffix
  , ruleNumeralSuffixesHalfsuffixText
  , ruleNumeralSuffixesHalfsuffixText2
  , ruleNumeralsPrefixWithNegativeOrMinus
  , ruleNumeralsSuffixesKMG
  , rulePowersOfTen
  , ruleQuarter
  , ruleTen
  , ruleMultiply
  ]


-- 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 #-}

module Duckling.Ordinal.Helpers
  ( ordinal
  , oneOf
  ) where

import Prelude

import Duckling.Dimensions.Types
import Duckling.Ordinal.Types (OrdinalData (..))
import Duckling.Types
import qualified Duckling.Ordinal.Types as TOrdinal

-- -----------------------------------------------------------------
-- Patterns

oneOf :: [Int] -> PatternItem
oneOf vs = Predicate $ \x ->
  case x of
    (Token Ordinal OrdinalData {TOrdinal.value = v}) -> elem v vs
    _ -> False

-- -----------------------------------------------------------------
-- Production

ordinal :: Int -> Token
ordinal x = Token Ordinal OrdinalData {TOrdinal.value = x}


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

module Duckling.Ordinal.Types where

import Control.DeepSeq
import Data.Aeson
import Data.Hashable
import Data.Text (Text)
import GHC.Generics
import Prelude

import Duckling.Resolve (Resolve(..))

newtype OrdinalData = OrdinalData { value :: Int }
  deriving (Eq, Generic, Hashable, Show, Ord, NFData)

instance Resolve OrdinalData where
  type ResolvedValue OrdinalData = OrdinalData
  resolve _ _ x = Just (x, False)

instance ToJSON OrdinalData where
  toJSON (OrdinalData value) = object
    [ "type" .= ("value" :: Text)
    , "value" .= value
    ]

isBetween :: Ord a => a -> a -> a -> Bool
isBetween x low high = low <= x && x <= high


-- 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 OverloadedStrings #-}

module Duckling.Ordinal.AR.Corpus
  ( corpus
  ) where

import Data.String
import Prelude

import Duckling.Locale
import Duckling.Ordinal.Types
import Duckling.Resolve
import Duckling.Testing.Types

corpus :: Corpus
corpus = (testContext {locale = makeLocale AR Nothing}, testOptions, allExamples)

allExamples :: [Example]
allExamples = concat
  [ examples (OrdinalData 1)
             [ "Ø§Ù„Ø§ÙˆÙ„"
             , "Ø§Ù„Ø£ÙˆÙ„"
             , "Ø§ÙˆÙ„"
             ]
  , examples (OrdinalData 2)
             [ "Ø§Ù„Ø«Ø§Ù†ÙŠ"
             , "Ø§Ù„Ø«Ø§Ù†"
             , "Ø«Ø§Ù†ÙŠ"
             ]
  , examples (OrdinalData 3)
             [ "Ø§Ù„Ø«Ø§Ù„Ø«"
             , "Ø«Ø§Ù„Ø«"
             ]
  , examples (OrdinalData 4)
             [ "Ø§Ù„Ø±Ø§Ø¨Ø¹"
             , "Ø±Ø§Ø¨Ø¹"
             ]
  , examples (OrdinalData 8)
             [ "Ø§Ù„Ø«Ø§Ù…Ù†"
             , "Ø«Ø§Ù…Ù†"
             ]
  , examples (OrdinalData 11)
             [ "Ø§Ù„Ø£ØØ¯ Ø¹Ø´Ø±"
             , "Ø§Ù„Ø¥ØØ¯Ù‰ Ø¹Ø´Ø±Ø©"
             , "Ø§Ù„ØØ§Ø¯ÙŠ Ø¹Ø´Ø±Ø©"
             ]
  , examples (OrdinalData 12)
             [ "Ø§Ù„Ø«Ø§Ù†ÙŠ Ø¹Ø´Ø±Ø©"
             , "Ø§Ù„Ø«Ø§Ù† Ø¹Ø´Ø±"
             , "Ø§Ù„Ø§Ø«Ù†Ù‰ Ø¹Ø´Ø±"
             ]
  , examples (OrdinalData 13)
             [ "Ø§Ù„Ø«Ø§Ù„Ø« Ø¹Ø´Ø±"
             , "Ø§Ù„Ø«Ø§Ù„Ø«Ø© Ø¹Ø´Ø±Ø©"
             ]
  , examples (OrdinalData 21)
             [ "Ø§Ù„ØØ§Ø¯ÙŠ ÙˆØ§Ù„Ø¹Ø´Ø±ÙŠÙ†"
             , "Ø§Ù„ÙˆØ§ØØ¯ Ùˆ Ø§Ù„Ø¹Ø´Ø±ÙˆÙ†"
             ]
  , examples (OrdinalData 25)
             [ "Ø§Ù„Ø®Ø§Ù…Ø³ ÙˆØ§Ù„Ø¹Ø´Ø±ÙŠÙ†"
             , "Ø§Ù„Ø®Ø§Ù…Ø³ Ùˆ Ø§Ù„Ø¹Ø´Ø±ÙˆÙ†"
             ]
  , examples (OrdinalData 31)
             [ "Ø§Ù„ÙˆØ§ØØ¯ ÙˆØ§Ù„Ø«Ù„Ø§Ø«ÙˆÙ†"
             , "Ø§Ù„ÙˆØ§ØØ¯ ÙˆØ§Ù„Ø«Ù„Ø§Ø«ÙŠÙ†"
             ]
  , examples (OrdinalData 72)
             [ "Ø§Ù„Ø«Ø§Ù† ÙˆØ§Ù„Ø³Ø¨Ø¹ÙˆÙ†"
             , "Ø§Ù„Ø«Ø§Ù†ÙŠ ÙˆØ§Ù„Ø³Ø¨Ø¹ÙŠÙ†"
             ]
  , examples (OrdinalData 90)
             [ "Ø§Ù„ØªØ³Ø¹ÙˆÙ†"
             , "Ø§Ù„ØªØ³Ø¹ÙŠÙ†"
             ]
  ]


-- 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 OverloadedStrings #-}

module Duckling.Ordinal.CA.Corpus
  ( corpus ) where

import Data.String
import Prelude

import Duckling.Locale
import Duckling.Ordinal.Types
import Duckling.Resolve
import Duckling.Testing.Types

corpus :: Corpus
corpus = (testContext {locale = makeLocale CA Nothing}, testOptions, allExamples)

allExamples :: [Example]
allExamples = concat
  [ examples (OrdinalData 1)
             [ "primer"
             , "primera"
             , "primers"
             , "primeres"
             ]
   , examples (OrdinalData 2)
              [ "segon"
              , "segona"
              , "segons"
              , "segones"
              ]
   , examples (OrdinalData 3)
              [ "tercer"
              , "tercera"
              , "tercers"
              , "terceres"
              ]
   , examples (OrdinalData 4)
              [ "quart"
              , "quarta"
              , "quarts"
              , "quartes"
              ]
   , examples (OrdinalData 5)
              [ "cinquÃ¨"
              , "cinquena"
              , "cinquens"
              , "cinquenes"
              ]
   , examples (OrdinalData 6)
              [ "sisÃ¨"
              , "sisena"
              , "sisens"
              , "sisenes"
              ]
   , examples (OrdinalData 7)
              [ "setÃ¨"
              , "setena"
              , "setens"
              , "setenes"
              ]
   , examples (OrdinalData 8)
              [ "vuitÃ¨"
              , "vuitena"
              , "vuitens"
              , "vuitenes"
              ]
   , examples (OrdinalData 9)
              [ "novÃ¨"
              , "novena"
              , "novens"
              , "novenes"
              ]
   , examples (OrdinalData 10)
              [ "desÃ¨"
              , "desena"
              , "desens"
              , "desenes"
              ]
    , examples (OrdinalData 11)
              [ "onzÃ¨"
              , "onzena"
              ]
    , examples (OrdinalData 12)
              [ "dotzÃ¨"
              , "dotzena"
              ]
    , examples (OrdinalData 13)
              [ "tretzÃ¨"
              , "tretzena"
              ]
    , examples (OrdinalData 14)
              [ "catorzÃ¨"
              , "catorzena"
              ]
    , examples (OrdinalData 15)
              [ "quinzÃ¨"
              , "quinzena"
              ]
    , examples (OrdinalData 16)
              [ "setzÃ¨"
              , "setzena"
              ]
    , examples (OrdinalData 17)
              [ "dissetÃ¨"
              , "dissetena"
              ]
    , examples (OrdinalData 18)
              [ "divuitÃ¨"
              , "divuitena"
              ]
    , examples (OrdinalData 19)
              [ "dinovÃ¨"
              , "dinovena"
              ]
    , examples (OrdinalData 20)
              [ "vintÃ¨"
              , "vintena"
              ]
  ]