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

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

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

public class UtilsConstantsTest extends TestCase {

	public void testNullToDefaultValueSwitchIfAbsentConstructor() {
		try {
			UtilsConstants.nullToDefaultSwitchIfAbsent(Integer.valueOf(1), null);
			fail();
		} catch (final NullPointerException expected) {
		}
	}

	public void testNullToDefaultValueSwitchIfAbsentNormal() {
		final Switchable<String, Integer> base = new SwitchBuilder<String, Integer>()
				.put("a3", 3).put("a4", 4).get(null);

		{
			final Switchable<String, Integer> switchable = UtilsConstants
					.nullToDefaultSwitchIfAbsent(2, base);
			assertEquals(Integer.valueOf(3), switchable.get("a3"));
			assertEquals(Integer.valueOf(4), switchable.get("a4"));
			assertEquals(Integer.valueOf(2), switchable.get(null));
			assertEquals(Integer.valueOf(2), switchable.get("a6"));
		}
		{
			final Switchable<String, Integer> switchable = UtilsConstants
					.nullToDefaultSwitchIfAbsent(null, base);
			assertEquals(Integer.valueOf(3), switchable.get("a3"));
			assertEquals(Integer.valueOf(4), switchable.get("a4"));
			assertEquals(null, switchable.get(null));
			assertEquals(null, switchable.get("a6"));
		}
	}

	public void testNullToDefaultValueSwitchIfAbsentNormal2() {
		final Switchable<String, Integer> base = new SwitchBuilder<String, Integer>()
				.put("a3", 3).put("a4", 4).get(6);

		{
			final Switchable<String, Integer> switchable = UtilsConstants
					.nullToDefaultSwitchIfAbsent(2, base);
			assertEquals(Integer.valueOf(3), switchable.get("a3"));
			assertEquals(Integer.valueOf(4), switchable.get("a4"));
			assertEquals(Integer.valueOf(6), switchable.get(null));
			assertEquals(Integer.valueOf(6), switchable.get("a6"));
		}
		{
			final Switchable<String, Integer> switchable = UtilsConstants
					.nullToDefaultSwitchIfAbsent(null, base);
			assertEquals(Integer.valueOf(3), switchable.get("a3"));
			assertEquals(Integer.valueOf(4), switchable.get("a4"));
			assertEquals(Integer.valueOf(6), switchable.get(null));
			assertEquals(Integer.valueOf(6), switchable.get("a6"));
		}
	}

	public void testInverseMap() {
		{
			final Map<String, Integer> before = new HashMap<String, Integer>();
			final Map<Integer, String> after = UtilsConstants
					.inverseMap(before);
			assertEquals(0, after.size());
		}
		{
			final Map<String, Integer> before = MapBuilder.get(
					new HashMap<String, Integer>()).put("1", 1).get();
			final Map<Integer, String> after = UtilsConstants
					.inverseMap(before);
			assertTrue(TestUtils.equals(MapBuilder.get(
					new HashMap<Integer, String>()).put(1, "1").get(), after));
		}
		{
			final Map<String, Integer> before = MapBuilder.get(
					new HashMap<String, Integer>()).put("1", 1).put("2", 2)
					.get();
			final Map<Integer, String> after = UtilsConstants
					.inverseMap(before);
			assertTrue(TestUtils.equals(MapBuilder.get(
					new HashMap<Integer, String>()).put(1, "1").put(2, "2")
					.get(), after));
		}
		{
			final Map<String, Integer> before = MapBuilder.get(
					new HashMap<String, Integer>()).put("1", 1).put("2", 1)
					.get();
			try {
				UtilsConstants.inverseMap(before);
			} catch (final IllegalStateException e) {
			}
		}
	}

	public void testInjectiveMap() {
		final Map<String, String> map = UtilsConstants
				.injectiveMap(new HashMap<String, String>());
		map.put("a", "A");
		map.put("b", "B");
		try {
			map.put("b", "A");
			fail();
		} catch (final IllegalStateException expected) {
			assertEquals("value duplicate:A", expected.getMessage());
		}
		map.put("a", "A");
		map.put("x", "X");
		{
			final Map<String, String> tmp = new HashMap<String, String>();
			tmp.put("a", "A");
			tmp.put("b", "B");
			map.putAll(tmp);
		}
		{
			final Map<String, String> tmp = new HashMap<String, String>();
			tmp.put("a", "C");
			tmp.put("b", "D");
			map.putAll(tmp);
		}
		try {
			final Map<String, String> tmp = new HashMap<String, String>();
			tmp.put("a", "C");
			tmp.put("b", "C");
			map.putAll(tmp);
			fail();
		} catch (final IllegalStateException expected) {
			assertEquals("value duplicate", expected.getMessage());
		}
		{
			final Map<String, String> tmp = new HashMap<String, String>();
			tmp.put("a", "D");
			tmp.put("b", "C");
			map.putAll(tmp);
		}
		TestUtils.equals("#{\"a\":\"D\",\"b\":\"C\",\"x\":\"X\"}", map);
	}

