// add more function to event
Event.implement({
	getCharCode: function(){
		return (typeof(this.event.charCode) != "undefined") ? this.event.charCode : this.event.keyCode;
	},
	
	getCharKey: function(){
		var code = this.getCharCode();
		return (code == 0) ? "" : String.fromCharCode(code);
	}
});

// Find all element in a form by name.
function $FS(selector, filter){
	var elArr = new Array();
	var form = filter ? $(filter) : false;
	for (var i = 0; i<document.forms.length; i++){
		if (!form || form == document.forms[i]) {
			for (var j = 0; j < document.forms[i].elements.length; j++) {
				if (selector == document.forms[i].elements[j].name) {
					elArr.push(document.forms[i].elements[j]);
				}
			}
		}
	}
	return elArr;
}

// find the first element in a form
function $F(selector, filter){
	return $FS(selector, filter)[0] || false;
}


// validate functions
function Quote(str, s1, s2){
    return str.substring(str.indexOf(s1) + s1.length, str.indexOf(s2));
}

function isBlank(str){
    return (typeof(str) == "undefined" || str == null || str.trim() == "");
}

function isEmail(str){
    var re = new RegExp("^\\w+((-\\w+)|(\\.\\w+))*\\@[A-Za-z0-9]+((\\.|-)[A-Za-z0-9]+)*\\.[A-Za-z0-9]{2,4}$");
    return (str.search(re) != -1);
}

function isEmails(str){
    var re = new RegExp("[;,]");
    var arr = str.split(re);
    for (var i = 0; i < arr.length; i++) {
        if (!isEmail(arr[i].trim())) { return false; }
    }
    return true;
};

function isImage(str){
    var re = new RegExp("\\.(png|gif|bmp|jpg|jpeg|jpe)$", "i");
    return (str.search(re) != -1);
}

function isPhone(str){
    var re = new RegExp("^[ ()-.0-9]{3,}$");
    return (str.search(re) != -1);
}

function isDate(format, str){
    var re = new RegExp("[.\/-]");
    var arr = str.split(re);	
    if (arr.length != 3) { return false; }	
    var y = parseInt(arr[format.indexOf("y")]);
    var m = parseInt(arr[format.indexOf("m")]);
    var d = parseInt(arr[format.indexOf("d")]);
    var date = new Date(y, m - 1, d);
    return (y == date.getFullYear() && m == date.getMonth() + 1 && d == date.getDate());
}

function compareDate(format, date1, date2){
    var re = new RegExp("[.\/-]");
    var a1 = date1.split(re);
    var y1 = parseInt(a1[format.indexOf("y")]);
    var m1 = parseInt(a1[format.indexOf("m")]);
    var iDate1 = parseInt(a1[format.indexOf("d")]);
    if (date2) {
        var a2 = date2.split(re);
        var y2 = parseInt(a2[format.indexOf("y")]);
        var m2 = parseInt(a2[format.indexOf("m")]);
        var iDate2 = parseInt(a2[format.indexOf("d")]);
    }
    else {
        var date2 = new Date();
        var y2 = date2.getFullYear();
        var m2 = date2.getMonth() + 1;
        var iDate2 = date2.getDate();
    }
    //
    if (y2 > y1) { return 1; }
    else if (y2 < y1) { return -1; }
    else {
        if (m2 > m1) { return 1; }
        else if (m2 < m1) { return -1; }
        else {
            if (iDate2 > iDate1) { return 1; }
            else if (iDate2 < iDate1) { return -1; }
            else { return 0; }
        }
    }
}

function isVisible(obj){
    var el = $(obj).getParent();
    while (el) {
        if (el.getStyle("display") == "none" || el.getStyle("visibility") == "hidden") { return false; }
        el = el.getParent();
    }
    return true;
}

