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

import qualified Data.Text as Text
import Prelude
import Data.String

import Duckling.Dimensions.Types
import Duckling.Numeral.Helpers (parseInt)
import Duckling.PhoneNumber.Types (PhoneNumberData(..))
import qualified Duckling.PhoneNumber.Types as TPhoneNumber
import Duckling.Regex.Types
import Duckling.Types

rulePhoneNumber :: Rule
rulePhoneNumber :: Rule
rulePhoneNumber = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"phone number"
  , pattern :: Pattern
pattern =
    -- We somewhat arbitrarly use 20 here to limit the length of matches,
    -- otherwise due to backtracking the regexp will take very long time
    -- or run out of stack for some inputs.
    [ String -> PatternItem
regex (String -> PatternItem) -> String -> PatternItem
forall a b. (a -> b) -> a -> b
$
        String
"(?:\\(?\\+(\\d{1,2})\\)?[\\s-\\.]*)?" String -> String -> String
forall a. [a] -> [a] -> [a]
++ -- area code
        String
"((?=[-\\d()\\s\\.]{6,16}(?:\\s*e?xt?\\.?\\s*(?:\\d{1,20}))?(?:[^\\d]+|$))(?:[\\d(]{1,20}(?:[-)\\s\\.]*\\d{1,20}){0,20}){1,20})" String -> String -> String
forall a. [a] -> [a] -> [a]
++ -- nums
        String
"(?:\\s*e?xt?\\.?\\s*(\\d{1,20}))?" -- extension
    ]
  , prod :: Production
prod = \[Token]
xs -> case [Token]
xs of
      (Token Dimension a
RegexMatch (GroupMatch (code:nums:ext:_)):[Token]
_) ->
        let parseNum :: Text -> Maybe Integer
parseNum Text
x = Int -> Integer
forall a. Integral a => a -> Integer
toInteger (Int -> Integer) -> Maybe Int -> Maybe Integer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> Maybe Int
parseInt Text
x
            mcode :: Maybe Integer
mcode = Text -> Maybe Integer
parseNum Text
code
            mext :: Maybe Integer
mext = Text -> Maybe Integer
parseNum Text
ext
            cleanup :: Text -> Text
cleanup = (Char -> Bool) -> Text -> Text
Text.filter (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isWhitespace)
            isWhitespace :: Char -> Bool
isWhitespace Char
x = Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Char
x [Char
'.', Char
' ', Char
'-', Char
'\t', Char
'(', Char
')']
        in Token -> Maybe Token
forall a. a -> Maybe a
Just (Token -> Maybe Token)
-> (PhoneNumberData -> Token) -> PhoneNumberData -> Maybe Token
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dimension PhoneNumberData -> PhoneNumberData -> Token
forall a.
(Resolve a, Eq a, Hashable a, Show a, NFData a) =>
Dimension a -> a -> Token
Token Dimension PhoneNumberData
PhoneNumber (PhoneNumberData -> Maybe Token) -> PhoneNumberData -> Maybe Token
forall a b. (a -> b) -> a -> b
$ PhoneNumberData :: Maybe Integer -> Text -> Maybe Integer -> PhoneNumberData
PhoneNumberData
          { prefix :: Maybe Integer
TPhoneNumber.prefix = Maybe Integer
mcode
          , number :: Text
TPhoneNumber.number = Text -> Text
cleanup Text
nums
          , extension :: Maybe Integer
TPhoneNumber.extension = Maybe Integer
mext
          }
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

rules :: [Rule]
rules :: [Rule]
rules = [ Rule
rulePhoneNumber ]