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;
  }
}