package org.extendj;
import org.extendj.ast.*;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class ScopeAnalysis extends Frontend {
  public ScopeAnalysis() {
    super("Java Scope Anaysis", ExtendJVersion.getVersion());
  }
  /**
   * Entry point for the Java checker.
   *
   * @param args command-line arguments
   */
  public static void main(String[] args) {
    if (args.length != 1) {
      System.out.println("usage: SccChecker <directory with java files>");
      System.exit(-1);
    }
    try {
      List<String> files = Files.walk(Paths.get(args[2]))
          .filter(Files::isRegularFile)
          .filter(x -> x.getFileName().toString().endsWith(".java")).map(Path::toString).collect(Collectors.toList());
      // measure the time (with parsing) from here
      long startMeasurementTime = System.nanoTime();
      Program program = new ScopeAnalysis().readProgram(files);
      // measure the time (without parsing) from here
      long startGenerationTime = System.nanoTime();
      ScopeTree scopeTree = program.scopeTree();
      long startAnalysisTime = System.nanoTime();
      Set<VariableShadowFinding> findings = scopeTree.variableShadowings();
      // measure the time until here
      long endTime = System.nanoTime();
      System.out.print("java,var,false,"
          + files.size() + ","
          + scopeTree.numScopes() + ","
          + scopeTree.numDeclarations() + ","
          + (scopeTree.numScopes() + scopeTree.numDeclarations()) + ","
          + findings.size() + ",");
      long parseTime = startGenerationTime - startMeasurementTime;
      long generationTime = startAnalysisTime - startGenerationTime;
      long analysisTime = endTime - startAnalysisTime;
      long fullTime = endTime - startMeasurementTime;
      System.out.print((fullTime / 1000000) + ",");
      System.out.print((parseTime / 1000000) + ",");
      System.out.print((generationTime / 1000000) + ",");
      System.out.print((analysisTime / 1000000) + ",");
      System.out.print(((generationTime + analysisTime) / 1000000) + ",");
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }
  private Program readProgram(Collection<String> files) throws IOException {
    Program program = new Program();
    program.resetStatistics();
    program.initBytecodeReader(Program.defaultBytecodeReader());
    program.initJavaParser(Program.defaultJavaParser());
    initOptions();
    for (String file : files) {
      program.addSourceFile(file);
    }
    TypeDecl object = program.lookupType("java.lang", "Object");
    if (object.isUnknown()) {
      // If we try to continue without java.lang.Object, we'll just get a stack overflow
      // in member lookups because the unknown (Object) type would be treated as circular.
      System.err.println("Error: java.lang.Object is missing."
          + " The Java standard library was not found.");
      throw new RuntimeException("exiting with unhandled error!");
    }
    return program;
  }
}