// 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.server.plugins;

import static com.google.gerrit.extensions.registration.PrivateInternals_DynamicTypes.dynamicItemsOf;
import static com.google.gerrit.extensions.registration.PrivateInternals_DynamicTypes.dynamicMapsOf;
import static com.google.gerrit.extensions.registration.PrivateInternals_DynamicTypes.dynamicSetsOf;

import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.annotations.RootRelative;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.registration.PrivateInternals_DynamicMapImpl;
import com.google.gerrit.extensions.registration.PrivateInternals_DynamicTypes;
import com.google.gerrit.extensions.registration.RegistrationHandle;
import com.google.gerrit.extensions.registration.ReloadableRegistrationHandle;
import com.google.gerrit.extensions.systemstatus.ServerInformation;
import com.google.gerrit.server.util.PluginRequestContext;
import com.google.gerrit.server.util.RequestContext;
import com.google.gerrit.server.util.ThreadLocalRequestContext;
import com.google.inject.AbstractModule;
import com.google.inject.Binding;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.internal.UniqueAnnotations;

import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Tracks Guice bindings that should be exposed to loaded plugins.
 * <p>
 * This is an internal implementation detail of how the main server is able to
 * export its explicit Guice bindings to tightly coupled plugins, giving them
 * access to singletons and request scoped resources just like any core code.
 */
@Singleton
public class PluginGuiceEnvironment {
  private final Injector sysInjector;
  private final ServerInformation srvInfo;
  private final ThreadLocalRequestContext local;
  private final CopyConfigModule copyConfigModule;
  private final Set<Key<?>> copyConfigKeys;
  private final List<StartPluginListener> onStart;
  private final List<StopPluginListener> onStop;
  private final List<ReloadPluginListener> onReload;

  private Module sysModule;
  private Module sshModule;
  private Module httpModule;

  private Provider<ModuleGenerator> sshGen;
  private Provider<HttpModuleGenerator> httpGen;

  private Map<TypeLiteral<?>, DynamicItem<?>> sysItems;
  private Map<TypeLiteral<?>, DynamicItem<?>> sshItems;
  private Map<TypeLiteral<?>, DynamicItem<?>> httpItems;

  private Map<TypeLiteral<?>, DynamicSet<?>> sysSets;
  private Map<TypeLiteral<?>, DynamicSet<?>> sshSets;
  private Map<TypeLiteral<?>, DynamicSet<?>> httpSets;

  private Map<TypeLiteral<?>, DynamicMap<?>> sysMaps;
  private Map<TypeLiteral<?>, DynamicMap<?>> sshMaps;
  private Map<TypeLiteral<?>, DynamicMap<?>> httpMaps;

  @Inject
  PluginGuiceEnvironment(
      Injector sysInjector,
      ThreadLocalRequestContext local,
      ServerInformation srvInfo,
      CopyConfigModule ccm) {
    this.sysInjector = sysInjector;
    this.srvInfo = srvInfo;
    this.local = local;
    this.copyConfigModule = ccm;
    this.copyConfigKeys = Guice.createInjector(ccm).getAllBindings().keySet();

    onStart = new CopyOnWriteArrayList<>();
    onStart.addAll(listeners(sysInjector, StartPluginListener.class));

    onStop = new CopyOnWriteArrayList<>();
    onStop.addAll(listeners(sysInjector, StopPluginListener.class));

    onReload = new CopyOnWriteArrayList<>();
    onReload.addAll(listeners(sysInjector, ReloadPluginListener.class));

    sysItems = dynamicItemsOf(sysInjector);
    sysSets = dynamicSetsOf(sysInjector);
    sysMaps = dynamicMapsOf(sysInjector);
  }

  ServerInformation getServerInformation() {
    return srvInfo;
  }

  boolean hasDynamicItem(TypeLiteral<?> type) {
    return sysItems.containsKey(type)
        || (sshItems != null && sshItems.containsKey(type))
        || (httpItems != null && httpItems.containsKey(type));
  }

  boolean hasDynamicSet(TypeLiteral<?> type) {
    return sysSets.containsKey(type)
        || (sshSets != null && sshSets.containsKey(type))
        || (httpSets != null && httpSets.containsKey(type));
  }

  boolean hasDynamicMap(TypeLiteral<?> type) {
    return sysMaps.containsKey(type)
        || (sshMaps != null && sshMaps.containsKey(type))
        || (httpMaps != null && httpMaps.containsKey(type));
  }

