// ========================================================================================@ MTechno
//  validator.js ---- JavaScript Common Library ver.1.0
// -------------------------------------------------------------------------------------------------
//  prototype.js は必要ありません  (!)
//  注意 (1) 配列型のフィールド(CHECKBOX等)で複数のノードにまたがっている場合は、エラーエリアを明示
//           的に生成しておく必要があります
//             例 -> name="何でお知りになりましたか？_gaito_RADIO" の場合
//                   <div id="gaito_RADIO_ERR" style="display:none;"></div> ← これで
//  注意 (2) 郵便番号自動取得機能を手動で設定する場合、 window.onload がまわる前に、下記を設定
//             例 -> Validator.zipGet.manualSet = true; ← これをセット
// =================================================================================================
//   FORM VALIDATION CLASS
//--------------------------------------------------------------------------------------------------
/* UTILITY --- */
var addEvent = ( window.addEventListener ) ?
	(function(elm, type, event) {
		elm.addEventListener(type, event, false);
	}) : (window.attachEvent) ?
	(function(elm, type, event) {
		elm.attachEvent('on'+type, event);
	}) :
	(function(elm, type, event) {
		elm['on'+type] = event;
	}) ;
var Position = {
	offset: function(elm) {
		var pos = {};
		pos.x = this.getOffset('Left', elm);
		pos.y = this.getOffset('Top', elm);
		return pos;
	},
	getOffset: function(prop, el) {
		if(!el.offsetParent || el.offsetParent.tagName.toLowerCase() == "body")
			return el['offset'+prop];
		else
			return el['offset'+prop]+ this.getOffset(prop, el.offsetParent);
	}
};
/* CORE --- */
var Validator = {
	/* 一度生成したエラーエリアを格納 */
	cache: {},
	/* VALIDATION 関数 */
	/*  使用例は後半部分に記載 */
	check: function(field, reg, extra) {
		var response;
		var rule = this.rule;
		rule.field = field;
		rule.value = field.value;
		rule.extra = extra;
		if(!reg || !reg.match(/^!/))
			response = rule.input();
		if(reg && !response && rule.value != '') {
			reg = reg.replace(/^!/, '');
			var mode = reg.split(/\s+/);
			for(var i = 0, m; m = mode[i]; i++) {
				m = m.replace(/([\d\-]+)?$/, '');
				response = rule[m](RegExp.$1);
				if(response) break;
			}
		}
		if(response)
			this.baloon.open(field, response);
	},
	/* 二つ以上のフィールドを使用しての VALIDATION 関数 */
	/*  使用例 ->  onblur="Validator.multiCheck(['*郵便番号M1_zipm1_TEXT',this], '-', 'zip')" */
	/*             第一引数の配列の順番で、第二引数をジョイントとして、結合したのちチェック */
	multiCheck: function(fieldArray, joint, reg, extra) {
		var response;
		var rule = this.rule;
		var b = [];
		for ( var i = 0, n = fieldArray.length; i < n; i++ ) {
			if ( typeof( fieldArray[i] ) == 'object' ) {
				rule.field = fieldArray[i];
				break;
			}
		}
		var a = [], fields = [];
		for ( var i = 0, n = fieldArray.length; i < n; i++ ) {
			if ( typeof( fieldArray[i] ) != 'object' ) {
				a.push( rule.field.form[ fieldArray[i] ].value );
				fields.push( rule.field.form[ fieldArray[i] ] );
			} else {
				a.push( fieldArray[i].value );
				fields.push( fieldArray[i] );
			}
		}
		rule.value = a.join( joint );
		rule.extra = extra;
		if(!reg || !reg.match(/^!/))
			response = rule.input();
		if(reg && !response && rule.value != '') {
			reg = reg.replace(/^!/, '');
			var mode = reg.split(/\s+/);
			for(var i = 0, m; m = mode[i]; i++) {
				m = m.replace(/([\d\-]+)?$/, '');
				response = rule[m](RegExp.$1);
				if(response) break;
			}
		}
		if(response)
			this.baloon.open(rule.field, response, fields);
	},
	/* あるフィールドで特定の値がはいったときに必須になる項目を VALIDATION 関数 */
	/*  使用例 ->  onblur="Validator.caseCheck(this, '何でお知りになりましたか？_gaito_RADIO', 'その他_15')" */
	/*             チェックをかけるフィールドにバインドする */
	caseCheck: function(field, target, value, reg, extra) {
		var f = field.form[ target ], v = '';
		if(f.length) {
			for(var i = 0, e; e = f[i]; i++) {
				if(e.checked) {
					v = e.value;
					if ( v == value ) {
						Validator.check(field, reg, extra);
						return;
					}
				}
			}
		} else if(f.value != '') {
			v = f.value;
		}
		if ( v == value )
			Validator.check(field, reg, extra);
	},
	/* フォームサブミットにバインドする 関数 */
	submit: function(form) {
		this.allclose(form);
		var btns = new Array();
		for(var i = 0, f; f = form[i]; i++) {
			if(f.onblur)
				f.onblur();
			// if( f.type.toLowerCase() == 'submit' )
			// 	btns.push(f);
		}
		for(var i = 0, f, z; f = form[i]; i++) {
			if(f._validbaloon && f._validbaloon.visible()) {
				while(z = btns.shift())
					this.baloon.open(z, this.rule.submit());
					// Validator.formError.style.display='none';
				return false;
			}
		}
		return true;
	},
	allclose: function(form) {
		for(var i = 0, f; f = form[i]; i++)
			if(f._validbaloon) f._validbaloon.close();
	}
};
/* ERROR AREA 出力オブジェクト --- */
Validator.baloon = {
	index: 0,
	open: function(field, msg, fields) {
		if(!field._validbaloon) {
			if ( field.name && Validator.cache[ field.name ] ) {
				field._validbaloon = Validator.cache[ field.name ];
			} else {
				var obj = new this.element(field, fields);
				obj.create();
				field._validbaloon = obj;
				if ( field.name ) Validator.cache[ field.name ] = obj;
			}
			if(field.type.toLowerCase() == 'radio' || field.type.toLowerCase() == 'checkbox') {
				for(var i = 0, e; e = field.form[field.name][i]; i++)
					addEvent(e, 'focus', function() { obj.close(); });
			}
		}
		field._validbaloon.show(msg);
	},
	element: function() {
		this.initialize.apply(this, arguments);
	}
};
Validator.baloon.element.prototype = {
	initialize: function(field, fields) {
		this.parent = Validator.baloon;
		this.field = field;
		this.fields = fields || null;
	},
	/* AREA 生成 --- */
	create: function() {
		var field  = this.field;
		if ( field.type.toLowerCase() == 'submit' ) {
			var box = Validator.formError;
		} else if ( field.name ) {
			var nm = field.name.split('_'), ne = document.getElementById( nm[1] + '_' + nm[2] + '_ERR' );
			if ( !!ne ) {
				var box = ne;
			} else {
				var box = document.createElement('div');
			}
		} else {
			var box = document.createElement('div');
		}
		box.className = 'baloon';
		var self = this;
		addEvent(box, 'click', function() { self.toTop(); });
		var bindClose = function() { self.close(); };
		var link = document.createElement('a');
		link.appendChild(document.createTextNode('X'));
		link.setAttribute('href', 'javascript:void(0);');
		addEvent(link, 'click', bindClose);
		if ( !this.fields ) {
			addEvent(field, 'focus', bindClose);
		} else {
			for ( var i = 0; i < this.fields.length; i++ ) {
				addEvent(this.fields[i], 'focus', bindClose);
			}
		}
		var msg = document.createElement('span');
		var div = document.createElement('div');
		div.appendChild(link);
		div.appendChild(msg);
		box.appendChild(div);
		if ( !field.parentNode ) var p = document.body;
		else var p = field.parentNode;
		if ( !ne && field.type.toLowerCase() != 'submit' ) p.appendChild( box );
		this.box = box;
		this.msg = msg;
	},
	show: function(msg) {
		var field = this.field, fields = this.fields;
		this.msg.innerHTML = msg;
		this.box.style.display = '';
		this.toTop();
		if(field.type.toLowerCase() != 'radio' && field.type.toLowerCase() != 'checkbox') {
			/* エラー時フィールド明滅用カラー --- */
			// var colors = new Array('#7cff7c', '#b7ffb7', '#7cff7c', '#b7ffb7');
			var colors = new Array('#fff0f0');
			window.setTimeout(function() {
				if(colors.length > 0) {
					if ( !fields ) {
						field.style.backgroundColor = colors.shift();
						// window.setTimeout(arguments.callee, 70);
					} else {
						var c = colors.shift();
						for ( var i = 0; i < fields.length; i++ ) {
							fields[i].style.backgroundColor = c;
							// window.setTimeout(arguments.callee, 70);
						}
					}
				}
			}, 10);
		}
		this.box.style.width = ( this.msg.offsetWidth + 30 ) + 'px';
		if ( field.type.toLowerCase() == 'submit' ) window.scrollTo(0, 0);
	},
	close: function() {
		this.box.style.display = 'none';
		if ( !this.fields ) {
			this.field.style.backgroundColor = '';
		} else {
			for ( var i = 0; i < this.fields.length; i++ ) {
				this.fields[i].style.backgroundColor = '';
			}
		}
	},
	visible: function() {
		return (this.box.style.display == '');
	},
	toTop: function() {
		this.box.style.zIndex = ++ this.parent.index;
	}
};
/* CHECK RULE --- */
Validator.rule = {
	msg: null,
	submit: function() {
		return this.msg.submit;
	},
	input: function() {
		if(this.field.type.toLowerCase() == 'radio' || this.field.type.toLowerCase() == 'checkbox') {
			for(var i = 0, e; e = this.field.form[this.field.name][i]; i++)
				if(e.checked) return;
			return this.msg.noselect;
		} else if(this.value == '')
			return (this.field.type.toLowerCase() == 'select-one') ? this.msg.noselect : this.msg.noinput;
	},
	/* メールアドレス */
	/*  使用例 ->  onblur="Validator.check(this, 'mail')" */
	mail: function() {
		if(!this.value.match(/^[\x01-\x7F]+@((([-a-z0-9]+\.)*[a-z]+)|(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}))$/))
			return this.msg.mail;
	},
	/* URL アドレス */
	/*  使用例 ->  onblur="Validator.check(this, 'url')" */
	url: function() {
		if(!this.value.match(/^(https?|ftp)(:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)$/))
			return this.msg.url;
	},
	/* 郵便番号 */
	/*  使用例 ->  onblur="Validator.check(this, 'zip')" */
	zip: function() {
		if(!this.value.match(/^[0-9]{3}(\-|)[0-9]{4}$/))
			return this.msg.zip;
	},
	/* 電話番号 */
	/*  使用例 ->  onblur="Validator.check(this, 'tel')" */
	tel: function() {
		if(this.value.match(/[^0-9\-\(\)]/))
			return this.msg.tel;
	},
	/* 他のフィールドと同じ値を入力 */
	/*  使用例 ->  onblur="Validator.check(this, 'equal', 'pass2')" */
 	equal: function() {
		if(this.field.form[this.extra].value && this.value != this.field.form[this.extra].value)
			return this.msg.unequal;
	},
	/* アルファベット */
	/*  使用例 ->  onblur="Validator.check(this, 'alphabet')" */
	alphabet: function() {
		if(!this.value.match(/^[a-zA-Z\-\d]+$/))
			return this.msg.alphabet;
	},
	/* 全角カタカナ */
	/*  使用例 ->  onblur="Validator.check(this, 'kana')" */
	kana: function() {
		for(var i = 0;i < this.value.length;i++) {
			if(this.value.charAt(i) == ' ' || this.value.charAt(i) == '\u3000') continue;
			if(this.value.charAt(i) < '\u30A1' || this.value.charAt(i) > '\u30F6')
				return this.msg.kana;
		}
	},
	/* 半角カタカナ 禁止 */
	/*  使用例 ->  onblur="Validator.check(this, 'hankaku')" */
	hankaku: function() {
		for(var i = 0;i < this.value.length;i++) {
			if(this.value.charAt(i) >= '\uFF71' && this.value.charAt(i) <= '\uFF9D')
				return this.msg.hankaku;
		}
	},
	/* 字数関連 */
	/*  使用例 ->  onblur="Validator.check(this, 'count5-')" 文字数の制限 - 5文字以上 */
	/*             onblur="Validator.check(this, 'count-10')" 文字数の制限 - 10文字以下 */
	count: function(arg) {
		return this._range(arg, this.value.length, this.msg.count);
	},
	/* 数字 */
	/*  使用例 ->  onblur="Validator.check(this, 'num')" */
	num: function(arg) {
		if(!this.value.match(/^[\d]+$/))
			return this.msg.num.nonumber;
		return this._range(arg, parseInt(this.value), this.msg.num);
	},
	/* 必須 */
	/*  使用例 ->  onblur="Validator.check(this)" */
	check: function(arg) {
		var value = 0;
		for(var i = 0, e; e = this.field.form[this.field.name][i]; i++)
			if(e.checked) value += 1;
		return this._range(arg, value, this.msg.check);
	},
	_range: function(range, value, msg) {
		if(!range) return;
		var result = '';
		var c = (" "+range).split(/\-/);
		var min = parseInt(c[0]) || 0;
		var max = parseInt(c[1]) || 0;
		if(value != min && /^\d+$/.test(range))
			result = msg.unequal;
		else if(min == 0 && value > max)
			result = msg.too_big;
		else if(max == 0 && value < min)
			result = msg.too_small;
		else if(min > 0 && max > 0 && (value < min || value > max))
			result = msg.outofrange;
		return result.replace(/%1/g, min).replace(/%2/g, max);
	}
};
/* 郵便番号自動取得 関数 --- */
Validator.zipGet = function () {
	var g = [ arguments.callee.fire, arguments.callee.target ];
	if ( !g[0] || !g[1] ) return;
	var v = g[0].value;
	if (!v) return;
	var http = new JKL.ParseXML( '/inquiry/confirm/zipGet.php?a=' + encodeURIComponent(v) + '&cache=' + (new Date()).getTime() );
	http.setOutputArrayElements('dt');
	http.async( function ( data ) {
		var str = '';
		if ( data.item.dt.length < 1 ) {
			g[1].value = '';
			Validator.baloon.open(g[0], Validator.rule.msg.zipGet.no_error);
		} else if ( data.item.dt.length == 1 ) {
			if ( data.item.dt[0].jusho == 'NON' ) {
				g[1].value = '';
				Validator.baloon.open(g[0], Validator.rule.msg.zipGet.no_error);
			} else {
				if ( !!g[0]._validbaloon ) g[0]._validbaloon.close();
				g[1].value = data.item.dt[0].jusho;
			}
		} else {
			Validator.baloon.open(g[0], Validator.rule.msg.zipGet.multi_error);
		}
	} );
	http.parse();
};
Validator.zipGet.fire = null;
Validator.zipGet.target = null;
Validator.zipGet.manualSet = null;
/* ERROR MESSAGE --- */
Validator.lang = {
	ja: {
		noselect: '\u9078\u629E\u304C\u5FC5\u8981\u3067\u3059\u3002',
		noinput: '\u5165\u529B\u304C\u5FC5\u8981\u3067\u3059\u3002',
		unequal: '\u5165\u529B\u304C\u63C3\u3063\u3066\u3044\u307E\u305B\u3093\u3002',
		submit: '\u5165\u529B\u30A8\u30E9\u30FC\u304C\u3042\u308A\u307E\u3059\u3002',
		mail: '\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u306E\u5F62\u5F0F\u304C\u6B63\u3057\u304F\u3042\u308A\u307E\u305B\u3093\u3002',
		url: '\uFF35\uFF32\uFF2C\u306E\u5F62\u5F0F\u304C\u6B63\u3057\u304F\u3042\u308A\u307E\u305B\u3093\u3002',
		zip: '\u90F5\u4FBF\u756A\u53F7\u306E\u5F62\u5F0F\u304C\u6B63\u3057\u304F\u3042\u308A\u307E\u305B\u3093\u3002',
		tel: '\u96FB\u8A71\u756A\u53F7\u306E\u5F62\u5F0F\u304C\u6B63\u3057\u304F\u3042\u308A\u307E\u305B\u3093\u3002',
		alphabet: '\u30A2\u30EB\u30D5\u30A1\u30D9\u30C3\u30C8\u3001\u6570\u5B57\u3001' + '- \u4EE5\u5916\u306F\u5165\u529B\u51FA\u6765\u307E\u305B\u3093\u3002',
		kana: '\u5168\u89D2\u30AB\u30BF\u30AB\u30CA\u3067\u5165\u529B\u3057\u3066\u4E0B\u3055\u3044\u3002',
		hankaku: '\u534A\u89D2\u30AB\u30BF\u30AB\u30CA\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002',
		count: {
			unequal: '%1'+'\u6587\u5B57\u3067\u5165\u529B\u3057\u3066\u4E0B\u3055\u3044\u3002',
			too_big: '%2'+'\u6587\u5B57\u4EE5\u5185\u3067\u5165\u529B\u3057\u3066\u4E0B\u3055\u3044\u3002',
			too_small: '%1'+'\u6587\u5B57\u4EE5\u4E0A\u5165\u529B\u3057\u3066\u4E0B\u3055\u3044\u3002',
			outofrange: '%1'+'\u304B\u3089'+'%2'+'\u6587\u5B57\u306E\u9593\u3067\u5165\u529B\u3057\u3066\u4E0B\u3055\u3044\u3002'
		},
		num: {
			nonumber: '\u6570\u5024\u3067\u5165\u529B\u3057\u3066\u4E0B\u3055\u3044\u3002',
			unequal: '%1'+'\u3068\u5165\u529B\u3057\u3066\u4E0B\u3055\u3044\u3002',
			too_big: '%2'+'\u4EE5\u4E0B\u306E\u5024\u3092\u5165\u529B\u3057\u3066\u4E0B\u3055\u3044\u3002',
			too_small: '%1'+'\u4EE5\u4E0A\u306E\u5024\u3092\u5165\u529B\u3057\u3066\u4E0B\u3055\u3044\u3002',
			outofrange: '%1'+'\u304B\u3089'+'%2'+'\u306E\u9593\u3067\u5165\u529B\u3057\u3066\u4E0B\u3055\u3044\u3002'
		},
		check: {
			unequal: '\u30C1\u30A7\u30C3\u30AF\u306F'+'%1'+'\u500B\u3057\u3066\u4E0B\u3055\u3044\u3002',
			too_big: '\u30C1\u30A7\u30C3\u30AF\u306F'+'%2'+'\u500B\u307E\u3067\u3067\u3059\u3002',
			too_small: '\u30C1\u30A7\u30C3\u30AF\u306F'+'%1'+'\u500B\u4EE5\u4E0A\u3057\u3066\u4E0B\u3055\u3044\u3002',
			outofrange: '\u30C1\u30A7\u30C3\u30AF\u306F'+'%1'+'\u500B\u304B\u3089'+'%2'+'\u500B\u307E\u3067\u3067\u3059\u3002'
		},
		zipGet: {
			btname: '\u81EA\u52D5\u5165\u529B',
			comms: '\uFF08\u90F5\u4FBF\u756A\u53F7\u3092\u5165\u308C\u305F\u3042\u3068\u306B\u3000\u30DC\u30BF\u30F3\u3092\u30AF\u30EA\u30C3\u30AF\u3057\u3066\u304F\u3060\u3055\u3044\uFF09',
			no_error: '<font color="red">\u6307\u5B9A\u306E\u4F4F\u6240\u306F\u3042\u308A\u307E\u305B\u3093</font>',
			multi_error: '<font color="red">\u8907\u6570\u306E\u4F4F\u6240\u304C\u8A72\u5F53\u3057\u307E\u3059</font>'
		}
	}
};
Validator.rule.msg = Validator.lang.ja;
addEvent(window, 'load', function() {
	/* フォームサブミット時のエラーエリア生成 */
	Validator.formError = document.createElement('div');
	var a = document.getElementsByTagName('form')[0], r = [/_zip_/, /_address_/], b, f = [false, false];
	a.parentNode.insertBefore(Validator.formError, a);
	if ( Validator.zipGet.manualSet ) return;
	/* 郵便番号自動取得ボタン生成 */
	for ( var i = 0, n = a.elements.length; i < n; i++ ) {
		b = a.elements[i];
		if ( b.name ) {
			if ( !f[0] && r[0].test( b.name ) ) {
				Validator.zipGet.fire = b;
				f[0] = true;
				if ( f[0] && f[1] ) break;
			} else if ( !f[1] && r[1].test( b.name ) ) {
				Validator.zipGet.target = b;
				f[1] = true;
				if ( f[0] && f[1] ) break;
			}
		}
	}
	if ( f[0] && f[1] ) {
		b = Validator.zipGet.fire;
		var p = document.createElement('div'), m = document.createElement('input'), p2 = b.parentNode;
		m.type = 'button';
		m.value = Validator.rule.msg.zipGet.btname;
		p.innerHTML = Validator.rule.msg.zipGet.comms;
		var nm = b.name.split('_'), ne = document.getElementById( nm[1] + '_' + nm[2] + '_ERR' );
		if (!ne) {
			var p1 = document.createElement('div');
			p1.id = nm[1] + '_' + nm[2] + '_ERR';
			p1.style.display = 'none';
			if ( b.nextSibling ) p2.insertBefore(p1, b.nextSibling);
			else p2.appendChild(p1);
		}
		if ( b.nextSibling ) p2.insertBefore(p, b.nextSibling);
		else p2.appendChild(p);
		p2.insertBefore(m, p);
		m.onclick = function () { Validator.zipGet(); return false; };
	}
});

