package com.limegroup.gnutella.search;
import org.limewire.collection.IntervalSet;
import org.limewire.collection.Range;
import com.limegroup.gnutella.URN;
/**
* Used to track the search results of a given URN. A single search will result
* in multiple URNs, and this class will track the total number of locations
* from which that URN is available including both whole and partial results.
*
*/
public class ResourceLocationCounter {
/**
* Size of the file.
*/
private final long _fileSize;
/**
* Temporary solution for our simplistic implementation of counting
* partial sources. We "compact" all of the partial search results into
* this interval set and when it is matches the size of the file, then
* no more computation is necessary.
*/
private final IntervalSet _psets = new IntervalSet();
/**
* The number of locations for which the entire file can
* be found.
*/
private int _wholeCount = 0;
/**
*
*/
private int _displayCount = 0;
/**
* The number of complete locations available based on
* all of the partial results that we know of.
*/
private int _partialCount = 0;
/**
* This value represent the percentage of the data that
* is available, up to 100%.
*/
private float _percentAvailable = 0.0f;
/**
* Creates a new instance for the given URN.
*
* @param urn The URN we are tracking
* @param fileSize The size of the file represented by the URN
*/
public ResourceLocationCounter (URN urn, long fileSize) {
if (fileSize < 0)
throw new IllegalArgumentException("fileSize may not be negative: " + fileSize);
_fileSize = fileSize;
}
/**
* When a search result is received the interval set data can be added to
* the results via addIntervalSet.
*
* @param is The ranges this source has.
*/
public void addPartialSource (IntervalSet is) {
synchronized (this) {
_psets.add( is );
}
calculateLocationCount();
}
/**
* Increments the count of complete (ie, non-partial) search
* results for the given URN.
*/
public void incrementWholeSources () {
synchronized (this) {
_wholeCount++;
_percentAvailable = 100;
}
}
/**
*
* @param num the amount by which to increase the display count
*/
public void updateDisplayLocationCount (int num) {
synchronized (this) {
_displayCount += num;
}
}
/**
* Combines the whole and partial result counts and returns the total
* number of locations from which this URN can be accessed.
*
* @return Number of locations from which this URN is available
*/
public int getLocationCount () {
synchronized (this) {
return _wholeCount + _partialCount;
}
}
/**
*
* @return the number of locations to display.
*/
public int getDisplayLocationCount () {
return _displayCount;
}
/**
* Returns the percentage of the data for the URN that is available. If
* whole count is >= 1 or the partial count is >= 1, then the return value
* is 100. The return value should not exceed 100.
*
* @return The percentage of the file that is accessible on the network
*/
public float getPercentAvailable () {
synchronized (this) {
return _percentAvailable;
}
}
/**
* Determine the percentage of the file that is accessible via the partial
* search results.
*
* If the entire file is available, then _partialCount will be set to 1;
* otherwise 0.
*/
private void calculateLocationCount () {
synchronized (this) {
long sum = 0;
if (_psets.getNumberOfIntervals() == 0) {
_partialCount = 0;
_percentAvailable = _wholeCount > 0 ? 100.0f : 0.0f;
return;
}
// if the flattened interval set contains the entire
// range for the file, then we have enough sources
// to obtain the entire file.
//
if (_psets.contains(Range.createRange(0, _fileSize-1))) {
_partialCount = 1;
_percentAvailable = 100.0f;
return;
}
// sum the amount of the file represented by this
// flattened interval set. we must add the +1
// because the range is inclusive and not strictly
// the difference between the two points of the
// range.
//
for (Range range : _psets.getAllIntervalsAsList()) {
sum += (range.getHigh() - range.getLow()) + 1;
}
_partialCount = 0;
// if the total number of bytes available in the
// partial search result is greater than zero, then
// determine what percentage of the file is available,
// rounding appropriately and if it rounds down to
// zero, set it to 1%.
//
if (sum > 0)
_percentAvailable = sum * 100f / _fileSize;
else
_percentAvailable = 0.0f;
}
}
}