/**
* project: lib.validate.js ver 0.1.1
* description: Æû Ã¼Å©, °ª Ç¥ÁØÈ­
* author: jstoy project
* date: 2004-03-10
*
* 2004-03-10 ver 0.0.1
* 2004-04-21 ver 0.1.0 - lainTT (¿¡·¯¸ðµå¿¡ µû¸¥ ºÎÇÏÃÖ¼ÒÈ­, trim Àç±¸¼º)
* 2004-04-23 ver 0.1.1 - lainTT (Ã¼Å©¹Ú½º Ä«¿îÆ® Ã¼Å©[mincheck, maxcheck] Ãß°¡)
* 2004-05-19           - ÇÏ´Ã¾ÆºÎÁö (»ç¿ëÀÚ Ã¼Å©ÇÔ¼ö¸¦ »ç¿ëÇÒ ¼ö ÀÖµµ·Ï ¼öÁ¤, ³»ºÎ Ã¼Å©ÇÔ¼ö¸í ±ÔÄ¢ Àû¿ë func_¿É¼Ç¸í)
* 2004-08-18           - ÇÏ´Ã¾ÆºÎÁö (Ã¼Å©¹Ú½º°¡ ÇÑ °³ÀÏ ¶§ÀÇ ¿À·ù ¼öÁ¤)
* 2004-08-27           - ÇÏ´Ã¾ÆºÎÁö (pattern ÁöÁ¤½Ã ¿À·ù ¼öÁ¤)
* 2004-09-03           - ÇÏ´Ã¾ÆºÎÁö (textarea¸¦ text¿Í ºÐ¸®)
*/

/**
* <pre>
* form check trigger function
* </pre>
*
* @param form Object
* @return boolean
*/
function validate(form) {
	var checker = new FormChecker(form);
	try {
		var result = checker.go();
	} catch (e) {
		alert(e);
		return false;
	}
	checker.destroy();
	return result;
}

FormChecker = function(form) {
	/**
	* <pre>
	* pre-set error messages
	* </pre>
	*/
	this.ERRMSG = {
		common   : "ÀÔ·ÂÇÏ½Å ³»¿ëÀÌ ±ÔÄ¢¿¡ ¾î±ß³³´Ï´Ù.\n±ÔÄ¢¿¡ ¾î±ß³ª´Â ³»¿ëÀ» ¹Ù·ÎÀâ¾ÆÁÖ¼¼¿ä.",

		required : "¹Ýµå½Ã ÀÔ·ÂÇÏ¼Å¾ß ÇÏ´Â »çÇ×ÀÔ´Ï´Ù.",
		required_group : "ÀÌ Ç×¸ñµé Áß¿¡ {requirenum}°³ ÀÌ»óÀÇ Ç×¸ñÀÌ ÀÔ·ÂµÇ¾î¾ß ÇÕ´Ï´Ù.",
		notequal : "ÀÔ·ÂµÈ ³»¿ëÀÌ ÀÏÄ¡ÇÏÁö ¾Ê½À´Ï´Ù.",
		invalid  : "ÀÔ·ÂµÈ ³»¿ëÀÌ Çü½Ä¿¡ ¾î±ß³³´Ï´Ù.",
		minbyte  : "ÀÔ·ÂµÈ ³»¿ëÀÇ ±æÀÌ°¡ {minbyte}Byte ÀÌ»óÀÌ¾î¾ß ÇÕ´Ï´Ù.",
		maxbyte  : "ÀÔ·ÂµÈ ³»¿ëÀÇ ±æÀÌ°¡ {maxbyte}Byte¸¦ ÃÊ°úÇÒ ¼ö ¾ø½À´Ï´Ù.",
		mincheck : "{mincheck}°³ÀÇ Ç×¸ñÀÌ»óÀ¸·Î ¼±ÅÃÇÏ¼¼¿ä.",
		maxcheck : "{maxcheck}°³ÀÇ Ç×¸ñÀÌÇÏ·Î ¼±ÅÃÇÏ¼¼¿ä."
	}

	/**
	* <pre>
	* form check function mapping
	* allocate function name as string
	* </pre>
	*/
	this.VALIDATE_FUNCTION = {
		trim    : "this.func_trim",
		email   : "this.func_email",
		userid  : "this.func_userid",
		hangul  : "this.func_hangul",
		engonly : "this.func_engonly",
		number  : "this.func_number",
		jumin   : "this.func_jumin",
		bizno   : "this.func_bizno",
		phone   : "this.func_phone",
		mobile  : "this.func_mobile"
	}

	/**
	* <pre>
	* default option
	* </pre>
	*/
	this.DEFAULT_OPTION = {
		text   : "trim",
		hidden : "trim"
	}

	/**
	* <pre>
	* default errordo
	* </pre>
	*/
	this.DEFAULT_ERRORDO = {
		text   : "focus",
		select : "focus",
		check  : "focus",
		radio  : "focus",
		file   : "focus",
		textarea : "focus",
		hidden : ""
	}

	this.form = form;
	this.errObj = null;
	this.curObj = null;
	this.errMsg = this.ERRMSG["common"] != "" ? this.ERRMSG["common"]+"\n\n" : "";
	this.errMode = 2; // all:1, one:2, one per object:3
}

