/*
 * Copyright 2017 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.google.auto.value.processor;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static java.util.stream.Collectors.toList;

import com.google.auto.common.MoreElements;
import com.google.auto.common.MoreTypes;
import com.google.auto.value.processor.MissingTypes.MissingTypeException;
import com.google.common.collect.ImmutableSet;
import java.util.List;
import java.util.OptionalInt;
import java.util.Set;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ErrorType;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.Elements;
import javax.lang.model.util.SimpleTypeVisitor8;
import javax.lang.model.util.Types;

/**
 * Encodes types so they can later be decoded to incorporate imports.
 *
 * <p>The idea is that types that appear in generated source code use {@link #encode}, which will
 * spell out a type like {@code java.util.List<? extends java.lang.Number>}, except that wherever a
 * class name appears it is replaced by a special token. So the spelling might actually be {@code
 * `java.util.List`<? extends `java.lang.Number`>}. Then once the entire class has been generated,
 * {@code #decode} scans for these tokens to determine what classes need to be imported, and
 * replaces the tokens with the correct spelling given the imports. So here, {@code java.util.List}
 * would be imported, and the final spelling would be {@code List<? extends Number>} (knowing that
 * {@code Number} is implicitly imported). The special token {@code `import`} marks where the
 * imports should be, and {@link #decode} replaces it with the correct list of imports.
 *
 * <p>The funky syntax for type annotations on qualified type names requires an adjustment to this
 * scheme. {@code `«java.util.Map`} stands for {@code java.util.} and {@code `»java.util.Map`}
 * stands for {@code Map}. If {@code java.util.Map} is imported, then {@code `«java.util.Map`} will
 * eventually be empty, but if {@code java.util.Map} is not imported (perhaps because there is
 * another {@code Map} in scope) then {@code `«java.util.Map`} will be {@code java.util.}. The end
 * result is that the code can contain {@code `«java.util.Map`@`javax.annotation.Nullable`
 * `»java.util.Map`}. That might decode to {@code @Nullable Map} or to {@code java.util.@Nullable
 * Map} or even to {@code java.util.@javax.annotation.Nullable Map}.
 *
 * @author emcmanus@google.com (Éamonn McManus)
 */
final class TypeEncoder {
  private TypeEncoder() {} // There are no instances of this class.

  private static final EncodingTypeVisitor ENCODING_TYPE_VISITOR = new EncodingTypeVisitor();
  private static final RawEncodingTypeVisitor RAW_ENCODING_TYPE_VISITOR =
      new RawEncodingTypeVisitor();

  /**
   * Returns the encoding for the given type, where class names are marked by special tokens. The
   * encoding for {@code int} will be {@code int}, but the encoding for {@code
   * java.util.List<java.lang.Integer>} will be {@code `java.util.List`<`java.lang.Integer`>}.
   */
  static String encode(TypeMirror type) {
    StringBuilder sb = new StringBuilder();
    return type.accept(ENCODING_TYPE_VISITOR, sb).toString();
  }

  /**
   * Like {@link #encode}, except that only the raw type is encoded. So if the given type is {@code
   * java.util.List<java.lang.Integer>} the result will be {@code `java.util.List`}.
   */
  static String encodeRaw(TypeMirror type) {
    StringBuilder sb = new StringBuilder();
    return type.accept(RAW_ENCODING_TYPE_VISITOR, sb).toString();
  }

  /**
   * Encodes the given type and its type annotations. The class comment for {@link TypeEncoder}
   * covers the details of annotation encoding.
   */
  static String encodeWithAnnotations(TypeMirror type) {
    return encodeWithAnnotations(type, ImmutableSet.of());
  }

  /**
   * Encodes the given type and its type annotations. The class comment for {@link TypeEncoder}
   * covers the details of annotation encoding.
   *
   * @param excludedAnnotationTypes annotations not to include in the encoding. For example, if
   *     {@code com.example.Nullable} is in this set then the encoding will not include this
   *     {@code @Nullable} annotation.
   */
  static String encodeWithAnnotations(TypeMirror type, Set<TypeMirror> excludedAnnotationTypes) {
    StringBuilder sb = new StringBuilder();
    return new AnnotatedEncodingTypeVisitor(excludedAnnotationTypes).visit2(type, sb).toString();
  }

