YAHOO.namespace('yao.cultural.common');

/**
 * バリデーションクラスの基底クラス
 * オプションは、json表記で指定する。
 * [
 * id: ターゲットID,
 * message: (option)バリデーション失敗時に表示するメッセージ,
 * valid: (option)バリデーション成功時に実行する関数を指定,
 * valid_arg: (option)バリデーション成功時に実行する関数に渡す値を指定,
 * invalid: (option)バリデーション失敗時に実行する関数を指定,
 * invalid_arg: (option)バリデーション失敗時に実行する関数に渡す値を指定,
 * is_exec: (option)バリデーション実行判定を行う関数を指定(true:実行する, false:実行しない)
 * ]
 *
 * 現在のバリデーションステータスは、valueプロパティにアクセスすることで取得可能。
 * バリデーション失敗時のメッセージは、「ターゲットID + "_msg"」というIDに表示される。
 */
YAHOO.yao.cultural.common.Validator = Class.create({
	id: "",
	msg_id: "",
	message: "",
	valid: function () {},
	valid_arg: null,
	invalid: function () {},
	invalid_arg: null,
	is_exec: function () {
		return true;
	},
	value: false,
	initialize: function (param) {
		this.id = param.id;
		this.msg_id = this.id + "_msg";
		if (param.message) {
			this.message = param.message;
		}
		this.message = param.message;
		if (param.valid) {
			this.valid = param.valid;
			if (param.valid_arg) {
				this.valid_arg = param.valid_arg;
			}
		}
		if (param.invalid) {
			this.invalid = param.invalid;
			if (param.invalid_arg) {
				this.invalid_arg = param.invalid_arg;
			}
		}
		if (param.is_exec) {
			this.is_exec = param.is_exec;
		}
	},
	validate: function () {
		if (this.is_exec() == true) {
			this.value = this.do_validate();
			if (this.value == true) {
				this.valid(this.valid_arg);
				Element.update(this.msg_id, "");
			} else {
				this.invalid(this.invalid_arg);
				if (this.message) {
					Element.update(this.msg_id, this.message);
				}
			}
			return this.value;
		}
		this.value = true;
		return this.value;
	},
	validate_callback: function (obj) {
		return obj.validate();
	},
	do_validate: function () {
		return true;
	}
});

/**
 * 正規表現を使用してバリデーションを行うクラス
 * オプションは、json表記で指定する。
 * [
 * id: ターゲットID,
 * regexp: 正規表現を指定する,
 * message: (option)バリデーション失敗時に表示するメッセージ,
 * valid: (option)バリデーション成功時に実行する関数を指定,
 * valid_arg: (option)バリデーション成功時に実行する関数に渡す値を指定,
 * invalid: (option)バリデーション失敗時に実行する関数を指定,
 * invalid_arg: (option)バリデーション失敗時に実行する関数に渡す値を指定,
 * is_exec: (option)バリデーション実行判定を行う関数を指定(true:実行する, false:実行しない)
 * ]
 *
 * 現在のバリデーションステータスは、valueプロパティにアクセスすることで取得可能。
 * バリデーション失敗時のメッセージは、「ターゲットID + "_msg"」というIDに表示される。
 */
YAHOO.yao.cultural.common.RegExpValidator = Class.create(YAHOO.yao.cultural.common.Validator, {
	regexp: null,
	initialize: function ($super, param) {
		$super(param);
		if (param.regexp) {
			this.regexp = param.regexp;
		}
	},
	do_validate: function () {
		var value = $F(this.id);
		if (this.regexp) {
			if (!value.match(this.regexp)) {
				return false;
			}
		}
		return true;
	}
});

/**
 * 必須項目のバリデーションを行うクラス
 * オプションは、json表記で指定する。
 * [
 * id: ターゲットID,
 * message: (option)バリデーション失敗時に表示するメッセージ,
 * valid: (option)バリデーション成功時に実行する関数を指定,
 * valid_arg: (option)バリデーション成功時に実行する関数に渡す値を指定,
 * invalid: (option)バリデーション失敗時に実行する関数を指定,
 * invalid_arg: (option)バリデーション失敗時に実行する関数に渡す値を指定,
 * is_exec: (option)バリデーション実行判定を行う関数を指定(true:実行する, false:実行しない)
 * ]
 *
 * 現在のバリデーションステータスは、valueプロパティにアクセスすることで取得可能。
 * バリデーション失敗時のメッセージは、「ターゲットID + "_msg"」というIDに表示される。
 */
YAHOO.yao.cultural.common.RequiredValidator = Class.create(YAHOO.yao.cultural.common.Validator, {
	initialize: function ($super, param) {
		$super(param);
	},
	do_validate: function () {
		var value = $F(this.id);
		if (value.length == 0) {
			return false;
		}
		return true;
	}
});

