/*
 * 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 woolpack.utils.UtilsConstants;

/**
 * 定数・静的メソッドの集まり。
 * @author nakamura
 *
 */
public 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){
				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){
				boolean flag = e.interpret(context);
				trueFlag &= flag;
				falseFlag &= !flag;
				if(!(trueFlag || falseFlag)){
					return false;
				}
			}
			return true;
		}
	};

	private ValidatorConstants(){}// カバレージがここを通過してはいけない
	
	/**
	 * 引数のキーが全て文字列型・値が全てオブジェクトの一覧とみなして変換する。
	 * request.getParameterMap()は Generics に対応していないので Map<String,Object> を生成してコピーする。
	 * @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 key:map.keySet()){
			final Iterable c = UtilsConstants.toIterable(map.get(key));
			final List<Object> list = new ArrayList<Object>();
			for(final Object o:c){
				list.add(o);
			}
			map1.put((String)key, list);
		}
		return map1;
	}
}