  /**
   * Decodes the given string, respelling class names appropriately. The text is scanned for tokens
   * like {@code `java.util.Locale`} or {@code `«java.util.Locale`} to determine which classes are
   * referenced. An appropriate set of imports is computed based on the set of those types. If the
   * special token {@code `import`} appears in {@code text} then it will be replaced by this set of
   * import statements. Then all of the tokens are replaced by the class names they represent,
   * spelled appropriately given the import statements.
   *
   * @param text the text to be decoded.
   * @param packageName the package of the generated class. Other classes in the same package do not
   *     need to be imported.
   * @param baseType a class or interface that the generated class inherits from. Nested classes in
   *     that type do not need to be imported, and if another class has the same name as one of
   *     those nested classes then it will need to be qualified.
   */
  static String decode(
      String text, ProcessingEnvironment processingEnv, String packageName, TypeMirror baseType) {
    return decode(
        text, processingEnv.getElementUtils(), processingEnv.getTypeUtils(), packageName, baseType);
  }

  static String decode(
      String text, Elements elementUtils, Types typeUtils, String pkg, TypeMirror baseType) {
    TypeRewriter typeRewriter = new TypeRewriter(text, elementUtils, typeUtils, pkg, baseType);
    return typeRewriter.rewrite();
  }

  private static String className(DeclaredType declaredType) {
    return MoreElements.asType(declaredType.asElement()).getQualifiedName().toString();
  }

  /**
   * Returns the formal type parameters of the given type. If we have {@code @AutoValue abstract
   * class Foo<T extends SomeClass>} then this method will return an encoding of {@code <T extends
   * SomeClass>} for {@code Foo}. Likewise it will return an encoding of the angle-bracket part of:
   * <br>
   * {@code Foo<SomeClass>}<br>
   * {@code Foo<T extends Number>}<br>
   * {@code Foo<E extends Enum<E>>}<br>
   * {@code Foo<K, V extends Comparable<? extends K>>}.
   *
   * <p>The encoding is simply that classes in the "extends" part are marked, so the examples will
   * actually look something like this:<br>
   * {@code <`bar.baz.SomeClass`>}<br>
   * {@code <T extends `java.lang.Number`>}<br>
   * {@code <E extends `java.lang.Enum`<E>>}<br>
   * {@code <K, V extends `java.lang.Comparable`<? extends K>>}.
   */
  static String formalTypeParametersString(TypeElement type) {
    List<? extends TypeParameterElement> typeParameters = type.getTypeParameters();
    if (typeParameters.isEmpty()) {
      return "";
    } else {
      StringBuilder sb = new StringBuilder("<");
      String sep = "";
      for (TypeParameterElement typeParameter : typeParameters) {
        sb.append(sep);
        sep = ", ";
        appendTypeParameterWithBounds(typeParameter, sb);
      }
      return sb.append(">").toString();
    }
  }

  private static void appendTypeParameterWithBounds(
      TypeParameterElement typeParameter, StringBuilder sb) {
    appendAnnotations(typeParameter.getAnnotationMirrors(), sb);
    sb.append(typeParameter.getSimpleName());
    String sep = " extends ";
    for (TypeMirror bound : typeParameter.getBounds()) {
      if (!isUnannotatedJavaLangObject(bound)) {
        sb.append(sep);
        sep = " & ";
        sb.append(encodeWithAnnotations(bound));
      }
    }
  }

  // We can omit "extends Object" from a type bound, but not "extends @NullableType Object".
  private static boolean isUnannotatedJavaLangObject(TypeMirror type) {
    return type.getKind().equals(TypeKind.DECLARED)
        && type.getAnnotationMirrors().isEmpty()
        && MoreTypes.asTypeElement(type).getQualifiedName().contentEquals("java.lang.Object");
  }

