function Validator(frmname)
{
	var validation = []; //array of fields to validate
	var isValid = true;
	var pos = {start:0, end:0}; //position of caret
	
	if((this.formobj = $("form[name="+frmname+"]")).size() <= 0) {
		alert("ERROR: could not get form object: " + frmname);
		return;
	}
	
	
	this.setup = function() {
		
		for(var i=0; i<arguments.length; i++) {
			var fieldobj = $("#"+arguments[i].id);
			fieldobj.num = i;
			if(fieldobj.size() <= 0) {
				alert("ERROR: Did not find: " + arguments[i].id);
				return;
			}
			for (var name in arguments[i]) {
				if(name == 'live' && arguments[i][name] == true) {
					fieldobj.bind("keypress",{num:i,validator:this}, function(e) {e.data.validator.validate("warning",e.data.num);}  );
					fieldobj.bind("focus",{num:i,validator:this}, function(e) {if (e.data.validator.isValid == true) {
						e.data.validator.validate("warning", e.data.num);
					}}  );
				}
			}
			if (val = arguments[i]['maxlength']) {
				fieldobj.bind("input blur change keyup keydown",{num:i,validator:this},function(e){
					 var value = $("#"+e.data.validator.validation[e.data.num].id).val();
					var maxlength = e.data.validator.validation[e.data.num].maxlength;
                   
					if( value.length > maxlength) {
						$("#" + e.data.validator.validation[e.data.num].id).val(value.substr(0,maxlength));
						setCaretPos($("#" + e.data.validator.validation[e.data.num].id)[0],e.data.validator.pos.start);
					} 
				});
			}
			fieldobj.bind("keydown",{num:i,validator:this},function(e){
				e.data.validator.pos = getCaretPos($("#" + e.data.validator.validation[e.data.num].id)[0]);
			});
			if(val = arguments[i]['restrict'] ) {
				fieldobj.bind("input blur change keyup",{val:val,num:i,validator:this},function(e){
                    var value = $("#"+e.data.validator.validation[e.data.num].id).val();
                    var len = value.length;
					if (len > 0) {
						var newstring = '';
						for (var j = 0; j < len; j++) {
							var char = value.substr(j, 1);
							if (char.search(e.data.val) != -1) {
								newstring += char;
								e.data.validator.pos.start++;
							} else if (char.toLowerCase().search(e.data.val) != -1) { //see if lowercase matches
								newstring += char.toLowerCase();
								e.data.validator.pos.start++;
							} else if (char.toUpperCase().search(e.data.val) != -1) { //or upper case
								newstring += char.toUpperCase();
								e.data.validator.pos.start++;
							} else if (e.data.val.search(/ /) == -1 && e.data.val.search(/_/) != -1 && char == " ") { //replace spaces with _
								newstring += "_";
								e.data.validator.pos.start++;
							}
						}	
						if(value != newstring) {
							$("#" + e.data.validator.validation[e.data.num].id).val(newstring);
							setCaretPos($("#" + e.data.validator.validation[e.data.num].id)[0],e.data.validator.pos.start);
						}
					}
                });
			}
		}
		this.validation =  Array.prototype.slice.call(arguments, 0); //arguments ia a array object but I want an array
	}
	
	this.addCustom = function(func, id) {
		found = false;
		for(i=0, len=this.validation.length; i<len; i++) {
			if(this.validation[i].id == id) {
				this.validation[i].custom  = func;
				found = true;
				break;
			}
		}
		if(found == false) {
			this.validation[i].id = id;
			this.validation[i].custom = func;
		}
	}
	
	this.validate = function (level) {
		this.isValid = true;
		if(arguments.length>1 && !isNaN(arguments[1])) {//specify a field to validate
			
			for (var name in this.validation[arguments[1]]) {
				errorstr = '';
				value = this.validation[arguments[1]][name];
				obj = $("#"+this.validation[arguments[1]].id);
				
				if(this.validation[i].custom != undefined && name != 'id' && this.validation[i].custom() == false || this.validation[arguments[1]].required==true && name != "id" && (errorstr = check(obj , name , value)) !=  true || obj.val() != "" && name != "id" && (errorstr = check(obj , name , value)) !=  true) {
					this.isValid = false;
					break;
				}
			}
		} else { //validate all fields
			for(var i=0; i < this.validation.length && this.isValid == true; i++) {
				for (var name in this.validation[i]) {
					errorstr = '';
					value = this.validation[i][name];
					obj = $("#"+this.validation[i].id);

					if(this.validation[i].custom != undefined && name != 'id' && ( errorstr = this.validation[i].custom()) !=  true  ||  this.validation[i].required==true && name != "id" && (errorstr = check(obj , name , value)) !=  true || obj.val() != "" && name != "id" && (errorstr = check(obj , name , value)) !=  true) {
						this.isValid = false;
						if(this.validation[i]['showError'] != undefined) {
							obj = $("#"+this.validation[i]['showError']);
						}
						break;
					}
				}
				
			}
		}
		
		if(this.isValid) {
			hideNotice();
		} else {
			if(level == "error") {
				obj.focus();
			}
			showNotice(level,errorstr,obj);
		}
		return this.isValid;
	}

	this.formobj.bind("submit",{validator:this}, function(e) {return e.data.validator.validate("error");}  );

}

