package org.itscool.weber.action;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.itscool.commons.request.GeneralForm;
import org.itscool.commons.util.InputCheckUtil;
import org.itscool.weber.mapping.MessageMappings;
import org.itscool.weber.mapping.ValidationMapping;

/**
 * 入力チェッククラス<BR>
 * weber-config.xmlのアクション要素内に以下の要素を追加することにより、
 * リクエストパラメータの入力チェックを行うことができます<BR>
 * <pre>
 *      &lt;action
 *         path="/tutorial2/input.do"
 *         type="tutorial2.InputAction"
 *         name="tutorial2.AskData"&gt;
 *         &lt;!-- リクエストパラメータの入力チェック --&gt;
 *         &lt;param name="name"&gt;
 *             &lt;!-- 必須チェック --&gt;
 *             &lt;validate type="requird" msgkey="E0001" /&gt;
 *         &lt;/param&gt;
 *         &lt;param name="id"&gt;
 *             &lt;!-- 必須チェック --&gt;
 *             &lt;validate type="requird" msgkey="E0002" /&gt;
 *             &lt;!-- 半角数値チェック --&gt;
 *             &lt;validate type="digit" msgkey="E0003" /&gt;
 *         &lt;/param&gt;
 *         &lt;param name="score"&gt;
 *             &lt;!-- 必須チェック --&gt;
 *             &lt;validate type="requird" msgkey="E0004" /&gt;
 *             &lt;!-- 半角英数チェック --&gt;
 *             &lt;validate type="eisu" msgkey="E0005" /&gt;
 *             &lt;!-- 数値範囲チェック --&gt;
 *             &lt;validate type="digit_length" msgkey="E0006" min="0" max="100" /&gt;
 *         &lt;/param&gt;
 *
 *         &lt;forward name="org.itscool.weber.action.INPUT_ERROR" path="/html/tutorial2/input.html"/&gt;
 *         &lt;forward name="success" path="/html/tutorial2/confirm.html"/&gt;
 *     &lt;/action&gt;
 * </pre>
 * param要素には、入力チェックの対象となるリクエストパラメータの論理名を指定します<BR>
 * param要素配下のvalidate要素にチェック項目を指定します<BR>
 * validate要素に指定する属性は以下の通りです<BR>
 * <table border="1">
 * 	<tr>
 * 		<td>属性</td><td>必須</td><td>説明</td>
 *  </tr>
 * 	<tr>
 * 		<td>type</td><td>必須</td>
 * 		<td>
 * 			チェックする内容を選択します<br>
 * 			type属性に指定可能なキーは以下の通りです<BR>
 * 			<li>requird 必須入力チェック
 * 			<li>zenkaku	全角チェック
 * 			<li>hankaku	半角チェック
 * 			<li>digit	半角数値チェック
 * 			<li>eisu	半角英数チェック(半角スペース許可)
 * 			<li>eiji	半角英字チェック(半角スペース許可)
 * 			<li>hankaku_kana	半角カナチェック
 * 			<li>str_length	文字列の桁数チェック（以下のmin、max属性必須）
 * 			<li>digit_length 数値の範囲チェック（以下のmin、max属性必須）
 *
 * 		</td>
 *  </tr>
 * 	<tr>
 * 		<td>msgkey</td><td>msgbodyを指定しない場合は必須</td>
 * 		<td>入力チェックでエラーになったときに出力するメッセージをmessage-config.xml
 * 		に登録されているメッセージIDで指定します</td>
 *  </tr>
 * 	<tr>
 * 		<td>msgbody</td><td>msgkeyを指定しない場合は必須</td>
 * 		<td>入力チェックでエラーになった時に出力するメッセージを指定します</td>
 *  </tr>
 * 	<tr>
 * 		<td>min</td><td>type属性にstr_lengthもしくはdigit_lengthを指定したとき必須</td>
 * 		<td>文字列の最小桁数あるいは数値の最小値を指定します</td>
 *  </tr>
 * 	<tr>
 * 		<td>max</td><td>type属性にstr_lengthもしくはdigit_lengthを指定したとき必須</td>
 * 		<td>文字列の最大桁数あるいは数値の最大値を指定します</td>
 *  </tr>
 * </table>
 * @author kanou
 *
 */
