/*
 * This file is part of Nuts Framework.
 * Copyright(C) 2009-2012 Nuts Develop Team.
 *
 * Nuts Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License any later version.
 *
 * Nuts Framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Nuts Framework. If not, see <http://www.gnu.org/licenses/>.
 */
package nuts.exts.struts2.util;

import nuts.core.lang.Classes;
import nuts.core.lang.Strings;
import nuts.exts.struts2.interceptor.ActionHelperInterceptor;
import nuts.exts.struts2.interceptor.LocaleInterceptor;
import nuts.exts.xwork2.util.ContextUtils;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.PageContext;

import org.apache.struts2.ServletActionContext;
import org.apache.struts2.StrutsStatics;
import org.apache.struts2.dispatcher.Dispatcher;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.interceptor.PrincipalProxy;
import org.apache.struts2.servlet.interceptor.ServletPrincipalProxy;

import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.TextProvider;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.mock.MockActionInvocation;
import com.opensymphony.xwork2.mock.MockActionProxy;
import com.opensymphony.xwork2.util.ValueStack;

/**
 * StrutsContextUtils
 */
public class StrutsContextUtils extends ContextUtils implements StrutsStatics {

	/**
	 * STATIC = "static";
	 */
	public static final String STATIC = "static";
	
    /** The static base url */
    public static final String NUTS_STATIC_BASE = "nuts-static-base";

    /**
	 * @return Container
	 */
	public static Container getContainer() {
		return Dispatcher.getInstance().getContainer();
	}

	/**
	 * Gets the current action context
	 *
	 * @param req The request
	 * @return The current action context
	 * @see ServletActionContext#getActionContext(HttpServletRequest)
	 */
	public static ActionContext getActionContext(HttpServletRequest req) {
		return ServletActionContext.getActionContext(req);
	}

	/**
	 * Gets the current value stack for this request
	 *
	 * @param req The request
	 * @return The value stack
	 * @see ServletActionContext#getValueStack(HttpServletRequest)
	 */
	public static ValueStack getValueStack(HttpServletRequest req) {
		return ServletActionContext.getValueStack(req);
	}

	/**
	 * Gets the action mapping for this context
	 *
	 * @return The action mapping
	 * @see ServletActionContext#getActionMapping()
	 */
	public static ActionMapping getActionMapping() {
		return ServletActionContext.getActionMapping();
	}

	/**
	 * Returns the HTTP page context.
	 *
	 * @return the HTTP page context.
	 * @see ServletActionContext#getPageContext()
	 */
	public static PageContext getPageContext() {
		return ServletActionContext.getPageContext();
	}

	/**
	 * Gets the HTTP servlet request object.
	 *
	 * @return the HTTP servlet request object.
	 * @see ServletActionContext#getRequest()
	 */
	public static HttpServletRequest getServletRequest() {
		return ServletActionContext.getRequest();
	}

	/**
	 * Gets the HTTP servlet request object.
	 *
	 * @param invocation action invocation
	 * @return the HTTP servlet request object.
	 */
	public static HttpServletRequest getServletRequest(ActionInvocation invocation) {
		return (HttpServletRequest)invocation.getInvocationContext().get(HTTP_REQUEST);
	}

	/**
	 * Gets the HTTP servlet response object.
	 *
	 * @return the HTTP servlet response object.
	 * @see ServletActionContext#getResponse()
	 */
	public static HttpServletResponse getServletResponse() {
		return ServletActionContext.getResponse();
	}

	/**
	 * Gets the HTTP servlet responset object.
	 *
	 * @param invocation action invocation
	 * @return the HTTP servlet response object.
	 */
	public static HttpServletResponse getServletResponse(ActionInvocation invocation) {
		return (HttpServletResponse)invocation.getInvocationContext().get(HTTP_RESPONSE);
	}

	/**
	 * Gets the servlet context.
	 *
	 * @return the servlet context.
	 * @see ServletActionContext#getServletContext()
	 */
	public static ServletContext getServletContext() {
		return ServletActionContext.getServletContext();
	}

	/**
	 * Gets the PrincipalProxy object.
	 *
	 * @return the PrincipalProxy object.
	 */
	public static PrincipalProxy getPrincipalProxy() {
		HttpServletRequest request = getServletRequest();
		if (request != null) {
			// We are in servtlet environment, so principal information resides in
			// HttpServletRequest
			return new ServletPrincipalProxy(request);
		}
		return null;
	}

	/**
	 * @return the static base path
	 */
	public static String getStaticBasePath() {
		HttpServletRequest request = getServletRequest();
		ValueStack stack = getValueStack();
		return getStaticBasePath(request, stack);
	}

	/**
	 * @param stack value stack
	 * @return the static base path
	 */
	public static String getStaticBasePath(ValueStack stack) {
		HttpServletRequest request = StrutsContextUtils.getServletRequest();
		return getStaticBasePath(request, stack);
	}

	/**
	 * 
	 * @param request http request
	 * @param stack value stack
	 * @return the static base path
	 */
	public static String getStaticBasePath(HttpServletRequest request, ValueStack stack) {
		if (stack == null) {
			stack = getValueStack(request);
		}
		TextProvider tp = findTextProviderInStack(stack);
		String sb = tp.getText(StrutsContextUtils.NUTS_STATIC_BASE, (String)null);
		if (Strings.isEmpty(sb)) {
			sb = request.getContextPath() + "/static";
		}
		else if (sb.charAt(0) == '~') {
			sb = request.getContextPath() + sb.substring(1);
		}
		return sb;
	}
	
	/**
	 * create mock action 
	 * @param location relative url
	 * @param container container
	 * @param ctx context
	 * @param mockAction mack action class name
	 * @throws Exception if an error occurs
	 */
	public static void createMockAction(String location, Container container, ActionContext ctx,
			String mockAction) throws Exception {
		String namespace = "";
		String actionName = "";
		int i = location.lastIndexOf('/');
		if (i >= 0) {
			actionName = location.substring(i + 1);
			namespace = location.substring(0, i + 1);
			i = actionName.lastIndexOf('.');
			if (i >= 0) {
				actionName = actionName.substring(0, i);
			}
		}

		// mock invocation & proxy
		MockActionProxy map = new MockActionProxy();
		MockActionInvocation mai = new MockActionInvocation();

		map.setActionName(actionName);
		map.setNamespace(namespace);
		map.setInvocation(mai);
		map.setMethod("");

		mai.setInvocationContext(ctx);
		mai.setProxy(map);
		mai.setResultCode(Action.SUCCESS);
		//mai.setResult(result);

		ctx.setActionInvocation(mai);

		// put in a dummy ActionSupport so basic functionality still works
		Object action;
		if (Strings.isNotEmpty(mockAction)) {
			action = Classes.newInstance(mockAction);
		}
		else {
			action = new ActionSupport();
		}
		container.inject(action);
		
		map.setAction(action);
		mai.setAction(action);
		ctx.getValueStack().push(action);

		LocaleInterceptor li = new LocaleInterceptor();
		container.inject(li);
		li.init();
		li.intercept(mai);

		ActionHelperInterceptor ahi = new ActionHelperInterceptor();
		container.inject(ahi);
		ahi.init();
		ahi.intercept(mai);
	}
}
