package com.apobates.forum.utils;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * 分页类
 * 
 * @author xiaofanku
 * @since 20190730
 */
public class Pagination {
	// 连接地址
	private final String link;
	// 当前页码值
	private final int currentPage;
	private final PaginationHelper helper;
	// 页码的参数
	private final String pageParameter;
	// 最多显示多少页
	private final int showTotalPages;
	// 连接的分隔符
	private final String delimiter;
	//
	public final static String PAGE_HOME = "Home";
	public final static String PAGE_END = "Tail";
	public final static String PAGE_TOTAL = "Size";
	public final static String PAGE_PREV = "Prev";
	public final static String PAGE_NEXT = "Next";

	//
	/**
	 * 初始化,分页的查询参数(p),不限制显示的页数
	 * 
	 * @param link
	 *            连接地址
	 * @param page
	 *            当前页码
	 * @param pageSize
	 *            每页显示的记数数
	 * @param total
	 *            总记录数
	 */
	public Pagination(String link, int page, int pageSize, long total) {
		this(link, page, pageSize, total, "p", -1);
	}

	/**
	 * 初始化,不限制显示的页数
	 * 
	 * @param link
	 *            连接地址
	 * @param page
	 *            当前页码
	 * @param pageSize
	 *            每页显示的记数数
	 * @param total
	 *            总记录数
	 * @param pageParameter
	 *            分页的查询参数
	 */
	public Pagination(String link, int page, int pageSize, long total, String pageParameter) {
		this(link, page, pageSize, total, pageParameter, -1);
	}

	/**
	 * 初始化
	 * 
	 * @param link
	 *            连接地址
	 * @param page
	 *            当前页码
	 * @param pageSize
	 *            每页显示的记数数
	 * @param total
	 *            总记录数
	 * @param pageParameter
	 *            分页的查询参数
	 * @param showMaxPages
	 *            最多显示多少页
	 */
	public Pagination(String link, int page, int pageSize, long total, String pageParameter, int showMaxPages) {
		this.link = link;
		this.currentPage = page;
		this.helper = new PaginationHelper(pageSize, total);
		//
		this.pageParameter = pageParameter;
		this.showTotalPages = showMaxPages;
		this.delimiter = link.contains("?") ? "&" : "?";
	}

	// 首页
	private String getHomeLink() {
		return link + delimiter + pageParameter + "=1";
	}

	// 尾页
	private String getTailLink() {
		return link + delimiter + pageParameter + "=" + showMaxPageNumber();
	}

	/**
	 * 显示的最大页码值/共几页
	 * @return
	 */
	public int showMaxPageNumber() {
		if (this.showTotalPages == -1) { // 不限制
			return helper.getTotalPage();
		} else {
			return (helper.getTotalPage() > showTotalPages) ? showTotalPages : helper.getTotalPage();
		}
	}

	// 有上一页吗
	private boolean hasPrevLink() {
		return currentPage > 1;
	}

	// 有下一页吗
	private boolean hasNextLink() {
		return currentPage < showMaxPageNumber();
	}

	/**
	 * 上一页的连接
	 * 
	 * @param isShowEmptyLink
	 *            是否显示无效的连接,false(null),true(#)
	 * @return
	 */
	private String getPrevLink(boolean isShowEmptyLink) {
		if (hasPrevLink()) {
			return link + delimiter + pageParameter + "=" + (currentPage - 1);
		}
		return (isShowEmptyLink) ? "#" : null;
	}

	/**
	 * 下一页的连接
	 * 
	 * @param isShowEmptyLink
	 *            是否显示无效的连接,false(null),true(#)
	 * @return
	 */
	private String getNextLink(boolean isShowEmptyLink) {
		if (hasNextLink()) {
			return link + delimiter + pageParameter + "=" + (currentPage + 1);
		}
		return (isShowEmptyLink) ? "#" : null;
	}

	/**
	 * 当前页显示的记录的最少ID(总记录数的步位) ID不表示实体的@ID
	 * 
	 * @return
	 */
	public int getViewMinRecordId() {
		return (currentPage - 1) * helper.getPageSize() + 1;
	}

	/**
	 * 当前页显示的记录的最大ID(总记录数的步位)
	 * 
	 * @return
	 */
	public long getViewMaxRecordId() {
		int maxId = currentPage * helper.getPageSize();
		return (maxId <= helper.getTotal()) ? maxId : helper.getTotal();
	}

