/*
 * Copyright 2016 HuntBugs contributors
 * 
 * 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 one.util.huntbugs.maven.plugin;

import one.util.huntbugs.analysis.AnalysisOptions;
import one.util.huntbugs.analysis.Context;
import one.util.huntbugs.output.Reports;
import one.util.huntbugs.repo.AuxRepository;
import one.util.huntbugs.repo.CompositeRepository;
import one.util.huntbugs.repo.DirRepository;
import one.util.huntbugs.repo.Repository;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;

import com.strobel.assembler.metadata.ClasspathTypeLoader;
import com.strobel.assembler.metadata.CompositeTypeLoader;
import com.strobel.assembler.metadata.ITypeLoader;
import com.strobel.assembler.metadata.JarTypeLoader;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.jar.JarFile;

/**
 * Goal which launches the HuntBugs static analyzer tool.
 */
@Mojo(name = "huntbugs", defaultPhase = LifecyclePhase.PREPARE_PACKAGE, requiresProject = true, threadSafe = true)
public class HuntBugsMojo extends AbstractMojo {
    /**
     * Location of the file.
     */
    @Parameter(defaultValue = "${project.build.directory}/huntbugs", property = "outputDir", required = true)
    private File outputDirectory;

    /**
     * Location of classes to analyze
     */
    @Parameter(defaultValue = "${project.build.outputDirectory}", property = "classesDir", required = true)
    private File classesDirectory;

    /**
     * Minimal warning score to report
     */
    @Parameter(defaultValue = "30", property = "minScore", required = true)
    private int minScore;
    
    /**
     * Do not print progress messages
     */
    @Parameter(defaultValue = "false", property = "quiet", required = true)
    private boolean quiet;
    
    @Parameter( defaultValue = "${project.compileClasspathElements}", readonly = true, required = true )
    private List<String> classpathElements;
    
    @Parameter( defaultValue = "${project}", readonly = true, required = true )
    private MavenProject project;

    @Parameter( defaultValue = "${session}", readonly = true, required = true )
    private MavenSession session;
    
    @Override
    public void execute() throws MojoExecutionException {
        try {
            Context ctx = new Context(constructRepository(), constructOptions());

            if (!quiet) {
                addAnalysisProgressListener(ctx);
            }

            ctx.analyzePackage("");
            writeReports(ctx);
        } catch (Exception e) {
            throw new MojoExecutionException("Failed to run HuntBugs", e);
        }
    }
    
    private Repository constructRepository() throws IOException {
        Repository repo = new DirRepository(classesDirectory.toPath());
        
        if (!quiet) {
            getLog().info("HuntBugs: +dir " + classesDirectory);
        }

        List<ITypeLoader> deps = new ArrayList<>();
        ArtifactRepository localRepository = session.getLocalRepository();

        for (Artifact art : project.getDependencyArtifacts()) {
            if (art.getScope().equals("compile")) {
                File f = localRepository.find(art).getFile();
                if (f != null) {
                    Path path = f.toPath();
                    if (!quiet) {
                        getLog().info("HuntBugs: +dep " + path);
                    }
                    if (Files.isRegularFile(path)) {
                        deps.add(new JarTypeLoader(new JarFile(path.toFile())));
                    } else if (Files.isDirectory(path)) {
                        deps.add(new ClasspathTypeLoader(path.toString()));
                    }
                }
            }
        }
        
        if (deps.isEmpty()) {
            return repo;
        }
        
        return new CompositeRepository(
            Arrays.asList(repo, new AuxRepository(new CompositeTypeLoader(deps.toArray(new ITypeLoader[0])))));
    }
    
    private AnalysisOptions constructOptions() {
        AnalysisOptions options = new AnalysisOptions();
        options.minScore = minScore;
        
        return options;
    }
    
    private void addAnalysisProgressListener(Context ctx) {
        long[] lastPrint = {0};
        ctx.addListener((stepName, className, count, total) -> {
            if (count == total || System.currentTimeMillis() - lastPrint[0] > 2000) {
                getLog().info("HuntBugs: " + stepName + " [" + count + "/" + total + "]");
                lastPrint[0] = System.currentTimeMillis();
            }
            return true;
        });
    }
    
    private void writeReports(Context ctx) throws IOException {
        getLog().info("HuntBugs: Writing report (" + ctx.getStat("Warnings") + " warnings)");
        Path path = outputDirectory.toPath();
        Files.createDirectories(path);
        Path xmlFile = path.resolve("report.xml");
        Path htmlFile = path.resolve("report.html");
        Reports.write(xmlFile, htmlFile, ctx);
    }
    
}

@@ -1827,24 +1827,46 @@
 .util.List;%0A
+import java.util.Set;%0A
 import java.
@@ -4054,21 +4054,20 @@
     
-for (
+Set%3C
 Artifact
  art
@@ -4066,14 +4066,31 @@
 fact
- art :
+%3E dependencyArtifacts =
  pro
@@ -4118,20 +4118,120 @@
 ifacts()
-) %7B%0A
+;%0A        if (dependencyArtifacts != null) %7B%0A            for (Artifact art : dependencyArtifacts) %7B%0A    
         
@@ -4270,24 +4270,28 @@
 ompile%22)) %7B%0A
+    
             
@@ -4352,24 +4352,28 @@
             
+ 
+   
 if (f != nul
@@ -4369,32 +4369,36 @@
 f (f != null) %7B%0A
+    
                 
@@ -4437,32 +4437,36 @@
                 
+    
 if (!quiet) %7B%0A  
@@ -4479,32 +4479,36 @@
                 
+ 
+   
 getLog().info(%22H
@@ -4528,24 +4528,28 @@
  %22 + path);%0A
+    
             
@@ -4574,24 +4574,28 @@
             
+    
 if (Files.is
@@ -4631,32 +4631,36 @@
                 
+  
+  
 deps.add(new Jar
@@ -4696,24 +4696,28 @@
 oFile())));%0A
+    
             
@@ -4778,32 +4778,36 @@
                 
+    
 deps.add(new Cla
@@ -4838,24 +4838,50 @@
 String()));%0A
+                        %7D%0A
             

fix for can not run huntbugs "java.lang.NullPointerException"