/**
 * 値の長さのバリデーションを行うクラス
 * オプションは、json表記で指定する。
 * [
 * id: ターゲットID,
 * min: (option)最小値を指定,
 * max: (option)最大値を指定,
 * message: (option)バリデーション失敗時に表示するメッセージ,
 * valid: (option)バリデーション成功時に実行する関数を指定,
 * valid_arg: (option)バリデーション成功時に実行する関数に渡す値を指定,
 * invalid: (option)バリデーション失敗時に実行する関数を指定,
 * invalid_arg: (option)バリデーション失敗時に実行する関数に渡す値を指定,
 * is_exec: (option)バリデーション実行判定を行う関数を指定(true:実行する, false:実行しない)
 * ]
 *
 * 現在のバリデーションステータスは、valueプロパティにアクセスすることで取得可能。
 * バリデーション失敗時のメッセージは、「ターゲットID + "_msg"」というIDに表示される。
 */
YAHOO.yao.cultural.common.LengthValidator = Class.create(YAHOO.yao.cultural.common.Validator, {
	min: null,
	max: null,
	initialize: function ($super, param) {
		$super(param);
		if (param.min) {
			this.min = param.min;
		}
		if (param.max) {
			this.max = param.max;
		}
	},
	do_validate: function () {
		var value = $F(this.id);
		if (this.min && this.min > value.length) {
			return false;
		}
		if (this.max && this.max < value.length) {
			return false;
		}
		return true;
	}
});

/**
 * ユーザ指定の検査ロジックを使用してバリデーションを行うクラス
 * オプションは、json表記で指定する。
 * [
 * id: ターゲットID,
 * validate: 検査ロジック関数を指定(true:成功, false:失敗),
 * message: (option)バリデーション失敗時に表示するメッセージ,
 * valid: (option)バリデーション成功時に実行する関数を指定,
 * valid_arg: (option)バリデーション成功時に実行する関数に渡す値を指定,
 * invalid: (option)バリデーション失敗時に実行する関数を指定,
 * invalid_arg: (option)バリデーション失敗時に実行する関数に渡す値を指定,
 * is_exec: (option)バリデーション実行判定を行う関数を指定(true:実行する, false:実行しない)
 * ]
 *
 * 現在のバリデーションステータスは、valueプロパティにアクセスすることで取得可能。
 * バリデーション失敗時のメッセージは、「ターゲットID + "_msg"」というIDに表示される。
 */
YAHOO.yao.cultural.common.CustomValidator = Class.create(YAHOO.yao.cultural.common.Validator, {
	initialize: function ($super, param) {
		$super(param);
		if (param.validate) {
			this.do_validate = param.validate;
		}
	},
	do_validate: function () {
		return true;
	}
});

/**
 * フィールドのバリデーションを行うクラス
 * オプションは、json表記で指定する。
 * [
 * id: ターゲットID,
 * validators: [
 *     [
 *     type:　バリデーションタイプ(required,length,regexp,custom,class),
 *     obj: (option)クラスオブジェクトを指定(バリデーションタイプにclassを指定した場合、必須),
 *     id: (option)ターゲットID(省略時は、FieldValidatorのターゲットIDがコピーされる),
 *     message: (option)バリデーション失敗時に表示するメッセージ,
 *     valid: (option)バリデーション成功時に実行する関数を指定,
 *     valid_arg: (option)バリデーション成功時に実行する関数に渡す値を指定,
 *     invalid: (option)バリデーション失敗時に実行する関数を指定,
 *     invalid_arg: (option)バリデーション失敗時に実行する関数に渡す値を指定,
 *     is_exec: (option)バリデーション実行判定を行う関数を指定(true:実行する, false:実行しない),
 *     ]
 * ],
 * message: (option)バリデーション失敗時に表示するメッセージ,
 * valid: (option)バリデーション成功時に実行する関数を指定,
 * valid_arg: (option)バリデーション成功時に実行する関数に渡す値を指定,
 * invalid: (option)バリデーション失敗時に実行する関数を指定,
 * invalid_arg: (option)バリデーション失敗時に実行する関数に渡す値を指定,
 * is_exec: (option)バリデーション実行判定を行う関数を指定(true:実行する, false:実行しない),
 * listener: (option)イベントリスナーへの自動登録を行うかどうか指定(true:自動登録する, false:自動登録しない)
 * ]
 *
 * 現在のバリデーションステータスは、valueプロパティにアクセスすることで取得可能。
 * バリデーション失敗時のメッセージは、「ターゲットID + "_msg"」というIDに表示される。
 */
