/**
 * 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.register = function(def_list) {
	this.def_list = def_list;
	Event.observe(window, 'load', this.dispatch);
};
validator.dispatch = function() {
	var def_list = validator.def_list;
	if (def_list.length == 0 || !('id' in def_list[0])) {
		return false;
	}
	var inner_node = $(def_list[0].id);
	if (inner_node == null) {
		return false;
	}
	if (inner_node.tagName == 'SPAN') {
		for (var i = 0; i < 10; ++i) {
			inner_node = $(def_list[0].id + i);
			if (inner_node != null) break;
		}
	}
	if (inner_node == null) {
		return false;
	}
	var form = inner_node.form;

	form.onkeydown = form.onmousedown = function(ev) {
		this.el = Event.element(ev || window.event);
	};
	form.onsubmit = function(ev) {
		var el = this.el;
		if (el.tagName != 'INPUT' || el.type != 'submit') {
			var elems = Form.getElements(this);
			elems[elems.indexOf(el) + 1].focus();
			return false;
		}
		var focused = false;
		el_list.each(function(el) {
			if (!el.validate(ev) && !focused) {
				focused = true;
				el.focus();
				Element.scrollTo(el.parentNode);
			}
		});
		return !focused;
	};
	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);
	};

	var el_list = [];
	def_list.each(function(def) {
		var el = $(def.id);
		if (el == null) return;

		// Element.cleanWhitespace(el.parentNode);
		el_list.push(el);
		var def_type = el.tagName == 'SPAN' ? el.className.charAt(0).toUpperCase() : el.tagName.charAt(0);
		var class_name = def_type + '_Define';
		if (class_name in window) {
			var define = new window[class_name]();
			Object.extend(define, def);
		} else {
			var define = new Object();
			def = {};
		}

		if (!('form' in el)) {
			var name = def_type == 'R' ? el.id : el.id + '[]';
			if (!(name in form)) {
				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;
		}
		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 mem in def) {
				var name = mem + '_check';
				if (typeof define[name] == 'function') {
					var result = define[name]();
					if (result === null) break;
					if (result === true) continue;
					var msg = define[mem + '_error'] + '。';
					msg = msg.replace('{form}', define.name);
					if (!has_err) {
						var tmp_el = this.parentNode.firstChild;
						// 最後のエラー文まで移動
						while (tmp_el.tagName == 'EM') {
							tmp_el = tmp_el.nextSibling;
						}
						err_el = document.createElement('em');
						err_el.id = el.id + '_error';
						this.parentNode.insertBefore(err_el, tmp_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);});
			});
		} 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() {
		if (this.required) {
			return $F(this.el) != '';
		} else if ($F(this.el) == '') {
			return null;
		}
		return true;
	};
	this.min = 0;
	this.min_error = '';
	this.min_check = function() {
		if (this.min_error == '') {
			this.min_error = '{form}は' + this.min + '文字以上にして下さい';
		}
		return $F(this.el).length >= this.min;
	};
	this.max = 2000;
	this.max_error = '';
	this.max_check = function() {
		if (this.max_error == '') {
			this.max_error = '{form}は' + this.max + '文字以内にして下さい';
		}
		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):\/\/.+/,
		alphabet: /^[a-z]+$/i,
		number: /^\d+$/,
		alphanum: /^[a-z\d]+$/i,
		integer: /^[1-9]\d*$/,
		zipcode: /^\d{3}-\d{4}$/,
		zipcode_d: /^\d{7}$/,
		phone: /^0[1-9]\d{0,3}-\d{1,4}-\d{4}$/,
		phone_d: /^0[1-9]\d{8}$/,
		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() {
		if (this.regexp in this.regexp_list) {
			return this.regexp_list[this.regexp].test($F(this.el));
		}
		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() {
		if (this.required) {
			var checked = false;
			this.el.inner_nodes.each(function(node) {
				if (node.checked) {
					checked = true;
					return;
				}
			});
			return checked;
		}
		return true;
	};
	this.min_check = function() {
		if (this.min_error == '') {
			this.min_error = '{form}は' + this.min + '文字以上にして下さい';
		}
		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() {
		if (this.max_error == '') {
			this.max_error = '{form}は' + this.max + '文字以下にして下さい';
		}
		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() {
		if (this.required) {
			var checked = false;
			this.el.inner_nodes.each(function(node) {
				if (node.checked) {
					checked = true;
					return;
				}
			});
			return checked;
		}
		return true;
	};
	this.min_check = function() {
		if (this.min_error == '') {
			this.min_error = '{form}は' + this.min + '箇所以上選択して下さい';
		}
		var checks = 0;
		this.el.inner_nodes.each(function(node) {
			if (node.checked) ++checks;
		});
		return checks >= this.min;
	};
	this.max_check = function() {
		if (this.max_error == '') {
			this.max_error = '{form}は' + this.max + '箇所以下選択して下さい';
		}
		var checks = 0;
		this.el.inner_nodes.each(function(node) {
			if (node.checked) ++checks;
		});
		return checks <= this.max;
	};
}
function F_Define()
{
	this.required_error = '{form}を選択して下さい';
}
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();
