package org.commonjava.maven.ext.manip.impl;

import static org.commonjava.maven.ext.manip.util.IdUtils.ga;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.maven.model.Build;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginExecution;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.commonjava.maven.ext.manip.ManipulationException;
import org.commonjava.maven.ext.manip.model.Project;
import org.commonjava.maven.ext.manip.state.ManipulationSession;
import org.commonjava.maven.ext.manip.state.ProjectSourcesInjectingState;

/**
 * Simple manipulator that detects the presence of the <a href="https://github.com/jdcasey/project-sources-maven-plugin">project-sources-maven-plugin</a>,
 * and injects it into the base build if it's not present. This plugin will simply create a source archive for the project sources AFTER this extension
 * has run, but BEFORE any sources are altered or generated by the normal build process. Configuration consists of a couple of properties, documented
 * in {@link ProjectSourcesInjectingState}.
 */
@Component( role = Manipulator.class, hint = "project-sources" )
public class ProjectSourcesInjectingManipulator
    implements Manipulator
{

    private static final String PROJECT_SOURCES_GID = "org.commonjava.maven.plugins";

    private static final String PROJECT_SOURCES_AID = "project-sources-maven-plugin";

    private static final String PROJECT_SOURCES_COORD = ga( PROJECT_SOURCES_GID, PROJECT_SOURCES_AID );

    private static final String BMMP_GID = "com.redhat.rcm.maven.plugin";

    private static final String BMMP_AID = "buildmetadata-maven-plugin";

    private static final String BMMP_COORD = ga( BMMP_GID, BMMP_AID );

    private static final String BMMP_GOAL = "provide-buildmetadata";

    private static final String BMMP_EXEC_ID = "build-metadata";

    private static final String PROJECT_SOURCES_GOAL = "archive";

    private static final String PROJECT_SOURCES_EXEC_ID = "project-sources-archive";

    private static final String VALIDATE_PHASE = "validate";

    private static final String INITIALIZE_PHASE = "initialize";

    @Override
    public void init( final ManipulationSession session )
        throws ManipulationException
    {
        session.setState( new ProjectSourcesInjectingState( session.getUserProperties() ) );
    }

    @Override
    public void scan( final List<Project> projects, final ManipulationSession session )
        throws ManipulationException
    {
    }

    /**
     * If enabled, grab the topmost POM in the current build (topmost in terms of inheritance, not necessarily directory structure). Check for the 
     * presence of the project-sources-maven-plugin in the base build (/project/build/plugins/). Inject a new plugin execution for creating project
     * sources if this plugin has not already been declared in the base build section.
     */
    @Override
    public Set<Project> applyChanges( final List<Project> projects, final ManipulationSession session )
        throws ManipulationException
    {
        final ProjectSourcesInjectingState state = session.getState( ProjectSourcesInjectingState.class );

        if ( state != null && state.isEnabled() )
        {
            for ( final Project project : projects )
            {
                if ( project.isTopPOM() )
                {
                    final Model model = project.getModel();
                    Build build = model.getBuild();
                    if ( build == null )
                    {
                        build = new Build();
                        model.setBuild( build );
                    }

                    boolean changed = false;
                    final Map<String, Plugin> pluginMap = build.getPluginsAsMap();
                    if ( !pluginMap.containsKey( PROJECT_SOURCES_COORD ) )
                    {
                        final PluginExecution execution = new PluginExecution();
                        execution.setId( PROJECT_SOURCES_EXEC_ID );
                        execution.setPhase( INITIALIZE_PHASE );
                        execution.setGoals( Collections.singletonList( PROJECT_SOURCES_GOAL ) );

                        final Plugin plugin = new Plugin();
                        plugin.setGroupId( PROJECT_SOURCES_GID );
                        plugin.setArtifactId( PROJECT_SOURCES_AID );
                        plugin.setVersion( state.getProjectSourcesPluginVersion() );
                        plugin.addExecution( execution );

                        build.addPlugin( plugin );

                        changed = true;
                    }

                    if ( !pluginMap.containsKey( BMMP_COORD ) )
                    {
                        final PluginExecution execution = new PluginExecution();
                        execution.setId( BMMP_EXEC_ID );
                        execution.setPhase( VALIDATE_PHASE );
                        execution.setGoals( Collections.singletonList( BMMP_GOAL ) );
                        
                        final Xpp3Dom xml = new Xpp3Dom( "configuration" );
                        
                        final Map<String, Object> config = new HashMap<String, Object>();
                        config.put( "createPropertiesReport", false );
                        config.put( "createXmlReport", false );
                        config.put( "hideCommandLineInfo", false );
                        config.put( "hideMavenOptsInfo", false );
                        config.put( "hideJavaOptsInfo", false );
                        config.put( "activateOutputFileMapping", false );
                        config.put( "propertiesOutputFile", "${basedir}/build.properties" );
                        config.put( "addJavaRuntimeInfo", true );
                        config.put( "addMavenExecutionInfo", true );
                        
                        for ( final Map.Entry<String, Object> entry : config.entrySet() )
                        {
                            final Xpp3Dom child = new Xpp3Dom( entry.getKey() );
                            if ( entry.getValue() != null )
                            {
                                child.setValue( entry.getValue().toString() );
                            }
                            
                            xml.addChild( child );
                        }
                        
                        execution.setConfiguration( xml );

                        final Plugin plugin = new Plugin();
                        plugin.setGroupId( BMMP_GID );
                        plugin.setArtifactId( BMMP_AID );
                        plugin.setVersion( state.getBuildMetadataPluginVersion() );
                        plugin.addExecution( execution );

                        build.addPlugin( plugin );

                        changed = true;
                    }

                    if ( changed )
                    {
                        return Collections.singleton( project );
                    }
                }
            }
        }

        return Collections.emptySet();
    }

}

@@ -5459,36 +5459,35 @@
 pertiesReport%22, 
-fals
+tru
 e );%0A           
@@ -6056,32 +6056,292 @@
                 
+config.put( %22addLocallyModifiedTagToFullVersion%22, false );%0A                        config.put( %22addToGeneratedSources%22, false );%0A                        config.put( %22validateCheckout%22, false );%0A                        config.put( %22forceNewProperties%22, true );%0A
 %0A               

Configure metadata plugin