/*
 * This file is part of Nuts Framework.
 * Copyright(C) 2009-2012 Nuts Develop Team.
 *
 * Nuts Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License any later version.
 *
 * Nuts Framework 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Nuts Framework. If not, see <http://www.gnu.org/licenses/>.
 */
package nuts.exts.struts2.views.java.simple;

import java.io.IOException;
import java.text.DecimalFormat;
import java.text.MessageFormat;

import nuts.core.lang.StringUtils;
import nuts.core.lang.TextUtils;
import nuts.exts.struts2.components.Select;
import nuts.exts.struts2.util.StrutsContextUtils;
import nuts.exts.struts2.views.java.AbstractTemplateRenderer;
import nuts.exts.struts2.views.java.Attributes;

import org.apache.struts2.components.template.TemplateRenderingContext;

public class NutsPagerRenderer extends AbstractTemplateRenderer {

	private final static DecimalFormat numberFormat = new DecimalFormat("###,###");
	
	private String id;
	private Integer start;
	private Integer count;
	private Integer begin;
	private Integer end;
	private Integer limit;
	private Integer total;
	private String linkHref;
	private String linkStart;
	private String linkEnd;
	
	private boolean iconStyle;
	private boolean disabledStyle;
	private String linkStyle;
	private Integer linkSize;
	private Integer pages;
	private Integer pageNo;

	public NutsPagerRenderer(TemplateRenderingContext context) {
		super(context);
	}

	public void render() throws IOException {
		id = (String)params.get("id");
		start = (Integer)params.get("start");
		count = (Integer)params.get("count");
		begin = start + 1;
		end = start + count;
		limit = (Integer)params.get("limit");
		total = (Integer)params.get("total");
		pages = (Integer)params.get("pages");
		pageNo = (Integer)params.get("pageNo");

		linkHref = defs((String)params.get("linkHref"), "#");
		linkStyle = defs((String)params.get("linkStyle"));
		linkSize = (Integer)params.get("linkSize");
		iconStyle = linkStyle.contains("i");
		disabledStyle = linkStyle.contains("d");
		
		int i = linkHref.lastIndexOf('?');
		if (i >= 0) {
			linkStart = linkHref.substring(0, i);
			linkEnd = linkHref.substring(i + 1);
		}

		Attributes a = new Attributes();
		
		String cssClass = (String)params.get("cssClass");
		a.add("id", id)
		 .add("class", "n-p" + (cssClass == null ? "" : " " + cssClass))
		 .add("start", defs(start))
		 .add("count", defs(count))
		 .add("limit", defs(limit))
		 .add("total", defs(total))
		 .add("click", (String)params.get("onLinkClick"))
		 .cssStyle(params);
		stag("div", a);
		
		if (total > 0) {
			write("<table class=\"n-p-table\"><tr>");
			
			writePagerInfo();
			
			writePagerLinks();

			writePagerLimit();
			
			write("</tr></table>");
			writeJsc("$(function() { nuts.pager(\"#" + jsstr(id) + "\"); });");
		}
		else if (count > 0) {
			write("<table class=\"n-p-table\"><tr>");

			writePagerLinkPrev();
			
			writePagerInfo();
			
			writePagerLinkNext();
			
			writePagerLimit();
			
			write("</tr></table>");
			writeJsc("$(function() { nuts.pager(\"#" + jsstr(id) + "\"); });");
		}
		else if (start > 0) {
			write("<table class=\"n-p-table\"><tr>");
			writePagerLinkFirst();
			writePagerLinkPrev();

			write("<td class=\"n-p-info\">");
			write((String)params.get("emptyText"));
			write("</td>");

			writePagerLimit();
			
			write("</tr></table>");
			writeJsc("$(function() { nuts.pager(\"#" + jsstr(id) + "\"); });");
		}
		else {
			write("<div class=\"n-p-info\">");
			write((String)params.get("emptyText"));
			write("</div>");
		}
		
		etag("div");
	}

	private void writePagerLimit() throws IOException {
		String onLimitChange = (String)params.get("onLimitChange");
		if (onLimitChange != null) {
			write("<td class=\"n-p-limitLabel\">");
			write((String)params.get("limitLabel"));
			write("</td>");
			
			write("<td class=\"n-p-limitSelect\">");
			
			Select select = new Select(stack,
					StrutsContextUtils.getServletRequest(),
					StrutsContextUtils.getServletResponse());

			StrutsContextUtils.getContainer(stack).inject(select);
			
			select.setTheme("simple");
			select.setId(id + "_limit");
			String limitName = (String)params.get("limitName");
			if (StringUtils.isEmpty(limitName)) {
				select.setName(id + "_limit");
			}
			select.setCssClass("select");
			select.setValue(limit.toString());
			select.setList(params.get("limitList"));
			select.setOnchange(onLimitChange);
			
			select.start(writer);
			select.end(writer, "");
			
			write("</td>");
		}
	}

	private String getLinkHref(int pn) {
		if (linkStart != null) {
			return linkStart + String.valueOf((pn - 1) * limit) + linkEnd;
		}
		else {
			return linkHref;
		}
	}
	
	private void writePagerInfo() throws IOException {
		write("<td class=\"n-p-info\">");
		String info = TextUtils.transform((String)params.get("infoText"), this, '$', '(', ')');
		write(info);
		write("</td>");
	}
	
	private void writePagerLinkFirst() throws IOException {
		write("<td");
		if (pageNo <= 1 || !linkStyle.contains("f")) {
			write(" class=\"n-p-hidden\"");
		}
		write("><a href=\"");
		write(getLinkHref(1));
		if (iconStyle) {
			write("\" class=\"n-p-first\" pageno=\"1\">");
			write("<span class=\"ui-icon ui-icon-seek-first\" title=\"");
			write((String)params.get("firstText"));
			write("\"></span>");
		}
		else {
			write("\" class=\"n-p-text n-p-first\" pageno=\"1\">");
			write((String)params.get("firstText"));
		}
		write("</a></td>");
	}
	
