/**
* フォーム入力チェック用関数群
* 
* @author Yuichiro Iwai <iwai@c-advan.co.jp>
* @version 1.01
* 
* 使用法については下記URLをご覧下さい。
* http://phpdevelopment/wiki/index.php?FormCheck
**

/**
* フォームチェックオブジェクト
**/
var FormCheck = {
	errors: [],
	passItems: [],
	currentForm: null,
	callback: null,
	breakFlag: false,
	customs: {},
	id: null,
	passwd: null,
	alphabetOnly: false,	//ID、passのアルファベットのみでの入力をチェック
	numberOnly: true,		//ID、passの数値のみでの入力をチェック
	autoTrim: false			//チェック時に自動でトリムする
};

/**
* 指定されたフォームのチェックを行なう。
**/
FormCheck.formCheck = function(n) {
	var f = document.forms[n];
	
	this.currentForm = f;
	
	//エラー配列を初期化
	this.errors = [];
	
	//スルーアイテムリストを初期化
	this.passItems = [];
	
	for(var j=0; j<f.elements.length; j++){
		var e = f.elements[j];
		var passFlag = false;
		
		for(var k=0; k<this.passItems.length; k++){
			if(this.passItems[k] == e.name){
				passFlag = true;
				break;
			}
		}
		
		if(passFlag) continue;
		
		if(e.tagName){
			switch(e.tagName.toLowerCase()){
				case "input":
				case "select":
				case "textarea":
					if(this.autoTrim){
						var v = e.value.replace(/^\s+/,"");
						v = v.replace(/\s+$/,"");
						e.value = v;
					}
					this.initCheck(e);
					break;
			}
		}
	}
	
	if(this.errors.length){
		if(this.callback){
			this.callback.call(this);
		}else{
			var errorstrs = [];
			
			for(var i=0; i<this.errors.length; i++){
				errorstrs.push(this.errors[i].errorstr);
			}
			
			alert(errorstrs.join("\n"));
			this.errors[0].element.focus();
		}
	}
}

/**
* フォームのチェックを行い
* エラーがなければ送信する。
**/
FormCheck.checkAndSubmit = function(n){
	this.formCheck(n);
	
	if(!this.errors.length){
		document.forms[n].submit();
	}
}

/**
* 指定されたエレメントのチェックを行なう。
**/
FormCheck.initCheck = function (e){
	var args = e.className.split("-");
	
	for(var i=0; i<args.length; i++){
		var params = args[i].split("_");
		var method = null;
		var err    = "";
		
		if(e.tagName.match(/select/i)){
			switch(params[0]){
				case "need":
					method = this.selectCheck;
					break;
			}
		}
		
		if(e.tagName.match(/textarea/i)){
			switch(params[0]){
				case "need":
					method = this.textareaCheck;
					break;
			}
		}
		
		if(e.type.match(/text/i)){
			switch(params[0]){
				case "witch":
					method = this.whichCheck;
					break;
				
				case "len":
					method = this.lengthCheck;
					break;
					
				case "need":
					method = this.needCheck;
					break;
					
				case "num":
					method = this.numCheck;
					break;
					
				case "alp":
					method = this.alphabetCheck;
					break;
					
				case "wod":
					method = this.wordCheck;
					break;
					
				case "mail":
					method = this.mailCheck;
					break;
					
				case "tel":
					method = this.telCheck;
					break;
					
				case "typeId":
					method = this.idCheck;
					break;
					
				case "typePass":
					method = this.passCheck;
					break;
					
				case "typePass2":
					method = this.pass2Check;
					break;
					
				case "eq":
					method = this.equalCheck;
					break;
			}
		}
		
		if(method){
			err = method.call(this,e,params);
		}
		
		if(err) this.errors.push(err);
	}
}

/**
* 複数のエレメントのうちいずれかが
* 入力されているかチェック
**/
FormCheck.whichCheck = function(e,params){
	if(!e.value){
		var flag = true;
		var titles = [];
		
		for(var i=1; i<params.length; i++){
			if(this.currentForm[params[i]].value){
				flag = false;
				break;
			}else{
				titles.push("『" + this.currentForm[params[i]].title + "』");
			}
		}
		
		if(flag){
			return this.makeError(e,"," + titles.join(",") + "のうち、いずれかを入力してください。");
		}
	}
}

/**
* 一般的なIDのチェック
* 
* 4〜12文字で数字とアルファベットの
* 混合の半角英数字とアンダースコア。
**/
FormCheck.idCheck = function(e,params){
	var err = "";
	
	//未入力チェック
	if(!e.value){
		return this.makeError(e,"は必ず入力してください。");
	}
	
	//文字数をチェック
	err = this.lengthCheck(e,[null,4,12]);
	if(err){
		this.errors.push(err);
	}
	
	//半角英数字とアンダースコアをチェック
	if(!e.value.match(/^[a-z0-9_]+$/i)){
		return this.makeError(e,"の入力に使用できるのは半角英数字および_のみです。");
	}
	
	if(this.numberOnly){
		//数字のみをチェック
		if(e.value.match(/^[0-9]+$/)){
			return this.makeError(e,"は数字のみでは使用できません。");
		}
	}
	
	if(this.alphabetOnly){
		//アルファベットのみをチェック
		if(e.value.match(/^[a-z]+$/i)){
			return this.makeError(e,"はアルファベットのみでは使用できません。");
		}
	}
	
	//アンダースコアのみをチェック
	if(e.value.match(/^_+$/)){
		return this.makeError(e,"は記号のみでは使用できません。");
	}
	
	//IDエレメントを保持
	this.id = e;
}

