/*
 * Copyright (C) 2012 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.caliper.runner;

import com.google.caliper.api.ResultProcessor;
import com.google.caliper.config.CaliperConfig;
import com.google.caliper.config.InstrumentConfig;
import com.google.caliper.model.Host;
import com.google.caliper.options.CaliperOptions;
import com.google.caliper.platform.Platform;
import com.google.caliper.runner.Instrument.Instrumentation;
import com.google.caliper.util.InvalidCommandException;
import com.google.caliper.util.ShortDuration;
import com.google.caliper.util.Stderr;
import com.google.caliper.util.Util;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Ordering;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.Service;

import dagger.MapKey;
import dagger.Module;
import dagger.Provides;
import dagger.Provides.Type;

import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;
import java.util.concurrent.Executors;

import javax.inject.Provider;
import javax.inject.Singleton;

/**
 * Configures a {@link CaliperRun} that performs experiments.
 */
@Module
final class ExperimentingRunnerModule {
  private static final String RUNNER_MAX_PARALLELISM_OPTION = "runner.maxParallelism";

  @Provides(type = Type.SET)
  static Service provideServerSocketService(ServerSocketService impl) {
    return impl;
  }

  @Provides(type = Type.SET)
  static Service provideTrialOutputFactoryService(TrialOutputFactoryService impl) {
    return impl;
  }

  @Provides
  static TrialOutputFactory provideTrialOutputFactory(TrialOutputFactoryService impl) {
    return impl;
  }

  @Provides
  static ExperimentSelector provideExperimentSelector(FullCartesianExperimentSelector impl) {
    return impl;
  }