FormChecker.prototype.go = function() {
	var oldRequired = new Array;
	for (var i=0; i<this.form.elements.length; i++) {
		var el = this.form.elements[i];
		if (!this.isValidElement(el)) continue;

		var elType = this.getType(el);
		var required   = el.getAttribute("REQUIRED");
		var requirenum = el.getAttribute("REQUIRENUM");

		if (required !== null) {
			if (required == "") {
				if (this.isEmpty(el, elType))
					if (!this.raiseError(el,"required")) return false;
			} else {
				var flOldRequired = false;
				for (var j=0; j<oldRequired.length; j++)
					if (oldRequired[j] == required) flOldRequired = true;

				if (!flOldRequired) {
					oldRequired[oldRequired.length] = required;
					var reqNum = 0;
					var reqHname = new Array;
					for (var j=0; j<this.form.elements.length; j++) {
						var reqEl = this.form.elements[j];
						var reqElType = this.getType(reqEl);
						if (!this.isValidElement(reqEl)) continue;
						if (reqEl.getAttribute("REQUIRED") == required) {
							if (!this.isEmpty(reqEl, reqElType)) reqNum++;
							reqHname[reqHname.length] = this.getName(reqEl);
						}
					}
					if (reqNum < requirenum)
						if (!this.raiseError(el,"required_group",reqHname.join(", "))) return false;
				}
			}
		}
		if (elType == "text" || elType == "hidden" || elType == "textarea") {
			var minbyte = el.getAttribute("MINBYTE");
			var maxbyte = el.getAttribute("MAXBYTE");
			var option  = el.getAttribute("OPTION") ? el.getAttribute("OPTION") : (this.DEFAULT_OPTION[elType] ? this.DEFAULT_OPTION[elType] : null);
			var match   = el.getAttribute("MATCH");
			var span    = el.getAttribute("SPAN");
			var glue    = el.getAttribute("GLUE");
			var pattern = eval(el.getAttribute("PATTERN"));

			if (minbyte != null) {
				minbyte = parseInt(minbyte,10);
				var _tmp = el.value;
				var elLen = 0;
				for (j=0; j<_tmp.length; j++) {
					var chr = _tmp.charAt(j);
					elLen += (chr.charCodeAt() > 128) ? 2 : 1;
					if (elLen < minbyte)
						if (!this.raiseError(el,"minbyte")) return false;
				}
			}
			if (maxbyte != null) {
				maxbyte = parseInt(maxbyte,10);
				var _tmp = el.value;
				var elLen = 0;
				for (j=0; j<_tmp.length; j++) {
					var chr = _tmp.charAt(j);
					elLen += (chr.charCodeAt() > 128) ? 2 : 1;
					if (elLen > maxbyte)
						if (!this.raiseError(el,"maxbyte")) return false;
				}
			}
			if (match != null) {
				if (typeof this.form.elements[match] == "undefined")
					throw "Element '"+ match +"' is not found.";
				else if (el.value != this.form.elements[match].value)
					if (!this.raiseError(el,"notequal")) return false;
			}

			if (el.value != "" && option !== null) {
				var elOption = option.split(" ");
				for (var j in elOption) {
					var _option = elOption[j];

					if (eval("typeof func_"+_option) == "function") {
						this.VALIDATE_FUNCTION[_option] = "func_"+_option;
					} else if (typeof eval(this.VALIDATE_FUNCTION[_option]) == "undefined") {
						throw "Function map '"+ _option +"' is not found.";
					}

					if (span !== null) {
						var _value = new Array();
						for (var j = 0; j < span; j++) {
							if (typeof this.form.elements[i+j] == "undefined")
								throw (i+j) +"th Element is not found.";
							_value[j] = this.form.elements[i+j].value;
						}
						var value = _value.join(glue === null ? "" : glue);
						var tmpMsg = eval(this.VALIDATE_FUNCTION[_option])(el, value);
						if (tmpMsg !== true)
							if (!this.raiseError(el,tmpMsg)) return false;
					} else {
						var tmpMsg = eval(this.VALIDATE_FUNCTION[_option])(el);
						if (tmpMsg !== true)
							if (!this.raiseError(el,tmpMsg)) return false;
					}
				}
			}
			if (el.value != "" && pattern !== null) {
				try {
					pattern = new RegExp(pattern);
				} catch (e) {
					throw "Invalid Regular Expression '"+ pattern +"'";
				}
				if (!pattern.test(el.value)) {
					if (!this.raiseError(el,"invalid")) return false;
				}
			}
		} else if (elType == "check") {
			var mincheck = parseInt(el.getAttribute("MINCHECK"),10);
			var maxcheck = parseInt(el.getAttribute("MAXCHECK"),10);
			if (mincheck > 0 || maxcheck > 0) {
				var elCheck  = this.form.elements[el.name];
				var elCheckNum = 0;
				if (elCheck.length) {
					for (var j=0; j<elCheck.length; j++) {
						if (elCheck[j].checked == true) elCheckNum++;
					}
				} else {
					if (elCheck.checked == true) elCheckNum++;
				}
				if (mincheck > 0 && elCheckNum < mincheck) {
					if (!this.raiseError(el,"mincheck")) return false;
				}
				if (maxcheck > 0 && elCheckNum > maxcheck) {
					if (!this.raiseError(el,"maxcheck")) return false;
				}
			}
		}
	}
	return !this.isErr;
}

