/*
 * Copyright 2006 Takahiro Nakamura.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package woolpack.ee;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import junit.framework.TestCase;
import woolpack.action.ActionConstants;
import woolpack.action.ActionDef;
import woolpack.action.ActionInvoker;
import woolpack.action.ForwardDef;
import woolpack.adapter.JXPFactory;
import woolpack.dom.DomContext;
import woolpack.dom.DomExpression;
import woolpack.dom.Serial;
import woolpack.el.AbstractToELTargetExceptionEL;
import woolpack.el.EL;
import woolpack.el.ELConstants;
import woolpack.el.FixEL;
import woolpack.el.PathEL;
import woolpack.test.TestBean;
import woolpack.test.TestUtils;
import woolpack.utils.MapBuilder;
import woolpack.utils.SwitchBuilder;

public class ActionBuilderTest extends TestCase {

	private ActionInvoker defs;

	private ActionBuilder builder;

	private EL localForwardBean0 = new PathEL("local.forwardBean0");

	private EL localForwardBean2 = new PathEL("local.forwardBean2");

	@Override
	protected void setUp() {
		final ForwardDef expectedForwardDef = new ForwardDef("forwardId0",
				localForwardBean0, ActionConstants.NOT_THROWABLE);
		defs = new ActionInvoker(new SwitchBuilder<String, ActionDef>().put(
				"id0",
				new ActionDef(ELConstants.NULL, new AbstractToELTargetExceptionEL() {
					@Override
					public Object execute(final Object root, final Object value)
							throws Exception {
						// new OGE("container.myBean.executeVoid()")
						((TestBean) ((Map) ((DomContext) root).getContainer())
								.get("myBean")).executeVoid();
						return null;
					}
				}, expectedForwardDef)).put("id1",
				new ActionDef(ELConstants.NULL, new AbstractToELTargetExceptionEL() {
					@Override
					public Object execute(final Object root, final Object value)
							throws Exception {
						// new OGE("container.myBean.executeInt()")
						return ((TestBean) ((Map) ((DomContext) root)
								.getContainer()).get("myBean")).executeInt();
					}
				}, expectedForwardDef)).put("id2",
				new ActionDef(ELConstants.NULL, new AbstractToELTargetExceptionEL() {
					@Override
					public Object execute(final Object root, final Object value)
							throws Exception {
						// new OGE("container.myBean.executeException()")
						((TestBean) ((Map) ((DomContext) root).getContainer())
								.get("myBean")).executeException();
						return null;
					}
				}, expectedForwardDef)).get(), new ForwardDef("forwardId2",
				localForwardBean2, ActionConstants.ANY));
		builder = new ActionBuilder(defs, Arrays.asList("name", "id"),
				new JXPFactory());
	}

	public void testConstructor() {
		try {
			new ActionBuilder(null, Arrays.asList("name", "id"),
					ELConstants.NULL, ELConstants.NULL, new JXPFactory());
			fail();
		} catch (final NullPointerException expected) {
		}
		try {
			new ActionBuilder(defs, null, ELConstants.NULL, ELConstants.NULL,
					new JXPFactory());
			fail();
		} catch (final NullPointerException expected) {
		}
		try {
			new ActionBuilder(defs, Arrays.asList("name", "id"), null,
					ELConstants.NULL, new JXPFactory());
			fail();
		} catch (final NullPointerException expected) {
		}
		try {
			new ActionBuilder(defs, Arrays.asList("name", "id"),
					ELConstants.NULL, null, new JXPFactory());
			fail();
		} catch (final NullPointerException expected) {
		}
		try {
			new ActionBuilder(defs, Arrays.asList("name", "id"),
					ELConstants.NULL, ELConstants.NULL, null);
			fail();
		} catch (final NullPointerException expected) {
		}
	}

	public void testGet() {
		final EL el0 = new FixEL("forwardComponent0");
		final EL el1 = new FixEL("return0");
		final ActionBuilder builder = new ActionBuilder(defs, Arrays.asList(
				"name", "id"), el0, el1, new JXPFactory());
		assertEquals(el0, builder.getForwardComponentELEL());
		assertEquals(el1, builder.getReturnEL());
	}

	public void testGetActionExpressionReturnVoid() {
		final DomContext context = new DomContext();
		context.setId("id0");
		context.setInput(MapBuilder.get(new HashMap<String, Object>()).put(
				"myInt", 7).get());
		context
				.setContainer(Collections
						.singletonMap("myBean", new TestBean()));
		builder.getActionExpression().interpret(context);
		assertEquals("forwardId0", context.getId());
		assertSame(localForwardBean0,
				ActionBuilder.DEFAULT_FORWARD_COMPONENT_EL_EL.getValue(context));
		assertNull(ActionBuilder.DEFAULT_RETURN_EL.getValue(context));
	}

	public void testGetActionExpressionReturnInteger() {
		final DomContext context = new DomContext();
		context.setId("id1");
		context.setInput(MapBuilder.get(new HashMap<String, Object>()).put(
				"myInt", 7).get());
		context
				.setContainer(Collections
						.singletonMap("myBean", new TestBean()));
		builder.getActionExpression().interpret(context);
		assertEquals("forwardId0", context.getId());
		assertSame(localForwardBean0,
				ActionBuilder.DEFAULT_FORWARD_COMPONENT_EL_EL.getValue(context));
		assertEquals(Integer.valueOf(1), ActionBuilder.DEFAULT_RETURN_EL
				.getValue(context));
	}

	public void testGetActionExpressionException() {
		final DomContext context = new DomContext();
		context.setId("id2");
		context.setInput(MapBuilder.get(new HashMap<String, Object>()).put(
				"myInt", 7).get());
		context
				.setContainer(Collections
						.singletonMap("myBean", new TestBean()));
		builder.getActionExpression().interpret(context);
		assertEquals("forwardId2", context.getId());
		assertSame(localForwardBean2,
				ActionBuilder.DEFAULT_FORWARD_COMPONENT_EL_EL.getValue(context));
		final Iterator iterator = ((Iterable) ActionBuilder.DEFAULT_RETURN_EL
				.getValue(context)).iterator();
		assertTrue(iterator.hasNext());
		assertEquals("java.lang.IndexOutOfBoundsException", iterator.next());
		assertFalse(iterator.hasNext());
	}

	public void testGetAutoUpdateExpression() {
		final DomExpression expression = new Serial(
				TestUtils
						.getToNodeForm("<TEXTAREA name=\"textarea0\" >value0</TEXTAREA>"
								+ "<DIV id=\"div0\" >value0</DIV>"
								+ "<SPAN id=\"span0\" >value0</SPAN>"
								+ "<INPUT name=\"input0\" value=\"value0\" />"
								+ "<SPAN id=\"span1\" >spanvalue1</SPAN>"),
				builder.getAutoUpdateExpression());
		{
			final DomContext context = new DomContext();
			context.getLocal().put(
					"forwardBean0",
					MapBuilder.get(new HashMap<String, Object>()).put(
							"textarea0", "textareavalue0").put("div0",
							"divvalue0").put("span0", "spanvalue0").put(
							"input0", "inputvalue0").get());
			ActionBuilder.DEFAULT_FORWARD_COMPONENT_EL_EL.setValue(context,
					new PathEL("local.forwardBean0"));
			expression.interpret(context);

			assertTrue(TestUtils.equalsForm(context,
					"<TEXTAREA name=\"textarea0\" >textareavalue0</TEXTAREA>"
							+ "<DIV id=\"div0\" >divvalue0</DIV>"
							+ "<SPAN id=\"span0\" >spanvalue0</SPAN>"
							+ "<INPUT name=\"input0\" value=\"inputvalue0\" />"
							+ "<SPAN id=\"span1\" >spanvalue1</SPAN>"));
		}
		{
			final DomContext context = new DomContext();
			ActionBuilder.DEFAULT_FORWARD_COMPONENT_EL_EL.setValue(context,
					new PathEL("local.forwardBean0"));
			expression.interpret(context);

			assertTrue(TestUtils.equalsForm(context,
					"<TEXTAREA name=\"textarea0\" >value0</TEXTAREA>"
							+ "<DIV id=\"div0\" >value0</DIV>"
							+ "<SPAN id=\"span0\" >value0</SPAN>"
							+ "<INPUT name=\"input0\" value=\"value0\" />"
							+ "<SPAN id=\"span1\" >spanvalue1</SPAN>"));
		}
	}
}
