/*
Copyright 2015 CrushPaper.com.
This file is part of CrushPaper.
CrushPaper is free software: you can redistribute it and/or modify
it under the terms of version 3 of the GNU Affero General Public
License as published by the Free Software Foundation.
CrushPaper 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.
You should have received a copy of the GNU Affero General Public License
along with CrushPaper. If not, see <http://www.gnu.org/licenses/>.
*/
package com.crushpaper;
import java.util.Map;
import org.apache.commons.lang3.StringEscapeUtils;
import com.crushpaper.Servlet.RequestAndResponse;
/**
* Contains the logic for deciding which list items should be included in a
* page.
*/
public class ResultsPaginator {
ResultsPaginator(RequestAndResponse requestAndResponse,
String noMatchesText, StringBuilder result, ServletText servletText) {
this.requestAndResponse = requestAndResponse;
this.noMatchesText = noMatchesText;
this.result = result;
this.servletText = servletText;
start = getStartForPagination(requestAndResponse);
end = start + getPageSizeForPagination();
resultNumber = start;
}
/**
* Returns the next action the iterator should take. 0 means break.
* Otherwise it is the 1 based index of the result.
*/
int next() {
++resultNumber;
if (resultNumber > end) {
return 0;
}
anyMatches = true;
return resultNumber;
}
/**
* The iterator should call this when it has finished iterating to print out
* the right message.
*/
public void done() {
if (resultNumber == (end + 1)) {
getPreviousAndNextLinksForPagination(start != 0, true,
requestAndResponse, result);
} else if (start == 0 && !anyMatches) {
result.append(noMatchesText);
} else if (start != 0 && !anyMatches) {
result.append(servletText.sentenceNoMoreResults());
} else if (start != 0) {
getPreviousAndNextLinksForPagination(true, false,
requestAndResponse, result);
}
}
/** Returns true if there would be more results. */
public boolean hasMore() {
return resultNumber == (end + 1);
}
/**
* Returns the name of the URL parameter that contains the start of the page
* for pagination.
*/
private String startParameterNameForPagination() {
return "start";
}
/** Returns the page size for the pagination of the results. */
private int getPageSizeForPagination() {
return 20;
}
/** Returns the starting point for the pagination of the results. */
private int getStartForPagination(RequestAndResponse requestAndResponse) {
String start = requestAndResponse
.getParameter(startParameterNameForPagination());
if (start == null) {
return 0;
}
try {
return Integer.parseInt(start);
} catch (Exception e) {
return 0;
}
}
/** Returns the HTML for the next link in pagination. */
private void getPreviousAndNextLinksForPagination(
boolean includePreviousLink, boolean includeNextLink,
RequestAndResponse requestAndResponse, StringBuilder result) {
StringBuilder baseUrl = new StringBuilder();
baseUrl.append(StringEscapeUtils.escapeHtml4(requestAndResponse
.getRequestURI()));
int start = getStartForPagination(requestAndResponse)
+ getPageSizeForPagination();
boolean addedQuestionMark = false;
java.util.Map<java.lang.String, java.lang.String[]> parameters = requestAndResponse
.getParameterMap();
for (Map.Entry<String, String[]> entry : parameters.entrySet()) {
String key = entry.getKey();
if (key == null || key.equals(startParameterNameForPagination())
|| key.equals("time"))
continue;
for (String value : entry.getValue()) {
if (!addedQuestionMark) {
baseUrl.append("?");
addedQuestionMark = true;
} else {
baseUrl.append("&");
}
baseUrl.append(StringEscapeUtils.escapeHtml4(key));
baseUrl.append("=");
baseUrl.append(StringEscapeUtils.escapeHtml4(value));
}
}
if (!addedQuestionMark) {
baseUrl.append("?");
} else {
baseUrl.append("&");
}
baseUrl.append(startParameterNameForPagination());
baseUrl.append("=");
result.append("<table width=\"100%\"><tr><td>");
if (includePreviousLink) {
result.append("<a onclick=\"replacePaneForLink(event, '"
+ servletText.pageTitleGetPreviousPage()
+ "', true); return false;\" class=\"previousLink\" href=\"");
result.append(baseUrl.toString());
result.append(start - getPageSizeForPagination() * 2);
result.append("\">");
result.append(servletText.linkPrevious());
result.append("</a>");
}
if (includeNextLink) {
result.append("<a onclick=\"replacePaneForLink(event, '"
+ servletText.pageTitleGetNextPage()
+ "', true); return false;\" class=\"nextLink\" href=\"");
result.append(baseUrl.toString());
result.append(start);
result.append("\">");
result.append(servletText.linkNext());
result.append("</a>");
}
result.append("</td></tr></table>");
}
/**
* Returns the starting position of the query. This is a multiple of the
* page size.
*/
public int getStartPosition() {
return start;
}
/**
* Returns the number of results that should be returned by a query for this
* page. This is the page size + 1 so that it can be determined if a next
* link should be included.
*/
public int getMaxResults() {
return getPageSizeForPagination() + 1;
}
RequestAndResponse requestAndResponse;
StringBuilder result;
private String noMatchesText;
ServletText servletText;
private int resultNumber, start, end;
private boolean anyMatches;
}