package com.fatima.life2; import java.util.ArrayList; import java.util.Collections; import java.util.Set; import com.limegroup.gnutella.Endpoint; import com.limegroup.gnutella.RemoteFileDesc; import com.limegroup.gnutella.search.HostData; import com.limegroup.gnutella.util.ApproximateMatcher; import com.limegroup.gnutella.util.I18NConvert; /** * A single SearchResult. * * (A collection of RemoteFileDesc, HostData, and Set of alternate locations.) */ public final class P2pSearchResult extends SearchResult implements Comparable<P2pSearchResult> { private static final int MAX_RFD = 16; private ArrayList<RemoteFileDesc> RFD = new ArrayList<RemoteFileDesc>(); /** The processed version of the filename used for approximate matching. * Not allocated until a match must be done. The assumption here is that * all matches will use the same ApproximateMatcher. TODO3: when we move * to Java 1.3, this should be a weak reference so the memory is reclaimed * after GC. */ private String processedFilename = null; private final byte[] mGuid; private Set<Endpoint> alt; /** * Constructs a new SearchResult with the given data. */ public P2pSearchResult(byte[] guid, RemoteFileDesc rfd, HostData data, Set<Endpoint> alts) { mGuid = guid; if (alts.size() > 0) { if (alt == null) { alt = alts; } else { alt.addAll(alts); } } RFD.add(rfd); } public Set<Endpoint> getAlt () { if (alt == null) { return Collections.emptySet(); } else { return alt; } } public void add(RemoteFileDesc rfd) { if (RFD.size() >= MAX_RFD) return; RFD.add(rfd); } public byte[] getGuid() { return mGuid; } /** * Gets the size of this SearchResult. */ public int getSize() { int size = RFD.size(); if (alt != null) { size += alt.size(); } return size; } public RemoteFileDesc[] getRFDArray() { RemoteFileDesc[] rfds = new RemoteFileDesc[RFD.size()]; return (RemoteFileDesc[])RFD.toArray(rfds); } public RemoteFileDesc getFirstRFD() { return RFD.get(0); } public String getFileName() { return RFD.get(0).getFileName(); } public long getFileSize() { return RFD.get(0).getSize(); } /** * Gets the filename without the extension. */ private String getFilenameNoExtension() { String fullname = RFD.get(0).getFileName(); int i = fullname.lastIndexOf("."); if (i < 0) return fullname; return I18NConvert.instance().compose(fullname.substring(0,i)); } /** * Returns the extension of this result. */ private String getExtension() { String fullname = RFD.get(0).getFileName(); int i = fullname.lastIndexOf("."); if (i < 0) return ""; return fullname.substring(i+1); } /** * Gets the processed filename. */ private String getProcessedFilename(ApproximateMatcher matcher) { if (processedFilename != null) return processedFilename; processedFilename = matcher.process(getFilenameNoExtension()); return processedFilename; } /** * Compares this against o approximately: * <ul> * <li> Returns 0 if o is similar to this. * <li> Returns 1 if they have non-similar extensions. * <li> Returns 2 if they have non-similar sizes. * <li> Returns 3 if they have non-similar names. * <ul> * * Design note: this takes an ApproximateMatcher as an argument so that many * comparisons may be done with the same matcher, greatly reducing the * number of allocations.<b> * * <b>This method is not thread-safe.</b> */ public int match(P2pSearchResult o, final ApproximateMatcher matcher) { //Same file type? if (!getExtension().equals(o.getExtension())) return 1; long thisSize = getSize(); long thatSize = o.getSize(); // Sizes same? if (thisSize != thatSize) return 2; //Preprocess the processed fileNames getProcessedFilename(matcher); o.getProcessedFilename(matcher); //Filenames close? This is the most expensive test, so it should go //last. Allow 5% edit difference in filenames or 4 characters, //whichever is smaller. int allowedDifferences = Math.round(Math.min( 0.10f*((float)getFilenameNoExtension().length()), 0.10f*((float)o.getFilenameNoExtension().length()))); allowedDifferences = Math.min(allowedDifferences, 4); if (!matcher.matches(getProcessedFilename(matcher), o.getProcessedFilename(matcher), allowedDifferences)) return 3; return 0; } @Override public int compareTo(P2pSearchResult arg0) { return arg0.getSize() - getSize(); } }