/*
 * Copyright (C) 2006 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.inject;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.inject.internal.Annotations.generateAnnotation;
import static com.google.inject.internal.Annotations.isAllDefaultMethods;

import com.google.inject.internal.Annotations;
import com.google.inject.internal.MoreTypes;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

/**
 * Binding key consisting of an injection type and an optional annotation. Matches the type and
 * annotation at a point of injection.
 *
 * <p>For example, {@code Key.get(Service.class, Transactional.class)} will match:
 *
 * <pre>
 *   {@literal @}Inject
 *   public void setService({@literal @}Transactional Service service) {
 *     ...
 *   }
 * </pre>
 *
 * <p>{@code Key} supports generic types via subclassing just like {@link TypeLiteral}.
 *
 * <p>Keys do not differentiate between primitive types (int, char, etc.) and their corresponding
 * wrapper types (Integer, Character, etc.). Primitive types will be replaced with their wrapper
 * types when keys are created.
 *
 * @author crazybob@google.com (Bob Lee)
 */
public class Key<T> {

  private final AnnotationStrategy annotationStrategy;

  private final TypeLiteral<T> typeLiteral;
  private final int hashCode;
  // This field is updated using the 'Data-Race-Ful' lazy intialization pattern
  // See http://jeremymanson.blogspot.com/2008/12/benign-data-races-in-java.html for a detailed
  // explanation.
  private String toString;

