/*
 * 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(new Integer(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(new Integer(3), switchable.get("a3"));
			assertEquals(new Integer(4), switchable.get("a4"));
			assertEquals(new Integer(2), switchable.get(null));
			assertEquals(new Integer(2), switchable.get("a6"));
		}
		{
			final Switchable<String,Integer> switchable = UtilsConstants.nullToDefaultSwitchIfAbsent(null,base);
			assertEquals(new Integer(3), switchable.get("a3"));
			assertEquals(new Integer(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(new Integer(3), switchable.get("a3"));
			assertEquals(new Integer(4), switchable.get("a4"));
			assertEquals(new Integer(6), switchable.get(null));
			assertEquals(new Integer(6), switchable.get("a6"));
		}
		{
			final Switchable<String,Integer> switchable = UtilsConstants.nullToDefaultSwitchIfAbsent(null,base);
			assertEquals(new Integer(3), switchable.get("a3"));
			assertEquals(new Integer(4), switchable.get("a4"));
			assertEquals(new Integer(6), switchable.get(null));
			assertEquals(new Integer(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, new Integer(3));
		assertEquals(3, array[1]);
		assertEquals(new Integer(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, new Integer(3));
		assertEquals(new Integer(3), array[1]);
		assertEquals(new Integer(3), list.get(1));
	}
	
	public void testToListFromList(){
		final List target = new ArrayList();
		assertEquals(target, UtilsConstants.toList(target));
	}
	
	public void testToListFromObject(){
		final Integer target = new Integer(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])));
	}
}