FormChecker.prototype.destroy = function() {
	if (this.isErr == true) {
		alert(this.errMsg);
		var _tmp = this.errObj.getAttribute("errordo");
		if (!_tmp) _tmp = this.DEFAULT_ERRORDO[this.getType(this.errObj)];
		var onError = _tmp ? _tmp.split(" ") : [];
		for (var i in onError) {
			switch (onError[i]) {
			case "delete": this.errObj.value = ""; break;
			case "select": this.errObj.select(); break;
			case "focus":  this.errObj.focus(); break;
			}
		}
	}
	this.errMsg = "";
	this.errObj = null;
	this.curObj = null;
}

FormChecker.prototype.raiseError = function(el, type, elName) {
	var pattern = /\{([a-zA-Z0-9_]+)\}/i;
	var msg = this.ERRMSG[type] ? this.ERRMSG[type] : type;
	var elName = elName ? elName : this.getName(el);

	if (el.getAttribute("errmsg") != null) msg = el.getAttribute("errmsg");
	if (pattern.test(msg) == true) {
		while (pattern.exec(msg)) msg = msg.replace(pattern, el.getAttribute(RegExp.$1));
	}
	if (!this.errObj || this.errMode != 2) {
		if (this.curObj == el && el.getAttribute("errmsg") == null) {
			if (this.errMode == 1)
				this.errMsg += "   - "+ msg +"\n";
		} else if (this.curObj != el) {
			if (this.curObj)
				this.errMsg += "\n";
			this.errMsg += "["+ elName +"]\n   - "+ msg +"\n";
		}
	}
	if (!this.errObj) this.errObj = el;
	this.curObj = el;
	this.isErr  = true;
	return this.errMode == 2 ? false : true;
}

FormChecker.prototype.isValidElement = function(el) {
	return (el.name && el.tagName.match(/^input|select|textarea$/i)) ? true : false;
//	return (el.tagName.toLowerCase() == "fieldset" || el.tagName.toLowerCase() == "object" || el.name == null || el.name == "") ? false : true;
}

FormChecker.prototype.isEmpty = function(el, type) {
	switch (type) {
	case "file": case "text": case "hidden": case "textarea" :
		if (el.value == null || el.value == "") return true;
		break;
	case "select":
		if (el[el.selectedIndex].value == null || el[el.selectedIndex].value == "") return true;
		break;
	case "check": case "radio":
		var elCheck = this.form.elements[el.name];
		var elChecked = false;
		if (elCheck.length) {
			for (var j=0; j<elCheck.length; j++) {
				if (elCheck[j].checked == true) elChecked = true;
			}
		} else {
			if (elCheck.checked == true) elChecked = true;
		}
		if (elChecked == false) return true;
		break;
	}
	return false;
}