  @Provides
  static ListeningExecutorService provideExecutorService(CaliperConfig config) {
    int poolSize = Integer.parseInt(config.properties().get(RUNNER_MAX_PARALLELISM_OPTION));
    return MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(poolSize));
  }

  @LocalPort
  @Provides
  static int providePortNumber(ServerSocketService serverSocketService) {
    return serverSocketService.getPort();
  }

  /**
   * Specifies the {@link Class} object to use as a key in the map of available
   * {@link ResultProcessor result processors} passed to
   * {@link #provideResultProcessors(CaliperConfig, Map)}.
   */
  @MapKey(unwrapValue = true)
  public @interface ResultProcessorClassKey {
    Class<? extends ResultProcessor> value();
  }

  @Provides(type = Type.MAP)
  @ResultProcessorClassKey(OutputFileDumper.class)
  static ResultProcessor provideOutputFileDumper(OutputFileDumper impl) {
    return impl;
  }

  @Provides(type = Type.MAP)
  @ResultProcessorClassKey(HttpUploader.class)
  static ResultProcessor provideHttpUploader(HttpUploader impl) {
    return impl;
  }

  @Provides static ImmutableSet<ResultProcessor> provideResultProcessors(
      CaliperConfig config,
      Map<Class<? extends ResultProcessor>, Provider<ResultProcessor>> availableProcessors) {
    ImmutableSet.Builder<ResultProcessor> builder = ImmutableSet.builder();
    for (Class<? extends ResultProcessor> processorClass : config.getConfiguredResultProcessors()) {
      Provider<ResultProcessor> resultProcessorProvider = availableProcessors.get(processorClass);
      ResultProcessor resultProcessor = resultProcessorProvider == null
          ? ResultProcessorCreator.createResultProcessor(processorClass)
          : resultProcessorProvider.get();
      builder.add(resultProcessor);
    }
    return builder.build();
  }

  @Provides static UUID provideUuid() {
    return UUID.randomUUID();
  }

  @Provides @BenchmarkParameters
  static ImmutableSetMultimap<String, String> provideBenchmarkParameters(
      BenchmarkClass benchmarkClass, CaliperOptions options) throws InvalidBenchmarkException {
    return benchmarkClass.userParameters().fillInDefaultsFor(options.userParameters());
  }

  @Provides @Singleton
  static Host provideHost(EnvironmentGetter environmentGetter) {
    return environmentGetter.getHost();
  }

  @Provides @Singleton
  static EnvironmentGetter provideEnvironmentGetter() {
    return new EnvironmentGetter();
  }

  /**
   * Specifies the {@link Class} object to use as a key in the map of available
   * {@link Instrument instruments} passed to {@link #provideInstruments},
   */
  @MapKey(unwrapValue = true)
  public @interface InstrumentClassKey {
    Class<? extends Instrument> value();
  }

  @Provides(type = Type.MAP)
  @InstrumentClassKey(ArbitraryMeasurementInstrument.class)
  static Instrument provideArbitraryMeasurementInstrument() {
    return new ArbitraryMeasurementInstrument();
  }

  @Provides(type = Type.MAP)
  @InstrumentClassKey(AllocationInstrument.class)
  static Instrument provideAllocationInstrument() {
    return new AllocationInstrument();
  }

  @Provides(type = Type.MAP)
  @InstrumentClassKey(RuntimeInstrument.class)
  static Instrument provideRuntimeInstrument(
      @NanoTimeGranularity ShortDuration nanoTimeGranularity) {
    return new RuntimeInstrument(nanoTimeGranularity);
  }

  @Provides
  static ImmutableSet<Instrument> provideInstruments(
      CaliperOptions options,
      final CaliperConfig config,
      Map<Class<? extends Instrument>, Provider<Instrument>> availableInstruments,
      Platform platform,
      @Stderr PrintWriter stderr)
      throws InvalidCommandException {

    ImmutableSet.Builder<Instrument> builder = ImmutableSet.builder();
    ImmutableSet<String> configuredInstruments = config.getConfiguredInstruments();
    for (final String instrumentName : options.instrumentNames()) {
      if (!configuredInstruments.contains(instrumentName)) {
        throw new InvalidCommandException("%s is not a configured instrument (%s). "
            + "use --print-config to see the configured instruments.",
            instrumentName, configuredInstruments);
      }
      final InstrumentConfig instrumentConfig = config.getInstrumentConfig(instrumentName);
      String className = instrumentConfig.className();
      try {
        Class<? extends Instrument> clazz =
            Util.lenientClassForName(className).asSubclass(Instrument.class);
        Provider<Instrument> instrumentProvider = availableInstruments.get(clazz);
        if (instrumentProvider == null) {
          throw new InvalidInstrumentException("Instrument %s not supported", className);
        }

        // Make sure that the instrument is supported on the platform.
        if (platform.supports(clazz)) {
          Instrument instrument = instrumentProvider.get();
          InstrumentInjectorModule injectorModule =
              new InstrumentInjectorModule(instrumentConfig, instrumentName);
          InstrumentComponent instrumentComponent = DaggerInstrumentComponent.builder()
              .instrumentInjectorModule(injectorModule)
              .build();
          instrumentComponent.injectInstrument(instrument);
          builder.add(instrument);
        } else {
          stderr.format("Instrument %s not supported on %s, ignoring\n",
              className, platform.name());
        }
      } catch (ClassNotFoundException e) {
        throw new InvalidCommandException("Cannot find instrument class '%s'", className);
      }
    }
    return builder.build();
  }

  @Provides @Singleton static NanoTimeGranularityTester provideNanoTimeGranularityTester() {
    return new NanoTimeGranularityTester();
  }

  @Provides @Singleton @NanoTimeGranularity static ShortDuration provideNanoTimeGranularity(
      NanoTimeGranularityTester tester) {
    return tester.testNanoTimeGranularity();
  }

  @Provides static ImmutableSet<Instrumentation> provideInstrumentations(CaliperOptions options,
      BenchmarkClass benchmarkClass, ImmutableSet<Instrument> instruments)
          throws InvalidBenchmarkException {
    ImmutableSet.Builder<Instrumentation> builder = ImmutableSet.builder();
    ImmutableSet<String> benchmarkMethodNames = options.benchmarkMethodNames();
    Set<String> unusedBenchmarkNames = new HashSet<String>(benchmarkMethodNames);
    for (Instrument instrument : instruments) {
      for (Method method : findAllBenchmarkMethods(benchmarkClass.benchmarkClass(), instrument)) {
        if (benchmarkMethodNames.isEmpty() || benchmarkMethodNames.contains(method.getName())) {
          builder.add(instrument.createInstrumentation(method));
          unusedBenchmarkNames.remove(method.getName());
        }
      }
    }
    if (!unusedBenchmarkNames.isEmpty()) {
      throw new InvalidBenchmarkException(
          "Invalid benchmark method(s) specified in options: " + unusedBenchmarkNames);
    }
    return builder.build();
  }

  private static ImmutableSortedSet<Method> findAllBenchmarkMethods(Class<?> benchmarkClass,
      Instrument instrument) throws InvalidBenchmarkException {
    ImmutableSortedSet.Builder<Method> result = ImmutableSortedSet.orderedBy(
        Ordering.natural().onResultOf(new Function<Method, String>() {
          @Override public String apply(Method method) {
            return method.getName();
          }
        }));
    Set<String> benchmarkMethodNames = new HashSet<String>();
    Set<String> overloadedMethodNames = new TreeSet<String>();
    for (Method method : benchmarkClass.getDeclaredMethods()) {
      if (instrument.isBenchmarkMethod(method)) {
        method.setAccessible(true);
        result.add(method);
        if (!benchmarkMethodNames.add(method.getName())) {
          overloadedMethodNames.add(method.getName());
        }
      }
    }
    if (!overloadedMethodNames.isEmpty()) {
      throw new InvalidBenchmarkException(
          "Overloads are disallowed for benchmark methods, found overloads of %s in benchmark %s",
          overloadedMethodNames,
          benchmarkClass);
    }
    return result.build();
  }
}
