//----------------------------------------------------------------------------------
// File: validationaide.js
//
// Copyright (c) 2007 Ste Brennan (dnaide.com)
// Licensed under the COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
// http://www.opensource.org/licenses/cddl1.php
//
//----------------------------------------------------------------------------------
//
//================ 変更履歴 ================
// 2007/08/25	validationaide_bi.js
//				エラーメッセージ位置、タグを一部修正
//				日付チェックにyyyy/mm/dd形式を追加
//				scrollto()を追加
//
//================ サンプル ================
//		<script type="text/javascript" src="../includes/jquery-1.1.4.pack.js"></script>
//		<script type="text/javascript" src="../includes//iutil.js"></script>
//		<script type="text/javascript" src="../includes//ifx.js"></script>
//		<script type="text/javascript" src="../includes//ifxscrollto.js"></script>
//		<script type="text/javascript" src="../includes//stringaide.js"></script>
//		<script type="text/javascript" src="../includes//validationaide.js"></script>
//		<script type="text/javascript">
//			$(document).ready(function() {
//				$("#inquiry_form").validationAideEnable(
//					null,
//					{showInlineMessages:true, showSummary:false}
//					,null, postCheck
//				);
//			});
//
//			function postCheck(fieldValue, fieldObj, success){
//				/* postCheckを使うと自前の細かいチェックが出来る */
//				if (fieldObj.id=="age"){
//					success = ($("#age").val()>18);
//				}
//
//				return success;
//			}
//		</script>
//		<style>
//			div.validation-inline-error-message{ display: block; float: left; padding: 5px; color: #C81212; }
//			input.validation-failed{ background-color: #ffc0cb; }
//		</style>
//		<form id=inquiry_form action=xxxx.html method=post>
//			<table>
//				<tr>
//					<td>名前</td>
//					<td><input type=text name=name id=name class="textbox validator-required" title="名前 - 名前を入力してください"></td>
//				</tr>
//				<tr>
//					<td>メール</td>
//					<td><input type=text name=email id=email class="textbox validator-required validator-email" title="メール - PCのメールアドレスを入力してください"></td>
//				</tr>
//				<tr>
//					<td>年齢</td>
//					<td><input type=text name=age id=age class="textbox validator-required" title="年齢 - 貴方の年齢を入力してください"></td>
//				</tr>
//				<tr>
//					<td>性別</td>
//					<td>
//						<input type=radio name=sex id=sex1 value="M" class="radio validator-required" title="性別 - 男女どちらか指定してください">男
//						<input type=radio name=sex id=sex2 value="F">女
//						<span id="ValidationInlineErrorMessage-sex1"></span>
//					</td>
//				</tr>
//			</table>
//			<input type=submit value=submit>
//		</form>
//
//
//================ 評価ルール ================
//
//Default Validation Rules
//
//    * validator-required
//    * validator-email
//    * validator-number
//    * validator-digits
//    * validator-alphanum
//    * validator-date-ddmmyyyy
//    * validator-date-mmddyyyy
//    * validator-url
//    * validator-postal
//
//Configuration Options
//
//================ メッセージオプション ================
//
//When initializing the validator, you can pass the following options:
//
//    * showInlineMessages - default false
//    * inlineShowSpeed - default "" (fastest)
//    * inlineMessageElementIdPrefix - default "ValidationInlineErrorMessage-"
//    * inlineMessageCssClass - default "validation-inline-error-message"
//    * showSummary - default true
//    * summaryElementId - default "ClientValidationSummary"
//    * summaryMessage - default "Please correct the following:"
//    * summaryFieldMessageFormat - default "##FIELD## - ##MESSAGE##"
//    * fieldErrorCssClass - default "validation-failed"
//
//
// Validator Rule classes
//
function ValidatorRule (name, errorMessage, validationMethod){
	this.validationMethod = validationMethod;
	this.errorMessage = errorMessage ? errorMessage : 'Validation failed.';
	this.name = name;
};
ValidatorRule.prototype = {
	doValidation : function(fieldValue, fieldObj) {
		return this.validationMethod(fieldValue, fieldObj);
	}
};

