package mb.scopegraph.oopsla20;

import java.util.AbstractMap;
import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;

import org.metaborg.util.functions.Function1;

import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;

public final class ScopeGraphUtil {

    private ScopeGraphUtil() {
        // not instantiatable
    }

    public static <S, L, D> String toString(IScopeGraph<S, L, D> scopeGraph, Function1<D, D> instantiateData) {
     // @formatter:off
        final Map<S, java.util.Set<Map.Entry<L, Iterable<S>>>> groupedScopes = scopeGraph.getEdges().entrySet().stream()
                .collect(Collectors.groupingBy(t -> t.getKey().getKey(), Collectors.mapping(
                        t -> (Map.Entry<L, Iterable<S>>)new AbstractMap.SimpleImmutableEntry<L, Iterable<S>>(t.getKey().getValue(), t.getValue()), Collectors.toSet())));
        // @formatter:off

        final SetView<S> scopes = Sets.union(groupedScopes.keySet(), scopeGraph.getData().keySet());

        final StringBuilder sb = new StringBuilder();
        for(S source : scopes) {
            sb.append(source);
            if(scopeGraph.getData(source).isPresent()) {
                sb.append(" : ");
                sb.append(instantiateData.apply(scopeGraph.getData(source).get()));
            }
            if(!groupedScopes.containsKey(source)) {
                sb.append("\n");
                continue;
            }
            sb.append(" {\n");
            for(Map.Entry<L, Iterable<S>> edges: groupedScopes.get(source)) {
                sb.append("  ");
                sb.append(edges.getKey());
                sb.append(": ");
                int indent = edges.getKey().toString().length() + 6;
                boolean first = true;
                for(S target: edges.getValue()) {
                    if(first) {
                        sb.append("[ ");
                        first = false;
                    } else {
                        sb.append(",\n");
                        sb.append(String.join("", Collections.nCopies(indent, " ")));
                    }
                    sb.append(target);
                }
                sb.append("]\n");
            }
            sb.append("}\n");
        }

        return sb.toString();
    }

}

@@ -104,24 +104,81 @@
 a.util.Map;%0A
+import java.util.Set;%0Aimport java.util.stream.Collector;%0A
 import java.
@@ -201,16 +201,16 @@
 ectors;%0A
-
 %0Aimport 
@@ -554,24 +554,27 @@
 ata) %7B%0A     
+   
 // @formatte
@@ -579,16 +579,117 @@
 ter:off%0A
+        final Map%3C? extends Map.Entry%3CS, L%3E, ? extends Iterable%3CS%3E%3E sgEdges = scopeGraph.getEdges();%0A
         
@@ -760,36 +760,22 @@
 opes = s
-copeGraph.get
+g
 Edges
-()
 .entrySe
@@ -786,16 +786,25 @@
 stream()
+.collect(
 %0A       
@@ -812,21 +812,8 @@
     
-    .collect(
 Coll
@@ -830,16 +830,33 @@
 upingBy(
+%0A                
 t -%3E t.g
@@ -917,44 +917,13 @@
     
-    
 t -%3E 
-(Map.Entry%3CL, Iterable%3CS%3E%3E)
 new 
@@ -955,30 +955,16 @@
 leEntry%3C
-L, Iterable%3CS%3E
 %3E(t.getK
@@ -1013,18 +1013,57 @@
 .toSet()
-))
+%0A                )%0A            )%0A        
 );%0A     

Fix inference