package org.javers.core.diff.appenders.levenshtein;
import org.javers.common.validation.Validate;
import org.javers.core.diff.EqualsFunction;
import org.javers.core.diff.NodePair;
import org.javers.core.diff.appenders.CorePropertyChangeAppender;
import org.javers.core.diff.changetype.container.ContainerElementChange;
import org.javers.core.diff.changetype.container.ListChange;
import org.javers.core.metamodel.object.*;
import org.javers.core.metamodel.property.Property;
import org.javers.core.metamodel.type.JaversProperty;
import org.javers.core.metamodel.type.JaversType;
import org.javers.core.metamodel.type.ListType;
import org.javers.core.metamodel.type.TypeMapper;
import java.util.List;
import java.util.Objects;
import static org.javers.common.collections.Lists.wrapNull;
/**
* @author kornel kiełczewski
*/
public class LevenshteinListChangeAppender extends CorePropertyChangeAppender<ListChange> {
private final TypeMapper typeMapper;
private final GlobalIdFactory globalIdFactory;
LevenshteinListChangeAppender(TypeMapper typeMapper, GlobalIdFactory globalIdFactory) {
Validate.argumentsAreNotNull(typeMapper, globalIdFactory);
this.typeMapper = typeMapper;
this.globalIdFactory = globalIdFactory;
}
@Override
public boolean supports(JaversType propertyType) {
return propertyType instanceof ListType;
}
@Override
public ListChange calculateChanges(final NodePair pair, final Property property) {
final List leftList = wrapNull( (List) pair.getLeftPropertyValue(property) );
final List rightList = wrapNull((List) pair.getRightPropertyValue(property));
EqualsFunction equalsFunction = createDehydratingEqualsFunction(pair, property);
Backtrack backtrack = new Backtrack(equalsFunction);
StepsToChanges stepsToChanges = new StepsToChanges(equalsFunction);
final BacktrackSteps[][] steps = backtrack.evaluateSteps(leftList, rightList);
final List<ContainerElementChange> changes = stepsToChanges.convert(steps, leftList, rightList);
ListChange result = getListChange(pair.getGlobalId(), property, changes);
if (result != null) {
ListType listType = ((JaversProperty) property).getType();
renderNotParametrizedWarningIfNeeded(listType.getItemType(), "item", "List", property);
}
return result;
}
private EqualsFunction createDehydratingEqualsFunction(NodePair pair, Property property){
ListType listType = ((JaversProperty) property).getType();
final JaversType listContentType = typeMapper.getJaversType(listType.getItemType());
final OwnerContext owner = new PropertyOwnerContext(pair.getGlobalId(), property.getName());
return new EqualsFunction() {
public boolean nullSafeEquals(Object left, Object right) {
Object leftDehydrated = globalIdFactory.dehydrate(left, listContentType, owner);
Object rightDehydrated = globalIdFactory.dehydrate(right, listContentType, owner);
return Objects.equals(leftDehydrated, rightDehydrated);
}
};
}
private ListChange getListChange(final GlobalId affectedCdoId, final Property property,
final List<ContainerElementChange> changes) {
final ListChange result;
if (changes.size() == 0) {
result = null;
} else {
result = new ListChange(affectedCdoId, property.getName(), changes);
}
return result;
}
}