/*
 * 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.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import woolpack.TestUtils;

import junit.framework.TestCase;

public class ValidatorConstantsTest extends TestCase {

	public void testGetLocalClassName(){
		assertEquals("ValidatorConstants", ValidatorConstants.getLocalClassName(ValidatorConstants.class));
	}
	
	public void testTrueInterpret(){
		final ValidatorContext context = new ValidatorContext();
		assertTrue(ValidatorConstants.TRUE.interpret(context));
	}
	
	public void testTrueAppendTo() throws IOException{
		final StringBuilder sb = new StringBuilder();
		ValidatorConstants.TRUE.appendTo(sb);
		assertEquals("new TrueValidator()", sb.toString());
	}
	
	public void testTrueAddMessageTo(){
		final Collection<String> expectedCollection = new ArrayList<String>();
		ValidatorConstants.TRUE.addMessageTo(expectedCollection);
		assertTrue(expectedCollection.isEmpty());
	}
	
	public void testFalseInterpret(){
		final ValidatorContext context = new ValidatorContext();
		assertFalse(ValidatorConstants.FALSE.interpret(context));
	}
	
	public void testFalseAppendTo() throws IOException{
		final StringBuilder sb = new StringBuilder();
		ValidatorConstants.FALSE.appendTo(sb);
		assertEquals("new FalseValidator()", sb.toString());
	}
	
	public void testFalseAddMessageToKey(){
		final Collection<String> expectedCollection = new ArrayList<String>();
		ValidatorConstants.FALSE.addMessageTo(expectedCollection);
		assertTrue(expectedCollection.isEmpty());
	}
	
	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("#{\"key0\":{1}}", context.getInputMap()));

		context.setTmpValue(null);
		assertFalse(ValidatorConstants.REQUIRED.interpret(context));
		assertTrue(TestUtils.equals("#{\"key0\":{null}}", context.getInputMap()));

		context.setTmpValue("a");
		assertTrue(ValidatorConstants.REQUIRED.interpret(context));
		assertTrue(TestUtils.equals("#{\"key0\":{\"a\"}}", context.getInputMap()));

		context.setTmpValue("");
		assertFalse(ValidatorConstants.REQUIRED.interpret(context));
		assertTrue(TestUtils.equals("#{\"key0\":{\"\"}}", context.getInputMap()));
	}
	
	public void testRequiredAppendTo() throws IOException{
		final StringBuilder sb = new StringBuilder();
		ValidatorConstants.REQUIRED.appendTo(sb);
		assertEquals("new RequiredValidator()", sb.toString());
	}
	
	public void testRequiredAddMessageToKey(){
		final Collection<String> expectedCollection = new ArrayList<String>();
		ValidatorConstants.REQUIRED.addMessageTo(expectedCollection);
		assertTrue(expectedCollection.isEmpty());
	}
	
	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).getIntepretCount());
			for(int j=0; j<expectedCount[i]; j++){
				assertTrue(context == list.get(i).getContextList().removeLast());
			}
		}
	}
	
	public void scenarioValidatorIterableAppendTo(
			final ValidatorIterable iterable,
			final String expected) throws IOException{
		final StringBuilder sb = new StringBuilder();
		iterable.appendTo(sb);
		assertEquals(expected, sb.toString());
	}
	
	public void testAndAnd() throws IOException{
		final ValidatorIterable it = ValidatorConstants.ANDAND;
		scenarioValidatorIterableAppendTo(it, "new AndAndValidatorIterable()");
		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;
		scenarioValidatorIterableAppendTo(it, "new AndValidatorIterable()");
		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;
		scenarioValidatorIterableAppendTo(it, "new OrOrValidatorIterable()");
		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;
		scenarioValidatorIterableAppendTo(it, "new OrValidatorIterable()");
		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;
		scenarioValidatorIterableAppendTo(it, "new EqEqValidatorIterable()");
		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;
		scenarioValidatorIterableAppendTo(it, "new EqValidatorIterable()");
		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("#{\"key0\":{\"value00\",\"value01\"}," +
				"\"key1\":{\"value10\",\"value11\",\"value12\"}}", 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){
		}
	}
}
