package jp.sourceforge.glad.struts.config.impl;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;

import jp.sourceforge.glad.struts.annotation.StrutsAction;
import jp.sourceforge.glad.struts.annotation.StrutsException;
import jp.sourceforge.glad.struts.annotation.StrutsForm;
import jp.sourceforge.glad.struts.annotation.StrutsForward;
import junit.framework.TestCase;

import org.apache.struts.config.ActionConfig;
import org.apache.struts.config.ExceptionConfig;
import org.apache.struts.config.FormBeanConfig;
import org.apache.struts.config.ForwardConfig;

/**
 * {@link ModuleConfigBuilderImpl} の単体テスト。
 * 
 * @author GLAD!!
 */
public class ModuleConfigBuilderImplTest extends TestCase {

    ModuleConfigBuilderImpl builder;

    protected void setUp() throws Exception {
        builder = new ModuleConfigBuilderImpl();
    }

    protected void tearDown() throws Exception {
        builder = null;
    }

    // ---- FormBeanConfig

    public void testCreateFormBeanConfig() {
        FormBeanConfig config = builder.createFormBeanConfig(SimpleForm.class);
        assertEquals("simpleForm", config.getName());
        assertEquals(SimpleForm.class.getName(), config.getType());
    }

    public void testCreateFormBeanConfig_withName() {
        FormBeanConfig config = builder.createFormBeanConfig(NamedForm.class);
        assertEquals("hogeForm", config.getName());
        assertEquals(NamedForm.class.getName(), config.getType());
    }

    @StrutsForm
    static class SimpleForm {
    }

    @StrutsForm(name = "hogeForm")
    static class NamedForm {
    }

    // ---- ActionConfig

    public void testCreateActionConfig() {
        ActionConfig config = builder.createActionConfig(SimpleAction.class);
        assertEquals("/simple", config.getPath());
        assertEquals(SimpleAction.class.getName(), config.getType());
        assertNull(config.getParameter());
        assertEquals("simpleForm", config.getName());
        assertEquals("request", config.getScope());
        assertFalse(config.getValidate());
        assertNull(config.getInput());
        
        ForwardConfig[] forwards = config.findForwardConfigs();
        assertEquals(1, forwards.length);
        ForwardConfig success = config.findForwardConfig("success");
        assertSame(forwards[0], success);
        assertEquals("success", success.getName());
        assertEquals("/WEB-INF/view/simple.jsp", success.getPath());
        
        ExceptionConfig[] exceptions = config.findExceptionConfigs();
        assertEquals(0, exceptions.length);
    }

    public void testCreateActionConfig_forIndex() throws Exception {
        Method method = DispatchAction.class.getMethod("index");
        ActionConfig config =
                builder.createActionConfig(DispatchAction.class, method);
        assertEquals("/dispatch", config.getPath());
        assertEquals(DispatchAction.class.getName(), config.getType());
        assertEquals("index", config.getParameter());
        assertNull(config.getName());
        assertEquals("request", config.getScope());
        assertFalse(config.getValidate());
        assertNull(config.getInput());
        
        ForwardConfig[] forwards = config.findForwardConfigs();
        assertEquals(1, forwards.length);
        ForwardConfig success = config.findForwardConfig("success");
        assertSame(forwards[0], success);
        assertEquals("success", success.getName());
        assertEquals("/dispatch/input.do", success.getPath());
        
        ExceptionConfig[] exceptions = config.findExceptionConfigs();
        assertEquals(0, exceptions.length);
    }

    public void testCreateActionConfig_forInput() throws Exception {
        Method method = DispatchAction.class.getMethod("input");
        ActionConfig config =
                builder.createActionConfig(DispatchAction.class, method);
        assertEquals("/dispatch/input", config.getPath());
        assertEquals(DispatchAction.class.getName(), config.getType());
        assertEquals("input", config.getParameter());
        assertNull(config.getName());
        assertEquals("request", config.getScope());
        assertFalse(config.getValidate());
        assertNull(config.getInput());
        
        ForwardConfig[] forwards = config.findForwardConfigs();
        assertEquals(1, forwards.length);
        ForwardConfig success = config.findForwardConfig("success");
        assertSame(forwards[0], success);
        assertEquals("success", success.getName());
        assertEquals("/WEB-INF/view/dispatch/input.jsp", success.getPath());
        
        ExceptionConfig[] exceptions = config.findExceptionConfigs();
        assertEquals(0, exceptions.length);
    }

    public void testCreateActionConfig_forConfirm() throws Exception {
        Method method = DispatchAction.class.getMethod(
                "confirm", SimpleForm.class, HttpServletRequest.class);
        ActionConfig config =
                builder.createActionConfig(DispatchAction.class, method);
        assertEquals("/dispatch/confirm", config.getPath());
        assertEquals(DispatchAction.class.getName(), config.getType());
        assertEquals("confirm", config.getParameter());
        assertEquals("simpleForm", config.getName());
        assertEquals("request", config.getScope());
        assertTrue(config.getValidate());
        assertEquals("/dispatch/input.do", config.getInput());
        
        ForwardConfig[] forwards = config.findForwardConfigs();
        assertEquals(1, forwards.length);
        ForwardConfig success = config.findForwardConfig("success");
        assertSame(forwards[0], success);
        assertEquals("success", success.getName());
        assertEquals("/WEB-INF/view/dispatch/confirm.jsp", success.getPath());
        
        ExceptionConfig[] exceptions = config.findExceptionConfigs();
        assertEquals(0, exceptions.length);
    }

