001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.jsp.search.config;
029
030import java.util.ArrayList;
031import java.util.Collections;
032import java.util.List;
033
034/** Search configuration for pagination. */
035public class CmsSearchConfigurationPagination implements I_CmsSearchConfigurationPagination {
036
037    /** The default page size. */
038    public static final List<Integer> DEFAULT_PAGE_SIZE = Collections.singletonList(Integer.valueOf(10));
039    /** The default "Google"-like page navigation length. */
040    public static final int DEFAULT_PAGE_NAV_LENGTH = 5;
041    /** The default request parameter to read the current page from. */
042    public static final String DEFAULT_PAGE_PARAM = "page";
043    /** The request parameter used to send the current page number. */
044    private final String m_pageParam;
045
046    /** The page sizes for the (i+1)th page. The last provided page size is the size of all following pages. */
047    private final List<Integer> m_pageSizes;
048
049    /** The page size for all pages, where no explicit size is specified. */
050    private final int m_pageSizeAllRemainingPages;
051
052    /** The length of the "Google"-like page navigation. Should be an odd number. */
053    private final int m_pageNavLength;
054
055    /** Constructor setting all configuration options for the pagination.
056     * @param pageParam The request parameter used to send the current page number.
057     * @param pageSize The page size.
058     * @param pageNavLength The length of the "Google"-like page navigation. Should be an odd number.
059     */
060    public CmsSearchConfigurationPagination(
061        final String pageParam,
062        final Integer pageSize,
063        final Integer pageNavLength) {
064
065        this(pageParam, null != pageSize ? Collections.singletonList(pageSize) : null, pageNavLength);
066    }
067
068    /** Constructor setting all configuration options for the pagination.
069     * @param pageParam The request parameter used to send the current page number.
070     * @param pageSizes The page sizes for the first pages. The last provided size is the size of all following pages.
071     * @param pageNavLength The length of the "Google"-like page navigation. Should be an odd number.
072     */
073    public CmsSearchConfigurationPagination(
074        final String pageParam,
075        final List<Integer> pageSizes,
076        final Integer pageNavLength) {
077
078        m_pageParam = pageParam == null ? DEFAULT_PAGE_PARAM : pageParam;
079        if ((pageSizes == null) || pageSizes.isEmpty()) {
080            m_pageSizes = DEFAULT_PAGE_SIZE;
081        } else {
082            m_pageSizes = new ArrayList<Integer>();
083            m_pageSizes.addAll(pageSizes);
084        }
085        m_pageSizeAllRemainingPages = (m_pageSizes.get(m_pageSizes.size() - 1)).intValue();
086
087        m_pageNavLength = pageNavLength == null ? DEFAULT_PAGE_NAV_LENGTH : pageNavLength.intValue();
088    }
089
090    /**
091     * Creates a new pagination configuration if at least one of the provided parameters is not null.
092     * Otherwise returns null.
093     * @param pageParam The request parameter used to send the current page number.
094     * @param pageSizes The page sizes for the first pages. The last provided size is the size of all following pages.
095     * @param pageNavLength The length of the "Google"-like page navigation. Should be an odd number.
096     * @return the pagination configuration, or <code>null</code> if none of the provided parameters is not null.
097     */
098    public static I_CmsSearchConfigurationPagination create(
099        String pageParam,
100        List<Integer> pageSizes,
101        Integer pageNavLength) {
102
103        return (pageParam != null) || (pageSizes != null) || (pageNavLength != null)
104        ? new CmsSearchConfigurationPagination(pageParam, pageSizes, pageNavLength)
105        : null;
106
107    }
108
109    /**
110     * @see org.opencms.jsp.search.config.I_CmsSearchConfigurationPagination#getNumPages(long)
111     */
112    @Override
113    public int getNumPages(long numFound) {
114
115        int result = 1;
116        for (int pageSize : m_pageSizes) {
117            numFound -= pageSize;
118            if (numFound <= 0) {
119                return result;
120            }
121            result++;
122        }
123        // calculation is save, since numFound must be > 0 at that place.
124        result += ((numFound - 1) / m_pageSizeAllRemainingPages);
125        return result;
126
127    }
128
129    /**
130     * @see org.opencms.jsp.search.config.I_CmsSearchConfigurationPagination#getPageNavLength()
131     */
132    @Override
133    public int getPageNavLength() {
134
135        return m_pageNavLength;
136    }
137
138    /**
139     * @see org.opencms.jsp.search.config.I_CmsSearchConfigurationPagination#getPageParam()
140     */
141    @Override
142    public String getPageParam() {
143
144        return m_pageParam;
145    }
146
147    /**
148     * @see org.opencms.jsp.search.config.I_CmsSearchConfigurationPagination#getPageSize()
149     *
150     * @deprecated see {@link org.opencms.jsp.search.config.I_CmsSearchConfigurationPagination#getPageSize()}
151     */
152    @Deprecated
153    @Override
154    public int getPageSize() {
155
156        return m_pageSizeAllRemainingPages;
157    }
158
159    /**
160     * @see org.opencms.jsp.search.config.I_CmsSearchConfigurationPagination#getPageSizes()
161     */
162    @Override
163    public List<Integer> getPageSizes() {
164
165        List<Integer> pageSizes = new ArrayList<>(m_pageSizes.size());
166        for (Integer pageSize : m_pageSizes) {
167            pageSizes.add(new Integer(pageSize.intValue()));
168        }
169        return pageSizes;
170    }
171
172    /**
173     * @see org.opencms.jsp.search.config.I_CmsSearchConfigurationPagination#getSizeOfPage(int)
174     */
175    @Override
176    public int getSizeOfPage(int pageNum) {
177
178        if (pageNum < 1) {
179            throw new IllegalArgumentException(
180                "You try to determine the size of page "
181                    + pageNum
182                    + ". But a valid page number must be greater than 0.");
183        } else if (pageNum <= m_pageSizes.size()) {
184            return m_pageSizes.get(pageNum - 1).intValue();
185        } else {
186            return m_pageSizeAllRemainingPages;
187        }
188    }
189
190    /**
191     * @see org.opencms.jsp.search.config.I_CmsSearchConfigurationPagination#getStartOfPage(int)
192     */
193    @Override
194    public int getStartOfPage(int pageNum) {
195
196        if (pageNum < 1) {
197            throw new IllegalArgumentException(
198                "The number of the page, you request the index of the first item for must be greater than 0, but is \""
199                    + pageNum
200                    + "\".");
201        }
202        int result = 0;
203        for (int i = 0; i < m_pageSizes.size(); i++) {
204            if (pageNum > 1) {
205                result += m_pageSizes.get(i).intValue();
206                pageNum--;
207            } else {
208                return result;
209            }
210        }
211        result += (pageNum - 1) * m_pageSizeAllRemainingPages;
212        return result;
213    }
214
215}