package de.markusmo3.urm;

import de.markusmo3.urm.presenters.Presenter;
import de.markusmo3.urm.presenters.Representation;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.*;
import org.apache.maven.project.MavenProject;
import org.reflections.Reflections;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

@Mojo(name = "map", defaultPhase = LifecyclePhase.PROCESS_CLASSES, requiresDependencyResolution = ResolutionScope.COMPILE)
public class DomainMapperMojo extends AbstractMojo {

    @Parameter(defaultValue = "${project.basedir}", property = "outputDir", required = true)
    private File outputDirectory;
    @Component
    private MavenProject project;
    @Parameter(property = "map.packages", required = true)
    private List<String> packages;
    @Parameter(property = "map.ignores", required = false)
    private List<String> ignores;
    @Parameter(property = "presenter", required = false)
    private String presenterString;
    @Parameter(property = "map.skipForProjects", required = false)
    private List<String> skipForProjects;

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        if (skipForProjects != null && !skipForProjects.isEmpty()) {
            String projectName = project.getName();
            if (skipForProjects.contains(projectName)) {
                getLog().info("Skip configured (in pom.xml) for current project \"" + projectName +"\". " +
                        "Plugin will not be executed!");
                return;
            }
        }

        if (packages.isEmpty())
            throw new MojoFailureException("No packages defined for scanning.");
        try {
            Presenter presenter = Presenter.parse(presenterString);

            String fileName = project.getName() + ".urm." + presenter.getFileEnding();
            Path path = Paths.get(outputDirectory.getPath(), fileName);

            if (!getLog().isDebugEnabled()) {
                // nullify the Reflections logger to prevent it from spamming
                // the console if we aren't in debug mode
                Reflections.log = null;
            }

            if (!Files.exists(path)) {
                List<URL> projectClasspathList = getClasspathUrls();
                DomainMapper mapper = DomainMapper.create(presenter, packages, ignores,
                        new URLClassLoader(projectClasspathList.toArray(new URL[projectClasspathList.size()])));

                Representation representation = mapper.describeDomain();
                Files.write(path, representation.getContent().getBytes());
                getLog().info(fileName + " successfully written to: \"" + path + "\"!");
            } else {
                getLog().info(fileName + " already exists, file was not overwritten!");
            }
        } catch (ClassNotFoundException | DependencyResolutionRequiredException | IOException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
    }

    @SuppressWarnings("unchecked")
    private List<URL> getClasspathUrls() throws DependencyResolutionRequiredException, MojoExecutionException {
        List<URL> projectClasspathList = new ArrayList<>();
        for (String element : (List<String>) project.getCompileClasspathElements()) {
            try {
                projectClasspathList.add(new File(element).toURI().toURL());
            } catch (MalformedURLException e) {
                throw new MojoExecutionException(element + " is an invalid classpath element", e);
            }
        }
        return projectClasspathList;
    }
}

@@ -746,16 +746,66 @@
 il.List;
+%0Aimport static java.util.stream.Collectors.toList;
 %0A%0A@Mojo(
@@ -1539,16 +1539,245 @@
 rojects;
+%0A    @Parameter(property =%22includeMainDirectory%22, defaultValue = %22true%22)%0A    private boolean includeMainDirectory;%0A    @Parameter(property =%22includeTestDirectory%22, defaultValue = %22false%22)%0A    private boolean includeTestDirectory;
 %0A%0A    @O
@@ -3941,58 +3941,31 @@
 t : 
-(List%3CString%3E) project.getCompile
+getProject
 Class
-pathElements
+PathList
 ()) 
@@ -4204,24 +4204,24 @@
 ement%22, e);%0A
-
             
@@ -4274,11 +4274,782 @@
 t;%0A    %7D
+%0A%0A    private List%3CString%3E getProjectClassPathList()throws DependencyResolutionRequiredException%7B%0A        List%3CString%3E projectClasspathList = new ArrayList%3C%3E();%0A        if(includeMainDirectory && includeTestDirectory)%0A            projectClasspathList = project.getTestClasspathElements();%0A        else if(includeMainDirectory)%0A            projectClasspathList = project.getCompileClasspathElements();%0A        else if(includeTestDirectory) %7B%0A            String outputDir = project.getBuild().getOutputDirectory();%0A%0A            projectClasspathList =  ((List%3CString%3E)project.getTestClasspathElements())%0A                    .stream().filter(url -%3E !outputDir.equalsIgnoreCase(url))%0A                    .collect(toList());%0A        %7D%0A        return projectClasspathList;%0A    %7D
 %0A%7D%0A

Fix for https://github.com/iluwatar/uml-reverse-mapper/issues/16 Add ability to parse test classes