/*
 * Copyright 2014 Google Inc.
 *
 * 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.gwt.dev.javac;

import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.util.Name.InternalName;
import com.google.gwt.thirdparty.guava.common.base.Function;
import com.google.gwt.thirdparty.guava.common.base.Joiner;
import com.google.gwt.thirdparty.guava.common.base.Predicate;
import com.google.gwt.thirdparty.guava.common.base.Strings;
import com.google.gwt.thirdparty.guava.common.collect.FluentIterable;
import com.google.gwt.thirdparty.guava.common.collect.ImmutableSet;
import com.google.gwt.thirdparty.guava.common.collect.Iterables;
import com.google.gwt.thirdparty.guava.common.collect.Lists;

import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.impl.BooleanConstant;
import org.eclipse.jdt.internal.compiler.impl.StringConstant;
import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.NestedTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
 * Utility functions to interact with JDT classes.
 */
public final class JdtUtil {
  private static final String JSO_CLASS = "com/google/gwt/core/client/JavaScriptObject";

  /**
   * Returns a source name from an array of names.
   */
  public static String asDottedString(char[][] name) {
    return join(name, ".");
  }

  /**
   * Returns a string name from an array of names using {@code separator}.
   */
  public static String join(char[][] name, String separator) {
    StringBuilder result = new StringBuilder();
    if (name.length > 0) {
      result.append(name[0]);
    }

    for (int i = 1; i < name.length; ++i) {
      result.append(separator);
      result.append(name[i]);
    }
    return result.toString();
  }

  /**
   * Returns the name of the class from reference binding.
   * <p>
   * JDT Core (at least 3.11.0.v20150407) returns <code>$Local$</code> synthetic name for local
   * classes.<br>
   * This method aware about local classes and instead of <code>$Local$</code> synthetic name
   * returns fully qualified name of the local class in form of anonymous class (e.g.
   * <code>test.Class1$2</code>).
   * </p>
   */
  public static String getClassName(ReferenceBinding binding) {
    if (binding instanceof LocalTypeBinding) {
      // Using here constantPoolName() instead of coumpoundName due JDT not computing the
      // right compoundName for lambdas inside local class.
      return InternalName.toBinaryName(String.valueOf(binding.constantPoolName()));
    }

    return asDottedString(binding.compoundName);
  }

  /**
   * Returns the top type of the compilation unit that defines
   * {@code binding}.
   */
  public static String getDefiningCompilationUnitType(ReferenceBinding binding) {
    // Get the compilation unit type name.
    // TODO(rluble): check that this is valid for classes declared in the same compilation unit
    // top scope.
    return asDottedString(binding.outermostEnclosingType().compoundName);
  }

  public static String getSourceName(TypeBinding classBinding) {
    return getSourceName(CharOperation.charToString(classBinding.qualifiedPackageName()),
        CharOperation.charToString(classBinding.qualifiedSourceName()));
  }

  public static String getSourceName(String qualifiedPackageName, String qualifiedSourceName) {
    return Joiner.on(".").skipNulls().join(new String[] {
        Strings.emptyToNull(qualifiedPackageName),
        qualifiedSourceName});
  }

  public static String getBinaryName(TypeBinding classBinding) {
    return getBinaryName(CharOperation.charToString(classBinding.qualifiedPackageName()),
        CharOperation.charToString(classBinding.qualifiedSourceName()));
  }

  public static String getBinaryName(String qualifiedPackageName, String qualifiedSourceName) {
    return Joiner.on(".").skipNulls().join(new String[] {
        Strings.emptyToNull(qualifiedPackageName),
        qualifiedSourceName.replace('.','$')});
  }

  public static boolean isInnerClass(ReferenceBinding binding) {
    return binding.isNestedType() && !binding.isStatic();
  }

