package it.mice.voila.runtime.springmvc.taglibs;

import javax.servlet.jsp.JspException;

import org.apache.commons.lang.StringUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.servlet.support.BindStatus;
import org.springframework.web.servlet.tags.form.TagWriter;

public class LabelTag extends org.springframework.web.servlet.tags.form.LabelTag {

	private static final String RENDER_FIELD_ERROR_SIDE = "side";
	private static final String RENDER_FIELD_ERROR_TITLE = "title";
	private static final String ERROR_DELIMITER_BR = "<br/>";
	private static final String ERROR_DELIMITER_N = " | ";

	/**
	 * serial version UID
	 */
	private static final long serialVersionUID = 24212777363059590L;

	private String renderFieldError = null;
	private String errorDelimiter = null;
	private String titleKey = null;
	
	/**
	 * The {@link TagWriter} instance being used.
	 * <p>Stored so we can close the tag on {@link #doEndTag()}.
	 */
	private TagWriter tagWriter;

	private String htmlTitle = null;

	/**
	 * @return the titleKey
	 */
	public String getTitleKey() {
		return titleKey;
	}

	/**
	 * @param titleKey the titleKey to set
	 */
	public void setTitleKey(String titleKey) {
		this.titleKey = titleKey;
	}

	
	/**
	 * @return the renderFieldError
	 */
	public String getRenderFieldError() {
		return renderFieldError;
	}


	/**
	 * @param renderFieldError the renderFieldError to set
	 */
	public void setRenderFieldError(String renderFieldError) {
		this.renderFieldError = renderFieldError;
	}


	/**
	 * @return the errorDelimiter
	 */
	public String getErrorDelimiter() {
		return errorDelimiter;
	}


	/**
	 * @param errorDelimiter the errorDelimiter to set
	 */
	public void setErrorDelimiter(String errorDelimiter) {
		this.errorDelimiter = errorDelimiter;
	}


	/**
	 * Writes the opening '<code>label</code>' tag and forces a block tag so
	 * that body content is written correctly.
	 * @return {@link javax.servlet.jsp.tagext.Tag#EVAL_BODY_INCLUDE}
	 */
	@Override
	protected int writeTagContent(TagWriter tagWriter) throws JspException {
		//data-toggle="tooltip" data-original-title="Another tooltip">Another tooltip</a></li>
		htmlTitle = null;

		if (getId() == null) {
			setId("label." + resolveFor());
		}
		
		if (!StringUtils.isEmpty(getTitleKey())) {
			setTitle(TagUtils.getMessage(getRequestContext(), getTitleKey(), getTitle()));
			setTitleKey(null);
		}
		if (getTitle() != null) {
			htmlTitle = it.mice.voila.runtime.util.StringUtils.stripCrLf(getTitle());
			setTitle(it.mice.voila.runtime.util.StringUtils.stripHtml(getTitle()));
		}

		BindStatus bindStatus = null;
		if (!StringUtils.isEmpty(getRenderFieldError())) {
			initErrorDelimiterIfBlank();
			bindStatus = getBindStatus();
			initTitleAttributeIfInError(bindStatus);
		}
		
		int result = super.writeTagContent(tagWriter);

		if (!StringUtils.isEmpty(getRenderFieldError())) {
			writeErrorSpanIfInError(tagWriter, bindStatus);
		}

		this.tagWriter = tagWriter;
		return result;
	}

	private void writeBootstrapTooltip(TagWriter tagWriter, String htmlTitle) throws JspException {
		tagWriter.startTag("script");
		tagWriter.writeAttribute("type", "text/javascript");
		tagWriter.appendValue("$(function() {");
//		tagWriter.appendValue("$(document).ready(function() {");
		tagWriter.appendValue("makeTooltip(\"" + getId() + "\", \"" + htmlTitle + "\");");
		tagWriter.appendValue("});");
		tagWriter.endTag();
	}

	private void writeStandardTooltip(TagWriter tagWriter, String htmlTitle) throws JspException {
		tagWriter.startTag("script");
		tagWriter.writeAttribute("type", "text/javascript");
		tagWriter.appendValue("$(document).ready(function() {");
		tagWriter.appendValue("new dijit.Tooltip({connectId: [\"" + getId() + "\"], label: \"" + htmlTitle + "\"});");
//		tagWriter.appendValue("document.getElementById(\"" + getId() + "\").title = \"\";");
		tagWriter.appendValue("$n(\"" + getId() + "\").removeAttr(\"title\");");
		tagWriter.appendValue("});");
		tagWriter.endTag();
	}

	/**
	 * @param tagWriter
	 * @param bindStatus
	 * @throws JspException
	 */
	public void writeErrorSpanIfInError(TagWriter tagWriter,
			BindStatus bindStatus) throws JspException {
		if (bindStatus.isError() && RENDER_FIELD_ERROR_SIDE.equals(getRenderFieldError())) {
			String msg = bindStatus.getErrorMessagesAsString(getErrorDelimiter());
			tagWriter.startTag("span");
			tagWriter.writeAttribute("id", resolveFor() + ".errors");
			tagWriter.writeAttribute("class", "fieldError");
			tagWriter.appendValue(msg);
			tagWriter.endTag();
		}
	}


	/**
	 * @param bindStatus
	 */
	public void initTitleAttributeIfInError(BindStatus bindStatus) {
		if (bindStatus.isError() && RENDER_FIELD_ERROR_TITLE.equals(getRenderFieldError())) {
			String msg = bindStatus.getErrorMessagesAsString(getErrorDelimiter());
			setTitle(msg);
		}
	}


	/**
	 * 
	 */
	public void initErrorDelimiterIfBlank() {
		if (getErrorDelimiter() == null) {
			if (RENDER_FIELD_ERROR_TITLE.equals(getRenderFieldError())) {
				setErrorDelimiter(ERROR_DELIMITER_N);
			} else {
				setErrorDelimiter(ERROR_DELIMITER_BR);
			}
		}
	}

	/**
	 * Close the '<code>label</code>' tag.
	 */
	@Override
	public int doEndTag() throws JspException {
		this.tagWriter.endTag();

		if (!StringUtils.isEmpty(htmlTitle)) {
			if (TagUtils.isBootstrapTheme()) {
				writeBootstrapTooltip(tagWriter, htmlTitle);
			} else {
				writeStandardTooltip(tagWriter, htmlTitle);
			}
		}
		return EVAL_PAGE;
	}

	/**
	 * Gets the appropriate CSS class to use based on the state of the current
	 * {@link org.springframework.web.servlet.support.BindStatus} object.
	 * Overriden in order to concatenate error css list to the base list.
	 */
	protected String resolveCssClass() throws JspException {
		if (getBindStatus().isError() && org.springframework.util.StringUtils.hasText(getCssErrorClass())) {
			return ObjectUtils.getDisplayString(evaluate("cssClass", getCssClass()) + " " + evaluate("cssErrorClass", getCssErrorClass()));
		}
		else {
			return ObjectUtils.getDisplayString(evaluate("cssClass", getCssClass()));
		}
	}

	/**
	 * Disposes of the {@link TagWriter} instance.
	 */
	@Override
	public void doFinally() {
		super.doFinally();
		this.errorDelimiter = null;
		this.renderFieldError = null;
		setTitleKey(null);
		setTitle(null);
		setId(null);
	}
}