	public void testUnoverwritableMap() {
		final Map<String, String> map = UtilsConstants
				.unoverwritableMap(new HashMap<String, String>());
		map.put("a", "z");
		map.put("b", "z");
		try {
			map.put("a", "y");
			fail();
		} catch (final IllegalStateException expected) {
			assertEquals("already registered:a", expected.getMessage());
		}
		{
			final Map<String, String> tmp = new HashMap<String, String>();
			tmp.put("c", "z");
			tmp.put("d", "z");
			map.putAll(tmp);
		}
		try {
			final Map<String, String> tmp = new HashMap<String, String>();
			tmp.put("e", "z");
			tmp.put("b", "z");
			map.putAll(tmp);
			fail();
		} catch (final IllegalStateException expected) {
			assertEquals("already registered:b", expected.getMessage());
		}
	}

	public void testNotNullMap() {
		final Map<String, String> map = UtilsConstants
				.notNullMap(new HashMap<String, String>());
		map.put("a", "z");
		map.put("b", "z");
		try {
			map.put(null, "y");
			fail();
		} catch (final NullPointerException expected) {
		}
		map.put("c", "z");
		try {
			map.put("d", null);
			fail();
		} catch (final NullPointerException expected) {
		}
		{
			final Map<String, String> tmp = new HashMap<String, String>();
			tmp.put("e", "z");
			tmp.put("f", "z");
			map.putAll(tmp);
		}
		try {
			final Map<String, String> tmp = new HashMap<String, String>();
			tmp.put("g", "z");
			tmp.put(null, "z");
			map.putAll(tmp);
			fail();
		} catch (final NullPointerException expected) {
		}
		try {
			final Map<String, String> tmp = new HashMap<String, String>();
			tmp.put("h", "z");
			tmp.put("i", null);
			map.putAll(tmp);
			fail();
		} catch (final NullPointerException expected) {
		}
	}

	public void testKeyNotEmptyMap() {
		final Map<String, String> map = UtilsConstants
				.keyNotEmptyMap(new HashMap<String, String>());
		map.put("a", "z");
		map.put("b", "z");
		{
			final Map<String, String> tmp = new HashMap<String, String>();
			map.put("c", "z");
			map.put("d", "z");
			map.putAll(tmp);
		}
		try {
			map.put("", "y");
			fail();
		} catch (final StringIndexOutOfBoundsException expected) {
		}
		{
			final Map<String, String> tmp = new HashMap<String, String>();
			tmp.put("c", "z");
			tmp.put("d", "z");
			map.putAll(tmp);
		}
		try {
			final Map<String, String> tmp = new HashMap<String, String>();
			tmp.put("e", "z");
			tmp.put("", "z");
			map.putAll(tmp);
			fail();
		} catch (final StringIndexOutOfBoundsException expected) {
		}
	}

	public void testUnmodifiableIterable() {
		final Iterable<String> iterable;
		{
			final List<String> list = new ArrayList<String>();
			list.add("a");
			iterable = UtilsConstants.unmodifiableIterable(list);
		}
		final Iterator<String> it = iterable.iterator();
		assertTrue(it.hasNext());
		assertEquals("a", it.next());
		assertFalse(it.hasNext());
		try {
			it.remove();
			fail();
		} catch (final UnsupportedOperationException expected) {
		}
	}

	public void testToListFromNull() {
		final List list = UtilsConstants.toList(null);
		assertEquals(1, list.size());
		assertNull(list.get(0));
	}

	public void testToListFromPrimitiveArray() {
		final int[] array = new int[2];
		final List list = UtilsConstants.toList(array);
		assertEquals(2, list.size());
		list.set(1, Integer.valueOf(3));
		assertEquals(3, array[1]);
		assertEquals(Integer.valueOf(3), list.get(1));
	}

