package de.saumya.mojo.jruby9.jar;

import java.io.File;
import java.lang.reflect.Field;

import org.apache.maven.archiver.MavenArchiveConfiguration;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
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.plugins.annotations.ResolutionScope;
import org.apache.maven.repository.RepositorySystem;
import org.codehaus.plexus.archiver.UnArchiver;

import de.saumya.mojo.jruby9.ArtifactHelper;
import de.saumya.mojo.jruby9.ArchiveType;
import de.saumya.mojo.jruby9.Versions;

/**
 * packs a ruby application into runnable jar.
 *
 * <li>shaded jruby-complete.jar</li>
 * <li>shaded jruby-mains.jar</li>
 * <li>all declared gems and transitive gems and jars</li>
 * <li>all declared jars and transitive jars</li>
 * <li>all declared resource</li>
 * 
 * the main class sets up the GEM_HOME, GEM_PATH and JARS_HOME and takes arguments
 * for executing jruby. any bin stubs from the gem are available via '-S' or any
 * script relative to jar's root can be found as the current directory is inside the jar.
 * 
 * <br/>
 * 
 * if there is a 'jar-bootstrap.rb' in the root of the jar, then the default main class will
 * execute this script and pass all the arguments to bootstrap script.
 * 
 * @author christian
 */
@Mojo( name = "jar", defaultPhase = LifecyclePhase.PACKAGE, requiresProject = true, threadSafe = true,
       requiresDependencyResolution = ResolutionScope.RUNTIME )
public class JarMojo extends org.apache.maven.plugin.jar.JarMojo {

    @Parameter( defaultValue = "runnable", property = "jruby.archive.type", required = true )
    private ArchiveType type;

    @Parameter( defaultValue = "org.jruby.mains.JarMain", required = false )
    private String mainClass;

    @Parameter( defaultValue = Versions.JRUBY, property = "jruby.version", required = true )
    private String jrubyVersion;

    @Parameter( defaultValue = Versions.JRUBY_MAINS, property = "jruby.mains.version", required = true )
    private String jrubyMainsVersion;

    @Parameter( readonly = true, defaultValue="${localRepository}" )
    protected ArtifactRepository localRepository;
    
    @Component
    RepositorySystem system;
    
    @Component( hint = "zip" )
    UnArchiver unzip;

    @Override
    public void execute() throws MojoExecutionException {
        switch(type) {
        case runnable:
            if (mainClass == null) {
                throw new MojoExecutionException( "runnable archive need mainClass configured" );
            }
            MavenArchiveConfiguration archive = getArchive();
            archive.getManifest().setMainClass(mainClass);

            ArtifactHelper helper = new ArtifactHelper(unzip, system,
                                                       localRepository, getProject().getRemoteArtifactRepositories());
            File output = new File( getProject().getBuild().getOutputDirectory());
            helper.unzip(output, "org.jruby", "jruby-complete", jrubyVersion);
            helper.unzip(output, "org.jruby.mains", "jruby-mains", jrubyMainsVersion);

        case archive:
            break;
        default:
            throw new MojoExecutionException("can not pack archive " + type + " with jruby-jar-plugin");
        }
        
        super.execute();
    }

    private MavenArchiveConfiguration getArchive() throws MojoExecutionException {
        try {
             Field archiveField = getClass().getSuperclass().getSuperclass().getDeclaredField("archive");
             archiveField.setAccessible(true);
             return (MavenArchiveConfiguration) archiveField.get(this);
        } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
            throw new MojoExecutionException("can not use reflection", e);
        }
    }
}
