/*
 * 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.test;

import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import junit.framework.TestCase;

import nuts.core.io.IOUtils;
import nuts.core.mock.web.MockHttpServletRequest;
import nuts.core.mock.web.MockHttpServletResponse;
import nuts.core.mock.web.MockHttpSession;
import nuts.core.mock.web.MockServletContext;
import nuts.exts.struts2.mock.StrutsMockSupport;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.dispatcher.Dispatcher;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionProxy;

/**
 * StrutsTestCase
 */
public abstract class StrutsTestCase extends TestCase {
	protected static final Log log = LogFactory.getLog(StrutsTestCase.class);

	private StrutsMockSupport mock = new StrutsMockSupport();
	
	/**
	 * Constructor
	 */
	public StrutsTestCase() {
		super();
	}

	/**
	 * Constructor
	 * @param name the name to set
	 */
	public StrutsTestCase(String name) {
		super(name);
	}

	@Override
	protected void setUp() throws Exception {
		super.setUp();
	}

	@Override
	protected void tearDown() throws Exception {
		super.tearDown();
		cleanUp();
	}

	protected static void initDispatcher(String contextRoot) {
		StrutsMockSupport.initDispatcher(contextRoot);
	}
	
	protected Map<String, String> loadRequestParameters(String requestFile) throws Exception {
		InputStream is = getClass().getResourceAsStream(requestFile);
		Properties p = new Properties();
		p.load(is);
		IOUtils.closeQuietly(is);

		Map<String, String> rps = new HashMap<String, String>();
		for (Entry<Object, Object> a : p.entrySet()) {
			rps.put(a.getKey().toString(), a.getValue().toString());
		}
		return rps;
	}

	protected ActionProxy createActionProxy(String namespace, String actionName) throws Exception {
		return createActionProxy(namespace, actionName, null);
	}

	protected ActionProxy createActionProxy(String namespace, String actionName, String methodName) throws Exception {
		return createActionProxy(namespace, actionName, methodName, (Map<String, String>)null);
	}

	protected ActionProxy createActionProxy(String namespace, String actionName,
			String methodName, String paramFile) throws Exception {
		Map<String, String> params = null;
		if (paramFile != null) {
			params = loadRequestParameters(paramFile);
		}
		return createActionProxy(namespace, actionName, methodName, params);
	}

	protected ActionProxy createActionProxy(String namespace, String actionName,
			String methodName, Map<String, String> requestParams) throws Exception {
		return mock.createActionProxy(namespace, actionName, methodName, requestParams);
	}

	protected void doRequest(String uri) throws Exception {
		doRequest(uri, (String)null);
	}

	protected void doRequest(String uri, String paramFile) throws Exception {
		Map<String, String> requestParams = null;
		if (paramFile != null) {
			requestParams = loadRequestParameters(paramFile);
		}
		doRequest(uri, requestParams);
	}

	protected void doRequest(String uri, Map<String, String> params) throws Exception {
		mock.doRequest(uri, params);
	}

	protected void doRequest(ServletRequest req, ServletResponse res) throws Exception {
		mock.doRequest(req, res);
	}

    protected void cleanUp() {
    	mock.cleanUp();
	}

	protected ActionContext getActionContext() {
		return ActionContext.getContext();
	}

	protected Object getAction() {
    	return getActionContext().getActionInvocation().getProxy().getAction();
	}

	protected String getTestMethodName() {
		String mn = "";

		StackTraceElement stack[] = (new Throwable()).getStackTrace();
		for (int i = 0; i < stack.length; i++) {
			StackTraceElement ste = stack[i];
			if (this.getClass().getName().equals(ste.getClassName())) {
				mn = ste.getMethodName();
				for (i++; i < stack.length; i++) {
					ste = stack[i];
					if (this.getClass().getName().equals(ste.getClassName())) {
						mn = ste.getMethodName();
					}
					else {
						break;
					}
				}
			}
		}
		return mn;
	}

	protected String getResponseContentAsString() throws UnsupportedEncodingException {
		return mock.getResponseContentAsString();
	}

	protected byte[] getResponseContentAsByteArray() {
		return mock.getResponseContentAsByteArray();
	}

	// setter & getter
	/**
	 * @return the mockServletContext
	 */
	protected static MockServletContext getMockServletContext() {
		return StrutsMockSupport.getMockServletContext();
	}

	/**
	 * @param mockServletContext the mockServletContext to set
	 */
	protected static void setMockServletContext(MockServletContext mockServletContext) {
		StrutsMockSupport.setMockServletContext(mockServletContext);
	}

	/**
	 * @return the dispatcher
	 */
	protected static Dispatcher getDispatcher() {
		return StrutsMockSupport.getDispatcher();
	}

	/**
	 * @return the mockSession
	 */
	protected MockHttpSession getMockSession() {
		return mock.getMockSession();
	}

	/**
	 * @param mockSession the mockSession to set
	 */
	protected void setMockSession(MockHttpSession mockSession) {
		mock.setMockSession(mockSession);
	}

	/**
	 * @return the mockRequest
	 */
	protected MockHttpServletRequest getMockRequest() {
		return mock.getMockRequest();
	}

	/**
	 * @param mockRequest the mockRequest to set
	 */
	protected void setMockRequest(MockHttpServletRequest mockRequest) {
		mock.setMockRequest(mockRequest);
	}

	/**
	 * @return the mockResponse
	 */
	protected MockHttpServletResponse getMockResponse() {
		return mock.getMockResponse();
	}

	/**
	 * @param mockResponse the mockResponse to set
	 */
	protected void setMockResponse(MockHttpServletResponse mockResponse) {
		mock.setMockResponse(mockResponse);
	}

	/**
	 * @return the actionExtension
	 */
	protected String getActionExtension() {
		return mock.getActionExtension();
	}
}