/**
* 一般的なパスワードのチェック
* 
* 半角英数字のみ、4〜12文字で
* 数字と英字の混合
* 
* もしidCheckが先に行なわれていた場合
* IDと同一のパスワードも拒否
**/
FormCheck.passCheck = function(e,params){
	if(!e.value){
		return this.makeError(e,"は必ず入力してください。");
	}
	
	//文字数をチェック
	err = this.lengthCheck(e,[null,3,12]);
	if(err){
		this.errors.push(err);
	}
	
	//半角英数字をチェック
	if(!e.value.match(/^[a-z0-9]+$/i)){
		return this.makeError(e,"の入力に使用できるのは半角英数字のみです。");
	}
	
	if(this.numberOnly){
		//数字のみをチェック
		if(e.value.match(/^[0-9]+$/)){
			return this.makeError(e,"は数字のみでは使用できません。");
		}
	}
	
	if(this.alphabetOnly){
		//アルファベットのみをチェック
		if(e.value.match(/^[a-z]+$/i)){
			return this.makeError(e,"はアルファベットのみでは使用できません。");
		}
	}
	
	if(this.id && this.id.value == e.value){
		return this.makeError(e,"にはIDと同じ値は使用できません。");
	}
	
	//パスワードエレメントを保持
	this.passwd = e;
}

/**
* 一般的なパスワードの再入力チェック
* (先にpassCheckを呼んでください)
**/
FormCheck.pass2Check = function(e,params){
	if(!e.value){
		return this.makeError(e,"は必ず入力してください。");
	}
	
	if(this.passwd && this.passwd.value != e.value){
		//return this.makeError(e,"が『パスワード』の値と異なっています。");
		return this.equalCheck(e,[this.passwd.id]);
	}
}

/**
* 文字列の長さをチェック
* 
* min_maxで指定。
* 長さがmin以上max以内の文字列かをチェック。
**/
FormCheck.lengthCheck = function(e,params){
	if(e.value){
		if(params.length == 3){
			if(params[0] == 0){
				if(e.value.length > params[2]){
					return this.makeError(e,"は" + params[2] + "文字以内で入力してください。");
				}
			}
			
			if(params[1] == params[2] && e.value.length != params[1]){
					return this.makeError(e,"は" + params[1] + "文字で入力してください。");
			}
			
			if(e.value.length < params[1] || e.value.length > params[2]){
				this.makeError(e,"は" + params[1] + "文字以上" + params[2] + "文字以内で入力してください。");
			}
		} else if(params.length == 2){
			if(e.value.length > params[1]){
				this.makeError(e,"は" + params[1] + "文字以上入力してください。");
			}
		}
	}
}

/**
* 数値チェック
* 完全に数字のみで構成された
* 文字列であるかチェックする。
**/
FormCheck.numCheck = function(e,params){
	if(e.value && !e.value.match(/^[0-9]+$/)){
		return this.makeError(e,"は半角数字のみで入力してください。");
	}
}

/**
* アルファベットのチェック
* 英字のみで構成された
* 文字列であるかチェックする。
**/
FormCheck.alphabetCheck = function(e,params){
	if(e.value && !e.value.match(/^[a-z]+$/i)){
		return this.makeError(e,"は半角英字のみで入力してください。");
	}
}

/**
* 半角英数字のチェック
* (記号は一切含まない)
**/
FormCheck.wordCheck = function(e,params){
	if(e.value && !e.value.match(/^[a-z0-9]+$/i)){
		return this.makeError(e,"は半角英数字のみで入力してください。");
	}
}

/**
* 値の存在をチェック
* 長さのみのチェックでは
* 未入力のチェックはスキップ
* されます。
**/
FormCheck.needCheck = function(e,params){
	if(!e.value){
		return this.makeError(e,"は必ず入力してください。");
	}
}

/**
* メールアドレスのチェック
* 極めて簡易式のチェックです。
**/
FormCheck.mailCheck = function(e,params){
	if(e.value && !e.value.match(/^\S+@\S+$/)){
		return this.makeError(e,"は正しいメールアドレスではありません。");
	}
}

/**
* 電話番号をチェック
**/
FormCheck.telCheck = function(e,params){
	if(e.value && !e.value.match(/^\d{2,5}(\-{0,1}\d{3,5}){1,3}$/)){
		return this.makeError(e,"が正しくありません。");
	}
}

/**
* 指定されたフォームと同値であることを
* チェックする
**/
FormCheck.equalCheck = function(e,params){
	var func = params.shift();
	var elem = $(params.join("_"));
	
	if(e.value != elem.value){
		return this.makeError(e,"の値が『" + elem.title + "』の値と異なっています。");
	}
}

/**
* セレクトボックスが選択済みかをチェック
* (選択肢のインデックスが0以上であることをチェックします)
**/
FormCheck.selectCheck = function(e,params){
	if(e.options.selectedIndex < 0){
		return this.makeError(e,"を選択してください。");
	}
}

/**
* テキストエリアの必須チェック
* 空白文字以外のものが入っていればOK。
**/
FormCheck.textareaCheck = function(e,params){
	if(!e.value.match(/\S/)){
		return this.makeError(e,"は必ず入力してください。");
	}
}

/**
* エラーの生成
**/
FormCheck.makeError = function(e,str){
	var err = {};
	err.errorstr = "『" + e.title + "』" + str;
	err.element  = e;
	
	return err;
}
