/*
 * Copyright (c) 2009 OrangeSignal.com All rights reserved.
 * 
 * これは Apache ライセンス Version 2.0 (以下、このライセンスと記述) に
 * 従っています。このライセンスに準拠する場合以外、このファイルを使用
 * してはなりません。このライセンスのコピーは以下から入手できます。
 * 
 * http://www.apache.org/licenses/LICENSE-2.0.txt
 * 
 * 適用可能な法律がある、あるいは文書によって明記されている場合を除き、
 * このライセンスの下で配布されているソフトウェアは、明示的であるか暗黙の
 * うちであるかを問わず、「保証やあらゆる種類の条件を含んでおらず」、
 * 「あるがまま」の状態で提供されるものとします。
 * このライセンスが適用される特定の許諾と制限については、このライセンス
 * を参照してください。
 */

package jp.sf.orangesignal.ta.util;

import java.util.Collection;
import java.util.Map;

/**
 * 表明(前提条件)検証用のユーティリティを提供します。
 * 
 * @author 杉澤 浩二
 * @since 2.1
 */
public abstract class Assert {

	/**
	 * 指定された式を表明します。
	 * 式が <code>false</code> の場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.isTrue(i &gt; 0, "The value must be greater than zero");
	 * </pre>
	 * 
	 * @param expression 式
	 * @param message 例外をスローする場合に使用するメッセージ
	 * @throws IllegalArgumentException 式が <code>false</code> の場合
	 */
	public static void isTrue(final boolean expression, final String message) throws IllegalArgumentException {
		if (!expression)
			throw new IllegalArgumentException(message);
	}

	/**
	 * 指定された式を表明します。
	 * 式が <code>false</code> の場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.isTrue(i &gt; 0);
	 * </pre>
	 * 
	 * @param expression 式
	 * @throws IllegalArgumentException 式が <code>false</code> の場合
	 */
	public static void isTrue(final boolean expression) throws IllegalArgumentException {
		isTrue(expression, "[Assertion failed] - this expression must be true");
	}

	/**
	 * 指定された式を表明します。
	 * 式が <code>true</code> の場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.isFalse(i &gt; 0, "The value must be greater than zero");
	 * </pre>
	 * 
	 * @param expression 式
	 * @param message 例外をスローする場合に使用するメッセージ
	 * @throws IllegalArgumentException 式が <code>true</code> の場合
	 */
	public static void isFalse(final boolean expression, final String message) throws IllegalArgumentException {
		if (expression)
			throw new IllegalArgumentException(message);
	}

	/**
	 * 指定された式を表明します。
	 * 式が <code>true</code> の場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.isFalse(i &gt; 0);
	 * </pre>
	 * 
	 * @param expression 式
	 * @throws IllegalArgumentException 式が <code>true</code> の場合
	 */
	public static void isFalse(final boolean expression) throws IllegalArgumentException {
		isFalse(expression, "[Assertion failed] - this expression must be false");
	}

	/**
	 * 指定されたオブジェクトが <code>null</code> であることを表明します。
	 * 
	 * <pre>
	 * Assert.isNull(value, "The value must be null");
	 * </pre>
	 * 
	 * @param object 検査するオブジェクト
	 * @param message 例外をスローする場合に使用するメッセージ
	 * @throws IllegalArgumentException オブジェクトが <code>null</code> でない場合
	 */
	public static void isNull(final Object object, final String message) throws IllegalArgumentException {
		if (object != null)
			throw new IllegalArgumentException(message);
	}

	/**
	 * 指定されたオブジェクトが <code>null</code> であることを表明します。
	 * 
	 * <pre>
	 * Assert.isNull(value);
	 * </pre>
	 * 
	 * @param object 検査するオブジェクト
	 * @throws IllegalArgumentException オブジェクトが <code>null</code> でない場合
	 */
	public static void isNull(final Object object) throws IllegalArgumentException {
		isNull(object, "[Assertion failed] - the object argument must be null");
	}

	/**
	 * 指定されたオブジェクトが <code>null</code> でないことを表明します。
	 * 
	 * <pre>
	 * Assert.notNull(clazz, "The class must not be null");
	 * </pre>
	 * 
	 * @param object 検査するオブジェクト
	 * @param message 例外をスローする場合に使用するメッセージ
	 * @throws IllegalArgumentException オブジェクトが <code>null</code> の場合
	 */
	public static void notNull(final Object object, final String message) throws IllegalArgumentException {
		if (object == null)
			throw new IllegalArgumentException(message);
	}

