class SceneGraph {

    public GroupNode<E, T> buildTree()
    {
        List<Entry<Object, Set<SceneGraphParameter>>> list = new LinkedList<>(
                myParameterTypeMap.entrySet());

        Collections.sort(list, myEntryComparator);

        GroupNode<E, T> root = new GroupNode<>(null, null);
        Stack<GroupNode<E, T>> parentStack = new Stack<>();
        parentStack.add(root);

        if (list.isEmpty())
        {
            return root;
        }

        Map<SceneGraphParameter, Set<E>> parameterMap = new HashMap<>(myParameterMap.size());
        for (Entry<SceneGraphParameter, Set<E>> entry : myParameterMap.entrySet())
        {
            parameterMap.put(entry.getKey(), new HashSet<>(entry.getValue()));
        }

        Stack<Iterator<SceneGraphParameter>> iterStack = new Stack<>();
        Stack<Set<E>> intersectingObjectsStack = new Stack<>();
        int level = 0;
        final int lastLevel = list.size() - 1;
        while (level >= 0)
        {
            Iterator<SceneGraphParameter> iter = getIter(list, iterStack, level);
            if (iter.hasNext())
            {
                SceneGraphParameter param = iter.next();
                Set<E> objs = parameterMap.get(param);
                Set<E> intersectingObjects = getIntersectingObjects(objs, level, intersectingObjectsStack);
                if (!intersectingObjects.isEmpty())
                {
                    Node<E, T> node;
                    GroupNode<E, T> parentNode = parentStack.get(level);
                    T paramForNode = castNode(param);
                    if (level == lastLevel)
                    {
                        LeafNode<E, T> leafNode = new LeafNode<>(parentNode, paramForNode);
                        leafNode.getObjects().addAll(intersectingObjects);
                        node = leafNode;
                        objs.removeAll(intersectingObjects);
                    }
                    else
                    {
                        intersectingObjectsStack.add(intersectingObjects);
                        GroupNode<E, T> groupNode = new GroupNode<>(parentNode, paramForNode);
                        parentStack.add(groupNode);
                        node = groupNode;
                    }
                    if (LOGGER.isTraceEnabled())
                    {
                        LOGGER.trace("Adding " + node.getClass().getSimpleName() + " with parameter [" + param
                                + "] and intersecting objects [" + intersectingObjects + "]");
                    }
                    if (level < lastLevel)
                    {
                        ++level;
                    }
                }
            }
            else
            {
                --level;
                parentStack.pop();
                iterStack.pop();
                if (level >= 0)
                {
                    intersectingObjectsStack.pop();
                }
            }
        }

        return root;
    }

}