  /**
   * Get a readable method description from {@code methodBinding} conforming with JSNI formatting.
   * <p>
   * See examples:
   * <ul>
   * <li>a constructor of class A with a java.lang.String parameter will be formatted as
   * "new(Ljava/lang/String;).</li>
   * <li>a method with name m with an parameter of class java.lang.Object and return type boolean
   * will be formatted as "m(Ljava/lang/Object;</li>
   * </ul>,
   */
  public static String formatMethodSignature(MethodBinding methodBinding) {
    ReferenceBinding declaringClassBinding = methodBinding.declaringClass;
    StringBuilder methodNameWithSignature = new StringBuilder();
    String methodName = String.valueOf(methodBinding.selector);
    List<TypeBinding> parameterTypeBindings = Lists.newArrayList();
    if (methodName.equals("<init>")) {
      // It is a constructor.
      // (1) use the JSNI methodName instead of <init>.
      methodName = "new";
      // (2) add the implicit constructor parameters types for non static inner classes.
      if (isInnerClass(declaringClassBinding)) {
        NestedTypeBinding nestedBinding = (NestedTypeBinding) declaringClassBinding;
        if (nestedBinding.enclosingInstances != null) {
          for (SyntheticArgumentBinding argumentBinding : nestedBinding.enclosingInstances) {
            parameterTypeBindings.add(argumentBinding.type);
          }
        }
      }
    }

    parameterTypeBindings.addAll(Arrays.asList(methodBinding.parameters));
    methodNameWithSignature.append(methodName);
    methodNameWithSignature.append("(");
    for (TypeBinding parameterTypeBinding : parameterTypeBindings) {
      methodNameWithSignature.append(parameterTypeBinding.signature());
    }
    methodNameWithSignature.append(")");
    return methodNameWithSignature.toString();
  }

  public static String formatBinding(MethodBinding methodBinding) {
    String accessModifier = null;
    if (methodBinding.isProtected()) {
      accessModifier = "protected";
    } else if (methodBinding.isPrivate()) {
      accessModifier = "private";
    } else if (methodBinding.isPublic()) {
      accessModifier = "public";
    }
    return Joiner.on(" ").skipNulls().join(
        accessModifier,
        methodBinding.isStatic() ? "static" : null,
        getSourceName(methodBinding.declaringClass) + "." +
            formatMethodSignature(methodBinding)
    );
  }

  private JdtUtil() {
  }

  public static String getAnnotationParameterString(
      AnnotationBinding annotationBinding, String parameterName) {
    if (annotationBinding != null) {
      for (ElementValuePair parameterNameValuePair : annotationBinding.getElementValuePairs()) {
        if (parameterNameValuePair.getValue() instanceof StringConstant &&
            parameterName.equals(String.valueOf(parameterNameValuePair.getName()))) {
          return ((StringConstant) parameterNameValuePair.getValue()).stringValue();
        }
      }
    }
    return null;
  }

  public static boolean getAnnotationParameterBoolean(
      AnnotationBinding annotationBinding, String parameterName, boolean defaultValue) {
    Boolean booleanParameterValue = getAnnotationParameterBoolean(annotationBinding, parameterName);
    return booleanParameterValue == null ? defaultValue : booleanParameterValue;
  }

  public static Boolean getAnnotationParameterBoolean(
      AnnotationBinding annotationBinding, String parameterName) {
    if (annotationBinding != null) {
      for (ElementValuePair parameterNameValuePair : annotationBinding.getElementValuePairs()) {
        if (parameterNameValuePair.getValue() instanceof BooleanConstant &&
            parameterName.equals(String.valueOf(parameterNameValuePair.getName()))) {
          return ((BooleanConstant) parameterNameValuePair.getValue()).booleanValue();
        }
      }
    }
    return null;
  }

  public static AnnotationBinding getAnnotationByName(Annotation[] annotations, String name) {
    if (annotations == null) {
      return null;
    }
    for (Annotation annotation : annotations) {
      AnnotationBinding annotationBinding = annotation.getCompilerAnnotation();
      if (matchAnnotationName(annotationBinding, name)) {
        return annotationBinding;
      }
    }
    return null;
  }

  public static AnnotationBinding getAnnotationByName(
      AnnotationBinding[] annotationsBindings, String name) {
    if (annotationsBindings == null) {
      return null;
    }
    for (AnnotationBinding annotationBinding : annotationsBindings) {
      if (matchAnnotationName(annotationBinding, name)) {
        return annotationBinding;
      }
    }
    return null;
  }

  private static boolean matchAnnotationName(AnnotationBinding annotationBinding, String name) {
    if (annotationBinding == null) {
      return false;
    }
    return name.equals(CharOperation.toString(annotationBinding.getAnnotationType().compoundName));
  }

  public static TypeBinding getAnnotationParameterTypeBinding(
      AnnotationBinding annotationBinding, String parameterName) {
    if (annotationBinding != null) {
      for (ElementValuePair parameterNameValuePair : annotationBinding.getElementValuePairs()) {
        if (parameterNameValuePair.getValue() instanceof Class &&
            parameterName.equals(String.valueOf(parameterNameValuePair.getName()))) {
          return (TypeBinding) parameterNameValuePair.getValue();
        }
      }
    }
    return null;
  }