YAHOO.yao.cultural.common.FormValidator = Class.create(YAHOO.yao.cultural.common.Validator, {
	validators: null,
	initialize: function ($super, param) {
		$super(param);
		if (param.validators) {
			this.validators = [];
			for (var i = 0; i < param.validators.length; i++) {
				var validator_param = param.validators[i];
				if (!validator_param.id) {
					validator_param.id = this.id;
				}
				if (validator_param.type == "required") {
					this.validators.push(new YAHOO.yao.cultural.common.RequiredValidator(validator_param));
				} else if (validator_param.type == "length") {
					this.validators.push(new YAHOO.yao.cultural.common.LengthValidator(validator_param));
				} else if (validator_param.type == "regexp") {
					this.validators.push(new YAHOO.yao.cultural.common.RegExpValidator(validator_param));
				} else if (validator_param.type == "custom") {
					this.validators.push(new YAHOO.yao.cultural.common.CustomValidator(validator_param));
				} else if (validator_param.type == "class") {
					this.validators.push(validator_param.obj);
				}
			}
		}
		if (param.listener && param.listener != false) {
			this.addListener();
		}
	},
	do_validate: function () {
		for (var i = 0; i < this.validators.length; i++) {
			var validator = this.validators[i];
			if (validator.validate() == false) {
				return false;
			}
		}
		return true;
	},
    callback: function (e, obj) {
       	obj.validate();
    },
	addListener: function () {
        var events = ['change'];
        var type = $(this.id).type;
        if (type == 'text') {
            events.push('keyup');
            events.push('blur');
        } else if (type == 'password') {
            events.push('keyup');
            events.push('blur');
        } else if (type == 'checkbox') {
		} else if (type == 'radio') {
		} else if (type == 'select') {
		} else if (type == 'textarea') {
			events.push('keyup');
            events.push('blur');
		}

		for (var i = 0; i < events.length; i++) {
            YAHOO.util.Event.addListener(this.id, events[i], this.callback, this);
		}
    }
});

/**
 * 複数フィールドを1単位としてバリデーションを行うクラス
 * オプションは、json表記で指定する。
 * [
 * id: ターゲットID,
 * validators: [[type: classのみサポート, obj: FieldValidatorを指定(クラスオブジェクト)]],
 * message: (option)バリデーション失敗時に表示するメッセージ,
 * valid: (option)バリデーション成功時に実行する関数を指定,
 * valid_arg: (option)バリデーション成功時に実行する関数に渡す値を指定,
 * invalid: (option)バリデーション失敗時に実行する関数を指定,
 * invalid_arg: (option)バリデーション失敗時に実行する関数に渡す値を指定,
 * is_exec: (option)バリデーション実行判定を行う関数を指定(true:実行する, false:実行しない),
 * listener: (option)イベントリスナーへの自動登録を行うかどうか指定(true:自動登録する, false:自動登録しない)
 * ]
 *
 * 現在のバリデーションステータスは、valueプロパティにアクセスすることで取得可能。
 * バリデーション失敗時のメッセージは、「ターゲットID + "_msg"」というIDに表示される。
 * validatorsに指定するクラスオブジェクトは、インスタンス化時、listener: falseを指定する必要あり。
 */
YAHOO.yao.cultural.common.FormChainValidator = Class.create(YAHOO.yao.cultural.common.FormValidator, {
	validators: null,
	initialize: function ($super, param) {
		$super(param);
	},
	do_validate: function () {
		var result = true;
		for (var i = 0; i < this.validators.length; i++) {
			var validator = this.validators[i];
			result = result & validator.validate();
		}
		return result;
	},
	addListener: function () {
        var events = ['change'];
        var type = $(this.id).type;
        if (type == 'text') {
            events.push('keyup');
            events.push('blur');
        } else if (type == 'password') {
            events.push('keyup');
            events.push('blur');
        } else if (type == 'checkbox') {
		} else if (type == 'radio') {
		} else if (type == 'select') {
		} else if (type == 'textarea') {
			events.push('keyup');
            events.push('blur');
		}

		for (var i = 0; i < events.length; i++) {
			for (var j = 0; j < this.validators.length; j++) {
				YAHOO.util.Event.addListener(this.validators[j].id, events[i], this.callback, this);
			}
		}
	}
});

/**
 * バリデータを格納するコンテナクラス
 */
YAHOO.yao.cultural.common.ValidatorContainer = Class.create({
	validators: {},
	initialize: function () {},
	value: function () {
		var v = true;
		for (var i in this.validators) {
			v = v & this.validators[i].value;
		}
		return v;
	},
	validate: function () {
		var v = true;
		for (var i in this.validators) {
			v = v & this.validators[i].validate_callback(this.validators[i]);
		}
		return v;
	},
	addValidator: function (validator) {
		this.validators[validator.id] = validator;
	},
	addListener: function () {
		for (var i in this.validators) {
			this.validators[i].addListener();
		}
	},
	get : function (id) {
	  return this.validators[id];
	}
});