	/**
	 * 指定されたオブジェクトが <code>null</code> でないことを表明します。
	 * 
	 * <pre>
	 * Assert.notNull(clazz);
	 * </pre>
	 * 
	 * @param object 検査するオブジェクト
	 * @throws IllegalArgumentException オブジェクトが <code>null</code> の場合
	 */
	public static void notNull(final Object object) throws IllegalArgumentException {
		notNull(object, "[Assertion failed] - this argument is required; it must not be null");
	}

	// ------------------------------------------------------------------------
	// isEmpty

	/**
	 * 指定された文字列が空であることを表明します。
	 * 指定された文字列が空でない場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.isEmpty(name, "Name must be empty");
	 * </pre>
	 * 
	 * @param str 検査する文字列
	 * @param message 例外をスローする場合に使用するメッセージ
	 * @throws IllegalArgumentException 文字列が空でない場合
	 */
	public static void isEmpty(final String str, final String message) throws IllegalArgumentException {
		if (str != null && !str.isEmpty())
			throw new IllegalArgumentException(message);
	}

	/**
	 * 指定された文字列が空であることを表明します。
	 * 指定された文字列が空でない場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.isEmpty(name);
	 * </pre>
	 * 
	 * @param str 検査する文字列
	 * @throws IllegalArgumentException 文字列が空でない場合
	 */
	public static void isEmpty(final String str) throws IllegalArgumentException {
		isEmpty(str, "[Assertion failed] - this String argument must be null or empty");
	}

	/**
	 * 指定された配列に要素が存在しないことを表明します。
	 * 指定された配列に要素が存在する場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.isEmpty(array, "The array must have no elements");
	 * </pre>
	 * 
	 * @param array 検査する配列
	 * @param message 例外をスローする場合に使用するメッセージ
	 * @throws IllegalArgumentException 配列に要素が存在する場合
	 */
	public static void isEmpty(final Object[] array, final String message) throws IllegalArgumentException {
		if (array != null && array.length > 0)
			throw new IllegalArgumentException(message);
	}

	/**
	 * 指定された配列に要素が存在しないことを表明します。
	 * 指定された配列に要素が存在する場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.isEmpty(array);
	 * </pre>
	 * 
	 * @param array 検査する配列
	 * @throws IllegalArgumentException 配列に要素が存在する場合
	 */
	public static void isEmpty(final Object[] array) throws IllegalArgumentException {
		isEmpty(array, "[Assertion failed] - this array must be empty");
	}

	/**
	 * 指定されたコレクションに要素が存在しないことを表明します。
	 * 指定されたコレクションに要素が存在する場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.isEmpty(collection, "Collection must have no elements");
	 * </pre>
	 * 
	 * @param collection 検査するコレクション
	 * @param message 例外をスローする場合に使用するメッセージ
	 * @throws IllegalArgumentException コレクションに要素が存在する場合
	 */
	public static void isEmpty(final Collection<?> collection, final String message) throws IllegalArgumentException {
		if (collection != null && collection.size() > 0)
			throw new IllegalArgumentException(message);
	}

	/**
	 * 指定されたコレクションに要素が存在しないことを表明します。
	 * 指定されたコレクションに要素が存在する場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.isEmpty(collection);
	 * </pre>
	 * 
	 * @param collection 検査するコレクション
	 * @throws IllegalArgumentException コレクションに要素が存在する場合
	 */
	public static void isEmpty(final Collection<?> collection) throws IllegalArgumentException {
		isEmpty(collection, "[Assertion failed] - this collection must be empty");
	}

	/**
	 * 指定されたマップにエントリが存在しないことを表明します。
	 * 指定されたマップにエントリが存在する場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.isEmpty(map, "Map must have no entries");
	 * </pre>
	 * 
	 * @param map 検査するマップ
	 * @param message 例外をスローする場合に使用するメッセージ
	 * @throws IllegalArgumentException マップにエントリが存在する場合
	 */
	public static void isEmpty(final Map<?, ?> map, final String message) throws IllegalArgumentException {
		if (map != null && map.size() > 0)
			throw new IllegalArgumentException(message);
	}