//
// Validator Rule Collection class
//
function ValidatorRuleCollection(){
	this.items = {};
};
ValidatorRuleCollection.prototype = {
	add : function(name, errorMessage, testFunction) {
		this.items[name] = new ValidatorRule(name, errorMessage, testFunction);
	}
};

//
// Static methods
//
jQuery.validationAide = {
	getDefaultValidationRules : function(){

		var rules = new ValidatorRuleCollection();

		rules.add('validator-required', 'Value required', function(fieldValue, fieldObj) {
			if (fieldValue == "")	return false;
			return true;
		});

		rules.add('validator-email', 'Invalid email address', function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			return /\w{1,}[@][\w\-]{1,}([.]([\w\-]{1,})){1,3}$/.test(fieldValue);
		});

		rules.add('validator-number', 'Invalid number', function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			return (!isNaN(fieldValue) && !/^\s+$/.test(fieldValue));
		});

		rules.add('validator-digits', 'Only digits allowed', function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			return !/[^\d]/.test(fieldValue);
		});

		rules.add('validator-alphanum', 'Only letters (a-z) or numbers (0-9) allowed', function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			return !/\W/.test(fieldValue);
		});

		rules.add('validator-date-ddmmyyyy', 'Invalid date, must be dd/mm/yyyy', function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			var regex = /^(\d{2})\/(\d{2})\/(\d{4})$/;			return !/^[0-9]{3}\-[0-9]{4}$/.test(fieldValue);

			if(!regex.test(fieldValue)) return false;
			var d = new Date(v.replace(regex, '$2/$1/$3'));
			return ( parseInt(RegExp.$2, 10) == (1+d.getMonth()) ) &&
							(parseInt(RegExp.$1, 10) == d.getDate()) &&
							(parseInt(RegExp.$3, 10) == d.getFullYear() );
		});

		rules.add('validator-date-mmddyyyy', 'Invalid date, must be mm/dd/yyyy', function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			var regex = /^(\d{2})\/(\d{2})\/(\d{4})$/;
			if(!regex.test(fieldValue)) return false;
			var d = new Date(fieldValue.replace(regex, '$2/$1/$3'));
			return ( parseInt(RegExp.$1, 10) == (1+d.getMonth()) ) &&
							(parseInt(RegExp.$2, 10) == d.getDate()) &&
							(parseInt(RegExp.$3, 10) == d.getFullYear() );
		});

		/* kasuga add start */
		rules.add('validator-date-yyyymmdd', 'Invalid date, must be yyyy/mm/dd', function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;			return !/^[0-9]{3}\-[0-9]{4}$/.test(fieldValue);

			var regex = /^(\d{4})\/(\d{2})\/(\d{2})$/;
			if(!regex.test(fieldValue)) return false;
			var d = new Date(v.replace(regex, '$2/$3/$1'));
			return ( parseInt(RegExp.$2, 10) == (1+d.getMonth()) ) &&
							(parseInt(RegExp.$3, 10) == d.getDate()) &&
							(parseInt(RegExp.$1, 10) == d.getFullYear() );
		});
		rules.add('validator-postal', 'Invalid format, must be 999-9999 Postal code', function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			return /^\d{3}-\d{4}$/.test(fieldValue);
		});
		/* kasuga add end */

		rules.add('validator-url', 'Invalid URL.', function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			return /^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i.test(fieldValue);
		});

		return rules;
	},


	extendOptions : function(options){

		var retval = jQuery.extend({}, options || {});

		if (typeof retval.showInlineMessages == 'undefined')
			retval.showInlineMessages = false;

		if (typeof retval.inlineShowSpeed == 'undefined')
			retval.inlineShowSpeed= "";

		if (typeof retval.inlineMessageElementIdPrefix == 'undefined')
			retval.inlineMessageElementIdPrefix= "ValidationInlineErrorMessage-";

		if (typeof retval.inlineMessageCssClass == 'undefined')
			retval.inlineMessageCssClass= "validation-inline-error-message";

		if (typeof retval.showSummary == 'undefined')
			retval.showSummary = true;

		if (typeof retval.summaryElementId == 'undefined')
			retval.summaryElementId = "ClientValidationSummary";

		if (typeof retval.summaryMessage == 'undefined')
			retval.summaryMessage = "Please correct the following:";

		if (typeof retval.summaryFieldMessageFormat == 'undefined')
			retval.summaryFieldMessageFormat = "##FIELD## - ##MESSAGE##";

		if (typeof retval.fieldErrorCssClass == 'undefined')
			retval.fieldErrorCssClass = "validation-failed";

		if (typeof retval.fieldMessageSeparator == 'undefined')
			retval.fieldMessageSeparator = ' - ';

		return retval;
	},


	resetForm : function (formId, options){

		if (typeof jQuery.fn.fieldStringVal != "function"){
			alert("Warning, validation will not work unless stringaide is loaded!");
		}

		var fullOptions = jQuery.validationAide.extendOptions(options);

		if (fullOptions.showSummary){
			// Hide summary container
			jQuery("#" + fullOptions.summaryElementId).html("").hide();
		}

		// Loop through each input and remove any previous inline error message / classes
		jQuery(formId + " :input").each( function(){
			var inlineMessageElementId = "#" + fullOptions.inlineMessageElementIdPrefix + this.id;

			/* kasuga modify start */
			//jQuery(inlineMessageElementId).remove();
			jQuery(inlineMessageElementId).hide();
			/* kasuga modify start */
			jQuery(this).removeClass(fullOptions.fieldErrorCssClass);
		});
	},


	validateForm : function(formId, validationRules, options, preFieldValidation, postFieldValidation){
		jQuery.validationAide.resetForm(formId, options);

		var fullOptions = jQuery.validationAide.extendOptions(options);

		var validatedOK = true;

		validationRules = validationRules ? validationRules : jQuery.validationAide.getDefaultValidationRules();

	  var scrollTo = "";
	  var focusField = "";
	  var firstErroredField = true;

	  if (fullOptions.showSummary){
			var messagesForSummary = new Array();
			var fieldsForSummary = new Array();
	  }

		// Loop through each input and validate
		jQuery(formId + " :input").each( function(){

			var elmId = this.id;

			if (elmId != ""){
				var jQueryElm = jQuery(this);
				var cssClassesStr = new String(jQueryElm.attr("class"));
				cssClassesStr = jQuery.trim(cssClassesStr);
				if (cssClassesStr.length > 0){
					var cssClasses = cssClassesStr.split(" ");

					for (var i=0; i<cssClasses.length; i++){

						var validationRule = validationRules.items[cssClasses[i]];

						if (validationRule){

							// Get value of the field as a string
							var fieldValue = jQueryElm.fieldStringVal();

							// Fire off preFieldValidation event
							if (typeof preFieldValidation == 'function') preFieldValidation(fieldValue, this);

							var retval = validationRule.doValidation(fieldValue, this);

							// Fire off postFieldValidation event
							if (typeof postFieldValidation == 'function')
								/* kasuga modify start */
								// postFieldValidation(fieldValue, this, retval);
								retval = postFieldValidation(fieldValue, this, retval);
								/* kasuga modify end */

							if (!retval){

								validatedOK = false;

								// Set focus and scroll to the first errored element
								if (firstErroredField){
									scrollTo = elmId;
									focusField = elmId;
									firstErroredField = false;
								}

								// Set the error css class
								jQueryElm.addClass(fullOptions.fieldErrorCssClass);

								var title = jQueryElm.attr("title");
								if (!title || title == 'undefined')
								{
									if (!title || title == 'undefined')
										title = elmId;
								}
								var fieldFriendlyName = title;
								var fieldMessage = validationRule.errorMessage;

								if (fieldFriendlyName.indexOf(fullOptions.fieldMessageSeparator) > -1){
									var messageArr = fieldFriendlyName.split(fullOptions.fieldMessageSeparator);
									fieldFriendlyName = messageArr[0];
									fieldMessage = messageArr[1];
								}

								if (fullOptions.showSummary){
									// Add the message to the summary array
									fieldsForSummary.push(elmId);
									var messageForSummary = new String(fullOptions.summaryFieldMessageFormat);
									messageForSummary = messageForSummary.replace("##FIELD##", fieldFriendlyName);
									messageForSummary = messageForSummary.replace("##MESSAGE##", fieldMessage);
									messagesForSummary.push(messageForSummary);
								}

								if (fullOptions.showInlineMessages){
									var inlineMessageElementId = fullOptions.inlineMessageElementIdPrefix + elmId;
									// Insert the inline error message

									/* kasuga modify start */
									if (jQuery("#"+inlineMessageElementId).size()>0){
										jQuery("#"+inlineMessageElementId).removeClass();
										jQuery("#"+inlineMessageElementId).addClass(fullOptions.inlineMessageCssClass);
										jQuery("#"+inlineMessageElementId).text(fieldMessage);
									} else {
										jQueryElm.after('<div id="' + inlineMessageElementId + '" class="' + fullOptions.inlineMessageCssClass + '">' + fieldMessage + '</div>');
									}

									if (fullOptions.inlineShowSpeed != ""){
										jQuery("#" + inlineMessageElementId).hide();
										jQuery("#" + inlineMessageElementId).show(fullOptions.inlineShowSpeed);
									} else {
										jQuery("#" + inlineMessageElementId).show();
									}
								}

								break;
							}
						}
					}
				}
			}

		});

		if (!validatedOK && fullOptions.showSummary){
			// Show the message summary
			var summaryHtml = "";
			if (fullOptions.summaryMessage != ""){
				summaryHtml = fullOptions.summaryMessage;
			}

			summaryHtml += "<ul>";
			for(var i=0;i<messagesForSummary.length; i++){
				summaryHtml += "<li><a href=\"#\" onclick=\"location.hash = '#" + fieldsForSummary[i] + "'; jQuery('#" + fieldsForSummary[i] + "')[0].focus(); return false;\">" + messagesForSummary[i] + "</a></li>";
			}
			summaryHtml += "</ul>";

			jQuery("#" + fullOptions.summaryElementId).html(summaryHtml).show();

			scrollTo = fullOptions.summaryElementId;
		}

		if (scrollTo != ""){
			/* kasuga modify start */
			// location.hash = "#" + scrollTo;
			$('#'+scrollTo).ScrollTo('fast');
			/* kasuga modify end */
		}

		if (focusField != ""){
			jQuery("#" + focusField)[0].focus();
		}

		return validatedOK;
	}
};


//
// jQuery object method extensions
//
jQuery.fn.validationAideEnable = function(validationRules, options, preFieldValidation, postFieldValidation){
	jQuery.validationAide.resetForm("#" + this[0].id, options);
	this.unbind("submit");
	this.bind("submit", function(){ return jQuery.validationAide.validateForm("#" + this.id, validationRules, options, preFieldValidation, postFieldValidation); });
	return this;
};

jQuery.fn.validationAideDisable = function(){
	this.unbind("submit");
	return this;
};

jQuery.fn.validationAideDisableOnClick = function(formId){
	this.unbind("click");
	this.bind("click", function(){ jQuery(formId).unbind("submit"); });
	return this;
};

jQuery.fn.validationAideEnableOnClick = function(formId, validationRules, options, preFieldValidation, postFieldValidation){
	jQuery.validationAide.resetForm(formId, options);
	this.unbind("click");
	this.bind("click", function(){ jQuery(formId).validationAideEnable(validationRules, options, preFieldValidation, postFieldValidation); });
	return this;
};

