package com.google.inject;

import com.google.inject.BinderImpl.CreationListener;
import com.google.inject.binder.BindingBuilder;
import com.google.inject.util.Objects;
import com.google.inject.util.ToStringBuilder;
import java.lang.annotation.Annotation;
import java.util.logging.Logger;

/**
 * Binds a {@link com.google.inject.Key} to an implementation in a given scope.
 */
class BindingBuilderImpl<T> implements BindingBuilder<T> {

  private static final Logger logger
      = Logger.getLogger(BindingBuilderImpl.class.getName());

  final Object source;
  Key<T> key;
  InternalFactory<? extends T> factory;
  TypeLiteral<? extends T> implementation;
  T instance;
  Scope scope;
  boolean preload = false;
  private BinderImpl binder;

  BindingBuilderImpl(BinderImpl binder, Key<T> key, Object source) {
    this.binder = binder;
    this.key = Objects.nonNull(key, "key");
    this.source = source;
  }

  Object getSource() {
    return source;
  }

  Key<T> getKey() {
    return key;
  }

  public BindingBuilder<T> annotatedWith(
      Class<? extends Annotation> annotationType) {
    if (this.key.hasAnnotationType()) {
      binder.addError(source, ErrorMessages.ANNOTATION_ALREADY_SPECIFIED);
    } else {
      this.key = Key.get(this.key.getType(), annotationType);
    }
    return this;
  }

  public BindingBuilder<T> annotatedWith(Annotation annotation) {
    if (this.key.hasAnnotationType()) {
      binder.addError(source, ErrorMessages.ANNOTATION_ALREADY_SPECIFIED);
    } else {
      // not test-covered?
      this.key = Key.get(this.key.getType(), annotation);
    }
    return this;
  }

  public <I extends T> BindingBuilder<T> to(Class<I> implementation) {
    return to(TypeLiteral.get(implementation));
  }

  public <I extends T> BindingBuilder<T> to(
      final TypeLiteral<I> implementation) {
    ensureImplementationIsNotSet();
    this.implementation = implementation;
    final DefaultFactory<I> defaultFactory
        = new DefaultFactory<I>(key, implementation, source);
    this.factory = defaultFactory;
    binder.creationListeners.add(defaultFactory);
    return this;
  }

  public BindingBuilder<T> to(Factory<? extends T> factory) {
    ensureImplementationIsNotSet();
    this.factory = new InternalFactoryToFactoryAdapter<T>(factory);
    return this;
  }

  public BindingBuilder<T> to(T instance) {
    ensureImplementationIsNotSet();
    this.instance = Objects.nonNull(instance, "instance");
    this.factory = new ConstantFactory<T>(instance);
    if (this.scope != null) {
      binder.addError(source, ErrorMessages.SINGLE_INSTANCE_AND_SCOPE);
    }
    this.scope = Scopes.CONTAINER;
    return this;
  }

  /**
   * Binds to instances from the given factory.
   */
  BindingBuilder<T> to(InternalFactory<? extends T> factory) {
    ensureImplementationIsNotSet();
    this.factory = factory;
    return this;
  }

  public BindingBuilder<T> toFactory(
      final Class<? extends Factory<T>> factoryType) {
    return toFactory(Key.get(factoryType));
  }

  public BindingBuilder<T> toFactory(
      final TypeLiteral<? extends Factory<T>> factoryType) {
    return toFactory(Key.get(factoryType));
  }

  public BindingBuilder<T> toFactory(
      final Key<? extends Factory<T>> factoryKey) {
    ensureImplementationIsNotSet();

    final BoundFactory<T> boundFactory =
        new BoundFactory<T>(factoryKey, source);
    binder.creationListeners.add(boundFactory);
    this.factory = boundFactory;

    return this;
  }

  /**
   * Adds an error message if the implementation has already been bound.
   */
  private void ensureImplementationIsNotSet() {
    if (factory != null) {
      binder.addError(source, ErrorMessages.IMPLEMENTATION_ALREADY_SET);
    }
  }

