package sk.stuba.fiit.perconik.activity.listeners.resource;
import java.util.Set;
import com.google.common.collect.ImmutableSet;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.runtime.CoreException;
import sk.stuba.fiit.perconik.activity.events.LocalEvent;
import sk.stuba.fiit.perconik.activity.listeners.ActivityListener;
import sk.stuba.fiit.perconik.activity.serializers.resource.ProjectSerializer;
import sk.stuba.fiit.perconik.core.annotations.Unsupported;
import sk.stuba.fiit.perconik.core.annotations.Version;
import sk.stuba.fiit.perconik.data.events.Event;
import sk.stuba.fiit.perconik.eclipse.core.resources.ResourceDeltaFlag;
import sk.stuba.fiit.perconik.eclipse.core.resources.ResourceDeltaKind;
import sk.stuba.fiit.perconik.eclipse.core.resources.ResourceEventType;
import sk.stuba.fiit.perconik.eclipse.core.resources.ResourceType;
import static sk.stuba.fiit.perconik.activity.listeners.resource.ProjectListener.Action.ADD;
import static sk.stuba.fiit.perconik.activity.listeners.resource.ProjectListener.Action.BUILD;
import static sk.stuba.fiit.perconik.activity.listeners.resource.ProjectListener.Action.CLOSE;
import static sk.stuba.fiit.perconik.activity.listeners.resource.ProjectListener.Action.DELETE;
import static sk.stuba.fiit.perconik.activity.listeners.resource.ProjectListener.Action.OPEN;
import static sk.stuba.fiit.perconik.activity.listeners.resource.ProjectListener.Action.REMOVE;
import static sk.stuba.fiit.perconik.data.content.StructuredContents.key;
import static sk.stuba.fiit.perconik.eclipse.core.resources.ResourceEventType.POST_CHANGE;
import static sk.stuba.fiit.perconik.eclipse.core.resources.ResourceEventType.PRE_BUILD;
import static sk.stuba.fiit.perconik.eclipse.core.resources.ResourceEventType.PRE_CLOSE;
import static sk.stuba.fiit.perconik.eclipse.core.resources.ResourceEventType.PRE_DELETE;
/**
* TODO
*
* @author Pavol Zbell
* @since 1.0
*/
@Version("0.0.0.alpha")
@Unsupported
public final class ProjectListener extends AbstractResourceListener {
static final Set<ResourceEventType> resourceEventTypes = ImmutableSet.of(PRE_BUILD, PRE_CLOSE, PRE_DELETE, POST_CHANGE);
public ProjectListener() {}
// TODO test DELETE vs REMOVE
// TODO figure out how to distinguish CREATE from ADD
enum Action implements ActivityListener.Action {
ADD,
REMOVE,
DELETE,
OPEN,
CLOSE,
BUILD;
private final String name;
private final String path;
private Action() {
this.name = actionName("eclipse", "project", this);
this.path = actionPath(this.name);
}
public String getName() {
return this.name;
}
public String getPath() {
return this.path;
}
}
static Event build(final long time, final Action action, final ResourceEventVisit visit, final IProject project) {
Event data = LocalEvent.of(time, action.getName());
put(data, visit);
data.put(key("project"), new ProjectSerializer().serialize(project));
return data;
}
void process(final long time, final Action action, final ResourceEventVisit visit, final IProject project) {
this.send(action.getPath(), build(time, action, visit, project));
}
private final class ProjectEventResolver extends ResourceEventResolver {
ProjectEventResolver(final long time, final ResourceEventInput input) {
super(time, input);
}
@Override
protected boolean resolveDelta(final ResourceEventInput input, final IResourceDelta delta) throws CoreException {
IResource resource = delta.getResource();
switch (ResourceType.valueOf(resource.getType())) {
case ROOT:
return true;
case PROJECT:
return this.resolveProject(ResourceEventVisit.of(input, delta), delta, (IProject) resource);
default:
return false;
}
}
@Override
protected boolean resolveResource(final ResourceEventInput input, final IResource resource) {
switch (ResourceType.valueOf(resource.getType())) {
case ROOT:
return true;
case PROJECT:
return this.resolveProject(ResourceEventVisit.of(input, resource), (IProject) resource);
default:
return false;
}
}
private boolean resolveProject(final ResourceEventVisit visit, final IResourceDelta delta, final IProject project) {
if (visit.input.type == POST_CHANGE) {
ResourceDeltaKind kind = ResourceDeltaKind.valueOf(delta.getKind());
Set<ResourceDeltaFlag> flags = ResourceDeltaFlag.setOf(delta.getFlags());
if (kind == ResourceDeltaKind.ADDED) {
this.process(ADD, visit, project);
}
if (kind == ResourceDeltaKind.REMOVED) {
this.process(REMOVE, visit, project);
}
if (flags.contains(ResourceDeltaFlag.OPEN) && project.isOpen()) {
this.process(OPEN, visit, project);
}
return false;
}
return this.resolveProject(visit, project);
}
private boolean resolveProject(final ResourceEventVisit visit, final IProject project) {
switch (visit.input.type) {
case PRE_BUILD:
this.process(BUILD, visit, project);
break;
case PRE_CLOSE:
this.process(CLOSE, visit, project);
break;
case PRE_DELETE:
this.process(DELETE, visit, project);
break;
default:
break;
}
return false;
}
void process(final Action action, final ResourceEventVisit visit, final IProject project) {
ProjectListener.this.process(this.time, action, visit, project);
}
}
@Override
void resolve(final long time, final IResourceChangeEvent event) {
new ProjectEventResolver(time, ResourceEventInput.of(event)).resolve(event);
}
public Set<ResourceEventType> getEventTypes() {
return resourceEventTypes;
}
}