package org.javacs;

import javax.lang.model.type.*;
import javax.lang.model.util.AbstractTypeVisitor8;
import java.util.stream.Collectors;

public class ShortTypePrinter extends AbstractTypeVisitor8<String, Void> {
    private ShortTypePrinter() {

    }

    public static String print(TypeMirror type) {
        return type.accept(new ShortTypePrinter(), null);
    }

    @Override
    public String visitIntersection(IntersectionType t, Void aVoid) {
        return t.getBounds().stream().map(ShortTypePrinter::print).collect(Collectors.joining(" & "));
    }

    @Override
    public String visitUnion(UnionType t, Void aVoid) {
        return t.getAlternatives().stream().map(ShortTypePrinter::print).collect(Collectors.joining(" | "));
    }

    @Override
    public String visitPrimitive(PrimitiveType t, Void aVoid) {
        return t.toString();
    }

    @Override
    public String visitNull(NullType t, Void aVoid) {
        return t.toString();
    }

    @Override
    public String visitArray(ArrayType t, Void aVoid) {
        return print(t.getComponentType()) + "[]";
    }

    @Override
    public String visitDeclared(DeclaredType t, Void aVoid) {
        String result = "";

        if (t.getEnclosingType().getKind() == TypeKind.DECLARED)
            result += print(t.getEnclosingType()) + ".";

        result += t.asElement().getSimpleName().toString();

        if (!t.getTypeArguments().isEmpty()) {
            String params = t.getTypeArguments()
                              .stream()
                              .map(ShortTypePrinter::print)
                              .collect(Collectors.joining(", "));

            result += "<" + params + ">";
        }

        return result;
    }

    @Override
    public String visitError(ErrorType t, Void aVoid) {
        return "???";
    }

    @Override
    public String visitTypeVariable(TypeVariable t, Void aVoid) {
        String result = t.asElement().toString();
        TypeMirror upper = t.getUpperBound();

        if (!upper.toString().equals("java.lang.Object"))
            result += " extends " + print(upper);

        return result;
    }

    @Override
    public String visitWildcard(WildcardType t, Void aVoid) {
        String result = "?";

        if (t.getSuperBound() != null)
            result += " super " + print(t.getSuperBound());

        if (t.getExtendsBound() != null)
            result += " extends " + print(t.getExtendsBound());

        return result;
    }

    @Override
    public String visitExecutable(ExecutableType t, Void aVoid) {
        return t.toString();
    }

    @Override
    public String visitNoType(NoType t, Void aVoid) {
        return t.toString();
    }
}

@@ -14,16 +14,100 @@
 avacs;%0A%0A
+import com.sun.tools.javac.code.Type;%0A%0Aimport javax.lang.model.element.ElementKind;%0A
 import j
@@ -130,16 +130,16 @@
 type.*;%0A
-
 import j
@@ -216,16 +216,44 @@
 lectors;
+%0Aimport java.util.logging.*;
 %0A%0Apublic
@@ -321,16 +321,85 @@
 Void%3E %7B%0A
+    private static final Logger LOG = Logger.getLogger(%22main%22);%0A    %0A
     priv
@@ -477,24 +477,68 @@
 ror type) %7B%0A
+        LOG.info(type.toString());%0A        %0A
         retu
@@ -1425,28 +1425,147 @@
 %22;%0A%0A        
-if (
+// If type is an inner class, add outer class name%0A        if (t.asElement().getKind() == ElementKind.CLASS &&%0A            
 t.getEnclosi
@@ -1604,16 +1604,19 @@
 ECLARED)
+ %7B%0A
 %0A       
@@ -1664,16 +1664,26 @@
 ) + %22.%22;
+%0A        %7D
 %0A%0A      
@@ -2362,24 +2362,78 @@
 ();%0A%0A       
+ // NOTE this can create infinite recursion%0A        //
  if (!upper.
@@ -2470,32 +2470,35 @@
 bject%22))%0A       
+ //
      result += %22

Fix infinite recursion