// Copyright 2016 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.windows.util;

import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.fail;

import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.devtools.build.lib.vfs.FileSystem;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.windows.jni.WindowsFileOperations;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/** Utilities for running Java tests on Windows. */
public final class WindowsTestUtil {

  /** A path where temp files can be created. It is NOT owned by this class. */
  private final String scratchRoot;

  public WindowsTestUtil(String scratchRoot) {
    this.scratchRoot = scratchRoot;
  }

  /**
   * Create directory junctions then assert their existence.
   *
   * <p>Each key in the map is a junction path, relative to {@link #scratchRoot}. These are the link
   * names.
   *
   * <p>Each value in the map is a directory or junction path, also relative to {@link
   * #scratchRoot}. These are the link targets.
   */
  public void createJunctions(Map<String, String> links) throws Exception {
    for (Map.Entry<String, String> e : links.entrySet()) {
      WindowsFileOperations.createJunction(
          scratchRoot + "/" + e.getKey(), scratchRoot + "/" + e.getValue());
    }

    for (Map.Entry<String, String> e : links.entrySet()) {
      assertWithMessage(
              String.format("Could not create junction '%s' -> '%s'", e.getKey(), e.getValue()))
          .that(new File(scratchRoot, e.getKey()).exists())
          .isTrue();
    }
  }

  /**
   * Create symbolic links.
   *
   * <p>Each key in the map is a symlink path relative to {@link #scratchRoot}. These are the link
   * names.
   *
   * <p>Each value in the map is a file path relative to {@link #scratchRoot}. These are the link
   * targets.
   */
  public void createSymlinks(Map<String, String> links) throws Exception {
    for (Map.Entry<String, String> entry : links.entrySet()) {
      WindowsFileOperations.createSymlink(
          scratchRoot + "/" + entry.getKey(), scratchRoot + "/" + entry.getValue());
    }
  }

  /** Delete everything under {@link #scratchRoot}/path. */
  public void deleteAllUnder(String path) throws IOException {
    if (Strings.isNullOrEmpty(path)) {
      path = scratchRoot;
    } else {
      path = scratchRoot + "\\" + path;
    }
    if (new File(path).exists()) {
      runCommand("cmd.exe /c rd /s /q \"" + path + "\"");
    }
  }

  /** Create a directory under `path`, relative to {@link #scratchRoot}. */
  public java.nio.file.Path scratchDir(String path) throws IOException {
    return Files.createDirectories(new File(scratchRoot, path).toPath());
  }

  /** Create a file with the given contents under `path`, relative to {@link #scratchRoot}. */
  public java.nio.file.Path scratchFile(String path, String... contents) throws IOException {
    File fd = new File(scratchRoot, path);
    Files.createDirectories(fd.toPath().getParent());
    try (FileWriter w = new FileWriter(fd)) {
      for (String line : contents) {
        w.write(line);
        w.write('\n');
      }
    }
    return fd.toPath();
  }

  /** Run a Command Prompt command. */
  public static void runCommand(List<String> args) throws IOException {
    runCommand(Joiner.on(' ').join(args));
  }

  /** Run a Command Prompt command. */
  public static void runCommand(String cmd) throws IOException {
    Process p = Runtime.getRuntime().exec(cmd);
    try {
      // Wait no more than 5 seconds to create all junctions.
      p.waitFor(5, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
      fail("Failed to execute command; cmd: " + cmd);
    }
    assertWithMessage("Command failed: " + cmd).that(p.exitValue()).isEqualTo(0);
  }

  public Path createVfsPath(FileSystem fs, String path) throws IOException {
    return fs.getPath(scratchRoot + "/" + path);
  }
}
