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. The item with the most sources should be the parent as it's
* likely to provide the fastest download.
*/
private VisualSearchResult findParent(VisualSearchResult o1, VisualSearchResult o2) {
VisualSearchResult parent1 = o1.getSimilarityParent();
VisualSearchResult parent2 = o2.getSimilarityParent();
int o1Count = o1.getSources().size();
int o2Count = o2.getSources().size();
int parent1Count = parent1 == null ? 0 : parent1.getSources().size();
int parent2Count = parent2 == null ? 0 : parent2.getSources().size();
// Parents should not have parents of their own
assert(parent1 == null || parent1.getSimilarityParent() == null);
assert(parent2 == null || parent2.getSimilarityParent() == null);
// Find the result with the highest count - if we're in the process of
// regrouping results, a child may have a higher count than its parent
if(parent2Count > parent1Count && parent2Count > o2Count &&
parent2Count > o1Count) {
return parent2;
} else if(parent1Count > o2Count && parent1Count > o1Count) {
return parent1;
} else if(o2Count > o1Count) {
return o2;
} else if(o1Count > o2Count) {
return o1;
}
// All the results have equal counts; keep the current parent (if any)
if(parent1 != null) {
return parent1;
} else if(parent2 != null) {
return parent2;
} else {
return o1; // Doesn't matter whether we return o1 or o2
}
}
}