// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils;

import com.android.tools.r8.ByteDataView;
import com.google.common.io.Closer;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipFile;

public class FileUtils {

  public static final String AAR_EXTENSION = ".aar";
  public static final String APK_EXTENSION = ".apk";
  public static final String CLASS_EXTENSION = ".class";
  public static final String DEX_EXTENSION = ".dex";
  public static final String VDEX_EXTENSION = ".vdex";
  public static final String JAR_EXTENSION = ".jar";
  public static final String ZIP_EXTENSION = ".zip";
  public static final String JAVA_EXTENSION = ".java";
  public static final String KT_EXTENSION = ".kt";
  public static final String MODULE_INFO_CLASS = "module-info.class";
  public static final String MODULES_PREFIX = "/modules";
  public static final String GLOBAL_SYNTHETIC_EXTENSION = ".global";

  public static final boolean isAndroid =
      System.getProperty("java.vm.name").equalsIgnoreCase("Dalvik");

  public static boolean isDexFile(Path path) {
    String name = path.getFileName().toString().toLowerCase();
    return name.endsWith(DEX_EXTENSION);
  }

  public static boolean isVDexFile(Path path) {
    String name = path.getFileName().toString().toLowerCase();
    return name.endsWith(VDEX_EXTENSION);
  }

  public static boolean isClassFile(String path) {
    String name = path.toLowerCase();
    // Android does not support Java 9 module, thus skip module-info.
    if (name.equals(MODULE_INFO_CLASS)) {
      return false;
    }
    return name.endsWith(CLASS_EXTENSION);
  }

  public static boolean isClassFile(Path path) {
    return isClassFile(path.getFileName().toString());
  }

  public static boolean isJarFile(Path path) {
    String name = path.getFileName().toString().toLowerCase();
    return name.endsWith(JAR_EXTENSION);
  }

  public static boolean isZipFile(Path path) {
    String name = path.getFileName().toString().toLowerCase();
    return name.endsWith(ZIP_EXTENSION);
  }

  public static boolean isApkFile(Path path) {
    String name = path.getFileName().toString().toLowerCase();
    return name.endsWith(APK_EXTENSION);
  }

  public static boolean isAarFile(Path path) {
    String name = path.getFileName().toString().toLowerCase();
    return name.endsWith(AAR_EXTENSION);
  }

  public static boolean isJavaFile(Path path) {
    String name = path.getFileName().toString().toLowerCase();
    return name.endsWith(JAVA_EXTENSION);
  }

  public static boolean isArchive(Path path) {
    String name = path.getFileName().toString().toLowerCase();
    return name.endsWith(APK_EXTENSION)
        || name.endsWith(JAR_EXTENSION)
        || name.endsWith(ZIP_EXTENSION)
        || name.endsWith(AAR_EXTENSION);
  }

  public static String readTextFile(Path file, Charset charset) throws IOException {
    return new String(Files.readAllBytes(file), charset);
  }

  public static byte[] uncheckedReadAllBytes(Path file) {
    try {
      return Files.readAllBytes(file);
    } catch (IOException e) {
      throw new UncheckedIOException(e);
    }
  }

  public static List<String> readAllLines(Path file) throws IOException {
    return Files.readAllLines(file);
  }

  public static void writeTextFile(Path file, List<String> lines) throws IOException {
    Files.write(file, lines);
  }

  public static void writeTextFile(Path file, String... lines) throws IOException {
    Files.write(file, Arrays.asList(lines));
  }

  public static Path validateOutputFile(Path path, Reporter reporter) {
    if (path != null) {
      boolean isJarOrZip = isZipFile(path) || isJarFile(path);
      if (!isJarOrZip && !(Files.exists(path) && Files.isDirectory(path))) {
        reporter.error(new StringDiagnostic(
            "Invalid output: "
                + path
                + "\nOutput must be a .zip or .jar archive or an existing directory"));
      }
    }
    return path;
  }

  public static OutputStream openPath(
      Closer closer,
      Path file,
      OpenOption... openOptions)
      throws IOException {
    assert file != null;
    return openPathWithDefault(closer, file, null, openOptions);
  }

  public static OutputStream openPathWithDefault(
      Closer closer,
      Path file,
      OutputStream defaultOutput,
      OpenOption... openOptions)
      throws IOException {
    OutputStream mapOut;
    if (file == null) {
      assert defaultOutput != null;
      mapOut = defaultOutput;
    } else {
      mapOut = Files.newOutputStream(file, openOptions);
      closer.register(mapOut);
    }
    return mapOut;
  }

  public static boolean isClassesDexFile(Path file) {
    String name = file.getFileName().toString().toLowerCase();
    if (!name.startsWith("classes") || !name.endsWith(DEX_EXTENSION)) {
      return false;
    }
    String numeral = name.substring("classes".length(), name.length() - DEX_EXTENSION.length());
    if (numeral.isEmpty()) {
      return true;
    }
    char c0 = numeral.charAt(0);
    if (numeral.length() == 1) {
      return '2' <= c0 && c0 <= '9';
    }
    if (c0 < '1' || '9' < c0) {
      return false;
    }
    for (int i = 1; i < numeral.length(); i++) {
      char c = numeral.charAt(i);
      if (c < '0' || '9' < c) {
        return false;
      }
    }
    return true;
  }

  public static void writeToFile(Path output, OutputStream defValue, byte[] contents)
      throws IOException {
    writeToFile(output, defValue, ByteDataView.of(contents));
  }

  public static void writeToFile(Path output, OutputStream defValue, ByteDataView contents)
      throws IOException {
    try (Closer closer = Closer.create()) {
      OutputStream outputStream =
          openPathWithDefault(
              closer,
              output,
              defValue,
              StandardOpenOption.CREATE,
              StandardOpenOption.TRUNCATE_EXISTING,
              StandardOpenOption.WRITE);
      outputStream.write(contents.getBuffer(), contents.getOffset(), contents.getLength());
    }
  }

  public static String withNativeFileSeparators(String path) {
    char fileSeparator = File.separatorChar;
    if (fileSeparator == '/') {
      return path.replace('\\', '/');
    } else {
      assert fileSeparator == '\\';
      return path.replace('/', '\\');
    }
  }

  public static ZipFile createZipFile(File file, Charset charset) throws IOException {
    if (!isAndroid) {
      return new ZipFile(file, charset);
    }
    // On Android pre-26 we cannot use the constructor ZipFile(file, charset).
    // By default Android use UTF_8 as the charset, so we can use the default constructor.
    if (Charset.defaultCharset() == StandardCharsets.UTF_8) {
      return new ZipFile(file);
    }
    // If the Android runtime is started with a different default charset, the default constructor
    // won't work. It is possible to support this case if we read/write the ZipFile not with it's
    // own Input/OutputStream, but an external one which one can define on a different Charset than
    // default. We do not support this at the moment since R8 on dex is used only in tests, and
    // UTF_8 is the default charset used in tests.
    throw new RuntimeException(
        "R8 can run on dex only with UTF_8 as the default charset, but the charset used is "
            + Charset.defaultCharset());
  }
}
