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

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import junit.framework.TestCase;
import woolpack.test.TestUtils;
import woolpack.utils.MapBuilder;

public class ValidatorConstantsTest extends TestCase {
	
	public void testTrueInterpret(){
		final ValidatorContext context = new ValidatorContext();
		assertTrue(ValidatorConstants.TRUE.interpret(context));
	}
	
	public void testFalseInterpret(){
		final ValidatorContext context = new ValidatorContext();
		assertFalse(ValidatorConstants.FALSE.interpret(context));
	}
	
	public void testRequiredInterpret(){
		final ValidatorContext context = new ValidatorContext();
		context.setInputMap(new HashMap<String,List<Object>>());
		context.setTmpKey("key0");

		context.setTmpValue(new Integer(1));
		assertTrue(ValidatorConstants.REQUIRED.interpret(context));
		assertTrue(TestUtils.equals(MapBuilder.get(new HashMap<String,Object>()).put("key0", Arrays.asList(1)).get(), context.getInputMap()));

		context.setTmpValue(null);
		assertFalse(ValidatorConstants.REQUIRED.interpret(context));
		assertTrue(TestUtils.equals(MapBuilder.get(new HashMap<String,Object>()).put("key0", Arrays.asList((Object)null)).get(), context.getInputMap()));

		context.setTmpValue("a");
		assertTrue(ValidatorConstants.REQUIRED.interpret(context));
		assertTrue(TestUtils.equals(MapBuilder.get(new HashMap<String,Object>()).put("key0", Arrays.asList("a")).get(), context.getInputMap()));

		context.setTmpValue("");
		assertFalse(ValidatorConstants.REQUIRED.interpret(context));
		assertTrue(TestUtils.equals(MapBuilder.get(new HashMap<String,Object>()).put("key0", Arrays.asList("")).get(), context.getInputMap()));
	}
	
	public void scenario(
			final ValidatorIterable iterable,
			final boolean[] input,
			final boolean expectedResult,
			final int[] expectedCount){
		final List<CountValidator> list = new ArrayList<CountValidator>();
		for(final boolean flag:input){
			list.add(new CountValidator(flag?ValidatorConstants.TRUE:ValidatorConstants.FALSE));
		}
		final ValidatorContext context = new ValidatorContext();
		assertEquals(expectedResult, iterable.interpret(context, list));
		for(int i=0; i<expectedCount.length; i++){
			assertEquals(expectedCount[i], list.get(i).getCount());
			for(int j=0; j<expectedCount[i]; j++){
				assertTrue(context == list.get(i).getContextList().removeLast());
			}
		}
	}
	
	public void testAndAnd() throws IOException{
		final ValidatorIterable it = ValidatorConstants.ANDAND;
		scenario(it, new boolean[0], true, new int[0]);
		scenario(it, new boolean[]{true}, true, new int[]{1});
		scenario(it, new boolean[]{false}, false, new int[]{1});
		scenario(it, new boolean[]{true,true}, true, new int[]{1,1});
		scenario(it, new boolean[]{true,false}, false, new int[]{1,1});
		scenario(it, new boolean[]{false,true}, false, new int[]{1,0});
		scenario(it, new boolean[]{false,false}, false, new int[]{1,0});
		scenario(it, new boolean[]{true,true,true}, true, new int[]{1,1,1});
		scenario(it, new boolean[]{true,true,false}, false, new int[]{1,1,1});
		scenario(it, new boolean[]{true,false,true}, false, new int[]{1,1,0});
		scenario(it, new boolean[]{true,false,false}, false, new int[]{1,1,0});
		scenario(it, new boolean[]{false,true,true}, false, new int[]{1,0,0});
		scenario(it, new boolean[]{false,true,false}, false, new int[]{1,0,0});
		scenario(it, new boolean[]{false,false,true}, false, new int[]{1,0,0});
		scenario(it, new boolean[]{false,false,false}, false, new int[]{1,0,0});
	}
	
	public void testAnd() throws IOException{
		final ValidatorIterable it = ValidatorConstants.AND;
		scenario(it, new boolean[0], true, new int[0]);
		scenario(it, new boolean[]{true}, true, new int[]{1});
		scenario(it, new boolean[]{false}, false, new int[]{1});
		scenario(it, new boolean[]{true,true}, true, new int[]{1,1});
		scenario(it, new boolean[]{true,false}, false, new int[]{1,1});
		scenario(it, new boolean[]{false,true}, false, new int[]{1,1});
		scenario(it, new boolean[]{false,false}, false, new int[]{1,1});
		scenario(it, new boolean[]{true,true,true}, true, new int[]{1,1,1});
		scenario(it, new boolean[]{true,true,false}, false, new int[]{1,1,1});
		scenario(it, new boolean[]{true,false,true}, false, new int[]{1,1,1});
		scenario(it, new boolean[]{true,false,false}, false, new int[]{1,1,1});
		scenario(it, new boolean[]{false,true,true}, false, new int[]{1,1,1});
		scenario(it, new boolean[]{false,true,false}, false, new int[]{1,1,1});
		scenario(it, new boolean[]{false,false,true}, false, new int[]{1,1,1});
		scenario(it, new boolean[]{false,false,false}, false, new int[]{1,1,1});
	}
	