FormChecker.prototype.getType = function(el) {
	switch (el.tagName.toLowerCase()) {
	case "select": return "select";
	case "textarea": return "textarea";
	case "input":
		switch (el.type.toLowerCase()) {
		case "radio": return "radio";
		case "checkbox": return "check";
		case "file": return "file";
		case "text": case "password": return "text";
		case "hidden": return "hidden";
		}
		break;
	}
}

FormChecker.prototype.getName = function(el) {
	return (el.getAttribute("HNAME") == null || el.getAttribute("HNAME") == "")
		? el.name : el.getAttribute("HNAME");
}

/**
* validate functions
*/
FormChecker.prototype.func_trim = function(el) {
	el.value = el.value.replace(/^\s+/, "").replace(/\s+$/, "");
	return true;
}

FormChecker.prototype.func_email = function(el, value) {
   var value = value ? value : el.value;
   var pattern = /^[_a-zA-Z0-9-\.]+@[\.a-zA-Z0-9-]+\.[a-zA-Z]+$/;
   return (pattern.test(value)) ? true : "invalid";
}

FormChecker.prototype.func_userid = function(el) {
   var pattern = /^[a-zA-Z]{1}[a-zA-Z0-9_]{4,11}$/;
   return (pattern.test(el.value)) ? true : "5ÀÚÀÌ»ó 12ÀÚ ¹Ì¸¸,\n ¿µ¹®,¼ýÀÚ, _ ¹®ÀÚ¸¸ »ç¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù";
}

FormChecker.prototype.func_hangul = function(el) {
   var pattern = /[°¡-ÆR]/;
   return (pattern.test(el.value)) ? true : "¹Ýµå½Ã ÇÑ±ÛÀ» Æ÷ÇÔÇØ¾ß ÇÕ´Ï´Ù";
}

FormChecker.prototype.func_engonly = function(el) {
   var pattern = /^[a-zA-Z]+$/;
   return (pattern.test(el.value)) ? true : "invalid";
}

FormChecker.prototype.func_number = function(el) {
   var pattern = /^[0-9]+$/;
   return (pattern.test(el.value)) ? true : "¹Ýµå½Ã ¼ýÀÚ·Î¸¸ ÀÔ·ÂÇØ¾ß ÇÕ´Ï´Ù";
}

FormChecker.prototype.func_jumin = function(el, value) {
	var pattern = /^([0-9]{6})-?([0-9]{7})$/;
	var num = value ? value : el.value;
	if (!pattern.test(num)) return "invalid";
	num = RegExp.$1 + RegExp.$2;

	var sum = 0;
	var last = num.charCodeAt(12) - 0x30;
	var bases = "234567892345";
	for (var i=0; i<12; i++) {
		if (isNaN(num.substring(i,i+1))) return "invalid";
		sum += (num.charCodeAt(i) - 0x30) * (bases.charCodeAt(i) - 0x30);
	}
	var mod = sum % 11;
	return ((11 - mod) % 10 == last) ? true : "invalid";
}

FormChecker.prototype.func_bizno = function(el, value) {
	var pattern = /([0-9]{3})-?([0-9]{2})-?([0-9]{5})/;
	var num = value ? value : el.value;
	if (!pattern.test(num)) return "invalid";
	num = RegExp.$1 + RegExp.$2 + RegExp.$3;
	var cVal = 0;
	for (var i=0; i<8; i++) {
		var cKeyNum = parseInt(((_tmp = i % 3) == 0) ? 1 : ( _tmp  == 1 ) ? 3 : 7);
		cVal += (parseFloat(num.substring(i,i+1)) * cKeyNum) % 10;
	}
	var li_temp = parseFloat(num.substring(i,i+1)) * 5 + "0";
	cVal += parseFloat(li_temp.substring(0,1)) + parseFloat(li_temp.substring(1,2));
	return (parseInt(num.substring(9,10)) == 10-(cVal % 10)%10) ? true : "invalid";
}

FormChecker.prototype.func_phone = function(el,value) {
    var pattern = /^([0]{1}[0-9]{1,2})-?([1-9]{1}[0-9]{2,3})-?([0-9]{4})$/;
    var num = value ? value : el.value;
    if (pattern.exec(num)) {
        return true;
    } else {
        return "invalid";
    }
}

FormChecker.prototype.func_mobile = function(el, value) {
	var pattern = /^(01[016-9]{1})-?([1-9]{1}[0-9]{2,3})-?([0-9]{4})$/;
	var num = value ? value : el.value;
	if (pattern.exec(num)) {
		return true;
	} else {
		return "invalid";
	}
}