function getCaretPos(input) {
	var result = { start: 0, end: 0 };
	if (input.setSelectionRange) {
		result.start = input.selectionStart;
		result.end = input.selectionEnd;
	} else if (document.selection && document.selection.createRange) {
		var range = document.selection.createRange();
		var r2 = range.duplicate();
		result.start = 0 - r2.moveStart('character', -100000);
		result.end = result.start + range.text.length;
	}
	return result;
}
function setCaretPos(field, pos) {
	if(field.setSelectionRange) {
		field.setSelectionRange(pos,pos);
		field.focus();
	} else if (field.createTextRange) {
		var range = field.createTextRange();
		range.collapse(true);
		range.moveEnd('character', pos);
		range.moveStart('character', pos);
		range.select();
	}
}
function validateEmail(email) {
    if(email.length <= 0) {
	  return false;
	}
    var splitted = email.match("^(.+)@(.+)$");
    if(splitted == null) return false;
    if(splitted[1] != null ) {
		var regexp_user=/^\"?[\w-_\.]*\"?$/;
		if(splitted[1].match(regexp_user) == null) return false;
    }
    if(splitted[2] != null) {
		var regexp_domain=/^[\w-\.]*\.[A-Za-z]{2,4}$/;
		if(splitted[2].match(regexp_domain) == null) {
			var regexp_ip =/^\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\]$/;
			if(splitted[2].match(regexp_ip) == null) return false;
		}
		return true;
    }
	return false;
}