	public void testOrOr() throws IOException{
		final ValidatorIterable it = ValidatorConstants.OROR;
		scenario(it, new boolean[0], true, new int[0]);
		scenario(it, new boolean[]{true}, true, new int[]{1});
		scenario(it, new boolean[]{false}, false, new int[]{1});
		scenario(it, new boolean[]{true,true}, true, new int[]{1,0});
		scenario(it, new boolean[]{true,false}, true, new int[]{1,0});
		scenario(it, new boolean[]{false,true}, true, new int[]{1,1});
		scenario(it, new boolean[]{false,false}, false, new int[]{1,1});
		scenario(it, new boolean[]{true,true,true}, true, new int[]{1,0,0});
		scenario(it, new boolean[]{true,true,false}, true, new int[]{1,0,0});
		scenario(it, new boolean[]{true,false,true}, true, new int[]{1,0,0});
		scenario(it, new boolean[]{true,false,false}, true, new int[]{1,0,0});
		scenario(it, new boolean[]{false,true,true}, true, new int[]{1,1,0});
		scenario(it, new boolean[]{false,true,false}, true, new int[]{1,1,0});
		scenario(it, new boolean[]{false,false,true}, true, new int[]{1,1,1});
		scenario(it, new boolean[]{false,false,false}, false, new int[]{1,1,1});
	}
	
	public void testOr() throws IOException{
		final ValidatorIterable it = ValidatorConstants.OR;
		scenario(it, new boolean[0], true, new int[0]);
		scenario(it, new boolean[]{true}, true, new int[]{1});
		scenario(it, new boolean[]{false}, false, new int[]{1});
		scenario(it, new boolean[]{true,true}, true, new int[]{1,1});
		scenario(it, new boolean[]{true,false}, true, new int[]{1,1});
		scenario(it, new boolean[]{false,true}, true, new int[]{1,1});
		scenario(it, new boolean[]{false,false}, false, new int[]{1,1});
		scenario(it, new boolean[]{true,true,true}, true, new int[]{1,1,1});
		scenario(it, new boolean[]{true,true,false}, true, new int[]{1,1,1});
		scenario(it, new boolean[]{true,false,true}, true, new int[]{1,1,1});
		scenario(it, new boolean[]{true,false,false}, true, new int[]{1,1,1});
		scenario(it, new boolean[]{false,true,true}, true, new int[]{1,1,1});
		scenario(it, new boolean[]{false,true,false}, true, new int[]{1,1,1});
		scenario(it, new boolean[]{false,false,true}, true, new int[]{1,1,1});
		scenario(it, new boolean[]{false,false,false}, false, new int[]{1,1,1});
	}
	
	public void testEqEq() throws IOException{
		final ValidatorIterable it = ValidatorConstants.EQEQ;
		scenario(it, new boolean[0], true, new int[0]);
		scenario(it, new boolean[]{true}, true, new int[]{1});
		scenario(it, new boolean[]{false}, true, new int[]{1});
		scenario(it, new boolean[]{true,true}, true, new int[]{1,1});
		scenario(it, new boolean[]{true,false}, false, new int[]{1,1});
		scenario(it, new boolean[]{false,true}, false, new int[]{1,1});
		scenario(it, new boolean[]{false,false}, true, new int[]{1,1});
		scenario(it, new boolean[]{true,true,true}, true, new int[]{1,1,1});
		scenario(it, new boolean[]{true,true,false}, false, new int[]{1,1,1});
		scenario(it, new boolean[]{true,false,true}, false, new int[]{1,1,0});
		scenario(it, new boolean[]{true,false,false}, false, new int[]{1,1,0});
		scenario(it, new boolean[]{false,true,true}, false, new int[]{1,1,0});
		scenario(it, new boolean[]{false,true,false}, false, new int[]{1,1,0});
		scenario(it, new boolean[]{false,false,true}, false, new int[]{1,1,1});
		scenario(it, new boolean[]{false,false,false}, true, new int[]{1,1,1});
	}
	
	public void testEq() throws IOException{
		final ValidatorIterable it = ValidatorConstants.EQ;
		scenario(it, new boolean[0], true, new int[0]);
		scenario(it, new boolean[]{true}, true, new int[]{1});
		scenario(it, new boolean[]{false}, true, new int[]{1});
		scenario(it, new boolean[]{true,true}, true, new int[]{1,1});
		scenario(it, new boolean[]{true,false}, false, new int[]{1,1});
		scenario(it, new boolean[]{false,true}, false, new int[]{1,1});
		scenario(it, new boolean[]{false,false}, true, new int[]{1,1});
		scenario(it, new boolean[]{true,true,true}, true, new int[]{1,1,1});
		scenario(it, new boolean[]{true,true,false}, false, new int[]{1,1,1});
		scenario(it, new boolean[]{true,false,true}, false, new int[]{1,1,1});
		scenario(it, new boolean[]{true,false,false}, false, new int[]{1,1,1});
		scenario(it, new boolean[]{false,true,true}, false, new int[]{1,1,1});
		scenario(it, new boolean[]{false,true,false}, false, new int[]{1,1,1});
		scenario(it, new boolean[]{false,false,true}, false, new int[]{1,1,1});
		scenario(it, new boolean[]{false,false,false}, true, new int[]{1,1,1});
	}

	public void testConvertNormal(){
		final Map<Object,Object> base = new HashMap<Object,Object>();
		base.put("key0", new String[]{"value00", "value01"});
		base.put("key1", new String[]{"value10", "value11", "value12"});

		assertTrue(TestUtils.equals(
				MapBuilder.get(new HashMap<String,Object>())
				.put("key0", Arrays.asList("value00", "value01"))
				.put("key1", Arrays.asList("value10", "value11", "value12"))
				.get()
				, ValidatorConstants.convert(base)));
	}
	
	public void testKeyClassCast(){
		final Map<Object,Object> base = new HashMap<Object,Object>();
		base.put(new Integer(1), new String[]{"value00", "value01"});
		try{
			ValidatorConstants.convert(base);
			fail();
		}catch(final ClassCastException expected){
		}
	}
}
