/*
 * 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 testDoReturn() {
		final Fn<Integer, String> fn = FnUtils.exec(
				FnUtils.fix(ConvertUtils.TO_STRING));
		assertEquals("4", fn.exec(4));
	}
	
	public void testEcho() {
		final Fn<String, String> fn = FnUtils.echo();
		assertEquals("a234a", fn.exec("a234a"));
	}
	
	public void testFix() {
		final Fn<Object, String> fn = FnUtils.fix("a234a");
		assertEquals("a234a", fn.exec("a345a"));
	}

	public void testIf() {
		final Fn<String, String> 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() {
		final Fn<Object, String> fn = FnUtils.join(
				ConvertUtils.format(ConvertUtils.formatFactory(new DecimalFormat())),
				ConvertUtils.convertRegExp(Pattern.compile("(.+)"), "a$1a"));
		assertEquals("a234a", fn.exec(Integer.valueOf(234)));
	}

	public void testJoin3() {
		final Fn<String, String> fn = FnUtils.join(
				ConvertUtils.convertRegExp(Pattern.compile("(.+)"), "$1a"),
				ConvertUtils.convertRegExp(Pattern.compile("(.+)"), "$1b"),
				ConvertUtils.convertRegExp(Pattern.compile("(.+)"), "$1c"));
		assertEquals("zabc", fn.exec("z"));
	}

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

	public void testJoin5() {
		final Fn<String, String> fn = 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"));
		assertEquals("zabcde", fn.exec("z"));
	}

	public void testDoNull() {
		final Fn<String, Object> fn = FnUtils.doNull();
		assertNull(fn.exec("a234a"));
	}

	public void testDoVoid() {
		final Fn<String, Void> fn = FnUtils.doVoid();
		assertNull(fn.exec("a234a"));
	}

	public void testDelegate() {
		final Fn<String, String> fn = FnUtils.delegate(FnUtils.fix("a"));
		assertEquals("a", fn.exec("a234a"));
	}

	public void testSeq() {
		final List<String> list = new ArrayList<String>();
		final List<Integer> contextList = new ArrayList<Integer>();
		final SeqFn<Integer, String> fn = FnUtils.seq(Utils
				.list(FnUtils.recode(FnUtils.fix("id0"), "fn0", list, contextList, null))
				.list(FnUtils.recode(FnUtils.fix("id1"), "fn1", list, contextList, null)));
		assertEquals("id1", fn.exec(4));
		assertEquals(Arrays.asList("fn0", "fn1"), list);
		assertEquals(Arrays.asList(4, 4), contextList);
	}
	
	public void testSwitching() {
		final Fn<Integer, String> 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>();
		final TryFn<Integer, String> fn = FnUtils.trying(
				ConvertUtils.TO_STRING,
				ConvertUtils.TO_STRING,
				FnUtils.recode(ConvertUtils.TO_STRING, "gate0", list));
		assertEquals("4", fn.exec(4));
		assertEquals(Arrays.asList("gate0"), list);
	}

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