  public Module getSysModule() {
    return sysModule;
  }

  public void setDbCfgInjector(Injector dbInjector, Injector cfgInjector) {
    final Module db = copy(dbInjector);
    final Module cm = copy(cfgInjector);
    final Module sm = copy(sysInjector);
    sysModule = new AbstractModule() {
      @Override
      protected void configure() {
        install(copyConfigModule);
        install(db);
        install(cm);
        install(sm);
      }
    };
  }

  public void setSshInjector(Injector injector) {
    sshModule = copy(injector);
    sshGen = injector.getProvider(ModuleGenerator.class);
    sshItems = dynamicItemsOf(injector);
    sshSets = dynamicSetsOf(injector);
    sshMaps = dynamicMapsOf(injector);
    onStart.addAll(listeners(injector, StartPluginListener.class));
    onStop.addAll(listeners(injector, StopPluginListener.class));
    onReload.addAll(listeners(injector, ReloadPluginListener.class));
  }

  boolean hasSshModule() {
    return sshModule != null;
  }

  Module getSshModule() {
    return sshModule;
  }

  ModuleGenerator newSshModuleGenerator() {
    return sshGen.get();
  }

  public void setHttpInjector(Injector injector) {
    httpModule = copy(injector);
    httpGen = injector.getProvider(HttpModuleGenerator.class);
    httpItems = dynamicItemsOf(injector);
    httpSets = dynamicSetsOf(injector);
    httpMaps = dynamicMapsOf(injector);
    onStart.addAll(listeners(injector, StartPluginListener.class));
    onStop.addAll(listeners(injector, StopPluginListener.class));
    onReload.addAll(listeners(injector, ReloadPluginListener.class));
  }

  boolean hasHttpModule() {
    return httpModule != null;
  }

  Module getHttpModule() {
    return httpModule;
  }

  HttpModuleGenerator newHttpModuleGenerator() {
    return httpGen.get();
  }

  public RequestContext enter(Plugin plugin) {
    return local.setContext(new PluginRequestContext(plugin.getPluginUser()));
  }

  public void exit(RequestContext old) {
    local.setContext(old);
  }

  public void onStartPlugin(Plugin plugin) {
    RequestContext oldContext = enter(plugin);
    try {
      attachItem(sysItems, plugin.getSysInjector(), plugin);
      attachItem(sshItems, plugin.getSshInjector(), plugin);
      attachItem(httpItems, plugin.getHttpInjector(), plugin);

      attachSet(sysSets, plugin.getSysInjector(), plugin);
      attachSet(sshSets, plugin.getSshInjector(), plugin);
      attachSet(httpSets, plugin.getHttpInjector(), plugin);

      attachMap(sysMaps, plugin.getSysInjector(), plugin);
      attachMap(sshMaps, plugin.getSshInjector(), plugin);
      attachMap(httpMaps, plugin.getHttpInjector(), plugin);
    } finally {
      exit(oldContext);
    }

    for (StartPluginListener l : onStart) {
      l.onStartPlugin(plugin);
    }
  }

  void onStopPlugin(Plugin plugin) {
    for (StopPluginListener l : onStop) {
      l.onStopPlugin(plugin);
    }
  }

  private void attachItem(Map<TypeLiteral<?>, DynamicItem<?>> items,
      @Nullable Injector src,
      Plugin plugin) {
    for (RegistrationHandle h : PrivateInternals_DynamicTypes
        .attachItems(src, items, plugin.getName())) {
      plugin.add(h);
    }
  }

  private void attachSet(Map<TypeLiteral<?>, DynamicSet<?>> sets,
      @Nullable Injector src,
      Plugin plugin) {
    for (RegistrationHandle h : PrivateInternals_DynamicTypes
        .attachSets(src, sets)) {
      plugin.add(h);
    }
  }

  private void attachMap(Map<TypeLiteral<?>, DynamicMap<?>> maps,
      @Nullable Injector src,
      Plugin plugin) {
    for (RegistrationHandle h : PrivateInternals_DynamicTypes
        .attachMaps(src, plugin.getName(), maps)) {
      plugin.add(h);
    }
  }

