-- | Build a tree of comments, given the root and replies. The replies are
-- not necessarily direct or indirect descendants of the root, but rather
-- may be siblings, nephews, etc. This is done to greatly simplify the
-- calling code of this function.
--
-- THIS FUNCTION RELIES ON THE SORT ORDER OF THE REPLIES! Specifically,
-- they must be sorted in ascending-parent-id major, ascending-timestamp
-- minor order.
buildCommentTree :: Entity Comment -> [Entity Comment] -> Tree (Entity Comment)
buildCommentTree r rs = unfoldTree step (r,rs)
  where
    step :: (Entity Comment, [Entity Comment])
         -> (Entity Comment, [(Entity Comment, [Entity Comment])])
    step (root, replies) = (root, children_and_their_descendants)
      where
        descendants :: [Entity Comment]
        descendants = dropWhile (not . isParentOf root) replies

        -- children :: [Entity Comment]
        -- children_descendants :: [Entity Comment]
        (children, children_descendants) = span (isParentOf root) descendants

        children_and_their_descendants :: [(Entity Comment, [Entity Comment])]
        children_and_their_descendants = map (, children_descendants) children

        isParentOf :: Entity Comment -> Entity Comment -> Bool
        isParentOf (Entity parent_key _) (Entity _ child) =
            Just parent_key == commentParent child
buildCommentTree :: Entity Comment -> [Entity Comment] -> Tree (Entity Comment)
buildCommentTree r rs = unfoldTree step (r,rs)
  where
    step :: (Entity Comment, [Entity Comment])
         -> (Entity Comment, [(Entity Comment, [Entity Comment])])
    step (root, replies) = (root, children_and_their_descendants)
      where
        descendants :: [Entity Comment]
        descendants = dropWhile (not . isParentOf root) replies

        -- children :: [Entity Comment]
        -- children_descendants :: [Entity Comment]
        (children, children_descendants) = span (isParentOf root) descendants

        children_and_their_descendants :: [(Entity Comment, [Entity Comment])]
        children_and_their_descendants = map (, children_descendants) children

        isParentOf :: Entity Comment -> Entity Comment -> Bool
        isParentOf (Entity parent_key _) (Entity _ child) =
            Just parent_key == commentParent child
buildCommentTree r rs = unfoldTree step (r,rs)
  where
    step :: (Entity Comment, [Entity Comment])
         -> (Entity Comment, [(Entity Comment, [Entity Comment])])
    step (root, replies) = (root, children_and_their_descendants)
      where
        descendants :: [Entity Comment]
        descendants = dropWhile (not . isParentOf root) replies

        -- children :: [Entity Comment]
        -- children_descendants :: [Entity Comment]
        (children, children_descendants) = span (isParentOf root) descendants

        children_and_their_descendants :: [(Entity Comment, [Entity Comment])]
        children_and_their_descendants = map (, children_descendants) children

        isParentOf :: Entity Comment -> Entity Comment -> Bool
        isParentOf (Entity parent_key _) (Entity _ child) =
            Just parent_key == commentParent child