/* Copyright (c) 2012-2014 Boundless and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/edl-v10.html
*
* Contributors:
* Gabriel Roldan (Boundless) - initial implementation
*/
package org.locationtech.geogig.api.plumbing.diff;
import static com.google.common.base.Preconditions.checkArgument;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.meta.When;
import org.locationtech.geogig.api.Node;
import org.locationtech.geogig.api.NodeRef;
import org.locationtech.geogig.api.ObjectId;
import org.locationtech.geogig.repository.SpatialOps;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.vividsolutions.jts.geom.Envelope;
/**
* Provides a way of describing the between two different {@link Node}s.
*/
public class DiffEntry {
/**
* The possible types of change between the two {@link Node}s
*/
public static enum ChangeType {
/**
* Add a new Feature
*/
ADDED {
@Override
public int value() {
return 0;
}
},
/**
* Modify an existing Feature
*/
MODIFIED {
@Override
public int value() {
return 1;
}
},
/**
* Delete an existing Feature
*/
REMOVED {
@Override
public int value() {
return 2;
}
};
public abstract int value();
public static ChangeType valueOf(int value) {
// relying in the enum ordinal, beware
return ChangeType.values()[value];
}
}
private final NodeRef oldObject;
private final NodeRef newObject;
/**
* Constructs a new {@code DiffEntry} from two different {@link Node}s
*
* @param oldObject the old node ref
* @param newObject the new node ref
*/
public DiffEntry(@Nonnull(when = When.MAYBE) NodeRef oldObject,
@Nonnull(when = When.MAYBE) NodeRef newObject) {
Preconditions.checkArgument(oldObject != null || newObject != null,
"Either oldObject or newObject shall not be null");
if (oldObject != null && oldObject.equals(newObject)) {
throw new IllegalArgumentException(
"Trying to create a DiffEntry for the same object id, means the object didn't change: "
+ oldObject.toString());
}
if (oldObject != null && newObject != null) {
checkArgument(oldObject.getType().equals(newObject.getType()), String.format(
"Types don't match: %s : %s", oldObject.getType().toString(), newObject
.getType().toString()));
}
this.oldObject = oldObject;
this.newObject = newObject;
}
/**
* @return the id of the old version id of the object, or {@link ObjectId#NULL} if
* {@link #changeType()} is {@code ADD}
*/
public ObjectId oldObjectId() {
return oldObject == null ? ObjectId.NULL : oldObject.objectId();
}
/**
* @return the old object, or {@code null} if {@link #changeType()} is {@code ADD}
*/
public NodeRef getOldObject() {
return oldObject;
}
/**
* @return the id of the new version id of the object, or {@link ObjectId#NULL} if
* {@link #changeType()} is {@code DELETE}
*/
public ObjectId newObjectId() {
return newObject == null ? ObjectId.NULL : newObject.objectId();
}
/**
* @return the id of the new version of the object, or {@code null} if {@link #changeType()} is
* {@code DELETE}
*/
public NodeRef getNewObject() {
return newObject;
}
/**
* @return the type of change
*/
public ChangeType changeType() {
ChangeType type;
if (oldObject == null || oldObject.objectId().isNull()) {
type = ChangeType.ADDED;
} else if (newObject == null || newObject.objectId().isNull()) {
type = ChangeType.REMOVED;
} else {
type = ChangeType.MODIFIED;
}
return type;
}
/**
* @return the affected geographic region of the change, may be {@code null}
*/
public Envelope where() {
Envelope bounds = SpatialOps.aggregatedBounds(oldObject.getNode(), newObject.getNode());
return bounds;
}
/**
* @return the {@code DiffEntry} in the form of a readable {@code String}
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder(changeType().toString());
if (!isAdd()) {
sb.append(" [").append(oldObject).append("]");
}
if (isChange()) {
sb.append(" -> ");
}
if (!isDelete()) {
sb.append(" [").append(newObject).append(']');
}
return sb.toString();
}
/**
* @return the path of the old object
*/
public @Nullable
String oldPath() {
return oldObject == null ? null : oldObject.path();
}
/**
* @return the path of the new object
*/
public @Nullable
String newPath() {
return newObject == null ? null : newObject.path();
}
/**
* @return the name of the new object
*/
public @Nullable
String newName() {
return newObject == null ? null : newObject.getNode().getName();
}
/**
* @return the name of the old object
*/
public @Nullable
String oldName() {
return oldObject == null ? null : oldObject.getNode().getName();
}
@Override
public boolean equals(Object o) {
if (!(o instanceof DiffEntry)) {
return false;
}
DiffEntry de = (DiffEntry) o;
return Objects.equal(oldObject, de.oldObject) && Objects.equal(newObject, de.newObject);
}
/**
*
* @param target
*/
public void expand (Envelope target){
if (oldObject != null) {
oldObject.expand(target);
}
if(newObject != null){
newObject.expand(target);
}
}
@Override
public int hashCode() {
return Objects.hashCode(oldObject, newObject);
}
public boolean isDelete() {
return ChangeType.REMOVED.equals(changeType());
}
public boolean isAdd() {
return ChangeType.ADDED.equals(changeType());
}
public boolean isChange() {
return ChangeType.MODIFIED.equals(changeType());
}
}