	/**
	 * 指定されたマップにエントリが存在しないことを表明します。
	 * 指定されたマップにエントリが存在する場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.isEmpty(map);
	 * </pre>
	 * 
	 * @param map 検査するマップ
	 * @throws IllegalArgumentException マップにエントリが存在する場合
	 */
	public static void isEmpty(final Map<?, ?> map) throws IllegalArgumentException {
		isEmpty(map, "[Assertion failed] - this map must be empty");
	}

	// ------------------------------------------------------------------------
	// notEmpty

	/**
	 * 指定された文字列が空でないことを表明します。
	 * 指定された文字列が <code>null</code> または空の場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.notEmpty(name, "Name must not be empty");
	 * </pre>
	 * 
	 * @param str 検査する文字列
	 * @param message 例外をスローする場合に使用するメッセージ
	 * @throws IllegalArgumentException 文字列が <code>null</code> または空の場合
	 */
	public static void notEmpty(final String str, final String message) throws IllegalArgumentException {
		if (str == null || str.isEmpty())
			throw new IllegalArgumentException(message);
	}

	/**
	 * 指定された文字列が空でないことを表明します。
	 * 指定された文字列が <code>null</code> または空の場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.notEmpty(name);
	 * </pre>
	 * 
	 * @param str 検査する文字列
	 * @throws IllegalArgumentException 文字列が <code>null</code> または空の場合
	 */
	public static void notEmpty(final String str) throws IllegalArgumentException {
		notEmpty(str, "[Assertion failed] - this String argument must have length; it must not be null or empty");
	}

	/**
	 * 指定された配列に要素が存在することを表明します。
	 * 指定された配列が <code>null</code> または配列に要素が存在しない場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.notEmpty(array, "The array must have elements");
	 * </pre>
	 * 
	 * @param array 検査する配列
	 * @param message 例外をスローする場合に使用するメッセージ
	 * @throws IllegalArgumentException 配列が <code>null</code> または配列に要素が存在しない場合
	 */
	public static void notEmpty(final Object[] array, final String message) throws IllegalArgumentException {
		if (array == null || array.length == 0)
			throw new IllegalArgumentException(message);
	}

	/**
	 * 指定された配列に要素が存在することを表明します。
	 * 指定された配列が <code>null</code> または配列に要素が存在しない場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.notEmpty(array);
	 * </pre>
	 * 
	 * @param array 検査する配列
	 * @throws IllegalArgumentException 配列が <code>null</code> または配列に要素が存在しない場合
	 */
	public static void notEmpty(final Object[] array) throws IllegalArgumentException {
		notEmpty(array, "[Assertion failed] - this array must not be empty: it must contain at least 1 element");
	}

	/**
	 * 指定されたコレクションに要素が存在することを表明します。
	 * 指定されたコレクションが <code>null</code> またはコレクションに要素が存在しない場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.notEmpty(collection, "Collection must have elements");
	 * </pre>
	 * 
	 * @param collection 検査するコレクション
	 * @param message 例外をスローする場合に使用するメッセージ
	 * @throws IllegalArgumentException コレクションが <code>null</code> またはコレクションに要素が存在しない場合
	 */
	public static void notEmpty(final Collection<?> collection, final String message) throws IllegalArgumentException {
		if (collection == null || collection.size() == 0)
			throw new IllegalArgumentException(message);
	}

	/**
	 * 指定されたコレクションに要素が存在することを表明します。
	 * 指定されたコレクションが <code>null</code> またはコレクションに要素が存在しない場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.notEmpty(collection);
	 * </pre>
	 * 
	 * @param collection 検査するコレクション
	 * @throws IllegalArgumentException コレクションが <code>null</code> またはコレクションに要素が存在しない場合
	 */
	public static void notEmpty(final Collection<?> collection) throws IllegalArgumentException {
		notEmpty(collection, "[Assertion failed] - this collection must not be empty: it must contain at least 1 element");
	}

	/**
	 * 指定されたマップにエントリが存在することを表明します。
	 * 指定されたマップが <code>null</code> またはマップにエントリが存在しない場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.notEmpty(map, "Map must have entries");
	 * </pre>
	 *
	 * @param map 検査するマップ
	 * @param message 例外をスローする場合に使用するメッセージ
	 * @throws IllegalArgumentException マップが <code>null</code> またはマップにエントリが存在しない場合
	 */
	public static void notEmpty(final Map<?, ?> map, final String message) throws IllegalArgumentException {
		if (map == null || map.size() == 0)
			throw new IllegalArgumentException(message);
	}

