@@ -0,0 +1,275 @@
/*******************************************************************************
* Copyright (c) 2008-2011 Sonatype, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Sonatype, Inc. - initial API and implementation
*******************************************************************************/


package org.eclipse.m2e.editor.xml.internal.lifecycle;


import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.VersionRange;
import org.apache.maven.repository.internal.DefaultVersionRangeResolver;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension5;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.IMarkerResolution;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.texteditor.MarkerAnnotation;
import org.eclipse.ui.views.markers.WorkbenchMarkerResolution;

import org.eclipse.m2e.core.internal.IMavenConstants;
import org.eclipse.m2e.core.internal.MavenPluginActivator;
import org.eclipse.m2e.core.internal.lifecyclemapping.model.LifecycleMappingMetadataSource;
import org.eclipse.m2e.core.internal.lifecyclemapping.model.PluginExecutionFilter;
import org.eclipse.m2e.core.internal.lifecyclemapping.model.PluginExecutionMetadata;
import org.eclipse.m2e.core.internal.lifecyclemapping.model.io.xpp3.LifecycleMappingMetadataSourceXpp3Reader;
import org.eclipse.m2e.core.internal.lifecyclemapping.model.io.xpp3.LifecycleMappingMetadataSourceXpp3Writer;
import org.eclipse.m2e.core.lifecyclemapping.model.PluginExecutionAction;
import org.eclipse.m2e.core.project.configurator.MojoExecutionKey;
import org.eclipse.m2e.core.ui.internal.UpdateConfigurationJob;
import org.eclipse.m2e.editor.xml.internal.Messages;

