-- | A trie like data structure for defining maps from 'BCP47' tags to values.
--
-- This structure supports collection and lookup of language tagged values. Its
-- semantics are based on those defined in the BCP 47 specification.
--
module Data.BCP47.Trie
  ( Trie
  , fromList
  , fromNonEmpty
  , singleton
  , lookup
  , match
  , elem
  , union
  , unionWith
  , mapMaybe
  )
where

import Prelude hiding (elem, lookup, null)

import Data.BCP47
import Data.BCP47.Trie.Internal
import qualified Data.Map as Map
import Data.Maybe (isJust)

-- | Lookup the most relevant item for a tag
--
-- "Lookup is used to select the single language tag that best matches the
-- language priority list for a given request...For example, if the language
-- range is 'de-ch', a lookup operation can produce content with the tags 'de'
-- or 'de-CH' but never content with the tag 'de-CH-1996'."
--
-- https://tools.ietf.org/html/bcp47#page-2-12
--
lookup :: BCP47 -> Trie a -> Maybe a
lookup :: BCP47 -> Trie a -> Maybe a
lookup BCP47
tag Trie a
trie = BCP47 -> Trie2 a -> Maybe a
forall a. BCP47 -> Trie2 a -> Maybe a
lookup2 BCP47
tag (Trie2 a -> Maybe a) -> Maybe (Trie2 a) -> Maybe a
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< ISO639_1 -> Map ISO639_1 (Trie2 a) -> Maybe (Trie2 a)
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup (BCP47 -> ISO639_1
language BCP47
tag) (Trie a -> Map ISO639_1 (Trie2 a)
forall a. Trie a -> Map ISO639_1 (Trie2 a)
unLanguage Trie a
trie)

-- | Lookup an exact match for a tag
match :: BCP47 -> Trie a -> Maybe a
match :: BCP47 -> Trie a -> Maybe a
match BCP47
tag Trie a
trie = BCP47 -> Trie2 a -> Maybe a
forall a. BCP47 -> Trie2 a -> Maybe a
match2 BCP47
tag (Trie2 a -> Maybe a) -> Maybe (Trie2 a) -> Maybe a
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< ISO639_1 -> Map ISO639_1 (Trie2 a) -> Maybe (Trie2 a)
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup (BCP47 -> ISO639_1
language BCP47
tag) (Trie a -> Map ISO639_1 (Trie2 a)
forall a. Trie a -> Map ISO639_1 (Trie2 a)
unLanguage Trie a
trie)

-- | Check if a tag exists in the 'Trie'
elem :: BCP47 -> Trie a -> Bool
elem :: BCP47 -> Trie a -> Bool
elem BCP47
tag = Maybe a -> Bool
forall a. Maybe a -> Bool
isJust (Maybe a -> Bool) -> (Trie a -> Maybe a) -> Trie a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BCP47 -> Trie a -> Maybe a
forall a. BCP47 -> Trie a -> Maybe a
match BCP47
tag