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

import it.mice.voila.runtime.springmvc.bean.PageStatus;
import it.mice.voila.runtime.springmvc.form.JfFormBean;
import it.mice.voila.runtime.springmvc.util.portlet.SpringMvcUtil;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;

import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.PropertyAccessor;
import org.springframework.web.servlet.support.BindStatus;
import org.springframework.web.servlet.support.RequestContext;
import org.springframework.web.servlet.tags.NestedPathTag;
import org.springframework.web.servlet.tags.RequestContextAwareTag;

public class TagUtils {
	public static final Object[] EMPTY_ARRAY = {};
	/**
	 * The prefix for all {@link PageContext} attributes created by this tag.
	 */
	private static final String PAGE_CONTEXT_ATTRIBUTE_PREFIX = "org.springframework.web.servlet.tags.form.TagIdGenerator.";

	public static boolean isMessageCode(String text) {
		if (text == null) return false;
		if (text.startsWith("{") && text.endsWith("}")) {
			return true;
		}
		return false;
	}

	public static String getMessageCode(String code) {
		if (isMessageCode(code)) {
			int length = code.length() - 1;
			return code.substring(1, length);
		}
		throw new IllegalArgumentException("The supplied code doesn't seem to be a valid message code entry such as: {example.code}");
	}

	public static void safeWrite(PageContext pageContext, String text) throws JspException {
		if (text == null) return;
		try {
			pageContext.getOut().append(text);
		} catch (IOException e) {
			throw new JspException("Unable to write to JspWriter", e);
		}
	}
	
	public static String safeAppend(String appendTo, String text) {
		if (text == null) return appendTo;
		return (StringUtils.isEmpty(appendTo) ? text : appendTo + text);
	}
	
	public static String safePrepend(String prependTo, String text) {
		if (text == null) return prependTo;
		return (StringUtils.isEmpty(prependTo) ? text : text + prependTo);
	}
	
	/**
	 * Get the {@link BindStatus} for this tag.
	 */
	public static JfFormBean getFormBean(PageContext pageContext) throws JspException {
		String beanName = "";
		RequestContext requestContext = (RequestContext) pageContext.getAttribute(RequestContextAwareTag.REQUEST_CONTEXT_PAGE_ATTRIBUTE);
		String nestedPath = (String) pageContext.getAttribute(NestedPathTag.NESTED_PATH_VARIABLE_NAME, PageContext.REQUEST_SCOPE);
		JfFormBean result = (JfFormBean)getBindObject(nestedPath, beanName, requestContext);
		if (result == null) {
			result = (JfFormBean)pageContext.findAttribute(normalizePath(nestedPath, beanName));
		}
		return result;
	}
	
	/**
	 * Get the {@link BindStatus} for this tag.
	 */
	public static PageStatus getPageStatus(PageContext pageContext) throws JspException {
		RequestContext requestContext = (RequestContext) pageContext.getAttribute(RequestContextAwareTag.REQUEST_CONTEXT_PAGE_ATTRIBUTE);
		String nestedPath = (String) pageContext.getAttribute(NestedPathTag.NESTED_PATH_VARIABLE_NAME, PageContext.REQUEST_SCOPE);

		return getPageStatus(getForm(nestedPath));
	}
	
	/**
	 * Get the {@link BindStatus} for this tag.
	 */
	public static PageStatus getPageStatus(String nestedPath) throws JspException {
		return getPageStatus(getForm(nestedPath));
	}
	
	/**
	 * Get the {@link BindStatus} for this tag.
	 */
	public static PageStatus getPageStatus(JfFormBean form) throws JspException {
		PageStatus pageStatus = null;
		if (form != null) {
			pageStatus = form.getPageStatus();
		}
		if (pageStatus == null) {
			return new PageStatus("", false);
		}
		return pageStatus;
	}
	
	public static JfFormBean getForm(String nestedPath) {
		String formName = nestedPath.substring(0, nestedPath.length() - 1);
		Object form = SpringMvcUtil.getRequest().getAttribute(formName);
		if (form != null && form instanceof JfFormBean) {
			return (JfFormBean)form;
		}
		form = SpringMvcUtil.getSession().getAttribute(formName);
		if (form != null && form instanceof JfFormBean) {
			return (JfFormBean)form;
		}
		return null;
	}
	
	/**
	 * Get the {@link BindStatus} for this tag.
	 */
	public static Object getBindObject(String nestedPath, String beanName, RequestContext requestContext) throws JspException {
		String pathToUse = normalizePath(nestedPath, beanName);
		Object result = null;
		try {
			result = new BindStatus(requestContext, pathToUse, false).getValue();
		} catch (Exception e) {
			//Ignore this.
		}
		return result;
	}
	
	public static String normalizePath(String nestedPath, String beanName) {
		String pathToUse = (nestedPath != null ? nestedPath + beanName : beanName);
		if (pathToUse.endsWith(PropertyAccessor.NESTED_PROPERTY_SEPARATOR)) {
			pathToUse = pathToUse.substring(0, pathToUse.length() - 1);
		}
		return pathToUse;
	}
	
	public static String getMessage(RequestContext requestContext, String key, String value) {
		if (StringUtils.isEmpty(key)) {
			return value;
		} else {
    		return requestContext.getMessage(key);
		}
	}
	
	public static String getMessage(RequestContext requestContext, Object key, Object value) {
		return getMessage(requestContext, ObjectUtils.toString(key), ObjectUtils.toString(value));
	}
	
	public static String getMessage(RequestContext requestContext, String input) {
    	if (isMessageCode(input)) {
    		return requestContext.getMessage(getMessageCode(input));
    	}
    	return input;
	}
	
	public static String getMessage(RequestContext requestContext, Object input) {
		return getMessage(requestContext, ObjectUtils.toString(input));
	}
	
	/**
	 * Get the current unique ID (within the given {@link PageContext}) for the supplied name.
	 */
	public static String currentId(String name, PageContext pageContext) {
		String attributeName = PAGE_CONTEXT_ATTRIBUTE_PREFIX + name;
		Integer currentCount = (Integer) pageContext.getAttribute(attributeName);
		return (name + currentCount);
	}
	
	/**
	 * Get the current unique ID (within the given {@link PageContext}) for the supplied name.
	 */
	public static String normalizeId(String id) {
		return StringUtils.replaceChars(id, "/\\[]$&<>", "________");
	}
	
	public static FormTag getCurrentForm(PageContext pageContext) {
		return (FormTag)pageContext.getAttribute(FormTag.FORM_BEAN_NAME, PageContext.REQUEST_SCOPE);
	}
}