  public static TypeBinding[] getAnnotationParameterTypeBindingArray(
      AnnotationBinding annotationBinding, String parameterName) {
    if (annotationBinding == null) {
      return null;
    }

    for (ElementValuePair parameterNameValuePair : annotationBinding.getElementValuePairs()) {
      Object value = parameterNameValuePair.getValue();
      if (!parameterName.equals(String.valueOf(parameterNameValuePair.getName()))) {
        continue;
      }
      if (value instanceof Object[]) {
        Object[] values = (Object[]) value;
        TypeBinding bindings[] = new TypeBinding[values.length];
        System.arraycopy(values, 0, bindings, 0, values.length);
        return bindings;
      }
      assert value instanceof TypeBinding;
      return new TypeBinding[] {(TypeBinding) value};
    }
    return null;
  }

  public static StringConstant[] getAnnotationParameterStringConstantArray(
      AnnotationBinding annotationBinding, String parameterName) {
    if (annotationBinding == null) {
      return null;
    }
    for (ElementValuePair parameterNameValuePair : annotationBinding.getElementValuePairs()) {
      if (!parameterName.equals(String.valueOf(parameterNameValuePair.getName()))) {
        continue;
      }
      Object value = parameterNameValuePair.getValue();
      if (value instanceof Object[]) {
        Object[] values = (Object[]) value;
        StringConstant[] stringConstants = new StringConstant[values.length];
        System.arraycopy(values, 0, stringConstants, 0, values.length);
        return stringConstants;
      }
      assert value instanceof StringConstant;
      return new StringConstant[] {(StringConstant) value};
    }
    return null;
  }

  public static Set<String> getSuppressedWarnings(Annotation[] annotations) {
    if (annotations == null) {
      return ImmutableSet.of();
    }
    AnnotationBinding suppressWarnings =
        getAnnotationByName(annotations, SuppressWarnings.class.getName());
    if (suppressWarnings != null) {
      StringConstant[] values =
          JdtUtil.getAnnotationParameterStringConstantArray(suppressWarnings, "value");
      return FluentIterable.from(Arrays.asList(values))
          .transform(new Function<StringConstant, String>() {
            @Override
            public String apply(StringConstant value) {
              return value.stringValue();
            }
          })
          .toSet();
    }
    return ImmutableSet.of();
  }

  public static String signature(FieldBinding binding) {
    StringBuilder sb = new StringBuilder();
    sb.append(binding.declaringClass.constantPoolName());
    sb.append('.');
    sb.append(binding.name);
    sb.append(':');
    sb.append(binding.type.signature());
    return sb.toString();
  }

  public static String signature(MethodBinding binding) {
    StringBuilder sb = new StringBuilder();
    sb.append(binding.declaringClass.constantPoolName());
    sb.append('.');
    sb.append(binding.selector);
    sb.append('(');
    for (TypeBinding paramType : binding.parameters) {
      sb.append(paramType.signature());
    }
    sb.append(')');
    sb.append(binding.returnType.signature());
    return sb.toString();
  }

  public static String signature(TypeBinding binding) {
    assert !binding.isIntersectionType18() && !binding.isIntersectionType();
    if (binding.isBaseType()) {
      return String.valueOf(binding.sourceName());
    } else {
      return String.valueOf(binding.constantPoolName());
    }
  }

  public static void setClassDispositionFromBinding(SourceTypeBinding binding, JDeclaredType type) {
    if (binding.isNestedType()) {
      if (isLocalClass(binding)) {
        type.setClassDisposition(JDeclaredType.NestedClassDisposition.LOCAL);
      } else if (binding.isAnonymousType()) {
        type.setClassDisposition(JDeclaredType.NestedClassDisposition.ANONYMOUS);
      } else if (isInnerClass(binding)) {
        type.setClassDisposition(JDeclaredType.NestedClassDisposition.INNER);
      } else if (isStaticClass(binding)) {
        type.setClassDisposition(JDeclaredType.NestedClassDisposition.STATIC);
      }
    } else {
      type.setClassDisposition(JDeclaredType.NestedClassDisposition.TOP_LEVEL);
    }
  }

  public static boolean isLocalClass(SourceTypeBinding binding) {
    return binding.isLocalType() && !binding.isAnonymousType();
  }

  public static boolean isStaticClass(SourceTypeBinding binding) {
    return binding.isNestedType() && binding.isStatic();
  }

  /**
   * Returns {@code true} if {@code typeBinding} is {@code JavaScriptObject} or
   * any subtype.
   */
  public static boolean isJso(TypeBinding typeBinding) {
    if (!(typeBinding instanceof ReferenceBinding)) {
      return false;
    }
    ReferenceBinding binding = (ReferenceBinding) typeBinding;
    while (binding != null) {
      if (JSO_CLASS.equals(String.valueOf(binding.constantPoolName()))) {
        return true;
      }
      binding = binding.superclass();
    }
    return false;
  }

