+ Right sub' -> mergeImport queryOp (depth - 1) $ sub' `merge` base'
+
+-- | If there is an element in the map with key "", merge the contents
+-- and remove this element. Do this recursively.
+mergeSelf :: NmcDom -> NmcDom
+mergeSelf base =
+ let
+ map = domMap base
+ base' = base {domMap = removeSelf map}
+ removeSelf Nothing = Nothing
+ removeSelf (Just map) = if size map' == 0 then Nothing else Just map'
+ where map' = M.delete "" map
+ in
+ case map of
+ Nothing -> base'
+ Just map' ->
+ case M.lookup "" map' of
+ Nothing -> base'
+ Just sub -> (mergeSelf sub) `merge` base'
+ -- recursion depth limited by the size of the record
+
+-- | Presence of some elements require removal of some others
+normalizeDom :: NmcDom -> NmcDom
+normalizeDom dom = foldr id dom [ translateNormalizer
+ -- , nsNormalizer -- FIXME retrun this
+ ]
+ where
+ nsNormalizer dom = case domNs dom of
+ Nothing -> dom
+ Just ns -> emptyNmcDom { domNs = domNs dom, domEmail = domEmail dom }
+ translateNormalizer dom = case domTranslate dom of
+ Nothing -> dom
+ Just tr -> dom { domMap = Nothing }
+
+-- | Merge imports and Selfs and follow the maps tree to get dom
+descendNmcDom ::
+ (String -> IO (Either String ByteString)) -- ^ query operation action
+ -> [String] -- ^ subdomain chain
+ -> NmcDom -- ^ base domain
+ -> IO (Either String NmcDom) -- ^ fully processed result
+descendNmcDom queryOp subdom base = do
+ base' <- mergeImport queryOp 10 base
+ case subdom of
+ [] -> return $ fmap normalizeDom base'
+ -- A hack to handle SRV records: don't descend if ["_prot","_serv"]
+ [('_':_),('-':_)] -> return $ fmap normalizeDom base'
+ d:ds ->
+ case base' of
+ Left err -> return base'
+ Right base'' ->
+ case domMap base'' of
+ Nothing -> return $ Right emptyNmcDom
+ Just map ->
+ case M.lookup d map of
+ Nothing -> return $ Right emptyNmcDom
+ Just sub -> descendNmcDom queryOp ds sub
+
+-- | Initial NmcDom populated with "import" only, suitable for "descend"
+seedNmcDom ::
+ String -- ^ domain key (without namespace prefix)
+ -> NmcDom -- ^ resulting seed domain
+seedNmcDom dn = emptyNmcDom { domImport = Just ("d/" ++ dn)}