-- | Find all distinct namespace IDs that are children of a given namespace.
--   Note that namespaces that are children by virtue of an import are excluded.
findNamespaceDescendents :: String -> L2.L2NamespaceID -> ModelTranslation (S.Set L2.L2NamespaceID)
findNamespaceDescendents why nsid = do
  nsc <- getNamespaceContents "getdescendents - self" nsid
  trueChildren <- 
    filterM (\childNS -> ((==nsid) . L2.l2nsParent) <$> getNamespaceContents ("descendents - child of " ++ show nsid ++ " - " ++ why) childNS) $
      M.elems (L2.l2nsNamespaces nsc)
  descs1 <- S.unions <$> mapM (findNamespaceDescendents (why++"(C)")) trueChildren
  return $ descs1 `S.union` (S.fromList trueChildren)

-- | Finds a namespace in a Level 2 model, treating a particular namespace as root and applying a level 1 namespace path. Fails with an error if the
--   namespace cannot be found. Does not look up the tree from the starting namespace for other matches if it is not found at the root.
findNamespaceDescendents :: String -> L2.L2NamespaceID -> ModelTranslation (S.Set L2.L2NamespaceID)
findNamespaceDescendents why nsid = do
  nsc <- getNamespaceContents "getdescendents - self" nsid
  trueChildren <- 
    filterM (\childNS -> ((==nsid) . L2.l2nsParent) <$> getNamespaceContents ("descendents - child of " ++ show nsid ++ " - " ++ why) childNS) $
      M.elems (L2.l2nsNamespaces nsc)
  descs1 <- S.unions <$> mapM (findNamespaceDescendents (why++"(C)")) trueChildren
  return $ descs1 `S.union` (S.fromList trueChildren)

-- | Finds a namespace in a Level 2 model, treating a particular namespace as root and applying a level 1 namespace path. Fails with an error if the
--   namespace cannot be found. Does not look up the tree from the starting namespace for other matches if it is not found at the root.
findNamespaceDescendents why nsid = do
  nsc <- getNamespaceContents "getdescendents - self" nsid
  trueChildren <- 
    filterM (\childNS -> ((==nsid) . L2.l2nsParent) <$> getNamespaceContents ("descendents - child of " ++ show nsid ++ " - " ++ why) childNS) $
      M.elems (L2.l2nsNamespaces nsc)
  descs1 <- S.unions <$> mapM (findNamespaceDescendents (why++"(C)")) trueChildren
  return $ descs1 `S.union` (S.fromList trueChildren)

-- | Finds a namespace in a Level 2 model, treating a particular namespace as root and applying a level 1 namespace path. Fails with an error if the
--   namespace cannot be found. Does not look up the tree from the starting namespace for other matches if it is not found at the root.