    public void testCreateActionConfig_forExecute() throws Exception {
        Method method = DispatchAction.class.getMethod(
                "execute", HttpServletRequest.class);
        ActionConfig config =
                builder.createActionConfig(DispatchAction.class, method);
        assertEquals("/dispatch/execute", config.getPath());
        assertEquals(DispatchAction.class.getName(), config.getType());
        assertEquals("execute", config.getParameter());
        assertNull(config.getName());
        assertEquals("request", config.getScope());
        assertFalse(config.getValidate());
        assertNull(config.getInput());
        
        ForwardConfig[] forwards = config.findForwardConfigs();
        assertEquals(2, forwards.length);
        ForwardConfig success = config.findForwardConfig("success");
        assertEquals("success", success.getName());
        assertEquals("/dispatch/complete.do", success.getPath());
        assertTrue(success.getRedirect());
        ForwardConfig error = config.findForwardConfig("error");
        assertEquals("error", error.getName());
        assertEquals("/dispatch/input.do", error.getPath());
        assertFalse(error.getRedirect());
        
        ExceptionConfig[] exceptions = config.findExceptionConfigs();
        assertEquals(1, exceptions.length);
        ExceptionConfig exception = config.findException(RuntimeException.class);
        assertSame(exceptions[0], exception);
        assertEquals(RuntimeException.class.getName(), exception.getType());
        assertEquals("/dispatch/input.do", exception.getPath());
    }

    public void testCreateActionConfig_forComplete() throws Exception {
        Method method = DispatchAction.class.getMethod(
                "complete", HttpServletRequest.class);
        ActionConfig config =
                builder.createActionConfig(DispatchAction.class, method);
        assertEquals("/dispatch/complete", config.getPath());
        assertEquals(DispatchAction.class.getName(), config.getType());
        assertEquals("complete", config.getParameter());
        assertNull(config.getName());
        assertEquals("request", config.getScope());
        assertFalse(config.getValidate());
        assertNull(config.getInput());
        
        ForwardConfig[] forwards = config.findForwardConfigs();
        assertEquals(1, forwards.length);
        ForwardConfig success = config.findForwardConfig("success");
        assertSame(forwards[0], success);
        assertEquals("success", success.getName());
        assertEquals("/WEB-INF/view/dispatch/complete.jsp", success.getPath());
        
        ExceptionConfig[] exceptions = config.findExceptionConfigs();
        assertEquals(0, exceptions.length);
    }

    @StrutsAction
    static class SimpleAction {

        public void index(SimpleForm form) {}

    }

    static class DispatchAction {

        @StrutsAction(
            path = "/dispatch",
            forwards = @StrutsForward(path = "/dispatch/input.do"))
        public void index() {}

        @StrutsAction
        public void input() {}

        @StrutsAction(validate = true)
        public void confirm(SimpleForm form, HttpServletRequest request) {}

        @StrutsAction(
            forwards = {
                @StrutsForward(path = "/dispatch/complete.do", redirect = true),
                @StrutsForward(name = "error", path = "/dispatch/input.do")
            },
            exceptions = @StrutsException(
                type = RuntimeException.class, path = "/dispatch/input.do"))
        public void execute(HttpServletRequest request) {}

        @StrutsAction
        public void complete(HttpServletRequest request) {}

    }

    public void testToPath() {
        assertEquals("/foo/bar", ModuleConfigBuilderImpl.toPath("fooBar"));
        assertEquals("/foo/bar", ModuleConfigBuilderImpl.toPath("fooBAR"));
        assertEquals("/foo/bar", ModuleConfigBuilderImpl.toPath("FooBar"));
        assertEquals("/foo/bar", ModuleConfigBuilderImpl.toPath("FooBAR"));
        assertEquals("/foo/bar", ModuleConfigBuilderImpl.toPath("FOOBar"));
        assertEquals("/foo/bar", ModuleConfigBuilderImpl.toPath("_foo_bar__"));
        assertEquals("/foo/bar", ModuleConfigBuilderImpl.toPath("_foo_Bar__"));
        assertEquals("/foo/bar", ModuleConfigBuilderImpl.toPath("_foo_BAR__"));
        assertEquals("/foo/bar", ModuleConfigBuilderImpl.toPath("_Foo_bar__"));
        assertEquals("/foo/bar", ModuleConfigBuilderImpl.toPath("_Foo_Bar__"));
        assertEquals("/foo/bar", ModuleConfigBuilderImpl.toPath("_Foo_BAR__"));
        assertEquals("/foo/bar", ModuleConfigBuilderImpl.toPath("_FOO_bar__"));
        assertEquals("/foo/bar", ModuleConfigBuilderImpl.toPath("_FOO_Bar__"));
        assertEquals("/foo/bar", ModuleConfigBuilderImpl.toPath("_FOO_BAR__"));
    }

}
