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

import java.util.Collection;
import java.util.regex.Pattern;

import woolpack.fn.FixFn;
import woolpack.fn.Fn;
import woolpack.fn.IfFn;

/**
 * ユーティリティです。
 * 型推論で表記を簡略するためのスタティックメソッドと変数を含みます。
 * 
 * @author nakamura
 *
 */
public final class BoolUtils {

	/**
	 * 引数が{@link Throwable}のサブクラスでないことを評価する{@link Fn}です。
	 */
	public static final Fn<Object, Boolean, RuntimeException> NOT_THROWABLE = not(matchObject(Throwable.class));
	
	public static final NotFn<RuntimeException> NOT = new NotFn<RuntimeException>();
	public static final NotEmptyChecker<RuntimeException> NOT_EMPTY = new NotEmptyChecker<RuntimeException>();
	public static final BooleanConverter<RuntimeException> TO_BOOLEAN = new BooleanConverter<RuntimeException>();
	
	public static final BooleanStateAndAndFactory ANDAND = new BooleanStateAndAndFactory();
	public static final BooleanStateAndFactory AND = new BooleanStateAndFactory();
	public static final BooleanStateEqEqFactory EQEQ = new BooleanStateEqEqFactory();
	public static final BooleanStateEqFactory EQ = new BooleanStateEqFactory();
	public static final BooleanStateOrFactory OR = new BooleanStateOrFactory();
	public static final BooleanStateOrOrFactory OROR = new BooleanStateOrOrFactory();
	
	private BoolUtils() {
	}
	
	public static <C, E extends Exception> BoolSeq<C, E> boolSeq(
			final Fn<Object, ? extends BooleanState, ? extends RuntimeException> factory,
			final Iterable<? extends Fn<? super C, Boolean, ? extends E>> iterable) {
		return new BoolSeq<C, E>(factory, iterable);
	}
	
	/**
	 * {@link #ANDAND}を使用します。
	 * @param <C>
	 * @param <E>
	 * @param iterable
	 * @return 関数。
	 */
	public static <C, E extends Exception> BoolSeq<C, E> boolSeq(
			final Iterable<? extends Fn<? super C, Boolean, ? extends E>> iterable) {
		return new BoolSeq<C, E>(ANDAND, iterable);
	}
	
	public static <C extends Comparable<C>> CompareFn<C, RuntimeException> compare(final C value) {
		return new CompareFn<C, RuntimeException>(value);
	}
	
	public static ContainsAllChecker<RuntimeException> containsAll(final Collection<?> value) {
		return new ContainsAllChecker<RuntimeException>(value);
	}
	
	public static ContainsChecker<RuntimeException> contains(final Collection<?> value) {
		return new ContainsChecker<RuntimeException>(value);
	}
	
	public static EqualsChecker<RuntimeException> checkEquals(final Object value) {
		return new EqualsChecker<RuntimeException>(value);
	}
	
	public static <C extends Comparable<C>> MaxChecker<C, RuntimeException> checkMax(final C value) {
		return new MaxChecker<C, RuntimeException>(value);
	}
	
	public static MaxLengthChecker<RuntimeException> checkMaxLength(final int value) {
		return new MaxLengthChecker<RuntimeException>(value);
	}
	
	public static <C extends Comparable<C>> MinChecker<C, RuntimeException> checkMin(final C value) {
		return new MinChecker<C, RuntimeException>(value);
	}
	
	public static MinLengthChecker<RuntimeException> checkMinLength(final int value) {
		return new MinLengthChecker<RuntimeException>(value);
	}
	
	public static <C, E extends Exception> NotDelegator<C, E> not(final Fn<? super C, Boolean, ? extends E> fn) {
		return new NotDelegator<C, E>(fn);
	}
	
	public static ObjectMatcher<RuntimeException> matchObject(final Object value) {
		return new ObjectMatcher<RuntimeException>(value);
	}
	
	public static RegExpChecker<RuntimeException> checkRegExp(final Pattern pattern) {
		return new RegExpChecker<RuntimeException>(pattern);
	}
	
	/**
	 * 評価結果が{@link Boolean#TRUE}の場合に委譲する{@link Fn}を返します。
	 * @param <C>
	 * @param <E>
	 * @param ifFn
	 * @param trueFn
	 * @return 評価結果が{@link Boolean#TRUE}の場合に委譲する{@link Fn}。
	 */
	public static <C, E extends Exception> IfFn<C, Boolean, E> ifTrue(
			final Fn<? super C, ?, ? extends E> ifFn,
			final Fn<? super C, ? extends Boolean, ? extends E> trueFn) {
		return new IfFn<C, Boolean, E>(ifFn, trueFn, new FixFn<C, Boolean, E>(false));
	}
	
	/**
	 * 評価結果が{@link Boolean#TRUE}でない場合に委譲する{@link Fn}を返します。
	 * @param <C>
	 * @param <E>
	 * @param ifFn
	 * @param falseFn
	 * @return 評価結果が{@link Boolean#TRUE}でない場合に委譲する{@link Fn}。
	 */
	public static <C, E extends Exception> IfFn<C, Boolean, E> ifNot(
			final Fn<? super C, ?, ? extends E> ifFn,
			final Fn<? super C, ? extends Boolean, ? extends E> falseFn) {
		return new IfFn<C, Boolean, E>(ifFn, new FixFn<C, Boolean, E>(true), falseFn);
	}
}
