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

import it.mice.voila.runtime.security.SecurityUtils;
import it.mice.voila.runtime.springmvc.util.ExpressionEvaluationUtils;
import it.mice.voila.runtime.web.menu.MenuFilterManager;
import javax.servlet.ServletContext;

import javax.servlet.jsp.JspException;

import org.springframework.web.context.support.WebApplicationContextUtils;

public class AuthorizationTag extends PageStatusTag {
	/**
	 * serial
	 */
	private static final long serialVersionUID = 3407922243756477174L;

	/**
	 * What if not authorized ? skip (default) - skip body; status - set page status
	 * to pageStatus specified property value none - do nothing
	 */
	private String notAuthorizedAction = "skip";

	/**
	 * the link to check for authorization check.
	 */
	private String link = null;

	/**
	 * The role the current user must have.
	 */
	private String hasRole = null;

	/**
	 * The role the current user must lack.
	 */
	private String hasNotRole = null;

	private String menuFilterManagerBeanName = "menuFilterManager";

	private boolean pageStatusTagCalled = false;

	/**
	 * @return the menuFilterManagerBeanName
	 */
	public String getMenuFilterManagerBeanName() {
		return menuFilterManagerBeanName;
	}

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

	/**
	 * @return the notAuthorizedAction
	 */
	public String getNotAuthorizedAction() {
		return notAuthorizedAction;
	}

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

	/**
	 * @return the link
	 */
	public String getLink() {
		return link;
	}

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

	/**
	 * @return the hasRole
	 */
	public String getHasRole() {
		return hasRole;
	}

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

	/**
	 * @return the hasNotRole
	 */
	public String getHasNotRole() {
		return hasNotRole;
	}

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

	/**
	 * Includes its body if condition() evaluates to true.
	 * 
	 * @throws JspException
	 */
	public int doStartTag() throws JspException {
		// execute our condition() method once per invocation
		boolean notAuthorized = condition();

		// handle conditional behavior
		if (notAuthorized) {
			if (getNotAuthorizedAction().equalsIgnoreCase("status")) {
				pageStatusTagCalled = true;
				return super.doStartTag();
			}
			if (getNotAuthorizedAction().equalsIgnoreCase("skip")) {
				return SKIP_BODY;
			}
		}
		return EVAL_BODY_INCLUDE;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.taglibs.standard.tag.rt.core.IfTag#condition()
	 */
	@Override
	protected boolean condition() {
		try {
			String link = (String) ExpressionEvaluationUtils.evaluate("link", getLink(), this.pageContext);
			if (link != null) {
				return checkLink(link);
			}
			if (hasRole != null) {
				return checkHasRole();
			}
			if (hasNotRole != null) {
				return checkHasNotRole();
			}
			throw new RuntimeException("One (and only one!) of: 'link', 'hasRole' or 'hasNotRole' must be specified.");
		} catch (JspException e) {
			throw new RuntimeException("Error evaluating link/hasRole/hasNotRole attribute.");
		}
	}

	/**
	 * @param link
	 * @return
	 */
	private boolean checkLink(String link) {
		MenuFilterManager menuFilterManager = (MenuFilterManager) WebApplicationContextUtils
				.getRequiredWebApplicationContext((ServletContext) this.pageContext.getServletContext())
				.getBean(getMenuFilterManagerBeanName());
		boolean isAuthorizationDenied = menuFilterManager.disableMenuItem(link);
		return isAuthorizationDenied;
	}

	/**
	 * @return
	 */
	private boolean checkHasRole() {
		return !SecurityUtils.isUserInRoles(hasRole);
	}

	/**
	 * @return
	 */
	private boolean checkHasNotRole() {
		return SecurityUtils.isUserInRoles(hasNotRole);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.servlet.jsp.tagext.TagSupport#doEndTag()
	 */
	@Override
	public int doEndTag() throws JspException {
		if (pageStatusTagCalled == true) {
			pageStatusTagCalled = false;
			return super.doEndTag();
		}
		return EVAL_PAGE;
	}

	/**
	 * Releases any resources this ConditionalTagSupport may have (or inherit).
	 */
	public void release() {
		super.release();
		pageStatusTagCalled = false;
		link = null;
		hasRole = null;
		hasNotRole = null;
		setMenuFilterManagerBeanName("menuFilterManager");
		setNotAuthorizedAction("skip");
	}

}