  private static void appendAnnotations(
      List<? extends AnnotationMirror> annotationMirrors, StringBuilder sb) {
    for (AnnotationMirror annotationMirror : annotationMirrors) {
      sb.append(AnnotationOutput.sourceFormForAnnotation(annotationMirror)).append(" ");
    }
  }

  /**
   * Converts a type into a string, using standard Java syntax, except that every class name is
   * wrapped in backquotes, like {@code `java.util.List`}.
   */
  private static class EncodingTypeVisitor
      extends SimpleTypeVisitor8<StringBuilder, StringBuilder> {
    /**
     * Equivalent to {@code visit(type, sb)} or {@code type.accept(sb)}, except that it fixes a bug
     * with javac versions up to JDK 8, whereby if the type is a {@code DeclaredType} then the
     * visitor is called with a version of the type where any annotations have been lost. We can't
     * override {@code visit} because it is final.
     */
    StringBuilder visit2(TypeMirror type, StringBuilder sb) {
      if (type.getKind().equals(TypeKind.DECLARED)) {
        // There's no point in using MoreTypes.asDeclared here, and in fact we can't, because it
        // uses a visitor, so it would trigger the bug we're working around.
        return visitDeclared((DeclaredType) type, sb);
      } else {
        return visit(type, sb);
      }
    }

    @Override
    protected StringBuilder defaultAction(TypeMirror type, StringBuilder sb) {
      return sb.append(type);
    }

    @Override
    public StringBuilder visitArray(ArrayType type, StringBuilder sb) {
      return visit2(type.getComponentType(), sb).append("[]");
    }

    @Override
    public StringBuilder visitDeclared(DeclaredType type, StringBuilder sb) {
      appendTypeName(type, sb);
      appendTypeArguments(type, sb);
      return sb;
    }

    void appendTypeName(DeclaredType type, StringBuilder sb) {
      TypeMirror enclosing = EclipseHack.getEnclosingType(type);
      if (enclosing.getKind().equals(TypeKind.DECLARED)) {
        // We might have something like com.example.Outer<Double>.Inner. We need to encode
        // com.example.Outer<Double> first, producing `com.example.Outer`<`java.lang.Double`>.
        // Then we can simply add .Inner after that. If Inner has its own type arguments, we'll
        // add them with appendTypeArguments below. Of course, it's more usual for the outer class
        // not to have type arguments, but we'll still follow this path if the nested class is an
        // inner (not static) class.
        visit2(enclosing, sb);
        sb.append(".").append(type.asElement().getSimpleName());
      } else {
        sb.append('`').append(className(type)).append('`');
      }
    }

    void appendTypeArguments(DeclaredType type, StringBuilder sb) {
      List<? extends TypeMirror> arguments = type.getTypeArguments();
      if (!arguments.isEmpty()) {
        sb.append("<");
        String sep = "";
        for (TypeMirror argument : arguments) {
          sb.append(sep);
          sep = ", ";
          visit2(argument, sb);
        }
        sb.append(">");
      }
    }

    @Override
    public StringBuilder visitWildcard(WildcardType type, StringBuilder sb) {
      sb.append("?");
      TypeMirror extendsBound = type.getExtendsBound();
      TypeMirror superBound = type.getSuperBound();
      if (superBound != null) {
        sb.append(" super ");
        visit2(superBound, sb);
      } else if (extendsBound != null) {
        sb.append(" extends ");
        visit2(extendsBound, sb);
      }
      return sb;
    }

    @Override
    public StringBuilder visitError(ErrorType t, StringBuilder p) {
      throw new MissingTypeException(t);
    }
  }

  /** Like {@link EncodingTypeVisitor} except that type parameters are omitted from the result. */
  private static class RawEncodingTypeVisitor extends EncodingTypeVisitor {
    @Override
    void appendTypeArguments(DeclaredType type, StringBuilder sb) {}
  }