  public BindingBuilder<T> in(Class<? extends Annotation> scopeAnnotation) {
    // this method not test-covered

    ensureScopeNotSet();

    // We could defer this lookup to when we create the container, but this
    // is fine for now.
    this.scope = binder.scopes.get(Objects.nonNull(scopeAnnotation, "scope annotation"));
    if (this.scope == null) {
      binder.addError(source, ErrorMessages.SCOPE_NOT_FOUND,
          "@" + scopeAnnotation.getSimpleName());
    }
    return this;
  }

  public BindingBuilder<T> in(Scope scope) {
    ensureScopeNotSet();
    this.scope = Objects.nonNull(scope, "scope");
    return this;
  }

  private void ensureScopeNotSet() {
    // Scoping isn't allowed when we have only one instance.
    if (this.instance != null) {
      binder.addError(source, ErrorMessages.SINGLE_INSTANCE_AND_SCOPE);
      return;
    }

    if (this.scope != null) {
      binder.addError(source, ErrorMessages.SCOPE_ALREADY_SET);
    }
  }

  public BindingBuilder<T> eagerly() {
    this.preload = true;
    return this;
  }

  boolean shouldPreload() {
    return preload;
  }

  InternalFactory<? extends T> getInternalFactory(
      final ContainerImpl container) {
    // If an implementation wasn't specified, use the injection type.
    if (this.factory == null) {
      to(key.getType());
    }

    // Look for @Scoped on the implementation type.
    if (implementation != null) {
      Scope fromAnnotation = Scopes.getScopeForType(
          implementation.getRawType(), binder.scopes,
          binder.configurationErrorHandler);
      if (fromAnnotation != null) {
        if (this.scope == null) {
          this.scope = fromAnnotation;
        } else {
          logger.info("Overriding scope specified by annotation at "
              + source + ".");
        }
      }
    }

    return Scopes.scope(this.key, container, this.factory, scope);
  }

  boolean isContainerScoped() {
    return this.scope == Scopes.CONTAINER;
  }

  /**
   * Delegates to a custom factory which is also bound in the container.
   */
  private static class BoundFactory<T>
      implements InternalFactory<T>, CreationListener {

    final Key<? extends Factory<? extends T>> factoryKey;
    final Object source;
    private InternalFactory<? extends Factory<? extends T>> factoryFactory;

    public BoundFactory(
        Key<? extends Factory<? extends T>> factoryKey,
        Object source) {
      this.factoryKey = factoryKey;
      this.source = source;
    }

    public void notify(final ContainerImpl container) {
      container.withDefaultSource(source, new Runnable() {
        public void run() {
          factoryFactory = container.getInternalFactory(null, factoryKey);
        }
      });
    }

    public String toString() {
      return factoryKey.toString();
    }

    public T get(InternalContext context) {
      return factoryFactory
          .get(context)
          .get(context.getExternalContext());
    }
  }

  /**
   * Injects new instances of the specified implementation class.
   */
  private static class DefaultFactory<T> implements InternalFactory<T>,
      CreationListener {

    private final TypeLiteral<T> implementation;
    private final Key<? super T> key;
    private final Object source;

    ConstructorInjector<T> constructor;

    DefaultFactory(Key<? super T> key, TypeLiteral<T> implementation,
        Object source) {
      this.key = key;
      this.implementation = implementation;
      this.source = source;
    }

    public void notify(final ContainerImpl container) {
      container.withDefaultSource(source, new Runnable() {
        public void run() {
          constructor = container.getConstructor(implementation);
        }
      });
    }

    public T get(InternalContext context) {
      // TODO: figure out if we can suppress this warning
      return constructor.construct(context, (Class<T>) key.getRawType());
    }

    public String toString() {
      return new ToStringBuilder(Locator.class)
          .add("implementation", implementation)
          .toString();
    }
  }
}
