/*
 * 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.EL;
import woolpack.el.ELConstants;
import woolpack.el.FixEL;
import woolpack.el.PathEL;
import woolpack.el.ToELTargetExceptionEL;
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 ToELTargetExceptionEL(){
					@Override public Object execute(Object root, 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 ToELTargetExceptionEL(){
					@Override public Object execute(Object root, 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 ToELTargetExceptionEL(){
					@Override public Object execute(Object root, 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(new Integer(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));
		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>"));
		}
	}
}