  void onReloadPlugin(Plugin oldPlugin, Plugin newPlugin) {
    // Index all old registrations by the raw type. These may be replaced
    // during the reattach calls below. Any that are not replaced will be
    // removed when the old plugin does its stop routine.
    ListMultimap<TypeLiteral<?>, ReloadableRegistrationHandle<?>> old =
        LinkedListMultimap.create();
    for (ReloadableRegistrationHandle<?> h : oldPlugin.getReloadableHandles()) {
      old.put(h.getKey().getTypeLiteral(), h);
    }

    RequestContext oldContext = enter(newPlugin);
    try {
      reattachMap(old, sysMaps, newPlugin.getSysInjector(), newPlugin);
      reattachMap(old, sshMaps, newPlugin.getSshInjector(), newPlugin);
      reattachMap(old, httpMaps, newPlugin.getHttpInjector(), newPlugin);

      reattachSet(old, sysSets, newPlugin.getSysInjector(), newPlugin);
      reattachSet(old, sshSets, newPlugin.getSshInjector(), newPlugin);
      reattachSet(old, httpSets, newPlugin.getHttpInjector(), newPlugin);

      reattachItem(old, sysItems, newPlugin.getSysInjector(), newPlugin);
      reattachItem(old, sshItems, newPlugin.getSshInjector(), newPlugin);
      reattachItem(old, httpItems, newPlugin.getHttpInjector(), newPlugin);
    } finally {
      exit(oldContext);
    }

    for (ReloadPluginListener l : onReload) {
      l.onReloadPlugin(oldPlugin, newPlugin);
    }
  }

  private void reattachMap(
      ListMultimap<TypeLiteral<?>, ReloadableRegistrationHandle<?>> oldHandles,
      Map<TypeLiteral<?>, DynamicMap<?>> maps,
      @Nullable Injector src,
      Plugin newPlugin) {
    if (src == null || maps == null || maps.isEmpty()) {
      return;
    }

    for (Map.Entry<TypeLiteral<?>, DynamicMap<?>> e : maps.entrySet()) {
      @SuppressWarnings("unchecked")
      TypeLiteral<Object> type = (TypeLiteral<Object>) e.getKey();

      @SuppressWarnings("unchecked")
      PrivateInternals_DynamicMapImpl<Object> map =
          (PrivateInternals_DynamicMapImpl<Object>) e.getValue();

      Map<Annotation, ReloadableRegistrationHandle<?>> am = Maps.newHashMap();
      for (ReloadableRegistrationHandle<?> h : oldHandles.get(type)) {
        Annotation a = h.getKey().getAnnotation();
        if (a != null && !UNIQUE_ANNOTATION.isInstance(a)) {
          am.put(a, h);
        }
      }

      for (Binding<?> binding : bindings(src, e.getKey())) {
        @SuppressWarnings("unchecked")
        Binding<Object> b = (Binding<Object>) binding;
        Key<Object> key = b.getKey();
        if (key.getAnnotation() == null) {
          continue;
        }

        @SuppressWarnings("unchecked")
        ReloadableRegistrationHandle<Object> h =
            (ReloadableRegistrationHandle<Object>) am.remove(key.getAnnotation());
        if (h != null) {
          replace(newPlugin, h, b);
          oldHandles.remove(type, h);
        } else {
          newPlugin.add(map.put(
              newPlugin.getName(),
              b.getKey(),
              b.getProvider()));
        }
      }
    }
  }

  /** Type used to declare unique annotations. Guice hides this, so extract it. */
  private static final Class<?> UNIQUE_ANNOTATION =
      UniqueAnnotations.create().getClass();

