/*
 * Copyright 2012-present Facebook, 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.facebook.buck.java;

import com.facebook.buck.event.MissingSymbolEvent;
import com.facebook.buck.log.Logger;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.rules.RuleKey;
import com.facebook.buck.step.ExecutionContext;
import com.facebook.buck.util.ClassLoaderCache;
import com.facebook.buck.util.HumanReadableException;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import javax.annotation.Nullable;
import javax.annotation.processing.Processor;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

/**
 * Command used to compile java libraries with a variety of ways to handle dependencies.
 * <p>
 * If {@code buildDependencies} is set to
 * {@link com.facebook.buck.rules.BuildDependencies#FIRST_ORDER_ONLY}, this class will invoke javac
 * using {@code declaredClasspathEntries} for the classpath. If {@code buildDependencies} is set to
 * {@link com.facebook.buck.rules.BuildDependencies#TRANSITIVE}, this class will invoke javac using
 * {@code transitiveClasspathEntries} for the classpath. If {@code buildDependencies} is set to
 * {@link com.facebook.buck.rules.BuildDependencies#WARN_ON_TRANSITIVE}, this class will first
 * compile using {@code declaredClasspathEntries}, and should that fail fall back to
 * {@code transitiveClasspathEntries} but warn the developer about which dependencies were in
 * the transitive classpath but not in the declared classpath.
 */
public class Jsr199Javac implements Javac {

  private static final Logger LOG = Logger.get(Jsr199Javac.class);
  private static final JavacVersion VERSION = new JavacVersion() {
    @Override
    public String getVersionString() {
      return "in memory";
    }
  };

  @Override
  public JavacVersion getVersion() {
    return VERSION;
  }

  private Optional<Path> javacJar;

  /**
   * @param javacJar If absent, use the system compiler.  Otherwise, load the compiler from this
   *                 path.
   */
  Jsr199Javac(Optional<Path> javacJar) {
    // XXX: maybe we can accept a Provider<JavaCompiler> or just a JavaCompiler instance.
    this.javacJar = javacJar;
  }

  @VisibleForTesting
  public Optional<Path> getJavacJar() {
    return javacJar;
  }

  @Override
  public String getDescription(
      ExecutionContext context,
      ImmutableList<String> options,
      ImmutableSet<Path> javaSourceFilePaths,
      Optional<Path> pathToSrcsList) {
    StringBuilder builder = new StringBuilder("javac ");
    Joiner.on(" ").appendTo(builder, options);
    builder.append(" ");

    if (pathToSrcsList.isPresent()) {
      builder.append("@").append(pathToSrcsList.get());
    } else {
      Joiner.on(" ").appendTo(builder, javaSourceFilePaths);
    }

    return builder.toString();
  }

  @Override
  public String getShortName() {
    return "javac";
  }

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

  @Override
  public RuleKey.Builder appendToRuleKey(RuleKey.Builder builder, String key) {
    return builder.setReflectively(key + ".javac", "jsr199")
        .setReflectively(key + ".javac.version", "in-memory")
        .setReflectively(key + ".javacjar", javacJar);
  }

