/*
 * 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(Integer.valueOf(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(Integer.valueOf(1), new String[] { "value00", "value01" });
		try {
			ValidatorConstants.convert(base);
			fail();
		} catch (final ClassCastException expected) {
		}
	}
}
