package jetbrains.mps.lang.test.matcher;
/*Generated by MPS */
import java.util.Map;
import org.jetbrains.mps.openapi.model.SNode;
import java.util.HashMap;
import java.util.List;
import java.util.Collections;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.HashSet;
import org.jetbrains.mps.openapi.language.SContainmentLink;
import org.jetbrains.mps.openapi.language.SReferenceLink;
import org.jetbrains.mps.openapi.model.SReference;
import org.jetbrains.mps.openapi.language.SProperty;
public final class NodesMatcher {
private final Map<SNode, SNode> map;
public NodesMatcher() {
map = new HashMap<SNode, SNode>();
// FIXME refactor to use instances instead of static method
}
public NodesMatcher(Map<SNode, SNode> map) {
this.map = map;
}
public Map<SNode, SNode> getMap() {
// I don't quite understand what's the map we either populate and use, or just use.
// why matchNodes(node,node) goes through matchNodes(list,list), creates and populates map,
// while matchNodes(node,node,map) does not populate the map
// Once I understand what map is, I can give method better name
return map;
}
/**
*
* @deprecated use instance method
*/
@Deprecated
public static NodeDifference matchNodes(SNode a, SNode b) {
List<SNode> aList = Collections.singletonList(a);
List<SNode> bList = Collections.singletonList(b);
// for whatever reason match(SNode,SNode) just reads map, while match(list<node>, list<node>) populates map first
List<NodeDifference> diffs = new NodesMatcher().match(aList, bList);
if (diffs != null) {
return diffs.get(0);
} else {
return null;
}
}
/**
*
* @deprecated use instance method
*/
@Deprecated
public static ArrayList<NodeDifference> matchNodes(List<SNode> a, List<SNode> b) {
return NodesMatcher.matchNodes(a, b, new HashMap<SNode, SNode>());
}
public List<NodeDifference> match(List<SNode> a, List<SNode> b) {
Iterator<SNode> iteratorA = a.iterator();
Iterator<SNode> iteratorB = b.iterator();
while (iteratorA.hasNext() && iteratorB.hasNext()) {
populateMap(iteratorA.next(), iteratorB.next());
}
ArrayList<NodeDifference> ret = new ArrayList<NodeDifference>();
iteratorA = a.iterator();
iteratorB = b.iterator();
while (iteratorA.hasNext() && iteratorB.hasNext()) {
NodeDifference diff = match(iteratorA.next(), iteratorB.next());
if (diff != null) {
ret.add(diff);
}
}
return (ret.isEmpty() ? null : ret);
}
/**
*
* @deprecated use instance method instead
*/
@Deprecated
public static ArrayList<NodeDifference> matchNodes(List<SNode> a, List<SNode> b, Map<SNode, SNode> map) {
NodesMatcher nm = new NodesMatcher(map);
List<NodeDifference> rv = nm.match(a, b);
return (rv == null ? null : new ArrayList<NodeDifference>(rv));
}
private void populateMap(SNode a, SNode b) {
if (!(a.getConcept().equals(b.getConcept()))) {
return;
}
HashSet<SContainmentLink> roles = new HashSet<SContainmentLink>();
for (SNode child : a.getChildren()) {
roles.add(child.getContainmentLink());
}
for (SNode child : b.getChildren()) {
roles.add(child.getContainmentLink());
}
for (SContainmentLink role : roles) {
Iterator<? extends SNode> iterator1 = a.getChildren(role).iterator();
Iterator<? extends SNode> iterator2 = b.getChildren(role).iterator();
while (iterator1.hasNext() && iterator2.hasNext()) {
populateMap(iterator1.next(), iterator2.next());
}
}
map.put(a, b);
}
public NodeDifference match(SNode a, SNode b) {
ArrayList<DifferenceItem> difference = new ArrayList<DifferenceItem>();
if (matchConcepts(a, b, difference)) {
return new NodeDifference(a.getPresentation(), difference);
}
matchProperties(a, b, difference);
matchChildren(a, b, difference);
matchReferences(a, b, difference);
if (difference.size() != 0) {
return new NodeDifference(a.getPresentation(), difference);
}
return null;
}
/**
*
* @deprecated use instance method instead
*/
@Deprecated
public static NodeDifference matchNodes(SNode a, SNode b, Map<SNode, SNode> map) {
return new NodesMatcher(map).match(a, b);
}
private boolean matchConcepts(SNode a, SNode b, ArrayList<DifferenceItem> difference) {
if (!(a.getConcept().equals(b.getConcept()))) {
difference.add(new ConceptDifference(a.getConcept(), b.getConcept()));
return true;
}
return false;
}
private void matchReferences(SNode a, SNode b, ArrayList<DifferenceItem> difference) {
HashSet<SReferenceLink> roles = new HashSet<SReferenceLink>();
for (SReference nextReference : a.getReferences()) {
roles.add(nextReference.getLink());
}
for (SReference nextReference : b.getReferences()) {
roles.add(nextReference.getLink());
}
for (SReferenceLink role : roles) {
SReference reference1 = a.getReference(role);
SNode referenceTarget1 = null;
if (reference1 != null) {
referenceTarget1 = reference1.getTargetNode();
}
SReference reference2 = b.getReference(role);
SNode referenceTarget2 = null;
if (reference2 != null) {
referenceTarget2 = reference2.getTargetNode();
}
if (map.containsKey(referenceTarget1)) {
if (map.get(referenceTarget1) != referenceTarget2) {
difference.add(new ReferenceDifference(role, true, map.get(referenceTarget1), referenceTarget2));
}
} else {
if (referenceTarget1 != referenceTarget2) {
difference.add(new ReferenceDifference(role, false, referenceTarget1, referenceTarget2));
}
}
}
}
private static int countElements(Iterator<?> it) {
int counter = 0;
while (it.hasNext()) {
it.next();
counter++;
}
return counter;
}
private void matchChildren(SNode a, SNode b, ArrayList<DifferenceItem> difference) {
HashSet<SContainmentLink> roles = new HashSet<SContainmentLink>();
for (SNode child : a.getChildren()) {
roles.add(child.getContainmentLink());
}
for (SNode child : b.getChildren()) {
roles.add(child.getContainmentLink());
}
for (SContainmentLink role : roles) {
Iterable<? extends SNode> children1 = a.getChildren(role);
Iterable<? extends SNode> children2 = b.getChildren(role);
int size1 = countElements(children1.iterator());
int size2 = countElements(children2.iterator());
if (size1 != size2) {
difference.add(new ChildrenCountDifference(role, size1, size2));
continue;
}
Iterator<? extends SNode> iterator1 = children1.iterator();
Iterator<? extends SNode> iterator2 = children2.iterator();
while (iterator1.hasNext() && iterator2.hasNext()) {
NodeDifference d = match(iterator1.next(), iterator2.next());
if (d != null) {
difference.add(d);
}
}
}
}
private void matchProperties(SNode a, SNode b, ArrayList<DifferenceItem> difference) {
HashSet<SProperty> properties = new HashSet<SProperty>();
for (SProperty p : a.getProperties()) {
properties.add(p);
}
for (SProperty p : b.getProperties()) {
properties.add(p);
}
for (SProperty key : properties) {
String p1 = a.getProperty(key);
String p2 = b.getProperty(key);
if (p1 == null && "false".equals(p2)) {
continue;
}
if (p2 == null && "false".equals(p1)) {
continue;
}
if (p1 == null || p2 == null || !(p1.equals(p2))) {
difference.add(new PropertyDifference(key, p1, p2));
}
}
}
}