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

import it.mice.voila.runtime.util.UserMessage;
import it.mice.voila.runtime.util.UserMessages;

import java.util.Enumeration;
import java.util.Iterator;

import javax.servlet.jsp.JspException;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.servlet.support.BindStatus;
import org.springframework.web.servlet.tags.form.AbstractFormTag;
import org.springframework.web.servlet.tags.form.TagWriter;

public class MessageAlertTag extends AbstractFormTag {
	String includeValidationMessage = "true";
	String type = "alert";
	boolean escapeHtml = true;
	boolean escapeHtmlParams = true;
	/*
	 * generic message key if you want to show a generic message when includeValidationMessage is false and there are validation messages
	 */
	String genericValidationMessageKey;

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getIncludeValidationMessage() {
		return includeValidationMessage;
	}

	public void setIncludeValidationMessage(String includeValidationMessage) {
		this.includeValidationMessage = includeValidationMessage;
	}

	/**
	 * @return the genericValidationMessageKey
	 */
	public String getGenericValidationMessageKey() {
		return genericValidationMessageKey;
	}

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

	/**
	 * @return the escapeHtml
	 */
	public boolean isEscapeHtml() {
		return escapeHtml;
	}

	/**
	 * @param escapeHtml the escapeHtml to set
	 */
	public void setEscapeHtml(boolean escapeHtml) {
		this.escapeHtml = escapeHtml;
	}

	/**
	 * @return the escapeHtmlParams
	 */
	public boolean isEscapeHtmlParams() {
		return escapeHtmlParams;
	}

	/**
	 * @param escapeHtmlParams the escapeHtmlParams to set
	 */
	public void setEscapeHtmlParams(boolean escapeHtmlParams) {
		this.escapeHtmlParams = escapeHtmlParams;
	}

	/**
	 * serial version UID
	 */
	private static final long serialVersionUID = 1365950626443575870L;
	@Override
	protected int writeTagContent(TagWriter tagWriter) throws JspException {
		UserMessages storedList = (UserMessages)this.pageContext.getRequest().getAttribute("message");
		UserMessages messageList = new UserMessages();
		if (storedList != null) {
			messageList.addAll(storedList);
		}
		
		if (evaluateBoolean("includeValidationMessage", getIncludeValidationMessage())) {
			messageList.addUserMessages(collectValidationResult());
		} else if ((getGenericValidationMessageKey()!=null) && !collectValidationResult().isEmpty()) {
			messageList.add(new UserMessage(getGenericValidationMessageKey()));
		}
		
		if (messageList != null && !messageList.isEmpty()) {
	        // Render the error messages appropriately
	        StringBuffer results = new StringBuffer();
			String evType = (String)evaluate("type", getType());
	        initializeOutput(results, evType, messageList);
	        String message = null;
	        
			if (messageList != null && !messageList.isEmpty()) {
		        Iterator<UserMessage> i = messageList.iterator();
		        while (i.hasNext()) {
		            UserMessage msg = (UserMessage) i.next();
	            	message = msg.getMessageText();
		            if (message == null) {
			            message = getRequestContext().getMessage(msg.getMessageKey(), msg.getMessageParams(escapeHtmlParams), msg.getMessageKey());
		            }
		            if (message != null) {
		                appendMessage(results, message, msg.getSeverity(), evType);
		            }
		        }
			}
	        finalizeOutput(results, evType, messageList);
		}
		
		return EVAL_BODY_INCLUDE;
	}

	@SuppressWarnings("unchecked")
	private UserMessages collectValidationResult() {
		UserMessages result = new UserMessages();
		Enumeration<String> e = pageContext.getRequest().getAttributeNames();
		while (e.hasMoreElements()) {
			String attrName = e.nextElement();
			if (attrName.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
				BindStatus bindStatus = new BindStatus(getRequestContext(), attrName.substring(BindingResult.MODEL_KEY_PREFIX.length()) + ".*", false);
				String[] errorMessages = bindStatus.getErrorMessages();
				for (int i = 0; i < errorMessages.length; i++) {
					UserMessage msg = new UserMessage();
					msg.setMessageText(errorMessages[i]);
					msg.setSeverity(UserMessage.SEVERITY_ERROR);
					result.add(msg);
				}
			}
		}
		return result;
	}
	
	private void appendMessage(StringBuffer results, String message, String severity, String evType) throws JspException {
		if (StringUtils.isEmpty(message)) {
			return;
		}
		if ("dojo".equalsIgnoreCase(evType)) {
			appendMessageDojo(results, message, severity);
			return;
		}
		if ("html".equalsIgnoreCase(evType)) {
			appendMessageHtml(results, message, severity);
			return;
		}
		appendMessageAlert(results, message);
	}

	private void appendMessageAlert(StringBuffer results, String message) throws JspException {
		results.append(StringEscapeUtils.escapeJavaScript(message));
		results.append("\\r\\n");
	}

	private void appendMessageDojo(StringBuffer results, String message, String severity) throws JspException {
		results.append("<p class='message " + severity + "'>");
		if (TagUtils.isBootstrapTheme()) {
			results.append("<i class='fa fa-" + convertToFa(severity) + "'></i>&nbsp;&nbsp;");
		}
		results.append(escapeIfRequired(StringEscapeUtils.escapeJavaScript(message)));
		results.append("<p/>");
	}

	private String convertToFa(String severity) {
		if (UserMessage.SEVERITY_ERROR.equals(severity)) {
			return "ban";
		}
		if (UserMessage.SEVERITY_WARNING.equals(severity)) {
			return "warning";
		}
		if (UserMessage.SEVERITY_INFO.equals(severity)) {
			return "check";
		}
		return "";
	}

	private void appendMessageHtml(StringBuffer results, String message, String severity) throws JspException {
		results.append("<p class='message " + severity + "'>");
		if (TagUtils.isBootstrapTheme()) {
			results.append("<i class=\"fa fa-" + convertToFa(severity) + "\"></i>&nbsp;&nbsp;");
		}
		results.append(escapeIfRequired(message));
		results.append("<p/>");
	}

	private String escapeIfRequired(String msg) {
		if (isEscapeHtml()) {
			return StringEscapeUtils.escapeHtml(msg);
		}
		return msg;
	}
	
	private void initializeOutput(StringBuffer results, String evType, UserMessages messageList) throws JspException {
		if ("dojo".equalsIgnoreCase(evType) || "html".equalsIgnoreCase(evType)) {
			results.append("<div class='message " + messageList.getHighestLevel() + "'>");
		}
	}

	private void finalizeOutput(StringBuffer results, String evType, UserMessages messageList) throws JspException {
		if ("dojo".equalsIgnoreCase(evType)) {
			results.append("</div>");
	        TagUtils.safeWrite(pageContext, "showDojoAlertDialog(\"" + results.toString() + "\", \"" + messageList.getHighestLevel() + "\");");
	        return;
		}
		if ("html".equalsIgnoreCase(evType)) {
			results.append("</div>");
	        TagUtils.safeWrite(pageContext, results.toString());
	        return;
		}
        TagUtils.safeWrite(pageContext, "var errorAlertMsg = \"" + results.toString() + "\"; alert(errorAlertMsg);");
	}
	
	@Override
	protected void finalize() throws Throwable {
		setType("alert");
		escapeHtml = true;
		escapeHtmlParams = true;
		super.finalize();
	}

}
