package org.javers.guava;
import com.google.common.collect.Multiset;
import com.google.common.collect.Multisets;
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.SetChange;
import org.javers.core.diff.changetype.container.ValueAdded;
import org.javers.core.diff.changetype.container.ValueRemoved;
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.TypeMapper;
import java.util.ArrayList;
import java.util.List;
/**
* Compares Guava Multisets.
* <br/>
*
* It's automatically registered, if Guava is detected on the classpath.
*
* @author akrystian
*/
class MultisetChangeAppender extends CorePropertyChangeAppender<SetChange> {
private final TypeMapper typeMapper;
private final GlobalIdFactory globalIdFactory;
MultisetChangeAppender(TypeMapper typeMapper, GlobalIdFactory globalIdFactory){
this.typeMapper = typeMapper;
this.globalIdFactory = globalIdFactory;
}
@Override
public boolean supports(JaversType propertyType) {
return propertyType instanceof MultisetType;
}
@Override
public SetChange calculateChanges(NodePair pair, Property property){
Multiset left = (Multiset)pair.getLeftPropertyValue(property);
Multiset right = (Multiset)pair.getRightPropertyValue(property);
MultisetType multisetType = ((JaversProperty) property).getType();
OwnerContext owner = new PropertyOwnerContext(pair.getGlobalId(), property.getName());
List<ContainerElementChange> entryChanges = calculateEntryChanges(multisetType, left, right, owner);
if (!entryChanges.isEmpty()){
renderNotParametrizedWarningIfNeeded(multisetType.getItemType(), "item", "Multiset", property);
return new SetChange(pair.getGlobalId(), property.getName(), entryChanges);
} else {
return null;
}
}
private List<ContainerElementChange> calculateEntryChanges(MultisetType multisetType, Multiset left, Multiset right, OwnerContext owner){
JaversType itemType = typeMapper.getJaversType(multisetType.getItemType());
DehydrateContainerFunction dehydrateFunction = new DehydrateContainerFunction(itemType, globalIdFactory);
Multiset leftMultiset = (Multiset) multisetType.map(left,dehydrateFunction,owner);
Multiset rightMultiset = (Multiset) multisetType.map(right,dehydrateFunction,owner);
List<ContainerElementChange> changes = new ArrayList<>();
for (Object globalCdoId : Multisets.difference(leftMultiset, rightMultiset)){
changes.add(new ValueRemoved(globalCdoId));
}
Multiset difference = Multisets.difference(rightMultiset, leftMultiset);
for (Object globalCdoId : difference){
changes.add(new ValueAdded(globalCdoId));
}
return changes;
}
}