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

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

import junit.framework.TestCase;
import woolpack.bool.BoolUtils;
import woolpack.convert.ConvertUtils;
import woolpack.utils.Utils;

public class FnUtilsTest extends TestCase {
	public void testToWrapper() {
		assertEquals(Boolean.class, FnUtils.TO_WRAPPER.exec(boolean.class));
		assertEquals(Character.class, FnUtils.TO_WRAPPER.exec(char.class));
		assertEquals(Byte.class, FnUtils.TO_WRAPPER.exec(byte.class));
		assertEquals(Short.class, FnUtils.TO_WRAPPER.exec(short.class));
		assertEquals(Integer.class, FnUtils.TO_WRAPPER.exec(int.class));
		assertEquals(Long.class, FnUtils.TO_WRAPPER.exec(long.class));
		assertEquals(Float.class, FnUtils.TO_WRAPPER.exec(float.class));
		assertEquals(Double.class, FnUtils.TO_WRAPPER.exec(double.class));

		assertEquals(Boolean.class, FnUtils.TO_WRAPPER.exec(Boolean.class));
		assertEquals(Character.class, FnUtils.TO_WRAPPER.exec(Character.class));
		assertEquals(Byte.class, FnUtils.TO_WRAPPER.exec(Byte.class));
		assertEquals(Short.class, FnUtils.TO_WRAPPER.exec(Short.class));
		assertEquals(Integer.class, FnUtils.TO_WRAPPER.exec(Integer.class));
		assertEquals(Long.class, FnUtils.TO_WRAPPER.exec(Long.class));
		assertEquals(Float.class, FnUtils.TO_WRAPPER.exec(Float.class));
		assertEquals(Double.class, FnUtils.TO_WRAPPER.exec(Double.class));
	}
	
	public void testCastTo() {
		final Integer i = FnUtils.castTo(Integer.class).exec((Object) 1);
		assertEquals(Integer.valueOf(1), i);
	}
	
	public void testExec() {
		final Fn<Integer, String, RuntimeException> fn = FnUtils.exec(
				FnUtils.fix(ConvertUtils.TO_STRING));
		assertEquals("4", fn.exec(4));
	}
	
	public void testEcho() {
		final Fn<String, String, RuntimeException> fn = FnUtils.echo();
		assertEquals("a234a", fn.exec("a234a"));
	}
	
	public void testFix() {
		assertEquals("a234a", FnUtils.fix("a234a").exec("a345a"));
	}

	public void testIf() {
		final Fn<String, String, RuntimeException> fn = FnUtils.ifTrue(
				BoolUtils.checkRegExp(Pattern.compile("a\\d\\d")),
				ConvertUtils.convertRegExp(Pattern.compile("a(\\d\\d)"), "A$1"),
				ConvertUtils.convertRegExp(Pattern.compile("z(\\d\\d)"), "Z$1"));
		assertEquals("A12", fn.exec("a12"));
		assertEquals("Z23", fn.exec("z23"));
	}

	public void testJoin() {
		assertEquals("a234a",
				FnUtils.join(
					ConvertUtils.format(ConvertUtils.formatFactory(new DecimalFormat())),
					ConvertUtils.convertRegExp(Pattern.compile("(.+)"), "a$1a"))
				.exec(Integer.valueOf(234)));
	}

	public void testJoin3() {
		assertEquals("zabc",
				FnUtils.join(
					ConvertUtils.convertRegExp(Pattern.compile("(.+)"), "$1a"),
					ConvertUtils.convertRegExp(Pattern.compile("(.+)"), "$1b"),
					ConvertUtils.convertRegExp(Pattern.compile("(.+)"), "$1c"))
				.exec("z"));
	}

	public void testJoin4() {
		assertEquals("zabcd",
				FnUtils.join(
						ConvertUtils.convertRegExp(Pattern.compile("(.+)"), "$1a"),
						ConvertUtils.convertRegExp(Pattern.compile("(.+)"), "$1b"),
						ConvertUtils.convertRegExp(Pattern.compile("(.+)"), "$1c"),
						ConvertUtils.convertRegExp(Pattern.compile("(.+)"), "$1d"))
				.exec("z"));
	}

	public void testJoin5() {
		assertEquals("zabcde",
				FnUtils.join(
						ConvertUtils.convertRegExp(Pattern.compile("(.+)"), "$1a"),
						ConvertUtils.convertRegExp(Pattern.compile("(.+)"), "$1b"),
						ConvertUtils.convertRegExp(Pattern.compile("(.+)"), "$1c"),
						ConvertUtils.convertRegExp(Pattern.compile("(.+)"), "$1d"),
						ConvertUtils.convertRegExp(Pattern.compile("(.+)"), "$1e"))
				.exec("z"));
	}

	public void testDelegate() {
		assertEquals("a", FnUtils.delegate(FnUtils.fix("a")).exec("a234a"));
	}

	public void testSeq() {
		final List<String> list = new ArrayList<String>();
		final List<Integer> contextList = new ArrayList<Integer>();
		
		assertEquals("id1",
				FnUtils.seq(Utils
					.list(FnUtils.recode(FnUtils.fix("id0"), "fn0", list, contextList, null))
					.list(FnUtils.recode(FnUtils.fix("id1"), "fn1", list, contextList, null)))
				.exec(4));
		
		assertEquals(Arrays.asList("fn0", "fn1"), list);
		assertEquals(Arrays.asList(4, 4), contextList);
	}
	
	public void testSwitching() {
		final Fn<Integer, String, RuntimeException> fn = FnUtils.switching(
				Utils.map(0, "key0").map(1, "key1").map(2, "key2"),
				"default0");
		assertEquals("key0", fn.exec(0));
		assertEquals("key1", fn.exec(1));
		assertEquals("key2", fn.exec(2));
		assertEquals("default0", fn.exec(3));
	}
	
	public void testTry() {
		final List<String> list = new ArrayList<String>();
		
		assertEquals("4",
				FnUtils.trying(
						ConvertUtils.TO_STRING,
						ConvertUtils.TO_STRING,
						FnUtils.recode(ConvertUtils.TO_STRING, "gate0", list))
				.exec(4));
		
		assertEquals(Arrays.asList("gate0"), list);
	}

	public void testTryException() {
		final List<String> list = new ArrayList<String>();
		assertEquals("java.lang.RuntimeException: hoge",
				FnUtils.trying(
						FnUtils.throwing(new RuntimeException("hoge")),
						ConvertUtils.TO_STRING,
						FnUtils.recode(ConvertUtils.TO_STRING, "gate0", list))
				.exec(4));
		assertEquals(Arrays.asList("gate0"), list);
	}
}