	private void writePagerLinkPrev() throws IOException {
		if (iconStyle) {
			write("<td");
			if (pageNo <= 1) {
				write(" class=\"n-p-hidden\"");
			}
			write("><a href=\"");
			write(getLinkHref(pageNo - 1));
			write("\" class=\"n-p-prev\" pageno=\"");
			write(String.valueOf(pageNo - 1));
			write("\">");

			write("<span class=\"ui-icon ui-icon-triangle-1-w\" title=\"");
			write(prevText());
			write("\"></span></a></td>");
		}
		else {
			write("<td");
			if (pageNo <= 1 && !disabledStyle) {
				write(" class=\"n-p-hidden\"");
			}
			write("><a href=\"");
			write(getLinkHref(pageNo - 1));
			write("\" class=\"n-p-text n-p-prev");
			if (pageNo <= 1 && disabledStyle) {
				write(" n-p-disabled");
			}
			write("\" pageno=\"");
			write(String.valueOf(pageNo - 1));
			write("\">");
			write(prevText());
			write("</a></td>");
		}
	}

	private void writePagerLinkNext() throws IOException {
		boolean hasNext = (limit == null || count >= limit || pageNo < pages);
		if (iconStyle) {
			write("<td");
			if (!hasNext) {
				write(" class=\"n-p-hidden\"");
			}
			write("><a href=\"");
			write(getLinkHref(pageNo + 1));
			write("\" class=\"n-p-next\" pageno=\"");
			write(String.valueOf(pageNo + 1));
			write("\">");
			write("<span class=\"ui-icon ui-icon-triangle-1-e\" title=\"");
			write(nextText());
			write("\"></span></a></td>");
		}
		else {
			write("<td");
			if (!hasNext && !disabledStyle) {
				write(" class=\"n-p-hidden\"");
			}
			write("><a href=\"");
			write(getLinkHref(pageNo + 1));
			write("\" class=\"n-p-text n-p-next");
			if (!hasNext && disabledStyle) {
				write(" n-p-disabled");
			}
			write("\" pageno=\"");
			write(String.valueOf(pageNo + 1));
			write("\">");
			write(nextText());
			write("</a></td>");
		}
	}

	private void writePagerLinkLast() throws IOException {
		write("<td");
		if (pageNo >= pages || !linkStyle.contains("l")) {
			write(" class=\"n-p-hidden\"");
		}
		write("><a href=\"");
		write(getLinkHref(pages));
		if (iconStyle) {
			write("\" class=\"n-p-last\" pageno=\"");
			write(pages.toString());
			write("\">");
			write("<span class=\"ui-icon ui-icon-seek-end\" title=\"");
			write((String)params.get("lastText"));
			write("\"></span>");
		}
		else {
			write("\" class=\"n-p-text n-p-last\" pageno=\"");
			write(pages.toString());
			write("\">");
			write((String)params.get("lastText"));
		}
		write("</a></td>");
	}

	private void writePagerLinks() throws IOException {
		writePagerLinkFirst();
		
		writePagerLinkPrev();
		
		int p = 1;
		if (pageNo > linkSize / 2) {
			p = pageNo - (linkSize / 2);
		}
		if (p + linkSize > pages) {
			p = pages - linkSize;
		}
		if (p < 1) {
			p = 1;
		}
		
		if (p == 1 || !linkStyle.contains("f")) {
			linkp(pageNo, 1);
		}
		
		if (p == 1) {
			p = 2;
		}
		else if (p > 2) {
			write("<td><span class=\"n-p-ellipsis\">...</span></td>");
		}
		for (int i = 0; i < linkSize && p <= pages; i++, p++) {
			linkp(pageNo, p);
		}
		
		if (p < pages) {
			write("<td><span class=\"n-p-ellipsis\">...</span></td>");
			if (linkStyle.contains("e")) {
				linkp(pageNo, pages);
			}
		}
		else if (p == pages) {
			linkp(pageNo, pages);
		}

		writePagerLinkNext();
		
		writePagerLinkLast();
	}
	
	private void linkp(int page, int p) throws IOException {
		write("<td><a href=\"");
		write(getLinkHref(p));
		write("\" class=\"");
		if (p == page) {
			write("n-p-active");
		}
		else {
			write("n-p-pageno");
		}
		write("\" pageno=\"");
		write(String.valueOf(p));
		write("\">");
		write(String.valueOf(p));
		write("</a></td>");
	}

	private String prevText() {
		return MessageFormat.format((String)params.get("prevText"), getLimit());
	}

	private String nextText() {
		return MessageFormat.format((String)params.get("nextText"), getLimit());
	}

	/**
	 * @return the start
	 */
	public String getStart() {
		return numberFormat.format(start);
	}

	/**
	 * @return the count
	 */
	public String getCount() {
		return numberFormat.format(count);
	}

	/**
	 * @return the begin
	 */
	public String getBegin() {
		return numberFormat.format(begin);
	}

	/**
	 * @return the end
	 */
	public String getEnd() {
		return numberFormat.format(end);
	}

	/**
	 * @return the limit
	 */
	public String getLimit() {
		return numberFormat.format(limit);
	}

	/**
	 * @return the total
	 */
	public String getTotal() {
		return numberFormat.format(total);
	}

	/**
	 * @return the pages
	 */
	public String getPages() {
		return numberFormat.format(pages);
	}

	/**
	 * @return the pageNo
	 */
	public String getPageNo() {
		return numberFormat.format(pageNo);
	}
	
}
