package org.limewire.ui.swing.search.model;
import org.limewire.logging.Log;
import org.limewire.logging.LogFactory;
public abstract class AbstractSimilarResultsDetector implements SimilarResultsDetector {
private static final Log LOG = LogFactory.getLog(AbstractSimilarResultsDetector.class);
/**
* Finds the parent correlating the two searchResults and then moves these
* search results under that parent. Then updates the visibility of these
* items based on their parents visibilities.
*
* Returns the parent chosen for these search results.
*/
protected VisualSearchResult update(VisualSearchResult o1, VisualSearchResult o2) {
VisualSearchResult parent = findParent(o1, o2);
boolean childrenVisible = o1.isChildrenVisible() || o2.isChildrenVisible()
|| parent.isChildrenVisible() || o1.getSimilarityParent() != null
&& o1.getSimilarityParent().isChildrenVisible() || o2.getSimilarityParent() != null
&& o2.getSimilarityParent().isChildrenVisible()
|| parent.getSimilarityParent() != null
&& parent.getSimilarityParent().isChildrenVisible();
updateParent(o1.getSimilarityParent(), parent);
updateParent(o1, parent);
updateParent(o2.getSimilarityParent(), parent);
updateParent(o2, parent);
updateVisibility(parent, childrenVisible);
return parent;
}
/**
* Update visibilities of newly changed parents.
*/
private void updateVisibility(VisualSearchResult parent, final boolean childrenVisible) {
if(LOG.isDebugEnabled()) {
LOG.debugf("Setting child visibility for {0} to {1}", parent.getCoreSearchResults().get(0).getUrn(), childrenVisible);
}
parent.setVisible(true);
parent.setChildrenVisible(childrenVisible);
}
/**
* Updates the child to use the given parent. The parent is set, the
* children are moved, and the visibility is copied. Also the given child is
* checked to see if it already has a parent, if so its parent is also
* updated to be a child of the given parent.
*/
private void updateParent(VisualSearchResult child, VisualSearchResult parent) {
parent.setSimilarityParent(null);
if (child != null && child != parent) {
child.setSimilarityParent(parent);
parent.addSimilarSearchResult(child);
moveChildren(child, parent);
}
}
/**
* Moves the children from the child to the parent.
*/
private void moveChildren(VisualSearchResult child, VisualSearchResult parent) {
child.removeSimilarSearchResult(parent);
for (VisualSearchResult item : child.getSimilarResults()) {
updateParent(item, parent);
child.removeSimilarSearchResult(item);
if(parent != item) {
parent.addSimilarSearchResult(item);
}
}
}
/**
* Returns which item should be the parent between the two similar search
* results. Currently the item with the most sources, is considered the
* parent.
*/
private VisualSearchResult findParent(VisualSearchResult o1, VisualSearchResult o2) {
VisualSearchResult parent = null;
VisualSearchResult parent1 = o1;
VisualSearchResult parent2 = o2;
VisualSearchResult parent3 = o1.getSimilarityParent();
VisualSearchResult parent4 = o2.getSimilarityParent();
int parent1Count = parent1 == null ? 0 : parent1.getRelevance();
int parent2Count = parent2 == null ? 0 : parent2.getRelevance();
int parent3Count = parent3 == null ? 0 : parent3.getRelevance();
int parent4Count = parent4 == null ? 0 : parent4.getRelevance();
if (parent4Count > parent3Count && parent4Count > parent2Count
&& parent4Count > parent1Count) {
parent = parent4;
} else if (parent3Count > parent2Count && parent3Count > parent1Count) {
parent = parent3;
} else if (parent2Count > parent1Count) {
parent = parent2;
} else if (parent1Count > parent2Count) {
parent = parent1;
} else {
// keep current parent the parent
// makes it easier to predict when testing
if (parent1 != null && parent1.getSimilarityParent() == null) {
parent = parent1;
} else if (parent2 != null && parent2.getSimilarityParent() == null) {
parent = parent2;
} else if (parent3 != null && parent3.getSimilarityParent() == null) {
parent = parent3;
} else if (parent4 != null && parent4.getSimilarityParent() == null) {
parent = parent4;
} else {
parent = parent1;
}
}
return parent;
}
}