  /**
   * Constructs a new key. Derives the type from this class's type parameter.
   *
   * <p>Clients create an empty anonymous subclass. Doing so embeds the type parameter in the
   * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
   *
   * <p>Example usage for a binding of type {@code Foo} annotated with {@code @Bar}:
   *
   * <p>{@code new Key<Foo>(Bar.class) {}}.
   */
  @SuppressWarnings("unchecked")
  protected Key(Class<? extends Annotation> annotationType) {
    this.annotationStrategy = strategyFor(annotationType);
    this.typeLiteral =
        MoreTypes.canonicalizeForKey(
            (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
    this.hashCode = computeHashCode();
  }

  /**
   * Constructs a new key. Derives the type from this class's type parameter.
   *
   * <p>Clients create an empty anonymous subclass. Doing so embeds the type parameter in the
   * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
   *
   * <p>Example usage for a binding of type {@code Foo} annotated with {@code @Bar}:
   *
   * <p>{@code new Key<Foo>(new Bar()) {}}.
   */
  @SuppressWarnings("unchecked")
  protected Key(Annotation annotation) {
    // no usages, not test-covered
    this.annotationStrategy = strategyFor(annotation);
    this.typeLiteral =
        MoreTypes.canonicalizeForKey(
            (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
    this.hashCode = computeHashCode();
  }

  /**
   * Constructs a new key. Derives the type from this class's type parameter.
   *
   * <p>Clients create an empty anonymous subclass. Doing so embeds the type parameter in the
   * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
   *
   * <p>Example usage for a binding of type {@code Foo}:
   *
   * <p>{@code new Key<Foo>() {}}.
   */
  @SuppressWarnings("unchecked")
  protected Key() {
    this.annotationStrategy = NullAnnotationStrategy.INSTANCE;
    this.typeLiteral =
        MoreTypes.canonicalizeForKey(
            (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
    this.hashCode = computeHashCode();
  }

  /** Unsafe. Constructs a key from a manually specified type. */
  @SuppressWarnings("unchecked")
  private Key(Type type, AnnotationStrategy annotationStrategy) {
    this.annotationStrategy = annotationStrategy;
    this.typeLiteral = MoreTypes.canonicalizeForKey((TypeLiteral<T>) TypeLiteral.get(type));
    this.hashCode = computeHashCode();
  }

  /** Constructs a key from a manually specified type. */
  private Key(TypeLiteral<T> typeLiteral, AnnotationStrategy annotationStrategy) {
    this.annotationStrategy = annotationStrategy;
    this.typeLiteral = MoreTypes.canonicalizeForKey(typeLiteral);
    this.hashCode = computeHashCode();
  }

  /** Computes the hash code for this key. */
  private int computeHashCode() {
    return typeLiteral.hashCode() * 31 + annotationStrategy.hashCode();
  }

  /** Gets the key type. */
  public final TypeLiteral<T> getTypeLiteral() {
    return typeLiteral;
  }

  /** Gets the annotation type. */
  public final Class<? extends Annotation> getAnnotationType() {
    return annotationStrategy.getAnnotationType();
  }

  /** Gets the annotation. */
  public final Annotation getAnnotation() {
    return annotationStrategy.getAnnotation();
  }

  boolean hasAnnotationType() {
    return annotationStrategy.getAnnotationType() != null;
  }

  String getAnnotationName() {
    Annotation annotation = annotationStrategy.getAnnotation();
    if (annotation != null) {
      return annotation.toString();
    }

    // not test-covered
    return annotationStrategy.getAnnotationType().toString();
  }

  Class<? super T> getRawType() {
    return typeLiteral.getRawType();
  }

  /** Gets the key of this key's provider. */
  Key<Provider<T>> providerKey() {
    return ofType(typeLiteral.providerType());
  }

  @Override
  public final boolean equals(Object o) {
    if (o == this) {
      return true;
    }
    if (!(o instanceof Key<?>)) {
      return false;
    }
    Key<?> other = (Key<?>) o;
    return annotationStrategy.equals(other.annotationStrategy)
        && typeLiteral.equals(other.typeLiteral);
  }

  @Override
  public final int hashCode() {
    return this.hashCode;
  }

  @Override
  public final String toString() {
    // Note: to not introduce dangerous data races the field should only be read once in this
    // method.
    String local = toString;
    if (local == null) {
      local = "Key[type=" + typeLiteral + ", annotation=" + annotationStrategy + "]";
      toString = local;
    }
    return local;
  }

  /** Gets a key for an injection type and an annotation strategy. */
  static <T> Key<T> get(Class<T> type, AnnotationStrategy annotationStrategy) {
    return new Key<T>(type, annotationStrategy);
  }

  /** Gets a key for an injection type. */
  public static <T> Key<T> get(Class<T> type) {
    return new Key<T>(type, NullAnnotationStrategy.INSTANCE);
  }

  /** Gets a key for an injection type and an annotation type. */
  public static <T> Key<T> get(Class<T> type, Class<? extends Annotation> annotationType) {
    return new Key<T>(type, strategyFor(annotationType));
  }

  /** Gets a key for an injection type and an annotation. */
  public static <T> Key<T> get(Class<T> type, Annotation annotation) {
    return new Key<T>(type, strategyFor(annotation));
  }

  /** Gets a key for an injection type. */
  public static Key<?> get(Type type) {
    return new Key<Object>(type, NullAnnotationStrategy.INSTANCE);
  }

  /** Gets a key for an injection type and an annotation type. */
  public static Key<?> get(Type type, Class<? extends Annotation> annotationType) {
    return new Key<Object>(type, strategyFor(annotationType));
  }

  /** Gets a key for an injection type and an annotation. */
  public static Key<?> get(Type type, Annotation annotation) {
    return new Key<Object>(type, strategyFor(annotation));
  }

  /** Gets a key for an injection type. */
  public static <T> Key<T> get(TypeLiteral<T> typeLiteral) {
    return new Key<T>(typeLiteral, NullAnnotationStrategy.INSTANCE);
  }

  /** Gets a key for an injection type and an annotation type. */
  public static <T> Key<T> get(
      TypeLiteral<T> typeLiteral, Class<? extends Annotation> annotationType) {
    return new Key<T>(typeLiteral, strategyFor(annotationType));
  }

  /** Gets a key for an injection type and an annotation. */
  public static <T> Key<T> get(TypeLiteral<T> typeLiteral, Annotation annotation) {
    return new Key<T>(typeLiteral, strategyFor(annotation));
  }

  /**
   * Returns a new key of the specified type with the same annotation as this key.
   *
   * @since 3.0
   */
  public <T> Key<T> ofType(Class<T> type) {
    return new Key<T>(type, annotationStrategy);
  }

  /**
   * Returns a new key of the specified type with the same annotation as this key.
   *
   * @since 3.0
   */
  public Key<?> ofType(Type type) {
    return new Key<Object>(type, annotationStrategy);
  }

  /**
   * Returns a new key of the specified type with the same annotation as this key.
   *
   * @since 3.0
   */
  public <T> Key<T> ofType(TypeLiteral<T> type) {
    return new Key<T>(type, annotationStrategy);
  }

  /**
   * Returns true if this key has annotation attributes.
   *
   * @since 3.0
   */
  public boolean hasAttributes() {
    return annotationStrategy.hasAttributes();
  }

  /**
   * Returns this key without annotation attributes, i.e. with only the annotation type.
   *
   * @since 3.0
   */
  public Key<T> withoutAttributes() {
    return new Key<T>(typeLiteral, annotationStrategy.withoutAttributes());
  }

  interface AnnotationStrategy {
    Annotation getAnnotation();

    Class<? extends Annotation> getAnnotationType();

    boolean hasAttributes();

    AnnotationStrategy withoutAttributes();
  }

  /** Gets the strategy for an annotation. */
  static AnnotationStrategy strategyFor(Annotation annotation) {
    checkNotNull(annotation, "annotation");
    Class<? extends Annotation> annotationType = annotation.annotationType();
    ensureRetainedAtRuntime(annotationType);
    ensureIsBindingAnnotation(annotationType);

    if (Annotations.isMarker(annotationType)) {
      return new AnnotationTypeStrategy(annotationType, annotation);
    }

    return new AnnotationInstanceStrategy(Annotations.canonicalizeIfNamed(annotation));
  }

  /** Gets the strategy for an annotation type. */
  static AnnotationStrategy strategyFor(Class<? extends Annotation> annotationType) {
    annotationType = Annotations.canonicalizeIfNamed(annotationType);
    if (isAllDefaultMethods(annotationType)) {
      return strategyFor(generateAnnotation(annotationType));
    }

    checkNotNull(annotationType, "annotation type");
    ensureRetainedAtRuntime(annotationType);
    ensureIsBindingAnnotation(annotationType);
    return new AnnotationTypeStrategy(annotationType, null);
  }

  private static void ensureRetainedAtRuntime(Class<? extends Annotation> annotationType) {
    checkArgument(
        Annotations.isRetainedAtRuntime(annotationType),
        "%s is not retained at runtime. Please annotate it with @Retention(RUNTIME).",
        annotationType.getName());
  }

  private static void ensureIsBindingAnnotation(Class<? extends Annotation> annotationType) {
    checkArgument(
        Annotations.isBindingAnnotation(annotationType),
        "%s is not a binding annotation. Please annotate it with @BindingAnnotation.",
        annotationType.getName());
  }

  static enum NullAnnotationStrategy implements AnnotationStrategy {
    INSTANCE;

    @Override
    public boolean hasAttributes() {
      return false;
    }

    @Override
    public AnnotationStrategy withoutAttributes() {
      throw new UnsupportedOperationException("Key already has no attributes.");
    }

    @Override
    public Annotation getAnnotation() {
      return null;
    }

    @Override
    public Class<? extends Annotation> getAnnotationType() {
      return null;
    }

    @Override
    public String toString() {
      return "[none]";
    }
  }

  // this class not test-covered
  static class AnnotationInstanceStrategy implements AnnotationStrategy {

    final Annotation annotation;

    AnnotationInstanceStrategy(Annotation annotation) {
      this.annotation = checkNotNull(annotation, "annotation");
    }

    @Override
    public boolean hasAttributes() {
      return true;
    }

    @Override
    public AnnotationStrategy withoutAttributes() {
      return new AnnotationTypeStrategy(getAnnotationType(), annotation);
    }

    @Override
    public Annotation getAnnotation() {
      return annotation;
    }

    @Override
    public Class<? extends Annotation> getAnnotationType() {
      return annotation.annotationType();
    }

    @Override
    public boolean equals(Object o) {
      if (!(o instanceof AnnotationInstanceStrategy)) {
        return false;
      }

      AnnotationInstanceStrategy other = (AnnotationInstanceStrategy) o;
      return annotation.equals(other.annotation);
    }

    @Override
    public int hashCode() {
      return annotation.hashCode();
    }

    @Override
    public String toString() {
      return annotation.toString();
    }
  }

  static class AnnotationTypeStrategy implements AnnotationStrategy {

    final Class<? extends Annotation> annotationType;

    // Keep the instance around if we have it so the client can request it.
    final Annotation annotation;

    AnnotationTypeStrategy(Class<? extends Annotation> annotationType, Annotation annotation) {
      this.annotationType = checkNotNull(annotationType, "annotation type");
      this.annotation = annotation;
    }

    @Override
    public boolean hasAttributes() {
      return false;
    }

    @Override
    public AnnotationStrategy withoutAttributes() {
      throw new UnsupportedOperationException("Key already has no attributes.");
    }

    @Override
    public Annotation getAnnotation() {
      return annotation;
    }

    @Override
    public Class<? extends Annotation> getAnnotationType() {
      return annotationType;
    }

    @Override
    public boolean equals(Object o) {
      if (!(o instanceof AnnotationTypeStrategy)) {
        return false;
      }

      AnnotationTypeStrategy other = (AnnotationTypeStrategy) o;
      return annotationType.equals(other.annotationType);
    }

    @Override
    public int hashCode() {
      return annotationType.hashCode();
    }

    @Override
    public String toString() {
      return "@" + annotationType.getName();
    }
  }
}