  /**
   * Like {@link EncodingTypeVisitor} except that annotations on the visited type are also included
   * in the resultant string. Class names in those annotations are also encoded using the {@code
   * `java.util.List`} form.
   */
  private static class AnnotatedEncodingTypeVisitor extends EncodingTypeVisitor {
    private final Set<TypeMirror> excludedAnnotationTypes;

    AnnotatedEncodingTypeVisitor(Set<TypeMirror> excludedAnnotationTypes) {
      this.excludedAnnotationTypes = excludedAnnotationTypes;
    }

    private void appendAnnotationsWithExclusions(
        List<? extends AnnotationMirror> annotations, StringBuilder sb) {
      // Optimization for the very common cases where there are no annotations or there are no
      // exclusions.
      if (annotations.isEmpty() || excludedAnnotationTypes.isEmpty()) {
        appendAnnotations(annotations, sb);
        return;
      }
      List<AnnotationMirror> includedAnnotations =
          annotations.stream()
              .filter(a -> !excludedAnnotationTypes.contains(a.getAnnotationType()))
              .collect(toList());
      appendAnnotations(includedAnnotations, sb);
    }

    @Override
    public StringBuilder visitPrimitive(PrimitiveType type, StringBuilder sb) {
      appendAnnotationsWithExclusions(type.getAnnotationMirrors(), sb);
      // We can't just append type.toString(), because that will also have the annotation, but
      // without encoding.
      return sb.append(type.getKind().toString().toLowerCase());
    }

    @Override
    public StringBuilder visitTypeVariable(TypeVariable type, StringBuilder sb) {
      appendAnnotationsWithExclusions(type.getAnnotationMirrors(), sb);
      return sb.append(type.asElement().getSimpleName());
    }

    /**
     * {@inheritDoc} The result respects the Java syntax, whereby {@code Foo @Bar []} is an
     * annotation on the array type itself, while {@code @Bar Foo[]} would be an annotation on the
     * component type.
     */
    @Override
    public StringBuilder visitArray(ArrayType type, StringBuilder sb) {
      visit2(type.getComponentType(), sb);
      List<? extends AnnotationMirror> annotationMirrors = type.getAnnotationMirrors();
      if (!annotationMirrors.isEmpty()) {
        sb.append(" ");
        appendAnnotationsWithExclusions(annotationMirrors, sb);
      }
      return sb.append("[]");
    }

    @Override
    public StringBuilder visitDeclared(DeclaredType type, StringBuilder sb) {
      List<? extends AnnotationMirror> annotationMirrors = type.getAnnotationMirrors();
      if (annotationMirrors.isEmpty()) {
        super.visitDeclared(type, sb);
      } else {
        TypeMirror enclosing = EclipseHack.getEnclosingType(type);
        if (enclosing.getKind().equals(TypeKind.DECLARED)) {
          // We have something like com.example.Outer<Double>.@Annot Inner.
          // We'll recursively encode com.example.Outer<Double> first,
          // which if it is also annotated might result in a mouthful like
          // `«com.example.Outer`@`org.annots.Nullable``»com.example.Outer`<`java.lang.Double`> .
          // That annotation will have been added by a recursive call to this method.
          // Then we'll add the annotation on the .Inner class, which we know is there because
          // annotationMirrors is not empty. That means we'll append .@`org.annots.Annot` Inner .
          visit2(enclosing, sb);
          sb.append(".");
          appendAnnotationsWithExclusions(annotationMirrors, sb);
          sb.append(type.asElement().getSimpleName());
        } else {
          // This isn't an inner class, so we have the simpler (but still complicated) case of
          // needing to place the annotation correctly in cases like java.util.@Nullable Map .
          // See the class doc comment for an explanation of « and » here.
          String className = className(type);
          sb.append("`«").append(className).append("`");
          appendAnnotationsWithExclusions(annotationMirrors, sb);
          sb.append("`»").append(className).append("`");
        }
        appendTypeArguments(type, sb);
      }
      return sb;
    }
  }

