class MainClassFinder {

  public static Result find(List<Path> files, Consumer<LogEvent> logger) {
    List<String> mainClasses = new ArrayList<>();
    for (Path file : files) {
      // Makes sure classFile is valid.
      if (!Files.exists(file)) {
        logger.accept(LogEvent.debug("MainClassFinder: " + file + " does not exist; ignoring"));
        continue;
      }
      if (!Files.isRegularFile(file)) {
        logger.accept(
            LogEvent.debug("MainClassFinder: " + file + " is not a regular file; skipping"));
        continue;
      }
      if (!file.toString().endsWith(".class")) {
        logger.accept(
            LogEvent.debug("MainClassFinder: " + file + " is not a class file; skipping"));
        continue;
      }

      MainClassVisitor mainClassVisitor = new MainClassVisitor();
      try (InputStream classFileInputStream = Files.newInputStream(file)) {
        ClassReader reader = new ClassReader(classFileInputStream);
        reader.accept(mainClassVisitor, 0);
        if (mainClassVisitor.visitedMainClass) {
          mainClasses.add(reader.getClassName().replace('/', '.'));
        }

      } catch (ArrayIndexOutOfBoundsException ignored) {
        // Not a valid class file (thrown by ClassReader if it reads an invalid format)
        logger.accept(LogEvent.warn("Invalid class file found: " + file));

      } catch (IOException ignored) {
        // Could not read class file.
        logger.accept(LogEvent.warn("Could not read file: " + file));
      }
    }

    if (mainClasses.size() == 1) {
      // Valid class found.
      return Result.success(mainClasses.get(0));
    }
    if (mainClasses.size() == 0) {
      // No main class found anywhere.
      return Result.mainClassNotFound();
    }
    // More than one main class found.
    return Result.multipleMainClasses(mainClasses);
  }

}