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

import it.mice.voila.runtime.springmvc.bean.PathStack;
import it.mice.voila.runtime.springmvc.bean.PathStackElement;
import it.mice.voila.runtime.springmvc.flashmap.FlashMap;

import java.io.IOException;

import javax.portlet.PortletContext;
import javax.portlet.PortletRequest;
import javax.portlet.PortletSession;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.portlet.context.PortletRequestAttributes;

/**
 * Spring MVC Utility class.
 *
 */
public class SpringMvcUtil {
	/**
	 * default logger.
	 */
	private static final Log log = LogFactory.getLog(SpringMvcUtil.class);
	/**
	 * The path stack identifier.
	 */
	public static final String PATH_STACK = SpringMvcUtil.class.getName() + ".pathStackForm";
	/**
	 * The last view name identifier.
	 */
	public static final String LAST_VIEW_NAME = SpringMvcUtil.class.getName() + ".lastViewNameForm";

	/**
	 * Return the current http request.
	 * @return the current http request.
	 */
	public static  PortletRequest getRequest() {
		RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
		return ((PortletRequestAttributes)requestAttributes).getRequest();
	}

	/**
	 * Return the current http session.
	 * @return the current http session.
	 */
	public static PortletSession getSession() {
		return getRequest().getPortletSession();
	}

	/**
	 * Return the current servlet context.
	 * @return the current servlet context.
	 */
	public static PortletContext getServletContext() {
		return getSession().getPortletContext();
	}

	/**
	 * Return the path stack.
	 * @return the path stack.
	 */
	public static PathStack getStack() {
		PortletSession session = getRequest().getPortletSession();
		PathStack stack = (PathStack)session.getAttribute(PATH_STACK);
		if (stack == null) {
			stack = new PathStack(); 
			session.setAttribute(PATH_STACK, stack);
		}
		return stack;
	}

	/**
	 * Return the url of the last path stack.
	 * @return url of the last path stack.
	 */
	public static String popLastStackPath() {
		PathStack stack = SpringMvcUtil.getStack();
		if (stack.empty()) {
			log.error("Stack is empty but a redirect:goBack was requested. Continue anyway...");
			return getRequest().getContextPath() + "/home";
		}
		return stack.pop().getPath();
	}

	/**
	 * Perform a response riderection to the last path.
	 * @param request the http request.
	 * @param response the http response
	 * @param requestURI the http request URI
	 * @param popCounter the number of steps to undo.
	 */
	public static void doLastPathRedirect(HttpServletRequest request,
			HttpServletResponse response, String requestURI, int popCounter) {
		PathStack stack = SpringMvcUtil.getStack();
		String lastStackPath = stack.lastElement().getPath();
		if (stack.size() < popCounter) {
			log.error("Stack contains " + stack.size() + " elements, so the go back cannot work properly. Redirecting to the home page...");
			lastStackPath = request.getContextPath() + "/";
			stack.clear();
		} else {
			for (int i=0; i < popCounter; i++) {
				lastStackPath = stack.pop().getPath();
			}
		}
		if (log.isDebugEnabled()) {
			log.debug("GoBack is about to redirect navigation to " + lastStackPath);
		}
		
		doRedirection(response, requestURI, lastStackPath);
	}

	/**
	 * Perform a response riderection to the path just before the new activated flow.
	 * @param request the http request.
	 * @param response the http response
	 * @param requestURI the http request URI
	 */
	public static void doPrevFlowRedirect(HttpServletRequest request,
			HttpServletResponse response, String requestURI) {
		String lastStackPath = null;
		PathStack stack = SpringMvcUtil.getStack();
		
		PathStackElement element = null;
		if (!stack.isEmpty()) {
			element = stack.pop();
			while (!element.isNewFlow() && !stack.isEmpty()) {
				element = stack.pop();
			}
		}
		
		if (element == null || !element.isNewFlow()) {
			log.error("No start flow found into path stack but a special.endFlow was requested, so the go back cannot work properly. Redirecting to the home page...");
			lastStackPath = request.getContextPath() + "/";
			stack.clear();
		} else {
			//element = stack.pop();
			lastStackPath = element.getPath();
			if (log.isDebugEnabled()) {
				log.debug("GoBack is about to redirect navigation to " + lastStackPath);
			}
		}
		
		doRedirection(response, requestURI, lastStackPath);
	}

	/**
	 * Return the request attribute or the request parameter of the given name.
	 * @param name request attribute or the request parameter name.
	 * @return the value of the request attribute or the request parameter of the given name.
	 */
	public static Object getRequestParameterOrAttribute(String name) {
		Object result = getRequest().getAttribute(name);
		if (result == null) {
			result = getRequest().getParameter(name);
		}
		return result;
	}
	
	/**
	 * Perform a response riderection to the given lastStackPath.
	 * @param response the http response
	 * @param requestURI the http request URI
	 * @param lastStackPath the last stack path to redirect to.
	 */
	private static void doRedirection(HttpServletResponse response,
			String requestURI, String lastStackPath) {
		int pos = requestURI.indexOf("?");
		if (pos > -1) {
			if (lastStackPath.indexOf("?") > -1) {
				lastStackPath += "&amp;" + requestURI.substring(pos+1);
			} else {
				lastStackPath += "?" + requestURI.substring(pos+1);
			}
		}
		try {
			response.sendRedirect(response.encodeRedirectURL(lastStackPath));
			FlashMap.recycleIntoSession();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

}