public class Validation {
    private static Validation instance = new Validation();
    public final static String ZENKAKU = "zenkaku";
    public final static String HANKAKU = "hankaku";
    public final static String DIGIT = "digit";
    public final static String EISU = "eisu";
    public final static String EIJI = "eiji";
    public final static String HANKAKU_KANA = "hankaku_kana";
    public final static String DIGIT_LENGTH = "digit_length";
    public final static String STR_LENGTH = "str_length";
    public final static String REQUIRD = "requird";
    public final static String MAIL = "mail";
    public final static String TEL = "tel";
    public final static String POST = "post";
    public final static String URL = "url";
    
    public static Validation getInstance(){
        return instance;
    }
    
    public HashMap isValidate(List validates, GeneralForm request){
        HashMap errList = new HashMap();
        if(validates == null){
            return errList;
        }
        int size = validates.size();
        for(int i=0; i<size; i++){
            ValidationMapping validation = (ValidationMapping)validates.get(i);
            String paramName = validation.getParamName();
            if(validation == null){
                continue;
            }
            Object value = request.getParameter(paramName);
            if( !(value instanceof String) ){
                continue;
            }
            validate(errList, paramName, validation, (String)value);
            
        }
        return errList;
    }
    
    protected void validate( HashMap errList, String paramName,
        ValidationMapping validation, String value ){
        String type = validation.getType();
        String msgkey = validation.getMsgkey();
        String msgbody = validation.getMsgbody();
        double max = validation.getMax();
        double min = validation.getMin();
        int length = validation.getLength();
        
        boolean ret = true;
        
        if(type.equals(ZENKAKU)){
            ret = InputCheckUtil.checkFullSize(value);
        }else if(type.equals(HANKAKU)){
            ret = InputCheckUtil.checkHalfSize(value);
        }else if(type.equals(DIGIT)){
            ret = InputCheckUtil.checkDigit(value);
        }else if(type.equals(EISU)){
            ret = InputCheckUtil.checkDigitAlphabet(value);
        }else if(type.equals(EIJI)){
            ret = InputCheckUtil.checkAlphabet(value);
        }else if(type.equals(HANKAKU_KANA)){
            ret = InputCheckUtil.checkHankakuKana(value);
        }else if(type.equals(DIGIT_LENGTH)){
            ret = InputCheckUtil.checkDigitLength(value, min, max);
        }else if(type.equals(STR_LENGTH)){
            ret = InputCheckUtil.checkStrLength(value, (int)min, (int)max);
        }else if(type.equals(REQUIRD)){
            ret = InputCheckUtil.checkRequerd(value);
        }else if(type.equals(MAIL)){
            ret = InputCheckUtil.checkMailAddr(value);
        }else if(type.equals(TEL)){
            ret = InputCheckUtil.checkTelNo(value);
        }else if(type.equals(POST)){
            ret = InputCheckUtil.checkPostCode(value);
        }else if(type.equals(URL)){
            ret = InputCheckUtil.checkUrl(value);
        }else{
            String errmsg = "Input Check Type Error [" + type + "]";
            putMessage( errList, msgkey, errmsg);
        }
        if(!ret){
            putMessage( errList, msgkey, msgbody);
        }
    }
    
    /**
     * エラーコードを追加します
     * @param key エラーを特定するためのユニークキー
     * @param msg エラーメッセージ
     */
    protected void putMessage( HashMap errList, Object key, Object msg){
        if( key != null ){
            putMessage(errList, key);
        }else{
            errList.put(msg, msg);
        }
    }
    
    /**
     * エラーコードを追加します<BR>
     * エラーキー(key)で指定されたメッセージをMessageResourcesインスタンス
     * から取得し、取得したエラーメッセージとエラーキーをエラーリストに追加します
     * @param key エラーを特定するためのユニークキー
     */
    protected void putMessage(HashMap errList, Object key ){
        MessageMappings messages = MessageMappings.getInstance();
        String message = (String)messages.get(key);
        errList.put(key, message);
    }
    
}
