// Copyright (C) 2012 The Android Open Source Project
//
// 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.gerrit.extensions.registration;

import com.google.inject.Binder;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.ProvisionException;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.util.Providers;
import com.google.inject.util.Types;

import java.util.concurrent.atomic.AtomicReference;

/**
 * A single item that can be modified as plugins reload.
 * <p>
 * DynamicItems are always mapped as singletons in Guice. Items store a Provider
 * internally, and resolve the provider to an instance on demand. This enables
 * registrations to decide between singleton and non-singleton members. If
 * multiple plugins try to provide the same Provider, an exception is thrown.
 */
public class DynamicItem<T> {
  /** Pair of provider implementation and plugin providing it. */
  static class NamedProvider<T> {
    final Provider<T> impl;
    final String pluginName;

    NamedProvider(Provider<T> provider, String pluginName) {
      this.impl = provider;
      this.pluginName = pluginName;
    }
  }

  /**
   * Declare a singleton {@code DynamicItem<T>} with a binder.
   * <p>
   * Items must be defined in a Guice module before they can be bound:
   * <pre>
   *   DynamicItem.itemOf(binder(), Interface.class);
   *   DynamicItem.bind(binder(), Interface.class).to(Impl.class);
   * </pre>
   *
   * @param binder a new binder created in the module.
   * @param member type of entry to store.
   */
  public static <T> void itemOf(Binder binder, Class<T> member) {
    itemOf(binder, TypeLiteral.get(member));
  }

  /**
   * Declare a singleton {@code DynamicItem<T>} with a binder.
   * <p>
   * Items must be defined in a Guice module before they can be bound:
   * <pre>
   *   DynamicSet.itemOf(binder(), new TypeLiteral<Thing<Foo>>() {});
   * </pre>
   *
   * @param binder a new binder created in the module.
   * @param member type of entry to store.
   */
  public static <T> void itemOf(Binder binder, TypeLiteral<T> member) {
    @SuppressWarnings("unchecked")
    Key<DynamicItem<T>> key = (Key<DynamicItem<T>>) Key.get(
        Types.newParameterizedType(DynamicItem.class, member.getType()));
    binder.bind(key)
      .toProvider(new DynamicItemProvider<>(member, key))
      .in(Scopes.SINGLETON);
  }

  /**
   * Bind one implementation as the item using a unique annotation.
   *
   * @param binder a new binder created in the module.
   * @param type type of entry to store.
   * @return a binder to continue configuring the new item.
   */
  public static <T> LinkedBindingBuilder<T> bind(Binder binder, Class<T> type) {
    return bind(binder, TypeLiteral.get(type));
  }

  /**
   * Bind one implementation as the item.
   *
   * @param binder a new binder created in the module.
   * @param type type of entry to store.
   * @return a binder to continue configuring the new item.
   */
  public static <T> LinkedBindingBuilder<T> bind(Binder binder,
      TypeLiteral<T> type) {
    return binder.bind(type);
  }

  private final Key<DynamicItem<T>> key;
  private final AtomicReference<NamedProvider<T>> ref;

  DynamicItem(Key<DynamicItem<T>> key, Provider<T> provider, String pluginName) {
    NamedProvider<T> in = null;
    if (provider != null) {
      in = new NamedProvider<>(provider, pluginName);
    }
    this.key = key;
    this.ref = new AtomicReference<>(in);
  }

  /**
   * Get the configured item, or null.
   *
   * @return the configured item instance; null if no implementation has been
   *         bound to the item. This is common if no plugin registered an
   *         implementation for the type.
   */
  public T get() {
    NamedProvider<T> item = ref.get();
    return item != null ? item.impl.get() : null;
  }

  /**
   * Set the element to provide.
   *
   * @param item the item to use. Must not be null.
   * @param pluginName the name of the plugin providing the item.
   * @return handle to remove the item at a later point in time.
   */
  public RegistrationHandle set(T item, String pluginName) {
    return set(Providers.of(item), pluginName);
  }

  /**
   * Set the element to provide.
   *
   * @param impl the item to add to the collection. Must not be null.
   * @param pluginName name of the source providing the implementation.
   * @return handle to remove the item at a later point in time.
   */
  public RegistrationHandle set(Provider<T> impl, String pluginName) {
    final NamedProvider<T> item = new NamedProvider<>(impl, pluginName);
    NamedProvider<T> old = null;
    while (!ref.compareAndSet(old, item)) {
      old = ref.get();
      if (old != null && !"gerrit".equals(old.pluginName)) {
        throw new ProvisionException(String.format(
            "%s already provided by %s, ignoring plugin %s",
            key.getTypeLiteral(), old.pluginName, pluginName));
      }
    }

    final NamedProvider<T> defaultItem = old;
    return new RegistrationHandle() {
      @Override
      public void remove() {
        ref.compareAndSet(item, defaultItem);
      }
    };
  }

  /**
   * Set the element that may be hot-replaceable in the future.
   *
   * @param key unique description from the item's Guice binding. This can be
   *        later obtained from the registration handle to facilitate matching
   *        with the new equivalent instance during a hot reload.
   * @param impl the item to set as our value right now. Must not be null.
   * @param pluginName the name of the plugin providing the item.
   * @return a handle that can remove this item later, or hot-swap the item.
   */
  public ReloadableRegistrationHandle<T> set(Key<T> key, Provider<T> impl,
      String pluginName) {
    final NamedProvider<T> item = new NamedProvider<>(impl, pluginName);
    NamedProvider<T> old = null;
    while (!ref.compareAndSet(old, item)) {
      old = ref.get();
      if (old != null
          && !"gerrit".equals(old.pluginName)
          && !pluginName.equals(old.pluginName)) {
        // We allow to replace:
        // 1. Gerrit core items, e.g. websession cache
        //    can be replaced by plugin implementation
        // 2. Reload of current plugin
        throw new ProvisionException(String.format(
            "%s already provided by %s, ignoring plugin %s",
            this.key.getTypeLiteral(), old.pluginName, pluginName));
      }
    }
    return new ReloadableHandle(key, item, old);
  }

  private class ReloadableHandle implements ReloadableRegistrationHandle<T> {
    private final Key<T> key;
    private final NamedProvider<T> item;
    private final NamedProvider<T> defaultItem;

    ReloadableHandle(Key<T> key, NamedProvider<T> item, NamedProvider<T> defaultItem) {
      this.key = key;
      this.item = item;
      this.defaultItem = defaultItem;
    }

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

    @Override
    public void remove() {
      ref.compareAndSet(item, defaultItem);
    }

    @Override
    public ReloadableHandle replace(Key<T> newKey, Provider<T> newItem) {
      NamedProvider<T> n = new NamedProvider<>(newItem, item.pluginName);
      if (ref.compareAndSet(item, n)) {
        return new ReloadableHandle(newKey, n, defaultItem);
      }
      return null;
    }
  }
}
