/**
 * livevalidation.js
 *
 * @author    MT312
 * @copyright 2008 MT312
 * @license   http://www.opensource.org/licenses/mit-license.php The MIT License
 * @version   CVS: $Id:$
 * @link      http://www.mt312.com/
 * @see       prototype.js 1.6 (http://www.prototypejs.org/)
 */

var validator = {};
validator.config = {
	// trueで上 falseで下
	error_pos: true,
	// 初期フォーカス
	first_focus: true,
	// フォームを含む要素名
	wrapper_element: 'td dd div'
};
validator.register = function(def_list) {
	if (typeof Prototype != 'object') {
		alert('prototype.js is not found.');
		return false;
	}
	if (def_list.length == 0) {
		return false;
	}
	this.def_list = def_list;
	Event.observe(window, 'load', this.dispatch);
	return true;
};
validator.dispatch = function() {
	var self = validator;
	var def_list = self.def_list;
	var id = def_list[0].id;
	var first_el = $(id);
	if (first_el == null) return false;
	// name属性だけで取得できるIEの対策
	if (first_el.id == '') return false;
	if (first_el.tagName == 'SPAN') {
		for (var i = 0; i < 10; ++i) {
			first_el = $(id + i);
			if (first_el != null) break;
		}
		if (first_el == null) return false;
	}

	var form = first_el.form;
	if (self.config.first_focus) {
		first_el.focus();
	}

	var parentBlockNode = function(el) {
		var wrapper = self.config.wrapper_element.toUpperCase();
		do {el = el.parentNode;}
		while (wrapper.indexOf(el.tagName) == -1);
		return el;
	};

	form.onmousedown = function(ev) {
		ev = ev || window.event;
		this.ev_el = Event.element(ev);
		return true;
	};
	form.onkeydown = function(ev) {
		ev = ev || window.event;
		this.ev_el = Event.element(ev);
		if (ev.keyCode == 13) {
			var el = this.ev_el;
			if (el.tagName == 'TEXTAREA') return true;
			if (el.tagName == 'INPUT' && el.type == 'reset') return true;
			var elems = Form.getElements(this);
			var i = elems.indexOf(el);
			if (i > -1 && i < elems.length - 1) {
				var next_el = elems[i + 1];
				next_el.focus();
				this.next_el = next_el;
			}
		}
		return true;
	};
	form.onsubmit = function(ev) {
		if (this.ev_el.tagName == 'INPUT' && this.ev_el.type == 'submit') {
			var focused = false;
			el_list.each(function(el) {
				if (!el.validate(ev) && !focused) {
					Element.scrollTo(parentBlockNode(el));
					if (el.tagName == 'SPAN') {
						el = el.inner_nodes[0];
					}
					el.focus();
					focused = true;
				}
			});
			return focused == false;
		}
		// IEでボタンがフォーカスされる対策
		if ('next_el' in this) {
			this.next_el.focus();
		}
		return false;
	};
	form.onreset = function() {
		el_list.each(function(el) {
			var err_el = $(el.id + '_error');
			var has_err = err_el != null && err_el.tagName == 'EM';
			if (has_err) {
				Element.remove(err_el);
				Element.removeClassName(el, 'error');
				Element.removeClassName(el, 'good');
			}
		});
		Element.scrollTo(this);
		first_el.focus();
		return true;
	};

	// 存在するエレメントのリスト
	var el_list = [];
	def_list.each(function(def) {
		if (typeof def.id != 'string') return;
		var el = $(def.id);
		if (el == null) return;
		if (el.tagName == 'SPAN') {
			var name = el.id;
			var def_type = el.id.charAt(0).toUpperCase();
			if (def_type == 'C') name += '[]';
			if (typeof form[name] == 'undefined') return;
			var inner_nodes = form[name];
			// チェックボックス配列以外
			if (typeof inner_nodes[0] == 'undefined') {
				inner_nodes = [inner_nodes];
			}
			el.inner_nodes = $A(inner_nodes);
			el.form = form;
		} else {
			def_type = el.tagName.charAt(0);
		}
		var class_name = def_type + '_Define';
		if (typeof window[class_name] != 'function') return;

		el_list.push(el);
		var define = new window[class_name]();
		Object.extend(define, def);
		define.el = el;
		el.def = def;
		el.define = define;
		el.validate = function(ev) {
			ev = ev || window.event;
			if (ev.keyCode == 9 || ev.keyCode == 13) {
				return true;
			}
			var err_el = $(el.id + '_error');
			var has_err = err_el != null && err_el.tagName == 'EM';
			for (var prop in def) {
				if (define[prop] == null) continue;
				var method_name = prop + '_check';
				if (typeof define[method_name] != 'function') continue;
				var result = define[method_name]();
				if (result === null) break;
				if (result === true) continue;
				var msg = define[prop + '_error'] + '。';
				msg = msg.replace('{form}', define.name);
				msg = msg.replace('%d', define[prop]);
				// エラー要素がなければ作成
				if (!has_err) {
					err_el = document.createElement('em');
					err_el.id = el.id + '_error';
					if (validator.config.error_pos) {
						var p_node = parentBlockNode(this);
						var first_el = p_node.firstChild;
						// 他のエラーがあれば最後尾まで移動
						while (typeof first_el.tagName == 'string' && first_el.tagName == 'EM') {
							first_el = first_el.nextSibling;
						}
						p_node.insertBefore(err_el, first_el);
					} else {
						var p_node = parentBlockNode(this);
						p_node.appendChild(err_el);
					}
				}
				err_el.className = 'error';
				err_el.innerHTML = msg;
				Element.removeClassName(el, 'good');
				Element.addClassName(el, 'error');
				return false;
			}
			if (has_err) {
				err_el.className = 'good';
				err_el.innerHTML = 'Good!';
				Element.removeClassName(el, 'error');
				Element.addClassName(el, 'good');
			}
			return true;
		};

		if (el.tagName == 'SPAN') {
			el.inner_nodes.each(function(node) {
				Event.observe(node, 'click', function(ev) {return el.validate(ev);}, false);
			});
		} else if (el.tagName == 'SELECT') {
			Event.observe(el, 'change', el.validate);
		} else {
			Event.observe(el, 'keyup', el.validate);
			// Event.observe(el, 'blur', el.validate);
		}
	});
	return true;
};
function Define()
{
	this.required = false;
	this.required_error = '{form}を入力して下さい';
	this.required_check = function() {
		var str = Convert.trim($F(this.el));
		if (this.required) return str != '';
		if (str == '') return null;
		return true;
	};
	this.min = 0;
	this.min_error = '{form}は%d文字以上にして下さい';
	this.min_check = function() {
		return $F(this.el).length >= this.min;
	};
	this.max = 3000;
	this.max_error = '{form}は%d文字以内にして下さい';
	this.max_check = function() {
		return $F(this.el).length <= this.max;
	};
}
function T_Define()
{
	this.regexp_list = {
		mailaddress: /^([a-z\d_]|\-|\.|\+)+@(([a-z\d_]|\-)+\.)+[a-z]{2,6}$/i,
		url: /^(https?|ftp):\/\/\S+$/,
		alphabet: /^[a-z]+$/i,
		alphanum: /^[a-z\d]+$/i,
		number: /^\d+$/,
		integer: /^[1-9]\d*$/,
		zipcode: /^\d{3}-\d{4}$/,
		zipcode_d: /^\d{7}$/,
		phone:   /^0[1-9]\d{0,4}-(\d{1,4}-)?\d{4}$/,
		phone_d: /^0[1-9]\d{8,9}$/,
		mbphone:   /^0[7-9]0-\d{4}-\d{4}$/,
		mbphone_d: /^0[7-9]0\d{8}$/,
		katakana: /^[ァ-ン　 ]+$/,
		hiragana: /^[ぁ-ん　 ]+$/
	};
	this.regexp = null;
	this.regexp_error = '{form}が正しくありません';
	this.regexp_check = function() {
		var regexp = this.regexp;
		if (regexp in this.regexp_list) {
			var str = Convert.trim($F(this.el));
			if (regexp == 'hiragana') {
				str = Convert.toHiragana(str);
			} else if (regexp == 'katakana') {
				str = Convert.toKatakana(str);
			} else {
				str = Convert.zenToHan(str);
			}
			return this.regexp_list[regexp].test(str);
		}
		return true;
	};
	this.repeat = false;
	this.repeat_error = '{form}が正しくありません';
	this.repeat_check = function() {
		var elems = Form.getElements(this.el.form);
		var n = elems.indexOf(this.el);
		return n > 0 && (elems[n - 1].value == this.el.value);
	};
}
function S_Define()
{
	this.required_error = '{form}を選択して下さい';
}
function R_Define()
{
	this.required_error = '{form}を選択して下さい';
	this.required_check = function() {
		var checked = false;
		this.el.inner_nodes.each(function(node) {
			if (node.checked) {
				checked = true;
				return;
			}
		});
		if (this.required) return checked;
		if (!checked) return null;
		return true;
	};
	this.min_check = function() {
		var length = 0;
		this.el.inner_nodes.each(function(node) {
			if (node.checked) {
				length = $F(node).length;
				return;
			}
		});
		return length >= this.min;
	};
	this.max_check = function() {
		var length = 0;
		this.el.inner_nodes.each(function(node) {
			if (node.checked) {
				length = $F(node).length;
				return;
			}
		});
		return length <= this.max;
	};
}
function C_Define()
{
	this.required_error = '{form}を選択して下さい';
	this.required_check = function() {
		var checked = false;
		this.el.inner_nodes.each(function(node) {
			if (node.checked) {
				checked = true;
				return;
			}
		});
		if (this.required) return checked;
		if (!checked) return null;
		return true;
	};
	this.min_check = function() {
		var ret = true;
		var min = this.min;
		this.el.inner_nodes.each(function(node) {
			if (node.checked && node.value.length < min) {
				ret = false;
				return;
			}
		});
		return ret;
	};
	this.max_check = function() {
		var ret = true;
		var max = this.max;
		this.el.inner_nodes.each(function(node) {
			if (node.checked && node.value.length > max) {
				ret = false;
				return;
			}
		});
		return ret;
	};
	this.checks_min_error = '{form}は%dヶ所以上選択して下さい';
	this.checks_min_check = function() {
		if (this.checks_min < 2) return true;
		var checks = 0;
		this.el.inner_nodes.each(function(node) {
			if (node.checked) ++checks;
		});
		return checks >= this.checks_min;
	};
	this.checks_max_error = '{form}は%dヶ所以下選択して下さい';
	this.checks_max_check = function() {
		if (this.checks_max < 2) return true;
		var checks = 0;
		this.el.inner_nodes.each(function(node) {
			if (node.checked) ++checks;
		});
		return checks <= this.checks_max;
	};
}
function F_Define()
{
	this.required_error = '{form}を選択して下さい';
	this.min = null;
	this.min_check = null;
	this.max = null;
	this.max_check = null;
}
I_Define = T_Define;
I_Define.prototype = new Define();
T_Define.prototype = new Define();
R_Define.prototype = new Define();
S_Define.prototype = new Define();
C_Define.prototype = new Define();
F_Define.prototype = new Define();
var Convert = {
	trim: function(str) {
		// str = str.replace(/^[\s　]+|[\s　]+$/, '');
		str = str.replace(/^[\s　]+/, '');
		str = str.replace(/[\s　]+$/, '');
		return str;
	},
	zenToHan: function(str) {
		var zen = '！”＃＄％＆’（）＝＾～／＊－＋．，？＿＠；：　';
		var han = '!"#$%&\'()=^~/*-+.,?_@;: ';
		var reg = new RegExp('[' + zen + ']', 'g');
		str = str.replace(reg, function($0) {
			return han.charAt(zen.indexOf($0));
		});
		return str.replace(/[Ａ-Ｚａ-ｚ０-９]/g, function($0) {
			return String.fromCharCode($0.charCodeAt(0) - 0xFEE0);
		});
	},
	toHiragana: function(str) {
		return str.replace(/[ァ-ン]/g, function($0) {
			return String.fromCharCode($0.charCodeAt(0) - 0x0060);
		});
	},
	toKatakana: function(str) {
		return str.replace(/[ぁ-ん]/g, function($0) {
			return String.fromCharCode($0.charCodeAt(0) + 0x0060);
		});
	}
};
function checksAll(id, checked)
{
	var el = $(id);
	if (el != null && typeof el.inner_nodes != 'undefined') {
		el.inner_nodes.each(function(node) {
			node.checked = Boolean(checked);
		});
	}
}

