// Copyright 2019 The Bazel Authors. All rights reserved.
//
// 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.devtools.build.lib.skyframe;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.actions.FileValue;
import com.google.devtools.build.lib.actions.MissingInputFileException;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
import com.google.devtools.build.lib.server.FailureDetails.BuildConfiguration;
import com.google.devtools.build.lib.server.FailureDetails.BuildConfiguration.Code;
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.syntax.Location;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.lib.vfs.Root;
import com.google.devtools.build.lib.vfs.RootedPath;
import com.google.devtools.build.skyframe.SkyFunction;
import com.google.devtools.build.skyframe.SkyFunctionException;
import com.google.devtools.build.skyframe.SkyKey;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;
import javax.annotation.Nullable;

/**
 * Function that reads the contents of a mapping file specified in {@code --platform_mappings} and
 * parses them for use in a {@link PlatformMappingValue}.
 *
 * <p>Note that this class only parses the mapping-file specific format, parsing (and validation) of
 * flags contained therein is left to the invocation of {@link
 * PlatformMappingValue#map(BuildConfigurationValue.Key, BuildOptions)}.
 */
public class PlatformMappingFunction implements SkyFunction {

  @Nullable
  @Override
  public PlatformMappingValue compute(SkyKey skyKey, Environment env)
      throws PlatformMappingException, InterruptedException {
    PlatformMappingValue.Key platformMappingKey = (PlatformMappingValue.Key) skyKey.argument();
    PathFragment workspaceRelativeMappingPath =
        platformMappingKey.getWorkspaceRelativeMappingPath();

    PathPackageLocator pkgLocator = PrecomputedValue.PATH_PACKAGE_LOCATOR.get(env);
    if (pkgLocator == null) {
      return null;
    }

    ImmutableList<Root> pathEntries = pkgLocator.getPathEntries();
    for (Root root : pathEntries) {
      RootedPath rootedMappingPath = RootedPath.toRootedPath(root, workspaceRelativeMappingPath);
      FileValue fileValue = (FileValue) env.getValue(FileValue.key(rootedMappingPath));
      if (fileValue == null) {
        return null;
      }

      if (!fileValue.exists()) {
        continue;
      }
      if (fileValue.isDirectory()) {
        throw new PlatformMappingException(
            new MissingInputFileException(
                createFailureDetail(
                    String.format(
                        "--platform_mappings was set to '%s' relative to the top-level workspace"
                            + " '%s' but that path refers to a directory, not a file",
                        workspaceRelativeMappingPath, root),
                    Code.PLATFORM_MAPPINGS_FILE_IS_DIRECTORY),
                Location.BUILTIN),
            SkyFunctionException.Transience.PERSISTENT);
      }

      Iterable<String> lines;
      try {
        lines =
            FileSystemUtils.readLines(fileValue.realRootedPath().asPath(), StandardCharsets.UTF_8);
      } catch (IOException e) {
        throw new PlatformMappingException(e, SkyFunctionException.Transience.TRANSIENT);
      }

      return new Parser(lines.iterator()).parse().toPlatformMappingValue();
    }

    if (!platformMappingKey.wasExplicitlySetByUser()) {
      // If no flag was passed and the default mapping file does not exist treat this as if the
      // mapping file was empty rather than an error.
      return PlatformMappingValue.EMPTY;
    }
    throw new PlatformMappingException(
        new MissingInputFileException(
            createFailureDetail(
                String.format(
                    "--platform_mappings was set to '%s' but no such file exists relative to the "
                        + "package path roots, '%s'",
                    workspaceRelativeMappingPath, pathEntries),
                Code.PLATFORM_MAPPINGS_FILE_NOT_FOUND),
            Location.BUILTIN),
        SkyFunctionException.Transience.PERSISTENT);
  }

  private static FailureDetail createFailureDetail(String message, Code detailedCode) {
    return FailureDetail.newBuilder()
        .setMessage(message)
        .setBuildConfiguration(BuildConfiguration.newBuilder().setCode(detailedCode))
        .build();
  }

  @Nullable
  @Override
  public String extractTag(SkyKey skyKey) {
    return null;
  }

  @VisibleForTesting
  static class PlatformMappingException extends SkyFunctionException {

    public PlatformMappingException(Exception cause, Transience transience) {
      super(cause, transience);
    }
  }

  @VisibleForTesting
  static class Parser {

    private final Iterator<String> lines;

    /**
     * Using an optional to represent the next line with contents, {@link Optional#empty()} if we
     * reached end of file.
     *
     * <p>Stores the current non-comment, non-empty, non-whitespace line. Don't access the field
     * directly, it can either be "used up" by calling {@link #consume()} or retrieved without
     * moving on by calling {@link #peek()}.
     */
    private Optional<String> line;

    Parser(Iterator<String> lines) {
      this.lines = lines;
    }

