module HPhone (HPhone.lookup, HPhone.validate, CountryCodeAbbr, PhoneNumber, Phone(..)) where
import PhoneNumberMetadata
import qualified Data.Map.Strict as Map
import Data.Maybe (isNothing, catMaybes, fromJust)
import Data.List
import Text.Regex.PCRE
import Data.Char (toUpper)
type CountryCodeAbbr = String
type TerritoryMap = Map.Map CountryCodeAbbr Territory
data Phone = Phone
{ number :: String
, code :: String
, countryAbbr :: String
, numberType :: String
} deriving (Eq, Read, Show)
ts :: [Territory]
ts = territories phoneNumberMetadata
territoryMap :: TerritoryMap
territoryMap = Map.fromList [(abbreviation t, t) | t <- ts]
validate :: PhoneNumber -> CountryCodeAbbr -> Bool
validate phone abbr
| isNothing $ HPhone.lookup phone abbr = False
| otherwise = True
lookup :: PhoneNumber -> CountryCodeAbbr -> Maybe Phone
lookup phone abbr = lookupPhone (ltrim phone) abbr territoryMap
where ltrim = dropWhile (`elem` "0")
normalize :: PhoneNumber -> PhoneNumber
normalize _ = undefined
lookupPhone :: PhoneNumber -> CountryCodeAbbr -> TerritoryMap -> Maybe Phone
lookupPhone phoneNumber abbr territoryMap =
Map.lookup abbr territoryMap >>= \t ->
HPhone.find phoneNumber t
find :: PhoneNumber -> Territory -> Maybe Phone
find p t
| null matches = Nothing
| otherwise = Just $ constructResponse p t phonetype
where phonetype = fmap toUpper $ intercalate "_or_" $ fmap phoneNumberType matches
matches = filter (isMatch p) (catMaybes $ phoneNumberPatterns t)
isMatch :: PhoneNumber -> PhoneNumberPatterns -> Bool
isMatch phone (PhoneNumberPatterns _ (Just np) _ _) = phone =~ ("^(" ++ np ++ ")$")::Bool
isMatch phone (PhoneNumberPatterns _ _ (Just pp) _) = phone =~ ("^(" ++ pp ++ ")$")::Bool
isMatch phone PhoneNumberPatterns {} = False
phoneNumberPatterns :: Territory -> [Maybe PhoneNumberPatterns]
phoneNumberPatterns t =
[ mobile, fixedLine, pager, tollFree, premiumRate, sharedCost, personalNumber, voip, uan, voicemail] <*> pure t
constructResponse :: PhoneNumber -> Territory -> String -> Phone
constructResponse number territory phoneType =
Phone { number = number
, code = countryCode territory
, countryAbbr = abbreviation territory
, numberType = phoneType
}