	/**
	 * 指定されたマップにエントリが存在することを表明します。
	 * 指定されたマップが <code>null</code> またはマップにエントリが存在しない場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.notEmpty(map);
	 * </pre>
	 *
	 * @param map 検査するマップ
	 * @throws IllegalArgumentException マップが <code>null</code> またはマップにエントリが存在しない場合
	 */
	public static void notEmpty(final Map<?, ?> map) throws IllegalArgumentException {
		notEmpty(map, "[Assertion failed] - this map must not be empty; it must contain at least one entry");
	}

	// ------------------------------------------------------------------------
	// noNullElements

	/**
	 * 指定された配列に <code>null</code> の要素が存在しないことを表明します。
	 * 指定された配列に <code>null</code> の要素が存在する場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.noNullElements(array, "The array must not contain null elements");
	 * </pre>
	 * 
	 * @param array 検査する配列
	 * @param message 例外をスローする場合に使用するメッセージ
	 * @throws IllegalArgumentException 配列に <code>null</code> の要素が存在する場合
	 */
	public static void noNullElements(final Object[] array, final String message) throws IllegalArgumentException {
		if (array != null) {
			for (final Object obj : array) {
				if (obj == null) {
					throw new IllegalArgumentException(message);
				}
			}
		}
	}

	/**
	 * 指定された配列に <code>null</code> の要素が存在しないことを表明します。
	 * 指定された配列に <code>null</code> の要素が存在する場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.noNullElements(array);
	 * </pre>
	 * 
	 * @param array 検査する配列
	 * @throws IllegalArgumentException 配列に <code>null</code> の要素が存在する場合
	 */
	public static void noNullElements(final Object[] array) throws IllegalArgumentException {
		noNullElements(array, "[Assertion failed] - this array must not contain any null elements");
	}

	/**
	 * 指定されたコレクションに <code>null</code> の要素が存在しないことを表明します。
	 * 指定されたコレクションに <code>null</code> の要素が存在する場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.noNullElements(collection, "The collection must not contain null elements");
	 * </pre>
	 * 
	 * @param collection 検査するコレクション
	 * @param message 例外をスローする場合に使用するメッセージ
	 * @throws IllegalArgumentException コレクションに <code>null</code> の要素が存在する場合
	 */
	public static void noNullElements(final Collection<?> collection, final String message) throws IllegalArgumentException {
		if (collection != null) {
			for (final Object obj : collection) {
				if (obj == null) {
					throw new IllegalArgumentException(message);
				}
			}
		}
	}

	/**
	 * 指定されたコレクションに <code>null</code> の要素が存在しないことを表明します。
	 * 指定されたコレクションに <code>null</code> の要素が存在する場合は、<code>IllegalArgumentException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.noNullElements(collection);
	 * </pre>
	 * 
	 * @param collection 検査するコレクション
	 * @throws IllegalArgumentException コレクションに <code>null</code> の要素が存在する場合
	 */
	public static void noNullElements(final Collection<?> collection) throws IllegalArgumentException {
		noNullElements(collection, "[Assertion failed] - this Collection must not contain any null elements");
	}

	// ------------------------------------------------------------------------

	/**
	 * 指定された式を表明します。
	 * 式が <code>false</code> の場合は、<code>IllegalStateException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.state(id == null, "The id property must not already be initialized");
	 * </pre>
	 * 
	 * @param expression 式
	 * @param message 例外をスローする場合に使用するメッセージ
	 * @throws IllegalStateException 式が <code>false</code> の場合
	 */
	public static void state(final boolean expression, final String message) throws IllegalStateException {
		if (!expression)
			throw new IllegalStateException(message);
	}

	/**
	 * 指定された式を表明します。
	 * 式が <code>false</code> の場合は、<code>IllegalStateException</code> をスローします。
	 * 
	 * <pre>
	 * Assert.state(id == null);
	 * </pre>
	 * 
	 * @param expression 式
	 * @throws IllegalStateException 式が <code>false</code> の場合
	 */
	public static void state(final boolean expression) throws IllegalStateException {
		state(expression, "[Assertion failed] - this state invariant must be true");
	}

}
