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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import woolpack.utils.UtilsConstants;

/**
 * 定数・静的メソッドの集まり。
 * 
 * @author nakamura
 * 
 */
public final class ValidatorConstants {

	/**
	 * 常に true を返す{@link ValidatorExpression}。
	 * {@link ValidatorContext}に対して状態を変更する操作を行わない。
	 */
	public static final ValidatorExpression TRUE = new ValidatorExpression() {
		public boolean interpret(final ValidatorContext context) {
			return true;
		}
	};

	/**
	 * 常に false を返す{@link ValidatorExpression}。
	 * {@link ValidatorContext}に対して状態を変更する操作を行わない。
	 */
	public static final ValidatorExpression FALSE = new ValidatorExpression() {
		public boolean interpret(final ValidatorContext context) {
			return false;
		}
	};

	/**
	 * {@link ValidatorContext#getTmpValue()}がnullでない、
	 * かつ文字列の場合は空でないことを検証しその結果を返す{@link ValidatorExpression}。
	 * {@link ValidatorContext}に対して状態を変更する操作を行わない。
	 */
	public static final ValidatorExpression REQUIRED
	= new ValidatorExpression() {
		public boolean interpret(final ValidatorContext context) {
			final Object value = context.getTmpValue();
			return value != null
					&& (!(value instanceof String)
							|| ((String) value).length() > 0);
		}
	};

	/**
	 * 全ての{@link ValidatorExpression}を呼び出す、 論理和の{@link ValidatorIterable}。
	 * {@link ValidatorContext}に対して状態を変更する操作を行わない。
	 */
	public static final ValidatorIterable OR = new ValidatorIterable() {
		public boolean interpret(final ValidatorContext context,
				final Iterable<? extends ValidatorExpression> iterable) {
			boolean result = false;
			boolean empty = true;
			for (final ValidatorExpression e : iterable) {
				empty = false;
				result |= e.interpret(context);
			}
			return result || empty;
		}
	};

	/**
	 * 検証結果が true になった時点で{@link ValidatorExpression}
	 * の呼び出しを停止する、 論理和の{@link ValidatorIterable}。
	 * {@link ValidatorContext}に対して状態を変更する操作を行わない。
	 */
	public static final ValidatorIterable OROR = new ValidatorIterable() {
		public boolean interpret(final ValidatorContext context,
				final Iterable<? extends ValidatorExpression> iterable) {
			boolean empty = true;
			for (final ValidatorExpression e : iterable) {
				empty = false;
				if (e.interpret(context)) {
					return true;
				}
			}
			return empty;
		}
	};

	/**
	 * 全ての{@link ValidatorExpression}を呼び出す、 論理積の{@link ValidatorIterable}。
	 * {@link ValidatorContext}に対して状態を変更する操作を行わない。
	 */
	public static final ValidatorIterable AND = new ValidatorIterable() {
		public boolean interpret(final ValidatorContext context,
				final Iterable<? extends ValidatorExpression> iterable) {
			boolean flag = true;
			for (final ValidatorExpression e : iterable) {
				flag &= e.interpret(context);
			}
			return flag;
		}
	};

	/**
	 * 検証結果が false になった時点で{@link ValidatorExpression}
	 * の呼び出しを停止する、 論理積の{@link ValidatorIterable}。
	 * {@link ValidatorContext}に対して状態を変更する操作を行わない。
	 */
	public static final ValidatorIterable ANDAND = new ValidatorIterable() {
		public boolean interpret(final ValidatorContext context,
				final Iterable<? extends ValidatorExpression> iterable) {
			for (final ValidatorExpression e : iterable) {
				final boolean flag = e.interpret(context);
				if (!flag) {
					return false;
				}
			}
			return true;
		}
	};

	/**
	 * 全ての{@link ValidatorExpression}を呼び出す、 同値の{@link ValidatorIterable}。
	 * {@link ValidatorContext}に対して状態を変更する操作を行わない。
	 */
	public static final ValidatorIterable EQ = new ValidatorIterable() {
		public boolean interpret(final ValidatorContext context,
				final Iterable<? extends ValidatorExpression> iterable) {
			boolean trueFlag = true;
			boolean falseFlag = true;
			for (final ValidatorExpression e : iterable) {
				final boolean flag = e.interpret(context);
				trueFlag &= flag;
				falseFlag &= !flag;
			}
			return trueFlag || falseFlag;
		}
	};

	/**
	 * 検証結果が同値でなくなった時点で{@link ValidatorExpression}
	 * の呼び出しを停止する、 同値の{@link ValidatorIterable}。
	 * {@link ValidatorContext}に対して状態を変更する操作を行わない。
	 */
	public static final ValidatorIterable EQEQ = new ValidatorIterable() {
		public boolean interpret(final ValidatorContext context,
				final Iterable<? extends ValidatorExpression> iterable) {
			boolean trueFlag = true;
			boolean falseFlag = true;
			for (final ValidatorExpression e : iterable) {
				final boolean flag = e.interpret(context);
				trueFlag &= flag;
				falseFlag &= !flag;
				if (!(trueFlag || falseFlag)) {
					return false;
				}
			}
			return true;
		}
	};

	private ValidatorConstants() {
	} // カバレージがここを通過してはいけない

	/**
	 * 引数のキーが全て文字列型・値が全てオブジェクトの一覧とみなして変換する。 request.getParameterMap()は Generics
	 * に対応していないので キーの型が{@link String}で
	 * 値の型が{@link Object}である{@link Map}を生成してコピーする。
	 * 
	 * @param map
	 *            変換元。
	 * @return 変換結果。キーが文字列、値が文字列の{@link List}になる。変換先を更新しても変換元には影響しない。
	 * @throws NullPointerException
	 *             引数が null の場合。
	 * @throws ClassCastException
	 *             引数のがキーが文字列型でない場合。
	 */
	public static Map<String, List<Object>> convert(final Map map) {
		final Map<String, List<Object>> map1
		= new HashMap<String, List<Object>>();
		for (final Object entryObject : map.entrySet()) {
			final Entry entry = (Entry) entryObject;
			final Iterable c = UtilsConstants.toIterable(entry.getValue());
			final List<Object> list = new ArrayList<Object>();
			for (final Object o : c) {
				list.add(o);
			}
			map1.put((String) entry.getKey(), list);
		}
		return map1;
	}
}