public class WorkspaceLifecycleMappingProposal extends WorkbenchMarkerResolution implements ICompletionProposal, ICompletionProposalExtension5, IMarkerResolution {
private static final Logger log = LoggerFactory.getLogger(WorkspaceLifecycleMappingProposal.class);


private IQuickAssistInvocationContext context;
private final IMarker marker;

private final PluginExecutionAction action;

public WorkspaceLifecycleMappingProposal(IQuickAssistInvocationContext context, MarkerAnnotation mark,
PluginExecutionAction action) {
this.context = context;
marker = mark.getMarker();
this.action = action;
}

public WorkspaceLifecycleMappingProposal(IMarker marker, PluginExecutionAction action) {
this.marker = marker;
this.action = action;
}

public void apply(final IDocument doc) {
run(marker);
}

/**
* @return
*/
private static LifecycleMappingMetadataSource getWorkspacePreferencesMetadataSources() {
LifecycleMappingMetadataSource source = new LifecycleMappingMetadataSource();
String mapp = MavenPluginActivator.getDefault().getPluginPreferences().getString("XXX_mappings");
if (mapp != null) {
LifecycleMappingMetadataSourceXpp3Reader reader = new LifecycleMappingMetadataSourceXpp3Reader();
try {
source = reader.read(new StringReader(mapp));
} catch(IOException ex) {
// TODO Auto-generated catch block
log.error(ex.getMessage(), ex);
} catch(XmlPullParserException ex) {
// TODO Auto-generated catch block
log.error(ex.getMessage(), ex);
}
}
return source;
}


private static void performIgnore(IMarker mark, LifecycleMappingMetadataSource source) throws IOException, CoreException {
String pluginGroupId = mark.getAttribute(IMavenConstants.MARKER_ATTR_GROUP_ID, ""); //$NON-NLS-1$
String pluginArtifactId = mark.getAttribute(IMavenConstants.MARKER_ATTR_ARTIFACT_ID, ""); //$NON-NLS-1$
String pluginVersion = mark.getAttribute(IMavenConstants.MARKER_ATTR_VERSION, ""); //$NON-NLS-1$
String goal = mark.getAttribute(IMavenConstants.MARKER_ATTR_GOAL, ""); //$NON-NLS-1$
String id = pluginGroupId + ":" + pluginArtifactId;
MojoExecutionKey key = new MojoExecutionKey(pluginGroupId, pluginArtifactId, pluginVersion, goal, null, null);
boolean found = false;
for (PluginExecutionMetadata pem : source.getPluginExecutions()) {
PluginExecutionFilter filter = pem.getFilter();
if (PluginExecutionAction.ignore.equals(pem.getAction())) {
if (filter.getGroupId().equals(pluginGroupId) && filter.getArtifactId().equals(pluginArtifactId)) {
found = true;
try {
VersionRange range = VersionRange.createFromVersionSpec(filter.getVersionRange());
DefaultArtifactVersion version = new DefaultArtifactVersion(pluginVersion);
if (!range.containsVersion(version)) {
filter.setVersionRange("[" + pluginVersion + ",)");
}
} catch(InvalidVersionSpecificationException e) {
log.error(e.getMessage(), e);
}
if (!filter.getGoals().contains(goal)) {
filter.addGoal(goal);
}
break;
}
}
}
if (!found) {
PluginExecutionMetadata pe = new PluginExecutionMetadata();
PluginExecutionFilter fil = new PluginExecutionFilter(pluginGroupId, pluginArtifactId, "[" + pluginVersion + ",)", goal);
pe.setFilter(fil);
source.addPluginExecution(pe);
Xpp3Dom actionDom = new Xpp3Dom("action");
actionDom.addChild(new Xpp3Dom(PluginExecutionAction.ignore.name()));
pe.setActionDom(actionDom);
}



}



public String getAdditionalProposalInfo() {
return null;
}

public IContextInformation getContextInformation() {
return null;
}

public String getDisplayString() {
String goal = marker.getAttribute(IMavenConstants.MARKER_ATTR_GOAL, ""); //$NON-NLS-1$
return PluginExecutionAction.ignore.equals(action) ? NLS.bind("Mark goal {0} in workspace as ignored in Eclipse build", goal)
: NLS.bind(Messages.LifecycleMappingProposal_execute_label, goal);
}

public Image getImage() {
return PluginExecutionAction.ignore.equals(action) ? PlatformUI.getWorkbench().getSharedImages()
.getImage(org.eclipse.ui.ISharedImages.IMG_TOOL_DELETE) : PlatformUI.getWorkbench().getSharedImages()
.getImage(org.eclipse.ui.ISharedImages.IMG_TOOL_FORWARD);
}

public Point getSelection(IDocument arg0) {
return null;
}

public Object getAdditionalProposalInfo(IProgressMonitor monitor) {
if (context == null) {
//no context in markerresolution, just to be sure..
return null;
}
String pluginGroupId = marker.getAttribute(IMavenConstants.MARKER_ATTR_GROUP_ID, ""); //$NON-NLS-1$
String pluginArtifactId = marker.getAttribute(IMavenConstants.MARKER_ATTR_ARTIFACT_ID, ""); //$NON-NLS-1$
String pluginVersion = marker.getAttribute(IMavenConstants.MARKER_ATTR_VERSION, ""); //$NON-NLS-1$
String goal = marker.getAttribute(IMavenConstants.MARKER_ATTR_GOAL, ""); //$NON-NLS-1$
String execution = marker.getAttribute(IMavenConstants.MARKER_ATTR_EXECUTION_ID, "-"); //$NON-NLS-1$
String phase = marker.getAttribute(IMavenConstants.MARKER_ATTR_LIFECYCLE_PHASE, "-"); //$NON-NLS-1$
String info = NLS.bind(Messages.LifecycleMappingProposal_all_desc,
new Object[] {goal, execution, phase, pluginGroupId + ":" + pluginArtifactId + ":" + pluginVersion, //$NON-NLS-1$ //$NON-NLS-2$
(PluginExecutionAction.ignore.equals(action)
? "This quickfix generates a plugin configuration snippet recognized by the m2e integration during project configuration. It marks the given goal as ignored for the purposes of the Eclipse build."
: Messages.LifecycleMappingProposal_execute_desc)});

return info;
}

public String getLabel() {
return getDisplayString();
}

public void run(final IMarker marker) {
try {
if(PluginExecutionAction.ignore.equals(action)) {
LifecycleMappingMetadataSource source = getWorkspacePreferencesMetadataSources();
performIgnore(marker, source);
LifecycleMappingMetadataSourceXpp3Writer writer = new LifecycleMappingMetadataSourceXpp3Writer();
StringWriter sw = new StringWriter();
writer.write(sw, source);
MavenPluginActivator.getDefault().getPluginPreferences().setValue("XXX_mappings", sw.toString());

//now update the project
new UpdateConfigurationJob(new IProject[] {marker.getResource().getProject()}).schedule();
MavenPluginActivator.getDefault().savePluginPreferences();

}
} catch(IOException e) {
log.error("Error generating code in pom.xml", e); //$NON-NLS-1$
} catch(CoreException e) {
log.error(e.getMessage(), e);
}
}

public String getDescription() {
// TODO Auto-generated method stub
return null;
}

@Override
public IMarker[] findOtherMarkers(IMarker[] markers) {
List<IMarker> handled = new ArrayList<IMarker>();

for (IMarker marker : markers) {
if (marker == this.marker) {
continue;
}
String hint = marker.getAttribute(IMavenConstants.MARKER_ATTR_EDITOR_HINT, null);
if ( hint != null && hint.equals(IMavenConstants.EDITOR_HINT_NOT_COVERED_MOJO_EXECUTION)) {
handled.add(marker);
}
}
return handled.toArray(new IMarker[handled.size()]);
}

@Override
public void run(IMarker[] markers, IProgressMonitor monitor) {
try {
if(PluginExecutionAction.ignore.equals(action)) {
Set<IProject> prjs = new HashSet<IProject>();
LifecycleMappingMetadataSource source = getWorkspacePreferencesMetadataSources();
for (IMarker mark : markers) {
performIgnore(mark, source);
prjs.add(mark.getResource().getProject());
}
LifecycleMappingMetadataSourceXpp3Writer writer = new LifecycleMappingMetadataSourceXpp3Writer();
StringWriter sw = new StringWriter();
writer.write(sw, source);
MavenPluginActivator.getDefault().getPluginPreferences().setValue("XXX_mappings", sw.toString());

MavenPluginActivator.getDefault().savePluginPreferences();
for (IMarker mark : markers) {
mark.delete();
}
//now update the projects
new UpdateConfigurationJob(prjs.toArray(new IProject[0])).schedule();

}
} catch(IOException e) {
log.error("Error generating code in pom.xml", e); //$NON-NLS-1$
} catch(CoreException e) {
log.error(e.getMessage(), e);
}
}

}