  /**
   * Returns {@code true} if {@code typeBinding} is a subtype of
   * {@code JavaScriptObject}, but not {@code JavaScriptObject} itself.
   */
  public static boolean isJsoSubclass(TypeBinding typeBinding) {
    if (!(typeBinding instanceof ReferenceBinding)) {
      return false;
    }
    ReferenceBinding binding = (ReferenceBinding) typeBinding;
    return isJso(binding.superclass());
  }

  public static Iterable<ReferenceBinding> getSuperInterfacesRequiringInitialization(
      ReferenceBinding type) {
    Iterable<ReferenceBinding> interfaces = Collections.emptyList();
    for (ReferenceBinding interfaceType : type.superInterfaces()) {
      interfaces =
          Iterables.concat(interfaces, getSuperInterfacesRequiringInitialization(interfaceType));
      if (hasDefaultMethods(interfaceType)) {
        interfaces = Iterables.concat(interfaces, Collections.singleton(interfaceType));
      }
    }
    return interfaces;
  }

  private static boolean hasDefaultMethods(ReferenceBinding interfaceType) {
    return Iterables.any(Arrays.asList(interfaceType.methods()), new Predicate<MethodBinding>() {
      @Override
      public boolean apply(MethodBinding methodBinding) {
        return methodBinding.isDefaultMethod();
      }
    });
  }

  /*
   * Implicit conversion helpers.
   */

  public static boolean requiresBoxing(int implicitConversion) {
    return implicitConversion != -1
        && (implicitConversion & TypeIds.BOXING) != 0;
  }

  public static boolean requiresUnboxing(int implicitConversion) {
    return implicitConversion != -1
        && (implicitConversion & TypeIds.UNBOXING) != 0;
  }

  public static BaseTypeBinding getBoxingPrimitiveType(ClassScope scope, int implicitConversion) {
    int typeId = (implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4;
    return getBaseTypeBinding(scope, typeId);
  }

  public static BaseTypeBinding getUnboxingPrimitiveType(
      ClassScope scope, int implicitConversion) {
    if (needsCastBeforeUnbox(scope, implicitConversion)) {
      int typeId = (implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4;
      return getBaseTypeBinding(scope, typeId);
    }
    int compileTypeId = implicitConversion & TypeIds.COMPILE_TYPE_MASK;
    return getBaseTypeBinding(scope, compileTypeId);
  }

  public static BaseTypeBinding getBaseTypeBinding(ClassScope scope, int typeId) {
    return  (BaseTypeBinding) TypeBinding.wellKnownType(scope, typeId);
  }

  public static ReferenceBinding getBoxedTypeBinding(
      ClassScope scope, BaseTypeBinding primitiveType) {
    return (ReferenceBinding) scope.boxing(primitiveType);
  }

  public static boolean needsCastBeforeUnbox(ClassScope scope, int implicitConversion) {
    // values of specific types like j.l.Object need casting before auto unboxing.
    int compileTypeId = implicitConversion & TypeIds.COMPILE_TYPE_MASK;
    return !(TypeBinding.wellKnownType(scope, compileTypeId) instanceof BaseTypeBinding);
  }

  private static final String VALUE_SUFFIX = "Value";
  private static final String VALUE_OF_METHOD_NAME = "valueOf";

  private static final char[] VALUE_SUFFIX_ = VALUE_SUFFIX.toCharArray();
  private static final char[] VALUE_OF_ = VALUE_OF_METHOD_NAME.toCharArray();

  public static MethodBinding getBoxingMethodBinding(
      ClassScope scope, BaseTypeBinding primitiveType) {
    ReferenceBinding boxType = (ReferenceBinding) scope.boxing(primitiveType);
    MethodBinding valueOfMethod = boxType.getExactMethod(VALUE_OF_,
        new TypeBinding[]{primitiveType}, scope.compilationUnitScope());
    assert valueOfMethod != null;
    return valueOfMethod;
  }

  public static MethodBinding getUnboxingMethodBinding(
      ClassScope scope, BaseTypeBinding primitiveType) {
    ReferenceBinding boxType = (ReferenceBinding) scope.boxing(primitiveType);
    char[] selector = CharOperation.concat(primitiveType.simpleName, VALUE_SUFFIX_);

    MethodBinding valueMethod =
        boxType.getExactMethod(selector, new TypeBinding[0], scope.compilationUnitScope());
    assert valueMethod != null;
    return valueMethod;
  }
}