  @Override
  public int buildWithClasspath(
      ExecutionContext context,
      BuildTarget invokingRule,
      ImmutableList<String> options,
      ImmutableSet<Path> javaSourceFilePaths,
      Optional<Path> pathToSrcsList,
      Optional<Path> workingDirectory) {
    JavaCompiler compiler;

    if (javacJar.isPresent()) {
      ClassLoaderCache classLoaderCache = context.getClassLoaderCache();
      ClassLoader compilerClassLoader = classLoaderCache.getClassLoaderForClassPath(
          ClassLoader.getSystemClassLoader(),
          ImmutableList.of(javacJar.get()));
      try {
        compiler = (JavaCompiler)
            compilerClassLoader.loadClass("com.sun.tools.javac.api.JavacTool")
            .newInstance();
      } catch (ClassNotFoundException | IllegalAccessException | InstantiationException ex) {
        throw new RuntimeException(ex);
      }
    } else {
      synchronized (ToolProvider.class) {
        // ToolProvider has no synchronization internally, so if we don't synchronize from the
        // outside we could wind up loading the compiler classes multiple times from different
        // class loaders.
        compiler = ToolProvider.getSystemJavaCompiler();
      }

      if (compiler == null) {
        throw new HumanReadableException(
            "No system compiler found. Did you install the JRE instead of the JDK?");
      }
    }

    StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
    Iterable<? extends JavaFileObject> compilationUnits = ImmutableSet.of();
    try {
      compilationUnits = createCompilationUnits(
          fileManager,
          context.getProjectFilesystem().getAbsolutifier(),
          javaSourceFilePaths);
    } catch (IOException e) {
      close(fileManager, compilationUnits);
      e.printStackTrace(context.getStdErr());
      return 1;
    }

    if (pathToSrcsList.isPresent()) {
      // write javaSourceFilePaths to classes file
      // for buck user to have a list of all .java files to be compiled
      // since we do not print them out to console in case of error
      try {
        context.getProjectFilesystem().writeLinesToPath(
            FluentIterable.from(javaSourceFilePaths)
                .transform(Functions.toStringFunction())
                .transform(ARGFILES_ESCAPER),
            pathToSrcsList.get());
      } catch (IOException e) {
        close(fileManager, compilationUnits);
        context.logError(
            e,
            "Cannot write list of .java files to compile to %s file! Terminating compilation.",
            pathToSrcsList.get());
        return 1;
      }
    }

    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
    List<String> classNamesForAnnotationProcessing = ImmutableList.of();
    Writer compilerOutputWriter = new PrintWriter(context.getStdErr());
    JavaCompiler.CompilationTask compilationTask = compiler.getTask(
        compilerOutputWriter,
        fileManager,
        diagnostics,
        options,
        classNamesForAnnotationProcessing,
        compilationUnits);

    // Ensure annotation processors are loaded from their own classloader. If we don't do this,
    // then the evidence suggests that they get one polluted with Buck's own classpath, which
    // means that libraries that have dependencies on different versions of Buck's deps may choke
    // with novel errors that don't occur on the command line.
    ProcessorBundle bundle = null;
    boolean isSuccess;

    try {
      bundle = prepareProcessors(
          compiler.getClass().getClassLoader(),
          invokingRule,
          options);
      compilationTask.setProcessors(bundle.processors);

      // Invoke the compilation and inspect the result.
      isSuccess = compilationTask.call();
    } finally {
      close(fileManager, compilationUnits);
    }

    if (isSuccess) {
      return 0;
    } else {
      if (context.getVerbosity().shouldPrintStandardInformation()) {
        int numErrors = 0;
        int numWarnings = 0;
        for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
          Diagnostic.Kind kind = diagnostic.getKind();
          if (kind == Diagnostic.Kind.ERROR) {
            ++numErrors;
            handleMissingSymbolError(invokingRule, diagnostic, context);
          } else if (kind == Diagnostic.Kind.WARNING ||
              kind == Diagnostic.Kind.MANDATORY_WARNING) {
            ++numWarnings;
          }

          context.getStdErr().println(diagnostic);
        }

        if (numErrors > 0 || numWarnings > 0) {
          context.getStdErr().printf("Errors: %d. Warnings: %d.\n", numErrors, numWarnings);
        }
      }
      return 1;
    }
  }

  private void close(
      JavaFileManager fileManager,
      Iterable<? extends JavaFileObject> compilationUnits) {
    try {
      fileManager.close();
    } catch (IOException e) {
      LOG.warn(e, "Unable to close java filemanager. We may be leaking memory.");
    }

    for (JavaFileObject unit : compilationUnits) {
      if (!(unit instanceof ZipEntryJavaFileObject)) {
        continue;
      }
      try {
        ((ZipEntryJavaFileObject) unit).close();
      } catch (IOException e) {
        LOG.warn(e, "Unable to close zipfile. We may be leaking memory.");
      }
    }
  }

  private ProcessorBundle prepareProcessors(
      ClassLoader compilerClassLoader,
      @Nullable BuildTarget target,
      List<String> options) {
    String processorClassPath = null;
    String processorNames = null;

    Iterator<String> iterator = options.iterator();
    while (iterator.hasNext()) {
      String curr = iterator.next();
      if ("-processorpath".equals(curr) && iterator.hasNext()) {
        processorClassPath = iterator.next();
      } else if ("-processor".equals(curr) && iterator.hasNext()) {
        processorNames = iterator.next();
      }
    }

    ProcessorBundle processorBundle = new ProcessorBundle();
    if (processorClassPath == null || processorNames == null) {
      return processorBundle;
    }

    // N.B. You might think that we could avoid some overhead by using the same classloader every
    // time we create an instance of annotation processor.  In an ideal world, that would work well,
    // but many annotation processors aren't thread-safe, and they store state in class-static
    // variables.  In the interest of maximum safety, we'll create a new ClassLoader every time we
    // need an annotation processor.

    Iterable<String> rawPaths = Splitter.on(File.pathSeparator)
        .omitEmptyStrings()
        .split(processorClassPath);
    URL[] urls = FluentIterable.from(rawPaths)
        .transform(
            new Function<String, URL>() {
              @Override
              public URL apply(String pathRelativeToProjectRoot) {
                try {
                  return Paths.get(pathRelativeToProjectRoot).toUri().toURL();
                } catch (MalformedURLException e) {
                  // The paths we're being given should have all been resolved from the file
                  // system already. We'd need to be unfortunate to get here. Bubble up a runtime
                  // exception.
                  throw new RuntimeException(e);
                }
              }
            })
        .toArray(URL.class);
    processorBundle.classLoader = new URLClassLoader(
        urls,
        compilerClassLoader);

    Iterable<String> names = Splitter.on(",")
        .trimResults()
        .omitEmptyStrings()
        .split(processorNames);
    for (String name : names) {
      try {
        LOG.debug("Loading %s from own classloader", name);

        Class<? extends Processor> aClass =
            Preconditions.checkNotNull(processorBundle.classLoader)
                .loadClass(name)
                .asSubclass(Processor.class);
        processorBundle.processors.add(aClass.newInstance());
      } catch (ReflectiveOperationException e) {
        // If this happens, then the build is really in trouble. Better warn the user.
        throw new HumanReadableException(
            "%s: javac unable to load annotation processor: %s",
            target != null ? target.getFullyQualifiedName() : "unknown target",
            name);
      }
    }

    return processorBundle;
  }

  private Iterable<? extends JavaFileObject> createCompilationUnits(
      StandardJavaFileManager fileManager,
      Function<Path, Path> absolutifier,
      Set<Path> javaSourceFilePaths) throws IOException {
    List<JavaFileObject> compilationUnits = Lists.newArrayList();
    for (Path path : javaSourceFilePaths) {
      if (path.toString().endsWith(".java")) {
        // For an ordinary .java file, create a corresponding JavaFileObject.
        Iterable<? extends JavaFileObject> javaFileObjects = fileManager.getJavaFileObjects(
            absolutifier.apply(path).toFile());
        compilationUnits.add(Iterables.getOnlyElement(javaFileObjects));
      } else if (path.toString().endsWith(SRC_ZIP)) {
        // For a Zip of .java files, create a JavaFileObject for each .java entry.
        ZipFile zipFile = new ZipFile(absolutifier.apply(path).toFile());
        for (Enumeration<? extends ZipEntry> entries = zipFile.entries();
             entries.hasMoreElements();
            ) {
          ZipEntry entry = entries.nextElement();
          if (!entry.getName().endsWith(".java")) {
            continue;
          }

          compilationUnits.add(new ZipEntryJavaFileObject(zipFile, entry));
        }
      }
    }
    return compilationUnits;
  }

  private void handleMissingSymbolError(
      BuildTarget invokingRule,
      Diagnostic<? extends JavaFileObject> diagnostic,
      ExecutionContext context) {
    JavacErrorParser javacErrorParser = new JavacErrorParser(
        context.getProjectFilesystem(),
        context.getJavaPackageFinder());
    Optional<String> symbol =
        javacErrorParser.getMissingSymbolFromCompilerError(diagnostic.toString());
    if (!symbol.isPresent()) {
      // This error wasn't related to a missing symbol, as far as we can tell.
      return;
    }
    MissingSymbolEvent event = MissingSymbolEvent.create(
        invokingRule,
        symbol.get(),
        MissingSymbolEvent.SymbolType.Java);
    context.getBuckEventBus().post(event);
  }

  private static class ProcessorBundle {
    @Nullable
    public ClassLoader classLoader;
    public List<Processor> processors = Lists.newArrayList();
  }
}
