package com.sap.ide.refactoring.core.reference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import com.sap.mi.textual.grammar.impl.DelayedReference;
import com.sap.tc.moin.repository.mmi.reflect.RefObject;
/**
* Log of all reference re-evaluations. Besides simple storing those, this class
* compresses log entries by tracking the current binding state.
*
* e.g. property set, property unset, property unset results is: FROM_BOUND_TO_FREE
*
* @author Stephan Erb (d049157)
*
*/
public class CompressingReEvaluationLog {
private static class InternalLogEntry {
private final DelayedReference ref;
private final RefObject modelElement;
private Object originalValue = null;
private Object currentValue = null;
private ReEvaluationType type;
public InternalLogEntry(DelayedReference ref, Object value, ReEvaluationType type) {
this.ref = ref;
this.type = type;
this.modelElement = (RefObject) ref.getModelElement();
switch (type) {
case FROM_BOUND_TO_FREE:
originalValue = value;
currentValue = null;
break;
case FROM_FREE_TO_BOUND:
originalValue = null;
currentValue = value;
break;
default:
throw new IllegalArgumentException(type + " is only meant for internal use");
}
}
@Override
public String toString() {
return asReadOnlyReEvaluationInfo().toString();
}
public void merge(InternalLogEntry latestOtherEntry) {
if (!latestOtherEntry.equals(this)) {
throw new IllegalArgumentException("Give does not match the current one");
}
this.currentValue = latestOtherEntry.currentValue;
if (originalValue != null && currentValue == null) {
type = ReEvaluationType.FROM_BOUND_TO_FREE;
} else if (originalValue == null && currentValue != null) {
type = ReEvaluationType.FROM_FREE_TO_BOUND;
} else if (currentValue.equals(originalValue)) {
type = ReEvaluationType.REBOUND_TO_SAME;
} else {
type = ReEvaluationType.REBOUND_TO_OTHER;
}
}
public ReEvaluationInfo asReadOnlyReEvaluationInfo() {
return new ReEvaluationInfo(ref, modelElement, originalValue, currentValue, type);
}
}
/**
* Key: ModelElement;
* Value: Map of PropertyName to Re-Evaluation state;
*/
private final HashMap<RefObject, HashMap<String, InternalLogEntry>> logEntries = new HashMap<RefObject, HashMap<String, InternalLogEntry>>();
public void log(DelayedReference ref, Object value, ReEvaluationType type) {
InternalLogEntry newEntry = new InternalLogEntry(ref, value, type);
InternalLogEntry existingEntry = findMatchingExistingLogEntryFor(newEntry);
if (existingEntry == null) {
storeInLog(newEntry);
} else {
existingEntry.merge(newEntry);
}
}
private void storeInLog(InternalLogEntry newEntry) {
if (!logEntries.containsKey(newEntry.ref.getModelElement())) {
logEntries.put(newEntry.modelElement, new HashMap<String, InternalLogEntry>());
}
logEntries.get(newEntry.modelElement).put(newEntry.ref.getPropertyName(), newEntry);
}
private InternalLogEntry findMatchingExistingLogEntryFor(InternalLogEntry newEntry) {
if (!logEntries.containsKey(newEntry.modelElement)) {
return null;
} else {
return logEntries.get(newEntry.modelElement).get(newEntry.ref.getPropertyName());
}
}
public Collection<ReEvaluationInfo> getLoggedReEvaluations() {
ArrayList<ReEvaluationInfo> reevaluations = new ArrayList<ReEvaluationInfo>();
for (HashMap<String, InternalLogEntry> entries : logEntries.values()) {
for (InternalLogEntry entry : entries.values()) {
reevaluations.add(entry.asReadOnlyReEvaluationInfo());
}
}
return reevaluations;
}
}