// FORM CLASS VALIDATION
var htmlform = new Class({

	initialize: function(obj){
		var thisForm = this;
		// check & create for alert layer
		var alertLayer = new Element("div", {
			"id": obj.id+"Layer",
			"class": "alertLayer"
		}).inject(document.body);
		
		//
		var closeBtn = new Element("a", {
			"href": "javascript:;",
			"html": "x",
			"events": {
				"click": function(e){
					thisForm.hideAlertLayer();
				}
			}
		}).inject(alertLayer);
		
		var display = new Element("p").inject(alertLayer);
		
		// init form
		if (!$(obj.id)) { return false; }
		thisForm.form = $(obj.id);
		thisForm.form.layer = obj.layer;
		thisForm.form.behaviors = obj.behaviors;
		thisForm.form.errorElement = null;
		thisForm.data = obj.data;
		thisForm.alertLayer = alertLayer;
		thisForm.initForm();
	},
	
	initForm: function(){
		var thisForm = this;
	    for (var i = 0; i < thisForm.data.length; i++) {
	        // init elements
			for (var j = 0; j < thisForm.form.elements.length; j++) {
	            var el = thisForm.form.elements[j];
	            if (el.name == thisForm.data[i].field) {
	                thisForm.initElement(el, thisForm.data[i]);
	            }
	        }
	    }
	    
	    // valid form on submit
	    thisForm.form.addEvent("submit", function(e){
			if (!thisForm.isValidForm(this)) {
				new Event(e).stop();
			} else {
				// call back
				if (thisForm.form.behaviors && thisForm.form.behaviors.onSubmit) {
					thisForm.form.behaviors.onSubmit(thisForm.form, thisForm);
					new Event(e).stop();
				}
			}
	    });
	},
	
	initElement: function(obj, data){
		var thisForm = this;
	    var el = $(obj);
	    
	    // add new properties
		if (!el.$form) {
			el.$form = new Object();
		}
	    for (var i in data) {
	        el.$form[i] = data[i];
	    }
		el.validated = true;
	    
	    // init behaviors
	    if (typeof(el.$form.init) != "undefined") {
	    
	        // if the input has its initialized value
			if (el.type == "text" || el.type == "textarea" || el.type == "password") {
				el.value = el.$form.init;
				el.addEvents({
					"focus": function(){
		                if (this.value == this.$form.init) {
		                    this.value = "";
		                }
					},
					"blur": function(){
		                if (this.value.trim() == "") {
		                    this.value = this.$form.init;
		                }
		            }
				});
			}
			
			if (el.type == "radio") {
				el.checked = el.$form.init;
			}
			
			if (el.type == "select-one" || el.type == "select-multiple") {
				el.selectedIndex = Number(el.$form.init);
			}
			
			if (el.type == "radio") {
				el.selectedIndex = Number(el.$form.init);
			}
	    }
		
		// apply maxlength to textarea
		if (typeof(el.$form.maxLength) != "undefined" && (el.type == "textarea" || el.type == "text" || el.type == "password")) {
			// maximum input characters
			if (el.type == "textarea"){
				el.addEvent("keypress", function(e){
		            var evt = new Event(e);
		            var code = evt.getCharCode();
		            if (this.value.length >= this.$form.maxLength && code != 0) { evt.stop(); }
		        });
			} else {
				el.maxLength = el.$form.maxLength;
			}
		}
	    
		// restrict input characters
	    if (typeof(el.$form.restrict) != "undefined" && (el.type == "textarea" || el.type == "text" || el.type == "password")) { 
			el.addEvent("keypress", function(e){
	            var evt = new Event(e);
				var key = evt.getCharKey();
	            var re = new RegExp(this.$form.restrict);
	            if (key != "" && !re.test(key)) { evt.stop(); }
	        });
	    }
		
		// hide alert & execute call back functions
		el.addEvents({
			"click": function(e){
				this.validated = thisForm.validFormElement(this);
				setCallBack(el);
			},
			"keyup": function(e){
				this.validated = thisForm.validFormElement(this);
				setCallBack(el);
			},
			"change": function(e){
				this.validated = thisForm.validFormElement(this);
				setCallBack(el);
			},
			"blur": function(e){
				this.validated = thisForm.validFormElement(this);
				setCallBack(el);
			}
		});
		
		// set call back function
		function setCallBack(elObj) {
			var form = elObj.form;
			if (elObj.$form.behaviors && elObj.$form.behaviors.onAfterChange) {elObj.$form.behaviors.onAfterChange(elObj);}
			if (form.behaviors && form.behaviors.onAfterChange) {form.behaviors.onAfterChange(elObj);}
			
			// hide alert layer
			thisForm.hideAlertLayer();
		}
	},
	
	isValidForm: function (formObj){
		var thisForm = this;
	    for (var i = 0; i < formObj.elements.length; i++) {
			formObj.elements[i].validated = thisForm.validFormElement(formObj.elements[i]);
	        if (!formObj.elements[i].validated) {
			    thisForm.showAlertLayer(formObj.elements[i]);
	            return false;
	        }
	    }
	    return true;
	},
	
	validFormElement: function(obj){
		var thisForm = this;
	    var el = $(obj);
	    
		// if (!el.$form)
		if (!el.$form) {
			return true;
		}
		
	    // valid types
	    switch (typeof(el.$form.valid)) {
	        case "function":
	            return el.$form.valid();
	            break;
	            
	        case "string":
	            
	            // no valid needed
	            if (typeof(el.$form.valid) == "undefined" || el.$form.valid == null || el.$form.valid.trim() == "" || el.$form.valid.trim() == "none") { return true; }
	            var validTag = el.$form.valid.trim();
	            
	            // compare to other input's value
	            if (validTag.indexOf("=") != -1 && validTag.indexOf(">") == -1 && validTag.indexOf("<") == -1) {
	                if (el.type == "text" || el.type == "password") {
	                    var target = $F(validTag.replace("=", ""), el.form);
	                    return !target || el.value.trim() == target.value.trim();
	                }
	                
	                // other type
	                return true;
	            }
	            if (validTag.indexOf(">") != -1) {
	                if (el.type == "text" || el.type == "password") {
	                    var target = $F(validTag.replace("=", ""), el.form);
	                    if (validTag.indexOf("=") != -1) { return !target || Number(el.value.trim()) >= Number(target.value.trim()); }
	                    else { return !target || Number(el.value.trim()) > Number(target.value.trim()); }
	                }
	                
	                // other type
	                return true;
	            }
	            if (validTag.indexOf("<") != -1) {
	                if (el.type == "text" || el.type == "password") {
	                    var target = $(validTag.replace("=", ""));
	                    if (validTag.indexOf("=") != -1) { return !target || Number(el.value.trim()) <= Number(target.value.trim()); }
	                    else { return !target || Number(el.value.trim()) < Number(target.value.trim()); }
	                }
	                
	                // other type
	                return true;
	            }
	            
	            // required value
	            if (validTag.indexOf("required") != -1) {
					if (el.type != "text" && el.type != "textarea" && el.type != "password") {
						return true;
					}

					if (!el.$form || !el.$form.init || el.$form.init == "") {
						return el.value.trim().length >= Math.max(Number(Quote(validTag, "(", ")")), 1);
					} else {
						return el.value.trim().length >= Math.max(Number(Quote(validTag, "(", ")")), 1) && el.value.trim() != el.$form.init;
					}
	                
	                // other type
	                return true;
	            }
	            
	            // range value
	            if (validTag.indexOf("range") != -1) {
	                if (el.type == "text") {
	                    var range = Quote(validTag, "(", ")").trim().split(";");
						if (range[0].trim() == "" && range[1].trim() == "") return true;
						if (range[0].trim() == "") return Number(el.value.trim()) <= Number(range[1].trim());
						if (range[1].trim() == "") return Number(el.value.trim()) >= Number(range[0].trim());
	                    return Number(el.value.trim()) >= Number(range[0].trim()) && Number(el.value.trim()) <= Number(range[1].trim());
	                }
	                
	                // other type
	                return true;
	            }
	            
	            // email value
	            if (validTag.indexOf("email") != -1) {
	            
	                if (el.type == "text" || el.type == "textarea") {
	                
	                    // if optional input & value is null or value = init value
	                    if (validTag.indexOf("[") != -1 && validTag.indexOf("]") != -1 && (isBlank(el.value) || (el.$form && el.$form.init && el.value.trim() == el.$form.init))) { return true; }
	                    
	                    // validate email(s)
						if (validTag.indexOf("emails") != -1) {
							return isEmails(el.value.trim());
						}
						return isEmail(el.value.trim());
	                }
	                
	                // other type
	                return true;
	            }
	            
	            // phone value
	            if (validTag.indexOf("date") != -1) {
	            
	                if (el.type == "text") {
	                	
						var fmt = Quote(validTag, "(", ")").trim();						
	                    // if optional input & value is null or value = init value
	                    if (validTag.indexOf("[") != -1 && validTag.indexOf("]") != -1 && (isBlank(el.value) || (el.$form && el.$form.init && el.value.trim() == el.$form.init))) { return true; }
	                    // validate phone
	                    return isDate(fmt, el.value.trim());
	                }
	                
	                // other type
	                return true;
	            }
				
				// phone value
	            if (validTag.indexOf("phone") != -1) {
	            
	                if (el.type == "text") {
	                
	                    // if optional input & value is null or value = init value
	                    if (validTag.indexOf("[") != -1 && validTag.indexOf("]") != -1 && (isBlank(el.value) || (el.$form && el.$form.init && el.value.trim() == el.$form.init))) { return true; }
	                    
	                    // validate phone
	                    return isPhone(el.value.trim());
	                }
	                
	                // other type
	                return true;
	            }
	            
	            // image value
	            if (validTag.indexOf("image") != -1) {
	            
	                if (el.type == "text" || el.type == "file") {
	                
	                    // if optional input & value is null or value = init value
	                    if (validTag.indexOf("[") != -1 && validTag.indexOf("]") != -1 && (isBlank(el.value) || (el.$form && el.$form.init && el.value.trim() == el.$form.init))) { return true; }
	                    
	                    // validate image
	                    return isImage(el.value.trim());
	                }
	                
	                // other type
	                return true;
	            }
	            
	            // "future" compare date
	            if (validTag.indexOf("future") !== -1) {
            
	                if (el.type == "text") {

	                    // if optional input & value is null or value = init value
	                    if (validTag.indexOf("[") != -1 && validTag.indexOf("]") != -1 && (isBlank(el.value) || (el.$form && el.$form.init && el.value.trim() == el.$form.init))) { return true; }
	                    
	                    var range = Quote(validTag, "(", ")").split(",");
	                    if (range.length == 0) { return true; }
	                    if (!isDate(range[0].trim(), el.value.trim()) || (range[1] && $F(range[1].trim(), el.form) && !isDate(range[0].trim(), $F(range[1].trim(), el.form).value.trim()))) { return false; }
	                    if (range[1] && $F(range[1].trim(), el.form)) { return (compareDate(range[0].trim(), el.value.trim(), $F(range[1].trim(), el.form).value.trim()) == -1); }
	                    else { return (compareDate(range[0].trim(), el.value.trim()) == -1); }
	                }
	                
	                // other type
	                return true;
	            }
	            
	            // "checked" for checkbox & radio button
	            if (validTag == "checked") {
	            
	                if (el.type == "checkbox") { return el.checked; }
	                
	                if (el.type == "radio") {
	                    var radioGroup = el.form[el.name];
	                    
	                    // contain 1 radio button
	                    if (radioGroup && !radioGroup.length) { return radioGroup.checked; }
	                    
	                    // more than 1 radio button
	                    for (var i = 0; i < radioGroup.length; i++) {
	                        if (radioGroup[i].checked) { return true; }
	                    }
	                    return false;
	                }
	                
	                // other type
	                return true;
	            }
	            
	            // "selected" for combo box
	            if (validTag == "selected") {
	            
	                if (el.type == "select-one" || el.type == "select-multiple") {
	                    if (typeof(el.$form.init) != "undefined") { return el.selectedIndex != Number(el.$form.init); }
	                    else { return el.selectedIndex != 0; }
	                }
	                
	                // other type
	                return true;
	            }
	            
	            return true;
	            break;
	            
	        default:
	            return true;
	            break;
	    }
	},
	
	showAlertLayer: function(obj){
	    try {			
	        var thisForm = this;
			var form = obj.form;
			var alertLyr = thisForm.alertLayer;
	        form.errorElement = obj;
			
	        // call back functions
			if (obj.$form.behaviors && obj.$form.behaviors.onAlertShow) {obj.$form.behaviors.onAlertShow(obj);}
			if (form.behaviors && form.behaviors.onAlertShow) {form.behaviors.onAlertShow(obj);}
	       
	        // display alert message
	        thisForm.alertLayer.getElement("p").set('html', obj.$form.alert);
			// show alert
	        var alertType = obj.$form.layer && obj.$form.layer.type ? obj.$form.layer.type : form.layer.type ? form.layer.type : "alert";
	        var offset = obj.$form.layer && obj.$form.layer.offset ? obj.$form.layer.offset.split(",") : ["0", "0"];
			var lyrW = obj.$form.layer && obj.$form.layer.layerWidth ? obj.$form.layer.layerWidth : form.layer.layerWidth ? form.layer.layerWidth : 200;
			
	        switch (alertType) {
	            case "layer":
					var dim = $(obj).getCoordinates();
					alertLyr.setStyles({
						"visibility": "visible",
						"display": "block",
						"top": (dim.top + dim.height + Number(offset[1].trim())) + "px",
						"left": (dim.left + Number(offset[0].trim())) + "px",
						"width": lyrW + "px",
						"z-index": 100000
					}).addClass("layer");
	                break;
	                
	            case "popup":
					var dim = thisForm.alertLayer.getCoordinates();
					alertLyr.set("styles", {
						visibility: "visible",
						display: "block",
						top: (window.getScrollTop() + window.getHeight() / 2 - dim.height / 2 + Number(offset[1].trim())) + "px",
						left: (window.getWidth() / 2 - lyrW / 2 + Number(offset[0].trim())) + "px",
						width: lyrW + "px",
						zIndex: 100000
					}).addClass("popup");
	                
	               
	                break;
	            
				case "classic":
					alert(obj.$form.alert);
	                break;
				
	            default:
	                
	                break;
	        }
	        // set focus
			
	        obj.focus();
			
			// autohide alert
			setTimeout(thisForm.hideAlertLayer, 3000);
	    } catch (e) {}
	},
	
	hideAlertLayer: function(){
	    try {
			var thisForm = this;
			var obj = thisForm.form.errorElement;
			if (obj) {
				var form = obj.form;
				// call back functions
				if (obj.$form.behaviors && obj.$form.behaviors.onAlertHide) {obj.$form.behaviors.onAlertHide(obj);}
				if (form.behaviors && form.behaviors.onAlertHide) {form.behaviors.onAlertHide(obj);}
			}
	        
			// hide frame
			thisForm.alertLayer.setStyle("visibility", "hidden");
			
	    } catch (e) {}
	}	
});