	/**
	 * 显示:首页(home)|上一页(prev)|下一页(next)|尾页(end)总页数(size)
	 *
	 * @param isShowEmptyLink
	 *            当上一页和下一页不存在时是否显示, false不显示无效的连接,true显示
	 * @param notPageNumberTitle
	 *            key:以PAGE_开头的类变量,value为相应的语言描述
	 * @return
	 */
	public Map<String, String> draw(final boolean isShowEmptyLink, final Map<String, String> notPageNumberTitle) {
		Map<String, String> struct = new LinkedHashMap<>();
		if(showMaxPageNumber() <= 0){
			return struct;
		}
		if(notPageNumberTitle.containsKey(Pagination.PAGE_HOME)){
			struct.put(notPageNumberTitle.get(Pagination.PAGE_HOME), getHomeLink());
		}
		if(notPageNumberTitle.containsKey(Pagination.PAGE_PREV)){
			String pl = getPrevLink(isShowEmptyLink);
			if(null!=pl){
				struct.put(notPageNumberTitle.get(Pagination.PAGE_PREV), pl);
			}
		}
		if(notPageNumberTitle.containsKey(Pagination.PAGE_NEXT)){
			String nl = getNextLink(isShowEmptyLink);
			if(null!=nl){
				struct.put(notPageNumberTitle.get(Pagination.PAGE_NEXT), nl);
			}
		}
		if(notPageNumberTitle.containsKey(Pagination.PAGE_END)){
			struct.put(notPageNumberTitle.get(Pagination.PAGE_END), getTailLink());
		}
		struct.put(Pagination.PAGE_TOTAL, showMaxPageNumber() + "");
		return struct;
	}
	/**
	 * 显示:首页(home)|上一页(prev)|下一页(next)|尾页(end)总页数(size)
	 *
	 * @param isShowEmptyLink
	 *            当上一页和下一页不存在时是否显示, false不显示无效的连接,true显示
	 * @return
	 */
	public Map<String, String> draw(final boolean isShowEmptyLink) {
		Map<String, String> struct = new LinkedHashMap<>();
		if(showMaxPageNumber() <= 0){
			return struct;
		}
		struct.put(Pagination.PAGE_HOME, getHomeLink());
		String pl = getPrevLink(isShowEmptyLink);
		if(null!=pl){
			struct.put(Pagination.PAGE_PREV, pl);
		}
		String nl = getNextLink(isShowEmptyLink);
		if(null!=nl){
			struct.put(Pagination.PAGE_NEXT, nl);
		}
		//
		struct.put(Pagination.PAGE_END, getTailLink());
		struct.put(Pagination.PAGE_TOTAL, showMaxPageNumber() + "");
		return struct;
	}
	/**
	 * {首页|上一页|1|2|...|下一页|尾页}
	 * 
	 * @param isShowEmptyLink
	 *            当上一页和下一页不存在时是否显示, false不显示无效的连接,true显示
	 * @param numberRange
	 *            显示的页码范围
	 * @param notPageNumberTitle
	 *            key:以PAGE_开头的类变量,value为相应的语言描述
	 * @return
	 */
	public Map<String, String> draw(final boolean isShowEmptyLink, final int numberRange, final Map<String, String> notPageNumberTitle) {
		Map<String, String> struct = new LinkedHashMap<>();
		if(showMaxPageNumber() <= 0){
			return struct;
		}
		//
		if(notPageNumberTitle.containsKey(Pagination.PAGE_HOME)){
			struct.put(notPageNumberTitle.get(Pagination.PAGE_HOME), getHomeLink());
		}
		if(notPageNumberTitle.containsKey(Pagination.PAGE_PREV)){
			String pl = getPrevLink(isShowEmptyLink);
			if(null!=pl){
				struct.put(notPageNumberTitle.get(Pagination.PAGE_PREV), pl);
			}
		}
		// 数字
		Map<Integer, String> pageNumber = drawPagination(numberRange);
		// 增补1... | ... EP(最后一页)
		Set<Integer> pnKeySet = pageNumber.keySet();
		for (Integer pn : pnKeySet) {
			struct.put(pn + "", pageNumber.get(pn));
		}
		//
		if(notPageNumberTitle.containsKey(Pagination.PAGE_NEXT)){
			String nl = getNextLink(isShowEmptyLink);
			if(null!=nl){
				struct.put(notPageNumberTitle.get(Pagination.PAGE_NEXT), nl);
			}
		}
		if(notPageNumberTitle.containsKey(Pagination.PAGE_END)){
			struct.put(notPageNumberTitle.get(Pagination.PAGE_END), getTailLink());
		}
		return struct;
	}

	/**
	 * 打印页码数字
	 * 
	 * @param numberRange 
	 *            显示的页码范围
	 * @return
	 */
	public Map<Integer, String> drawPagination(final int numberRange) {
		final int pageCount = showMaxPageNumber();
		final Map<Integer, String> pagination = new LinkedHashMap<>();
		// 防止无数据时显示1
		if (pageCount < 1) {
			return pagination;
		}
		final String procssurl = link + delimiter + pageParameter + "=";
		int[] d = getPagePanel(numberRange);
		for (int i = d[0]; i <= d[1]; i++) {
			pagination.put(i, procssurl + i);
		}
		return pagination;
	}

	/**
	 * drawPagination方法的助手方法.私有 返回一个只有两个元素的数组.
	 * key说明: index=0:可视页码的下限数字 index=1:可视页码的上限数字
	 *
	 * @param pageCount
	 *            总页数
	 * @param numberRange 
	 *            显示的页码范围
	 */
	private int[] getPagePanel(final int numberRange) {
        int safeNumberRange = (numberRange<5)?5:numberRange;
        int[] data = {1, 1};
        int pageCount = showMaxPageNumber(); //显示的页码上限
        int nR = currentPage / safeNumberRange;
        if(currentPage % safeNumberRange>0){
            nR += 1;
        }
        int rangeEnd = nR * safeNumberRange;
        if(rangeEnd > pageCount){
            rangeEnd = pageCount;
        }
        data[0] = nR * safeNumberRange - safeNumberRange + 1; //下限
        data[1] = rangeEnd; //上限
        return data;
	}

	// 内部助手类
	private class PaginationHelper {
		// 每页显示的记录数
		private final int pageSize;
		// 总记录数
		private final long total;
		// 总页数
		private final int totalPage;

		public PaginationHelper(int pageSize, long total) {
			super();
			this.pageSize = pageSize;
			this.total = total;
			this.totalPage = (total>0)?calcTotalPage(total, pageSize):1;
		}

		private int calcTotalPage(long total, int pageSize) {
			if (total <= pageSize) {
				return 1;
			}
			// 整除
			long totalPages = total / pageSize;
			// 不整除
			double a = total % pageSize;
			if (a != 0) {
				totalPages += 1;
			}
			return Long.valueOf(totalPages).intValue();
		}

		public int getPageSize() {
			return pageSize;
		}

		public long getTotal() {
			return total;
		}

		public int getTotalPage() {
			return totalPage;
		}

	}

}
