package com.fitbank.persistencefinder;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collection;
import java.util.LinkedList;

import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;

import static org.apache.maven.plugins.annotations.LifecyclePhase.PROCESS_CLASSES;
import static org.apache.maven.plugins.annotations.ResolutionScope.COMPILE;

/**
 * Genera los archivos META-INF/services/persistence-classes conteniendo una
 * lista de clases de persistencia.
 */
@Mojo(name = "generate", defaultPhase = PROCESS_CLASSES, threadSafe = true, requiresDependencyResolution = COMPILE)
public class PersistenceFinderMojo extends AbstractMojo {

    /**
     * Output
     */
    @Parameter(defaultValue = "${project.build.outputDirectory}")
    private File outputDirectory;

    /**
     * The Maven project.
     */
    @Parameter(defaultValue = "${project}", readonly = true)
    private MavenProject project;

    @Override
    public void execute() throws MojoExecutionException {
        File services = new File(outputDirectory, "META-INF/services");

        if (!services.exists()) {
            services.mkdirs();
        }

        URLClassLoader dcl;
        try {
            Collection<URL> urls = new LinkedList<URL>();
            for (Object s : project.getCompileClasspathElements()) {
                urls.add(new File((String) s).toURI().toURL());
            }
            urls.add(outputDirectory.toURI().toURL());
            dcl = new URLClassLoader(urls.toArray(new URL[urls.size()]));
        } catch (MalformedURLException e) {
            throw new MojoExecutionException("Cannot load classpath", e);
        } catch (DependencyResolutionRequiredException e) {
            throw new MojoExecutionException("Cannot load classpath", e);
        }

        File service = new File(services, "persistence-classes");
        FileWriter w = null;
        try {
            w = new FileWriter(service);

            getLog().info("Buscando clases de persistencia en "
                    + outputDirectory);
            for (String className : getClassNames(outputDirectory, outputDirectory)) {
                getLog().info("Encontrado " + className);
                w.write(className + "\n");
            }
        } catch (IOException e) {
            throw new MojoExecutionException("Error creando archivo " + service,
                    e);
        } finally {
            if (w != null) {
                try {
                    w.close();
                } catch (IOException e) {
                    getLog().error("No se pudo guardar el archivo");
                }
            }
        }
    }

    private Collection<String> getClassNames(File start, File parent) {
        Collection<String> classNames = new LinkedList<String>();

        for (File f : parent.listFiles()) {
            if (f.isDirectory()) {
                classNames.addAll(getClassNames(start, f));
            } else if (f.getName().endsWith(".hbm.xml")) {
                classNames.add(f.getAbsolutePath().replace(
                        start.getAbsolutePath(), "").replaceAll(".hbm.xml$", "").
                        replace(File.separator, ".").substring(1));
            } else if (f.getName().endsWith(".jpa.txt")) {
                classNames.add(f.getAbsolutePath().replace(
                        start.getAbsolutePath(), "").replaceAll(".jpa.txt$", "").
                        replace(File.separator, ".").substring(1));
            }
        }

        return classNames;
    }

}