    Mappings parse() throws PlatformMappingException {
      goToNextContentLine();

      if (!line.isPresent()) {
        return new Mappings(ImmutableMap.of(), ImmutableMap.of());
      }

      Map<Label, Collection<String>> platformsToFlags = ImmutableMap.of();
      Map<Collection<String>, Label> flagsToPlatforms = ImmutableMap.of();

      if (!peek().equalsIgnoreCase("platforms:") && !peek().equalsIgnoreCase("flags:")) {
        throwParsingException("Expected 'platforms:' or 'flags:' but got " + peek());
      }

      if (peek().equalsIgnoreCase("platforms:")) {
        consume();
        platformsToFlags = platformsToFlags();
      }

      if (line.isPresent()) {
        if (!peek().equalsIgnoreCase("flags:")) {
          throwParsingException("Expected 'flags:' but got " + peek());
        }
        consume();
        flagsToPlatforms = flagsToPlatforms();
      }

      if (line.isPresent()) {
        throwParsingException("Expected end of file but got " + peek());
      }
      return new Mappings(platformsToFlags, flagsToPlatforms);
    }

    private Map<Label, Collection<String>> platformsToFlags() throws PlatformMappingException {
      ImmutableMap.Builder<Label, Collection<String>> platformsToFlags = ImmutableMap.builder();
      while (line.isPresent() && !peek().equalsIgnoreCase("flags:")) {
        Label platform = platform();
        Collection<String> flags = flags();
        platformsToFlags.put(platform, flags);
      }

      try {
        return platformsToFlags.build();
      } catch (IllegalArgumentException e) {
        throw throwParsingException(
            e, "Got duplicate platform entries but each platform key must be unique");
      }
    }

    private Label platform() throws PlatformMappingException {
      if (!line.isPresent()) {
        throwParsingException("Expected platform label but got end of file");
      }
      String label = consume();

      Label platform;
      try {
        ImmutableMap<RepositoryName, RepositoryName> emptyRepositoryMapping = ImmutableMap.of();
        // It is ok for us to use an empty repository mapping in this instance because all platform
        // labels used in the mapping file should be relative to the root repository. Repository
        // mappings however only apply within a repository imported by the root repository.
        platform = Label.parseAbsolute(label, emptyRepositoryMapping);
      } catch (LabelSyntaxException e) {
        throw throwParsingException(e, "Expected platform label but got " + label);
      }
      return platform;
    }

    private Collection<String> flags() throws PlatformMappingException {
      ImmutableSet.Builder<String> flags = ImmutableSet.builder();
      // Note: Short form flags are not supported.
      while (lineIsFlag()) {
        flags.add(consume());
      }
      ImmutableSet<String> parsedFlags = flags.build();
      if (parsedFlags.isEmpty()) {
        if (!line.isPresent()) {
          throwParsingException("Expected a flag but got end of file");
        }
        throwParsingException(
            "Expected a standard format flag (starting with --) but got " + peek());
      }

      return parsedFlags;
    }

    private Map<Collection<String>, Label> flagsToPlatforms() throws PlatformMappingException {
      ImmutableMap.Builder<Collection<String>, Label> flagsToPlatforms = ImmutableMap.builder();
      while (lineIsFlag()) {
        Collection<String> flags = flags();
        Label platform = platform();
        flagsToPlatforms.put(flags, platform);
      }
      try {
        return flagsToPlatforms.build();
      } catch (IllegalArgumentException e) {
        throw throwParsingException(
            e, "Got duplicate flags entries but each flags key must be unique");
      }
    }

    private String consume() {
      Preconditions.checkState(
          line.isPresent(), "Must make sure that a line exists before consuming.");
      String value = line.get();
      goToNextContentLine();
      return value;
    }

    private String peek() {
      Preconditions.checkState(
          line.isPresent(), "Must make sure that a line exists before peeking.");
      return line.get();
    }

    private AssertionError throwParsingException(Exception e, String message)
        throws PlatformMappingException {
      throw new PlatformMappingException(
          new PlatformMappingParsingException(message, e),
          SkyFunctionException.Transience.PERSISTENT);
    }

    private void throwParsingException(String message) throws PlatformMappingException {
      throw new PlatformMappingException(
          new PlatformMappingParsingException(message), SkyFunctionException.Transience.PERSISTENT);
    }

    private boolean lineIsFlag() {
      return line.isPresent() && peek().startsWith("--");
    }

    private void goToNextContentLine() {
      while (lines.hasNext()) {
        String line = lines.next().trim();
        if (line.isEmpty() || line.startsWith("#")) {
          continue;
        }
        this.line = Optional.of(line);
        return;
      }
      line = Optional.empty();
    }
  }

  /**
   * Simple data holder to make testing easier. Only for use internal to this file/tests thereof.
   */
  @VisibleForTesting
  static class Mappings {
    final Map<Label, Collection<String>> platformsToFlags;
    final Map<Collection<String>, Label> flagsToPlatforms;

    Mappings(
        Map<Label, Collection<String>> platformsToFlags,
        Map<Collection<String>, Label> flagsToPlatforms) {
      this.platformsToFlags = platformsToFlags;
      this.flagsToPlatforms = flagsToPlatforms;
    }

    PlatformMappingValue toPlatformMappingValue() {
      return new PlatformMappingValue(platformsToFlags, flagsToPlatforms);
    }
  }

  /**
   * Inner wrapper exception to work around the fact that {@link SkyFunctionException} cannot carry
   * a message of its own.
   */
  private static class PlatformMappingParsingException extends Exception {
    public PlatformMappingParsingException(String message) {
      super(message);
    }

    public PlatformMappingParsingException(String message, Throwable cause) {
      super(message, cause);
    }
  }
}
