/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.cpd;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class MatchCollector {
private List<Match> matchList = new ArrayList<>();
private Map<Integer, Map<Integer, Match>> matchTree = new TreeMap<>();
private MatchAlgorithm ma;
public MatchCollector(MatchAlgorithm ma) {
this.ma = ma;
}
public void collect(List<TokenEntry> marks) {
// first get a pairwise collection of all maximal matches
for (int i = 0; i < marks.size() - 1; i++) {
TokenEntry mark1 = marks.get(i);
for (int j = i + 1; j < marks.size(); j++) {
TokenEntry mark2 = marks.get(j);
int diff = mark1.getIndex() - mark2.getIndex();
if (-diff < ma.getMinimumTileSize()) {
continue;
}
if (hasPreviousDupe(mark1, mark2)) {
continue;
}
// "match too small" check
int dupes = countDuplicateTokens(mark1, mark2);
if (dupes < ma.getMinimumTileSize()) {
continue;
}
// is it still too close together
if (diff + dupes >= 1) {
continue;
}
reportMatch(mark1, mark2, dupes);
}
}
}
private void reportMatch(TokenEntry mark1, TokenEntry mark2, int dupes) {
Map<Integer, Match> matches = matchTree.get(dupes);
if (matches == null) {
matches = new TreeMap<>();
matchTree.put(dupes, matches);
addNewMatch(mark1, mark2, dupes, matches);
} else {
Match matchA = matchTree.get(dupes).get(mark1.getIndex());
Match matchB = matchTree.get(dupes).get(mark2.getIndex());
if (matchA == null && matchB == null) {
addNewMatch(mark1, mark2, dupes, matches);
} else if (matchA == null) {
matchB.addTokenEntry(mark1);
matches.put(mark1.getIndex(), matchB);
} else if (matchB == null) {
matchA.addTokenEntry(mark2);
matches.put(mark2.getIndex(), matchA);
}
}
}
private void addNewMatch(TokenEntry mark1, TokenEntry mark2, int dupes, Map<Integer, Match> matches) {
Match match = new Match(dupes, mark1, mark2);
matches.put(mark1.getIndex(), match);
matches.put(mark2.getIndex(), match);
matchList.add(match);
}
@SuppressWarnings("PMD.CompareObjectsWithEquals")
public List<Match> getMatches() {
Collections.sort(matchList);
return matchList;
}
private boolean hasPreviousDupe(TokenEntry mark1, TokenEntry mark2) {
if (mark1.getIndex() == 0) {
return false;
}
return !matchEnded(ma.tokenAt(-1, mark1), ma.tokenAt(-1, mark2));
}
private int countDuplicateTokens(TokenEntry mark1, TokenEntry mark2) {
int index = 0;
while (!matchEnded(ma.tokenAt(index, mark1), ma.tokenAt(index, mark2))) {
index++;
}
return index;
}
private boolean matchEnded(TokenEntry token1, TokenEntry token2) {
return token1.getIdentifier() != token2.getIdentifier() || token1 == TokenEntry.EOF || token2 == TokenEntry.EOF;
}
}