  private void reattachSet(
      ListMultimap<TypeLiteral<?>, ReloadableRegistrationHandle<?>> oldHandles,
      Map<TypeLiteral<?>, DynamicSet<?>> sets,
      @Nullable Injector src,
      Plugin newPlugin) {
    if (src == null || sets == null || sets.isEmpty()) {
      return;
    }

    for (Map.Entry<TypeLiteral<?>, DynamicSet<?>> e : sets.entrySet()) {
      @SuppressWarnings("unchecked")
      TypeLiteral<Object> type = (TypeLiteral<Object>) e.getKey();

      @SuppressWarnings("unchecked")
      DynamicSet<Object> set = (DynamicSet<Object>) e.getValue();

      // Index all old handles that match this DynamicSet<T> keyed by
      // annotations. Ignore the unique annotations, thereby favoring
      // the @Named annotations or some other non-unique naming.
      Map<Annotation, ReloadableRegistrationHandle<?>> am = Maps.newHashMap();
      List<ReloadableRegistrationHandle<?>> old = oldHandles.get(type);
      Iterator<ReloadableRegistrationHandle<?>> oi = old.iterator();
      while (oi.hasNext()) {
        ReloadableRegistrationHandle<?> h = oi.next();
        Annotation a = h.getKey().getAnnotation();
        if (a != null && !UNIQUE_ANNOTATION.isInstance(a)) {
          am.put(a, h);
          oi.remove();
        }
      }

      // Replace old handles with new bindings, favoring cases where there
      // is an exact match on an @Named annotation. If there is no match
      // pick any handle and replace it. We generally expect only one
      // handle of each DynamicSet type when using unique annotations, but
      // possibly multiple ones if @Named was used. Plugin authors that want
      // atomic replacement across reloads should use @Named annotations with
      // stable names that do not change across plugin versions to ensure the
      // handles are swapped correctly.
      oi = old.iterator();
      for (Binding<?> binding : bindings(src, type)) {
        @SuppressWarnings("unchecked")
        Binding<Object> b = (Binding<Object>) binding;
        Key<Object> key = b.getKey();
        if (key.getAnnotation() == null) {
          continue;
        }

        @SuppressWarnings("unchecked")
        ReloadableRegistrationHandle<Object> h1 =
            (ReloadableRegistrationHandle<Object>) am.remove(key.getAnnotation());
        if (h1 != null) {
          replace(newPlugin, h1, b);
        } else if (oi.hasNext()) {
          @SuppressWarnings("unchecked")
          ReloadableRegistrationHandle<Object> h2 =
            (ReloadableRegistrationHandle<Object>) oi.next();
          oi.remove();
          replace(newPlugin, h2, b);
        } else {
          newPlugin.add(set.add(b.getKey(), b.getProvider()));
        }
      }
    }
  }
  private void reattachItem(
      ListMultimap<TypeLiteral<?>, ReloadableRegistrationHandle<?>> oldHandles,
      Map<TypeLiteral<?>, DynamicItem<?>> items,
      @Nullable Injector src,
      Plugin newPlugin) {
    if (src == null || items == null || items.isEmpty()) {
      return;
    }

    for (Map.Entry<TypeLiteral<?>, DynamicItem<?>> e : items.entrySet()) {
      @SuppressWarnings("unchecked")
      TypeLiteral<Object> type = (TypeLiteral<Object>) e.getKey();

      @SuppressWarnings("unchecked")
      DynamicItem<Object> item = (DynamicItem<Object>) e.getValue();

      Iterator<ReloadableRegistrationHandle<?>> oi =
          oldHandles.get(type).iterator();

      for (Binding<?> binding : bindings(src, type)) {
        @SuppressWarnings("unchecked")
        Binding<Object> b = (Binding<Object>) binding;
        if (oi.hasNext()) {
          @SuppressWarnings("unchecked")
          ReloadableRegistrationHandle<Object> h =
            (ReloadableRegistrationHandle<Object>) oi.next();
          oi.remove();
          replace(newPlugin, h, b);
        } else {
          newPlugin.add(item.set(b.getKey(), b.getProvider(),
              newPlugin.getName()));
        }
      }
    }
  }

  private static <T> void replace(Plugin newPlugin,
      ReloadableRegistrationHandle<T> h, Binding<T> b) {
    RegistrationHandle n = h.replace(b.getKey(), b.getProvider());
    if (n != null){
      newPlugin.add(n);
    }
  }

  static <T> List<T> listeners(Injector src, Class<T> type) {
    List<Binding<T>> bindings = bindings(src, TypeLiteral.get(type));
    int cnt = bindings != null ? bindings.size() : 0;
    List<T> found = Lists.newArrayListWithCapacity(cnt);
    if (bindings != null) {
      for (Binding<T> b : bindings) {
        found.add(b.getProvider().get());
      }
    }
    return found;
  }

  private static <T> List<Binding<T>> bindings(Injector src, TypeLiteral<T> type) {
    return src.findBindingsByType(type);
  }

