private static <T, G> Map<G, ItemGroup<T, G>> createBaseInfoMap(final Iterable<T> items,
           @Nullable final Function<T, G> groupMapper, @Nullable final Function<G, G> groupGroupMapper) {
        final Map<G, ItemGroup<T, G>> groupMap = new HashMap<>();
        groupMap.put(null, new ItemGroup<>(null));
        //shortcut
        if (items == null) {
            return groupMap;
        }
        for (T item : items) {
            final G group = groupMapper == null ? null : groupMapper.apply(item);
            if (!groupMap.containsKey(group)) {
                G currentGroup = group;
                ItemGroup<T, G> lastGroup = null;
                while (!groupMap.containsKey(currentGroup)) {
                    final ItemGroup<T, G> gi = new ItemGroup<>(currentGroup);
                    groupMap.put(currentGroup, gi);
                    if (lastGroup != null) {
                        gi.groups.add(lastGroup);
                        lastGroup.parent = gi;
                    }
                    lastGroup = gi;
                    currentGroup = groupGroupMapper == null ? null : groupGroupMapper.apply(currentGroup);
                }
                if (lastGroup != null) {
                    groupMap.get(currentGroup).groups.add(lastGroup);
                    lastGroup.parent = groupMap.get(currentGroup);
                }
            }
            groupMap.get(group).items.add(item);
        }
        return groupMap;
    }
Creates a new tree of grouped items and returns it

@param items items to group
@param groupMapper function to map an item to a group
@param groupGroupMapper function to map groups to other groups (thus creating a tree)
@param itemOrder function to order groups and items within each other
@param pruner checker for created groups if the group should be pruned from the tree
@return root of grouped tree
main/src/main/java/cgeo/geocaching/utils/ItemGroup.java