/*
* Copyright (c) 2010-2014 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.evolveum.midpoint.prism.delta;
import com.evolveum.midpoint.prism.SimpleVisitable;
import com.evolveum.midpoint.prism.SimpleVisitor;
import com.evolveum.midpoint.util.Cloner;
import com.evolveum.midpoint.util.DebugDumpable;
import com.evolveum.midpoint.util.DebugUtil;
import com.evolveum.midpoint.util.MiscUtil;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
/**
*
* @author Radovan Semancik
*/
public class DeltaMapTriple<K,V> implements DebugDumpable, Serializable, SimpleVisitable<Map.Entry<K, V>> {
/**
* Collection of values that were not changed.
*/
protected Map<K,V> zeroMap;
/**
* Collection of values that were added.
*/
protected Map<K,V> plusMap;
/**
* Collection of values that were deleted.
*/
protected Map<K,V> minusMap;
public DeltaMapTriple() {
zeroMap = createMap();
plusMap = createMap();
minusMap = createMap();
}
public DeltaMapTriple(Map<K,V> zeroMap, Map<K,V> plusMap, Map<K,V> minusMap) {
this.zeroMap = zeroMap;
this.plusMap = plusMap;
this.minusMap = minusMap;
}
protected Map<K,V> createMap() {
return new HashMap<>();
}
public Map<K,V> getZeroMap() {
return zeroMap;
}
public Map<K,V> getPlusMap() {
return plusMap;
}
public Map<K,V> getMinusMap() {
return minusMap;
}
public Map<K,V> getMap(PlusMinusZero plusMinusZero) {
if (plusMinusZero == null) {
return null;
}
switch (plusMinusZero) {
case PLUS: return plusMap;
case MINUS: return minusMap;
case ZERO: return zeroMap;
}
// notreached
throw new IllegalStateException();
}
public boolean hasPlusMap() {
return (plusMap != null && !plusMap.isEmpty());
}
public boolean hasZeroMap() {
return (zeroMap != null && !zeroMap.isEmpty());
}
public boolean hasMinusMap() {
return (minusMap != null && !minusMap.isEmpty());
}
public boolean isZeroOnly() {
return hasZeroMap() && !hasPlusMap() && !hasMinusMap();
}
public void addToPlusMap(K key, V value) {
addToMap(plusMap, key, value);
}
public void addToMinusMap(K key, V value) {
addToMap(minusMap, key, value);
}
public void addToZeroMap(K key, V value) {
addToMap(zeroMap, key, value);
}
public void addAllToPlusMap(Map<K,V> map) {
addAllToMap(plusMap, map);
}
public void addAllToMinusMap(Map<K,V> map) {
addAllToMap(minusMap, map);
}
public void addAllToZeroMap(Map<K,V> map) {
addAllToMap(zeroMap, map);
}
public void addAllToMap(PlusMinusZero destination, Map<K,V> map) {
if (destination == null) {
return;
} else if (destination == PlusMinusZero.PLUS) {
addAllToMap(plusMap, map);
} else if (destination == PlusMinusZero.MINUS) {
addAllToMap(minusMap, map);
} else if (destination == PlusMinusZero.ZERO) {
addAllToMap(zeroMap, map);
}
}
private void addAllToMap(Map<K,V> set, Map<K,V> items) {
if (items == null) {
return;
}
for (Entry<K, V> item: items.entrySet()) {
addToMap(set, item.getKey(), item.getValue());
}
}
private void addToMap(Map<K,V> set, K key, V value) {
if (set == null) {
set = createMap();
}
set.put(key, value);
}
public void clearPlusMap() {
clearMap(plusMap);
}
public void clearMinusMap() {
clearMap(minusMap);
}
public void clearZeroMap() {
clearMap(zeroMap);
}
private void clearMap(Map<K,V> set) {
if (set != null) {
set.clear();
}
}
public int size() {
return sizeMap(zeroMap) + sizeMap(plusMap) + sizeMap(minusMap);
}
private int sizeMap(Map<K,V> set) {
if (set == null) {
return 0;
}
return set.size();
}
public void merge(DeltaMapTriple<K,V> triple) {
addAllToZeroMap(triple.zeroMap);
addAllToPlusMap(triple.plusMap);
addAllToMinusMap(triple.minusMap);
}
/**
* Returns all values, regardless of the internal sets.
*/
public Collection<K> unionKeySets() {
return MiscUtil.union(zeroMap.keySet(), plusMap.keySet(), minusMap.keySet());
}
public DeltaMapTriple<K,V> clone(Cloner<Entry<K, V>> cloner) {
DeltaMapTriple<K,V> clone = new DeltaMapTriple<K,V>();
copyValues(clone, cloner);
return clone;
}
protected void copyValues(DeltaMapTriple<K,V> clone, Cloner<Entry<K, V>> cloner) {
clone.zeroMap = cloneSet(this.zeroMap, cloner);
clone.plusMap = cloneSet(this.plusMap, cloner);
clone.minusMap = cloneSet(this.minusMap, cloner);
}
private Map<K,V> cloneSet(Map<K,V> origSet, Cloner<Entry<K, V>> cloner) {
if (origSet == null) {
return null;
}
Map<K,V> clonedSet = createMap();
for (Entry<K, V> origVal: origSet.entrySet()) {
Entry<K, V> clonedVal = cloner.clone(origVal);
clonedSet.put(clonedVal.getKey(), clonedVal.getValue());
}
return clonedSet;
}
public boolean isEmpty() {
return isEmpty(minusMap) && isEmpty(plusMap) && isEmpty(zeroMap);
}
private boolean isEmpty(Map<K,V> set) {
if (set == null) {
return true;
}
return set.isEmpty();
}
@Override
public void accept(SimpleVisitor<Entry<K, V>> visitor) {
acceptMap(visitor, zeroMap);
acceptMap(visitor, plusMap);
acceptMap(visitor, minusMap);
}
private void acceptMap(SimpleVisitor<Entry<K, V>> visitor, Map<K,V> set) {
if (set == null) {
return;
}
for (Entry<K, V> element: set.entrySet()) {
visitor.visit(element);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(debugName()).append("(");
dumpMap(sb, "zero", zeroMap);
dumpMap(sb, "plus", plusMap);
dumpMap(sb, "minus", minusMap);
sb.append(")");
return sb.toString();
}
protected String debugName() {
return "DeltaMapTriple";
}
private void dumpMap(StringBuilder sb, String label, Map<K,V> set) {
sb.append(label).append(": ").append(set).append("; ");
}
/* (non-Javadoc)
* @see com.evolveum.midpoint.util.DebugDumpable#debugDump()
*/
@Override
public String debugDump() {
return debugDump(0);
}
/* (non-Javadoc)
* @see com.evolveum.midpoint.util.DebugDumpable#debugDump(int)
*/
@Override
public String debugDump(int indent) {
StringBuilder sb = new StringBuilder();
DebugUtil.indentDebugDump(sb, indent);
sb.append("DeltaSetTriple:\n");
debugDumpMap(sb, "zero", zeroMap, indent + 1);
sb.append("\n");
debugDumpMap(sb, "plus", plusMap, indent + 1);
sb.append("\n");
debugDumpMap(sb, "minus", minusMap, indent + 1);
return sb.toString();
}
private void debugDumpMap(StringBuilder sb, String label, Map<K,V> set, int indent) {
DebugUtil.debugDumpLabel(sb, label, indent);
sb.append("\n");
DebugUtil.debugDumpMapMultiLine(sb, set, indent + 1);
}
}