  private Module copy(Injector src) {
    Set<TypeLiteral<?>> dynamicTypes = Sets.newHashSet();
    Set<TypeLiteral<?>> dynamicItemTypes = Sets.newHashSet();
    for (Map.Entry<Key<?>, Binding<?>> e : src.getBindings().entrySet()) {
      TypeLiteral<?> type = e.getKey().getTypeLiteral();
      if (type.getRawType() == DynamicItem.class) {
        ParameterizedType t = (ParameterizedType) type.getType();
        dynamicItemTypes.add(TypeLiteral.get(t.getActualTypeArguments()[0]));
      } else if (type.getRawType() == DynamicSet.class
          || type.getRawType() == DynamicMap.class) {
        ParameterizedType t = (ParameterizedType) type.getType();
        dynamicTypes.add(TypeLiteral.get(t.getActualTypeArguments()[0]));
      }
    }

    final Map<Key<?>, Binding<?>> bindings = Maps.newLinkedHashMap();
    for (Map.Entry<Key<?>, Binding<?>> e : src.getBindings().entrySet()) {
      if (dynamicTypes.contains(e.getKey().getTypeLiteral())
          && e.getKey().getAnnotation() != null) {
        // A type used in DynamicSet or DynamicMap that has an annotation
        // must be picked up by the set/map itself. A type used in either
        // but without an annotation may be magic glue implementing F and
        // using DynamicSet<F> or DynamicMap<F> internally. That should be
        // exported to plugins.
        continue;
      } else if (dynamicItemTypes.contains(e.getKey().getTypeLiteral())) {
        continue;
      } else if (shouldCopy(e.getKey())) {
        bindings.put(e.getKey(), e.getValue());
      }
    }
    bindings.remove(Key.get(Injector.class));
    bindings.remove(Key.get(java.util.logging.Logger.class));

    @Nullable
    final Binding<HttpServletRequest> requestBinding =
        src.getExistingBinding(Key.get(HttpServletRequest.class));

    @Nullable
    final Binding<HttpServletResponse> responseBinding =
        src.getExistingBinding(Key.get(HttpServletResponse.class));

    return new AbstractModule() {
      @SuppressWarnings("unchecked")
      @Override
      protected void configure() {
        for (Map.Entry<Key<?>, Binding<?>> e : bindings.entrySet()) {
          Key<Object> k = (Key<Object>) e.getKey();
          Binding<Object> b = (Binding<Object>) e.getValue();
          bind(k).toProvider(b.getProvider());
        }

        if (requestBinding != null) {
          bind(HttpServletRequest.class)
              .annotatedWith(RootRelative.class)
              .toProvider(requestBinding.getProvider());
        }
        if (responseBinding != null) {
          bind(HttpServletResponse.class)
              .annotatedWith(RootRelative.class)
              .toProvider(responseBinding.getProvider());
        }
      }
    };
  }

  private boolean shouldCopy(Key<?> key) {
    if (copyConfigKeys.contains(key)) {
      return false;
    }
    Class<?> type = key.getTypeLiteral().getRawType();
    if (LifecycleListener.class.isAssignableFrom(type)
        // This is needed for secondary index to work from plugin listeners
        && !is("com.google.gerrit.server.index.IndexCollection", type)) {
      return false;
    }
    if (StartPluginListener.class.isAssignableFrom(type)) {
      return false;
    }
    if (StopPluginListener.class.isAssignableFrom(type)) {
      return false;
    }

    if (type.getName().startsWith("com.google.inject.")) {
      return false;
    }

    if (is("org.apache.sshd.server.Command", type)) {
      return false;
    }

    if (is("javax.servlet.Filter", type)) {
      return false;
    }
    if (is("javax.servlet.ServletContext", type)) {
      return false;
    }
    if (is("javax.servlet.ServletRequest", type)) {
      return false;
    }
    if (is("javax.servlet.ServletResponse", type)) {
      return false;
    }
    if (is("javax.servlet.http.HttpServlet", type)) {
      return false;
    }
    if (is("javax.servlet.http.HttpServletRequest", type)) {
      return false;
    }
    if (is("javax.servlet.http.HttpServletResponse", type)) {
      return false;
    }
    if (is("javax.servlet.http.HttpSession", type)) {
      return false;
    }
    if (Map.class.isAssignableFrom(type)
        && key.getAnnotationType() != null
        && "com.google.inject.servlet.RequestParameters"
            .equals(key.getAnnotationType().getName())) {
      return false;
    }
    if (type.getName().startsWith("com.google.gerrit.httpd.GitOverHttpServlet$")) {
      return false;
    }
    return true;
  }

  static boolean is(String name, Class<?> type) {
    while (type != null) {
      if (name.equals(type.getName())) {
        return true;
      }

      Class<?>[] interfaces = type.getInterfaces();
      if (interfaces != null) {
        for (Class<?> i : interfaces) {
          if (is(name, i)) {
            return true;
          }
        }
      }

      type = type.getSuperclass();
    }
    return false;
  }
}
