/*
* This is eMonocot, a global online biodiversity information resource.
*
* Copyright © 2011–2015 The Board of Trustees of the Royal Botanic Gardens, Kew and The University of Oxford
*
* eMonocot is free software: you can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* eMonocot is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* The complete text of the GNU Affero General Public License is in the source repository as the file
* ‘COPYING’. It is also available from <http://www.gnu.org/licenses/>.
*/
package org.emonocot.pager;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.RangeFacet;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author ben
*
* @param <T>
*/
public abstract class AbstractPageImpl<T> implements Page<T>, Serializable {
private static long serialVersionUID = 3235700796905201107L;
protected static Integer MAX_PAGE_LABELS = 3;
protected static String LABEL_DIVIDER = " - ";
private static Logger logger = LoggerFactory
.getLogger(AbstractPageImpl.class);
private Map<String, Object> parameters = new HashMap<String, Object>();
private Integer pagesAvailable;
private Integer prevIndex;
private Integer nextIndex;
private Integer currentIndex;
private Integer firstRecord;
private Integer lastRecord;
private Integer size;
private List<T> records;
private Integer pageSize;
private QueryResponse queryResponse = null;
private Map<Integer, String> pageNumbers;
private ArrayList<Integer> indices;
private Map<String, String> selectedFacets
= new HashMap<String, String>();
private String sort;
private String suggestedSpelling = null;
private boolean correctlySpelled = true;
/**
* Constructor.
*
* @param newCurrentIndex
* the page of this result set (0-based), can be null
* @param count
* the total number of results available for this query
* @param newPageSize
* The size of pages (can be null if all results should be
* returned if available)
* @param newRecords
* A list of objects in this page (can be empty if there were no
* results)
*/
public AbstractPageImpl(Integer count, Integer newCurrentIndex,
Integer newPageSize, List<T> newRecords, QueryResponse queryResponse) {
if (newCurrentIndex != null) {
this.currentIndex = newCurrentIndex;
} else {
this.currentIndex = 0;
}
this.queryResponse = queryResponse;
this.pageSize = newPageSize;
this.pageNumbers = new HashMap<Integer, String>();
indices = new ArrayList<Integer>();
if (count == 0) {
pagesAvailable = 1;
} else if (newPageSize != null) {
if (0 == count % newPageSize) {
pagesAvailable = count / newPageSize;
Integer labelsStart = 0;
if (this.currentIndex > AbstractPageImpl.MAX_PAGE_LABELS) {
labelsStart = this.currentIndex
- AbstractPageImpl.MAX_PAGE_LABELS;
}
Integer labelsEnd = pagesAvailable.intValue();
if ((pagesAvailable - this.currentIndex)
> AbstractPageImpl.MAX_PAGE_LABELS) {
labelsEnd = this.currentIndex
+ AbstractPageImpl.MAX_PAGE_LABELS;
}
for (int index = labelsStart; index < labelsEnd; index++) {
indices.add(index);
String startLabel = getLabel(index * pageSize);
String endLabel = getLabel(((index + 1) * pageSize) - 1);
pageNumbers.put(index, createLabel(startLabel, endLabel));
}
} else {
pagesAvailable = (count / newPageSize) + 1;
Integer labelsStart = 0;
if (this.currentIndex > AbstractPageImpl.MAX_PAGE_LABELS) {
labelsStart = this.currentIndex
- AbstractPageImpl.MAX_PAGE_LABELS;
}
Integer labelsEnd = pagesAvailable.intValue();
if ((pagesAvailable - this.currentIndex)
> AbstractPageImpl.MAX_PAGE_LABELS) {
labelsEnd = this.currentIndex
+ AbstractPageImpl.MAX_PAGE_LABELS;
for (int index = labelsStart; index < labelsEnd; index++) {
indices.add(index);
String startLabel = getLabel(index * pageSize);
String endLabel =
getLabel(((index + 1) * pageSize) - 1);
pageNumbers.put(index,
createLabel(startLabel, endLabel));
}
} else {
for (int index = labelsStart;
index < (labelsEnd - 1); index++) {
indices.add(index);
String startLabel = getLabel(index * pageSize);
String endLabel
= getLabel(((index + 1) * pageSize) - 1);
pageNumbers.put(index,
createLabel(startLabel, endLabel));
}
indices.add(pagesAvailable.intValue() - 1);
String startLabel = getLabel((pagesAvailable.intValue() - 1)
* pageSize);
String endLabel = getLabel(count.intValue() - 1);
pageNumbers.put(pagesAvailable.intValue() - 1,
createLabel(startLabel, endLabel));
}
}
} else {
pagesAvailable = 1;
}
if (pagesAvailable == 1) {
nextIndex = null;
prevIndex = null;
} else {
if (0 < this.currentIndex) {
prevIndex = this.currentIndex - 1;
}
if (this.currentIndex < (pagesAvailable - 1)) {
nextIndex = this.currentIndex + 1;
}
}
if (newPageSize == null) {
this.firstRecord = 1;
this.lastRecord = newRecords.size();
} else {
this.firstRecord = (this.currentIndex * newPageSize) + 1;
this.lastRecord = (this.currentIndex * newPageSize)
+ newRecords.size();
}
this.size = count;
this.records = newRecords;
if(this.queryResponse != null && this.queryResponse.getSpellCheckResponse() != null) {
if(this.queryResponse.getSpellCheckResponse().getCollatedResults() != null &&
this.queryResponse.getSpellCheckResponse().getCollatedResults().size() != 0) {
this.suggestedSpelling = this.queryResponse.getSpellCheckResponse().getCollatedResults().get(0).getCollationQueryString();
}
}
if(this.queryResponse != null && this.queryResponse.getSpellCheckResponse() != null) {
this.correctlySpelled = this.queryResponse.getSpellCheckResponse().isCorrectlySpelled();
}
}
/**
*
* @return the number of pages available
*/
public Integer getPagesAvailable() {
return pagesAvailable;
}
/**
*
* @return the index of the next page
*/
public Integer getNextIndex() {
return nextIndex;
}
/**
*
* @return the index of the previous page
*/
public Integer getPrevIndex() {
return prevIndex;
}
/**
*
* @return the index of this page
*/
public Integer getCurrentIndex() {
return currentIndex;
}
@JsonIgnore
public String getCurrentPageNumber() {
return this.pageNumbers.get(currentIndex);
}
/**
*
* @return the total number of objects available.
*/
public Integer getSize() {
return size;
}
/**
*
* @return the index of the first record in this result set
*/
public Integer getFirstRecord() {
return firstRecord;
}
/**
*
* @return the index of the last record in this result set
*/
public Integer getLastRecord() {
return lastRecord;
}
/**
*
* @return the records in this page
*/
public List<T> getRecords() {
return records;
}
/**
*
* @return the page size
*/
public Integer getPageSize() {
return pageSize;
}
/**
* @return a map of the calculated facets
*/
@JsonIgnore
public FacetField getFacetField(String facetName) {
return queryResponse.getFacetField(facetName);
}
@JsonIgnore
public RangeFacet getRangeFacet(String facetName) {
for(RangeFacet rangeFacet : queryResponse.getFacetRanges()) {
if(rangeFacet.getName().equals(facetName)) {
return rangeFacet;
}
}
return null;
}
/**
* @return a list of the calculated facet names
*/
@JsonIgnore
public List<String> getFacetNames() {
List<String> facetNames = new ArrayList<String>();
for(FacetField facetField : queryResponse.getFacetFields()) {
facetNames.add(facetField.getName());
}
for(RangeFacet facetRange : queryResponse.getFacetRanges()) {
facetNames.add(facetRange.getName());
}
Collections.sort(facetNames, new FacetNameComparator());
return facetNames;
}
/**
* @param name Set the parameter name
* @param value Set the parameter value
*/
@JsonIgnore
public void putParam(String name, Object value) {
this.parameters.put(name, value);
}
/**
* @return a map of the parameters
*/
public Map<String, Object> getParams() {
return parameters;
}
/**
* @return the parameter names
*/
@JsonIgnore
public Set<String> getParamNames() {
return parameters.keySet();
}
/**
* @param index set the page number
* @return the label for a given page
*/
@JsonIgnore
public String getPageNumber(int index) {
return pageNumbers.get(index);
}
/**
*
* @param i set the index
* @return the label
*/
@JsonIgnore
protected String getLabel(Integer i) {
Integer label = new Integer(i + 1);
return label.toString();
}
/**
*
* @param startLabel Set the start label
* @param endLabel Set the end label
* @return a page label
*/
protected abstract String createLabel(String startLabel, String endLabel);
/**
*
* @return the list of indices for which we have a page label
*/
public List<Integer> getIndices() {
return indices;
}
/**
*
* @return a list of the names of selected facets
*/
@JsonIgnore
public Set<String> getSelectedFacetNames() {
return selectedFacets.keySet();
}
/**
*
* @return The index of the selected facet, or null if the facet is not
* selected
*/
public Map<String, String> getSelectedFacets() {
return selectedFacets;
}
/**
*
* @param facetName
* Set the facet name
* @return true if the facet is selected, false otherwise
*/
@JsonIgnore
public boolean isFacetSelected(String facetName) {
return selectedFacets.containsKey(facetName);
}
/**
* @param facetName
* Set the facet name
* @param selected
* Set the index of the selected facet
*/
public void setSelectedFacets(Map<String,String> selectedFacets) {
this.selectedFacets = selectedFacets;
}
/**
* @return the sort
*/
public String getSort() {
return sort;
}
/**
* @param newSort set the sorting
*/
public void setSort(String newSort) {
this.sort = newSort;
}
/**
* @return the parameters
*/
public Map<String, Object> getParameters() {
return parameters;
}
/**
* @param parameters the parameters to set
*/
public void setParameters(Map<String, Object> parameters) {
this.parameters = parameters;
}
/**
* @param pagesAvailable the pagesAvailable to set
*/
public void setPagesAvailable(Integer pagesAvailable) {
this.pagesAvailable = pagesAvailable;
}
/**
* @param prevIndex the prevIndex to set
*/
public void setPrevIndex(Integer prevIndex) {
this.prevIndex = prevIndex;
}
/**
* @param nextIndex the nextIndex to set
*/
public void setNextIndex(Integer nextIndex) {
this.nextIndex = nextIndex;
}
/**
* @param currentIndex the currentIndex to set
*/
public void setCurrentIndex(Integer currentIndex) {
this.currentIndex = currentIndex;
}
/**
* @param firstRecord the firstRecord to set
*/
public void setFirstRecord(Integer firstRecord) {
this.firstRecord = firstRecord;
}
/**
* @param lastRecord the lastRecord to set
*/
public void setLastRecord(Integer lastRecord) {
this.lastRecord = lastRecord;
}
/**
* @param size the size to set
*/
public void setSize(Integer size) {
this.size = size;
}
/**
* @param records the records to set
*/
public void setRecords(List<T> records) {
this.records = records;
}
/**
* @param pageSize the pageSize to set
*/
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
/**
* @param indices the indices to set
*/
public void setIndices(ArrayList<Integer> indices) {
this.indices = indices;
}
public String getSuggestedSpelling() {
return this.suggestedSpelling;
}
public boolean getCorrectlySpelled() {
return this.correctlySpelled;
}
public void setCorrectlySpelled(boolean correctlySpelled) {
this.correctlySpelled = correctlySpelled;
}
public void setSuggestedSpelling(String suggestedSpelling) {
this.suggestedSpelling = suggestedSpelling;
}
}