	public void testToListFromObjectArray() {
		final Integer[] array = new Integer[2];
		final List list = UtilsConstants.toList(array);
		assertEquals(2, list.size());
		list.set(1, Integer.valueOf(3));
		assertEquals(Integer.valueOf(3), array[1]);
		assertEquals(Integer.valueOf(3), list.get(1));
	}

	public void testToListFromList() {
		final List target = new ArrayList();
		assertEquals(target, UtilsConstants.toList(target));
	}

	public void testToListFromObject() {
		final Integer target = Integer.valueOf(3);
		final List list = UtilsConstants.toList(target);
		assertEquals(1, list.size());
		assertEquals(target, list.get(0));
	}

	public void testToCollectionFromCollection() {
		final Collection target = new ArrayList();
		assertEquals(target, UtilsConstants.toCollection(target));
	}

	public void testToIterableFromIterable() {
		final Iterable target = new ArrayList();
		assertEquals(target, UtilsConstants.toIterable(target));
	}

	public void testSimilarKeyMap() {
		final Map<String, String> mapA = new HashMap<String, String>();
		mapA.put("hoge_piyo", "hoge_piyo");
		mapA.put("NARU_HODO", "NARU_HODO");
		mapA.put("fooBar", "fooBar");
		mapA.put("GinowanOkinawa", "GinowanOkinawa");
		final Map<String, String> mapB = UtilsConstants.similarKeyMap(mapA);

		assertEquals(mapA.get("hoge_piyo"), mapB.get("hoge_piyo"));
		assertEquals(mapA.get("hoge_piyo"), mapB.get("HOGE_PIYO"));
		assertEquals(mapA.get("hoge_piyo"), mapB.get("hogePiyo"));
		assertEquals(mapA.get("hoge_piyo"), mapB.get("HogePiyo"));

		assertEquals(mapA.get("NARU_HODO"), mapB.get("NARU_HODO"));
		assertEquals(mapA.get("NARU_HODO"), mapB.get("naru_hodo"));
		assertEquals(mapA.get("NARU_HODO"), mapB.get("naruHodo"));
		assertEquals(mapA.get("NARU_HODO"), mapB.get("NaruHodo"));

		assertEquals(mapA.get("fooBar"), mapB.get("fooBar"));
		assertEquals(mapA.get("fooBar"), mapB.get("FooBar"));
		assertEquals(mapA.get("fooBar"), mapB.get("foo_bar"));
		assertEquals(mapA.get("fooBar"), mapB.get("FOO_BAR"));

		assertEquals(mapA.get("GinowanOkinawa"), mapB.get("GinowanOkinawa"));
		assertEquals(mapA.get("GinowanOkinawa"), mapB.get("ginowanOkinawa"));
		assertEquals(mapA.get("GinowanOkinawa"), mapB.get("GINOWAN_OKINAWA"));
		assertEquals(mapA.get("GinowanOkinawa"), mapB.get("ginowan_okinawa"));

		assertTrue(mapB.containsKey("hoge_piyo"));
		assertTrue(mapB.containsKey("HOGE_PIYO"));
		assertTrue(mapB.containsKey("hogePiyo"));
		assertTrue(mapB.containsKey("HogePiyo"));
		assertFalse(mapB.containsKey("HogePiyo "));

		assertNull(mapB.get("hoge_piy0"));
	}

	public void testToMessageList() {
		assertEquals(Arrays.asList(new String[] { "message0", "message1",
				"message2", }), Arrays.asList(UtilsConstants.toMessageList(
				new Exception("message0", new Exception("message1",
						new Exception("message2")))).toArray(new String[0])));
		assertEquals(Arrays.asList(new String[] { "message0", "message2" }),
				Arrays.asList(UtilsConstants.toMessageList(
						new Exception("message0", new Exception(null,
								new Exception("message2")))).toArray(
						new String[0])));
		assertEquals(Arrays.asList(new String[] { "message1", "message2" }),
				Arrays.asList(UtilsConstants.toMessageList(
						new Exception(new Exception("message1", new Exception(
								"message2")))).toArray(new String[0])));
		assertEquals(Arrays.asList(new String[] { "message0", "message2" }),
				Arrays.asList(UtilsConstants.toMessageList(
						new Exception("message0", new Exception(new Exception(
								"message2")))).toArray(new String[0])));
		assertEquals(Arrays.asList(new String[] { "message0", "message1",
				"java.lang.IllegalArgumentException", }), Arrays
				.asList(UtilsConstants.toMessageList(
						new Exception("message0", new Exception("message1",
								new IllegalArgumentException()))).toArray(
						new String[0])));
	}
}
