blob: d18076cb38aa5d51b2b4c0ed11427d7f2ad148e4 [file] [log] [blame]
package net.sf.taverna.biocatalogue.model.search;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import net.sf.taverna.biocatalogue.model.LoadingResource;
import net.sf.taverna.biocatalogue.model.Resource.TYPE;
import net.sf.taverna.biocatalogue.model.connectivity.BeansForJSONLiteAPI;
import net.sf.taverna.biocatalogue.model.connectivity.BeansForJSONLiteAPI.ResourceIndex;
import net.sf.taverna.biocatalogue.model.connectivity.BeansForJSONLiteAPI.ResourceLinkWithName;
import org.apache.log4j.Logger;
import org.biocatalogue.x2009.xml.rest.ResourceLink;
/**
* Generic class for any kinds of search results.
*
* @author Sergejs Aleksejevs
*/
public class SearchResults implements Serializable
{
private static final long serialVersionUID = 6994685875323246165L;
private transient Logger logger; // don't want to serialise the logger...
private final TYPE typeOfResourcesInTheResultSet;
private final int totalResultCount;
// Data store for found items
protected ArrayList<ResourceLink> foundItems;
private int fullyFetchedItemCount;
public SearchResults(TYPE typeOfResourcesInTheResultSet, BeansForJSONLiteAPI.ResourceIndex resourceIndex)
{
this.typeOfResourcesInTheResultSet = typeOfResourcesInTheResultSet;
this.totalResultCount = resourceIndex.getResources().length;
this.fullyFetchedItemCount = 0;
this.logger = Logger.getLogger(this.getClass());
initialiseSearchResultCollection(resourceIndex);
}
/**
* The collection of results is initialised to cater for the expected number of
* values - placeholder with just a name and URL for each of the expected result entries is stored.
*
* @param resourceIndex
*/
protected void initialiseSearchResultCollection(ResourceIndex resourceIndex)
{
foundItems = new ArrayList<ResourceLink>();
foundItems.ensureCapacity(getTotalMatchingItemCount());
ResourceLinkWithName resourceLink = null;
for (int i = 0; i < getTotalMatchingItemCount(); i++) {
resourceLink = resourceIndex.getResources()[i];
this.foundItems.add(new LoadingResource(resourceLink.getURL(), resourceLink.getName()));
}
}
public synchronized void addSearchResults(List<ResourceLink> searchResultsData, int positionToStartAddingResults)
{
// only update a specific portion of results
for (int i = 0; i < searchResultsData.size(); i++) {
this.foundItems.set(i + positionToStartAddingResults, searchResultsData.get(i));
}
fullyFetchedItemCount += searchResultsData.size();
}
public TYPE getTypeOfResourcesInTheResultSet() {
return typeOfResourcesInTheResultSet;
}
/**
* @return List of resources that have matched the search query
* and/or specified filtering criteria.
*/
public List<ResourceLink> getFoundItems() {
return (this.foundItems);
}
/**
* @return Number of resources that have matched the search query
* (and/or specified filtering criteria) that have already been
* fetched.
*/
public int getFetchedItemCount() {
return (this.fullyFetchedItemCount);
}
/**
* @return Total number of resources that have matched the search query
* (and/or specified filtering criteria) - most of these will
* likely not be fetched yet.
*/
public int getTotalMatchingItemCount() {
return (this.totalResultCount);
}
/**
* @return Total number of pages in the current result set.
*/
public int getTotalResultPageNumber() {
int numberOfResourcesPerPageForThisResourceType = this.getTypeOfResourcesInTheResultSet().getApiResourceCountPerIndexPage();
return (int)(Math.ceil((double)getTotalMatchingItemCount() / numberOfResourcesPerPageForThisResourceType));
}
/**
* List of matching items will be partial and populated sequentially
* based on user actions. Therefore, this method helps to check
* which list entries are still not populated.
*
* @param startIndex Beginning of the range to check.
* @param endIndex End of the range to check.
* @return Zero-based index of the first entry in the list of
* matching resources that hasn't been fetched yet.
* Will return <code>-1</code> if the provided range
* parameters are incorrect or if all items in the
* specified range are already available.
*/
public int getFirstMatchingItemIndexNotYetFetched(int startIndex, int endIndex)
{
// check the specified range is correct
if (startIndex < 0 || endIndex > getTotalMatchingItemCount() - 1) {
return (-1);
}
// go through the search results in the specified range
// in an attempt to find an item that hasn't been fetched
// just yet
for (int i = startIndex; i <= endIndex; i++) {
ResourceLink item = this.foundItems.get(i);
if (item != null && item instanceof LoadingResource && !((LoadingResource)item).isLoading()) {
return (i);
}
}
// apparently, all items in the provided range are fetched
return (-1);
}
/**
* @param matchingItemIndex Index of the matching item from search results.
* @return Index (starting from "1") of page in the search results, where
* the matching item with a specified index is located. If the
* <code>matchingItemIndex</code> is wrong, <code>-1</code> is returned.
*/
public int getMatchingItemPageNumberFor(int matchingItemIndex)
{
// check the specified index is correct
if (matchingItemIndex < 0 || matchingItemIndex > getTotalMatchingItemCount() - 1) {
return (-1);
}
int resultsPerPageForThisType = this.getTypeOfResourcesInTheResultSet().getApiResourceCountPerIndexPage();
return (matchingItemIndex / resultsPerPageForThisType + 1);
}
/**
* @param resultPageNumber Number of the page, for which the calculations are to be done.
* @return Index of the first result entry on the specified result page. If <code>resultPageNumber</code>
* is less than <code>1</code> or greater than the total number of pages in the result set,
* a value of <code>-1</code> will be returned.
*/
public int getFirstItemIndexOn(int resultPageNumber)
{
// page number must be in a valid range - starting with 1..onwards
if (resultPageNumber < 1 || resultPageNumber > getTotalResultPageNumber()) {
return (-1);
}
int numberOfResourcesPerPageForThisResourceType = this.getTypeOfResourcesInTheResultSet().getApiResourceCountPerIndexPage();
return ((resultPageNumber - 1) * numberOfResourcesPerPageForThisResourceType);
}
/**
* Mainly for testing - outputs number of search results per item type.
*/
public String toString()
{
// FIXME
// StringBuilder out = new StringBuilder("Breakdown of item counts by type:\n");
// for (Map.Entry<Integer,String> itemTypeNamePair : Resource.ALL_SUPPORTED_RESOURCE_COLLECTION_NAMES.entrySet()) {
// out.append(itemTypeNamePair.getValue() + ": " +getFetchedItemCount(itemTypeNamePair.getKey()) +
// "/" + getTotalItemCount(itemTypeNamePair.getKey()) + "\n");
// }
//
// return (out.toString());
return ("search results... not implemented!!!");
}
}