function check(fieldobj, type, value) {
	
	var fieldvalue = (fieldobj.attr("value")==undefined?"":fieldobj.attr("value"));
	switch(type) { 
		case "required": 
		case "req":
			if(fieldvalue.length == 0) { 
				return "This is a required field";
			}
		break;             
		case "maxlength": 
		case "maxlen":
			if(fieldvalue.length >  parseInt(value)) { 
				return "Too many characters entered. Please enter "+value; 
			}
		break;
        case "minlength": 
        case "minlen": 
			if(fieldvalue.length > 0 && fieldvalue.length <  parseInt(value)) { 
				return value+" characters are required";                 
			}
		break; 
        case "alnum": 
        case "alphanumeric"://contains alphabetic or numeric values
			var charpos = fieldvalue.search("[^A-Za-z0-9]");
			if(charpos == null) { 
				alert(charpos)
				return false; 
			} 
		break;
		case "reqalphanumeric"://requires alphabetic and numeric values
			var charpos = fieldvalue.search("[^A-Za-z]");
			if(charpos == -1) { 
				return false; 
			} 
			var charpos = fieldvalue.search("[^0-9]");
			if(charpos == -1) { 
				return false; 
			} 
		break;
        case "num": 
        case "numeric":  
			var charpos = fieldvalue.search("[^0-9]"); 
			if(fieldvalue.length > 0 &&  charpos >= 0) { 
				return "Please enter a numeric value"; 
			}
		break;               
        case "alphabetic": 
        case "alpha": 
			var charpos = fieldvalue.search("[^A-Za-z]"); 
			if(fieldvalue.length > 0 &&  charpos >= 0) { 
				return false; 
			} 
		break;
		case "alnumhyphen":
			var charpos = fieldvalue.search("[^A-Za-z0-9\-_]"); 
			if(fieldvalue.length > 0 &&  charpos >= 0) { 
				return false; 
			}			
			break;
        case "email": 
			if(fieldvalue.length > 0 && !validateEmail(fieldvalue)) { 
				return "Please enter a valid email address"; 
			}
		break; 
        case "email_confirm": 
			if(fieldvalue != $('email').value) {
				return false; 
			}
		break;  
        case "lt": 
        case "lessthan": 
			if(isNaN(fieldvalue)) { 
				return false; 
			}
			if(fieldvalue >=  parseInt(value)) { 
				return false;                 
			}             
		break; 
        case "gt": 
        case "greaterthan": 
			if(isNaN(fieldvalue)) { 
				return false; 
			}
			if(fieldvalue <=  parseInt(value)) { 
				return false;                 
			}            
		break; 
		case "confirm": 
			if(fieldvalue != $("#"+value).val() ) {
				return "Confirm e-mail doesn't match";
			} 
		break; 
        case "regexp": 
		 	if(fieldvalue.length > 0) {
	            if(!fieldvalue.match(value)) { 
	              return false;                   
	            }
			}
		break; 
    } 
	return true;
}
function selectDay(field_id) {
	var year = $('#'+field_id+'_year').val();
	var month = $('#'+field_id+'_month').val();
	var dayObj = $('#'+field_id+'_day');
	if(year != "" && month != "") {
		var currentSel = dayObj[0].selectedIndex;
		var dim = days_in_month(year, month-1);

		html = '<option></option>';
		for(var i=1;i<=dim; i++) {
			html += '<option>'+i+'</option>';
		}
		dayObj.html(html);
		if(currentSel > dim) {
			dayObj[0].selectedIndex = dim;
		} else {
			dayObj[0].selectedIndex = currentSel;
		}
	}
	updateDate(field_id);
}
function updateDate(field_id) {
	var year = $('#'+field_id+'_year').val();
	var month = $('#'+field_id+'_month').val();
	var day = $('#'+field_id+'_day').val();
	dateString = '';
	if(year != '') {
		dateString += year + '-'; 
	} else {
		dateString += '0000-';
	}
	if(month != '') {
		dateString += month + '-';
	} else {
		dateString += '00-';
	}
	if(day != '') {
		dateString += day;
	} else {
		dateString += '00';
	}
	$('#'+field_id).attr('value',dateString);
}
function days_in_month (year, month) {
     return 32 - new Date(year, month, 32).getDate();
}
var fadeId = null;
function showNotice(type, message, obj){
	$("#notice").attr("className", type);
	positionNotice(obj);
	$(window).bind("resize", function(){
		positionNotice(obj);
	});
	$("#notice table tr td.c").html(message);
	if ($("#notice").css("display") != "block" || $("#notice").css("display") == "block"  && $("#notice").css("opacity") < 1) {
		$("#notice").fadeIn('slow');
	}
	clearInterval(fadeId);
	fadeId = setInterval(hideNotice,6000);
}

function hideNotice() {
	$("#notice").fadeOut('slow');
	$(window).unbind("resize");
}

function positionNotice(obj) {
	var offset = obj.offset();
	$('#notice').css('left', ((offset.left+obj.outerWidth())-5)+'px');
	$('#notice').css('top', offset.top+'px');
}

function countryChange(countryObj, stateObj) {
	var country = $('#'+countryObj+'_country');
	value = country.val().split(':');
	
	if(stateObj != null) {
		var stateSelect = $('#'+stateObj+'_stateSelect');
		var stateText = $('#'+stateObj);
	}
	
	if(value.length == 1) {
		if(stateObj != null) {
			//show textfield
			stateSelect.hide();
			stateText.show();
		}
		$('#'+countryObj).val(value);
	} else {
		$('#'+countryObj).val(value[0]);
		
		if(stateObj != null) {
			//show select
			stateSelect.show();
			stateText.hide();
			
			states = value[1].split(",");	
			html = '<option></option>';
			for(i=0;i<states.length;i++) {
				html += '<option value="'+states[i]+'">'+states[i]+'</option>';
			}
			stateSelect.html(html);
			stateSelect.val('option:first').attr('selected', 'selected');
		}
	}
}

function stateUpdate(obj) {
	$('#'+obj).val($('#'+obj+'_stateSelect').val());
}
/* Preload Images */
var preloaded = new Array();
function preload_images() {
	for (var i = 0; i < arguments.length; i++){
		preloaded[i] = document.createElement('img');
		preloaded[i].setAttribute('src',arguments[i]);
	};
};
//preload validation images
preload_images(
	"/puppy/images/validation/error.png",
	"/puppy/images/validation/warning.png"
);