  private static class TypeRewriter {
    private final String text;
    private final int textLength;
    private final JavaScanner scanner;
    private final Elements elementUtils;
    private final Types typeUtils;
    private final String packageName;
    private final TypeMirror baseType;

    TypeRewriter(
        String text, Elements elementUtils, Types typeUtils, String pkg, TypeMirror baseType) {
      this.text = text;
      this.textLength = text.length();
      this.scanner = new JavaScanner(text);
      this.elementUtils = elementUtils;
      this.typeUtils = typeUtils;
      this.packageName = pkg;
      this.baseType = baseType;
    }

    String rewrite() {
      // Scan the text to determine what classes are referenced.
      Set<TypeMirror> referencedClasses = findReferencedClasses();
      // Make a type simplifier based on these referenced types.
      TypeSimplifier typeSimplifier =
          new TypeSimplifier(elementUtils, typeUtils, packageName, referencedClasses, baseType);

      StringBuilder output = new StringBuilder();
      int copyStart;

      // Replace the `import` token with the import statements, if it is present.
      OptionalInt importMarker = findImportMarker();
      if (importMarker.isPresent()) {
        output.append(text, 0, importMarker.getAsInt());
        for (String toImport : typeSimplifier.typesToImport()) {
          output.append("import ").append(toImport).append(";\n");
        }
        copyStart = scanner.tokenEnd(importMarker.getAsInt());
      } else {
        copyStart = 0;
      }

      // Replace each of the classname tokens with the appropriate spelling of the classname.
      int token;
      for (token = copyStart; token < textLength; token = scanner.tokenEnd(token)) {
        if (text.charAt(token) == '`') {
          output.append(text, copyStart, token);
          decode(output, typeSimplifier, token);
          copyStart = scanner.tokenEnd(token);
        }
      }
      output.append(text, copyStart, textLength);
      return output.toString();
    }

    private Set<TypeMirror> findReferencedClasses() {
      Set<TypeMirror> classes = new TypeMirrorSet();
      for (int token = 0; token < textLength; token = scanner.tokenEnd(token)) {
        if (text.charAt(token) == '`' && !text.startsWith("`import`", token)) {
          String className = classNameAt(token);
          classes.add(classForName(className));
        }
      }
      return classes;
    }

    private DeclaredType classForName(String className) {
      TypeElement typeElement = elementUtils.getTypeElement(className);
      checkState(typeElement != null, "Could not find referenced class %s", className);
      return MoreTypes.asDeclared(typeElement.asType());
    }

    private void decode(StringBuilder output, TypeSimplifier typeSimplifier, int token) {
      String className = classNameAt(token);
      DeclaredType type = classForName(className);
      String simplified = typeSimplifier.simplifiedClassName(type);
      int dot;
      switch (text.charAt(token + 1)) {
        case '«':
          // If this is `«java.util.Map` then we want "java.util." here.
          // That's because this is the first part of something like "java.util.@Nullable Map"
          // or "java.util.Map.@Nullable Entry".
          // If there's no dot, then we want nothing here, for "@Nullable Map".
          dot = simplified.lastIndexOf('.');
          output.append(simplified.substring(0, dot + 1)); // correct even if dot == -1
          break;
        case '»':
          dot = simplified.lastIndexOf('.');
          output.append(simplified.substring(dot + 1)); // correct even if dot == -1
          break;
        default:
          output.append(simplified);
          break;
      }
    }

    private OptionalInt findImportMarker() {
      for (int token = 0; token < textLength; token = scanner.tokenEnd(token)) {
        if (text.startsWith("`import`", token)) {
          return OptionalInt.of(token);
        }
      }
      return OptionalInt.empty();
    }

    private String classNameAt(int token) {
      checkArgument(text.charAt(token) == '`');
      int end = scanner.tokenEnd(token) - 1; // points to the closing `
      int t = token + 1;
      char c = text.charAt(t);
      if (c == '«' || c == '»') {
        t++;
      }
      return text.substring(t, end);
    }
  }
}
