TRvalidator = function(formId, focusFirst, errorCode, o) {
	this.fields = {};
	this.self = this;
	this.form = this.i(formId);
	this.errorsOn = {};
	this.o = o ? o : {};
	
	this._initFields('input');
	this._initFields('select');
	this._initFields('textarea');
		
	/* --- Error Codes --- */
	this.i('tr_master_error').innerHTML = ' Please fix the errors below. ';
	this.errors = new Array();
	this.errors[1] = {
					'msg':'Email already exists in our database',
					'field':'email'
					};

	this.errors[2] = {
					'msg':'The password you entered is incorrect',
					'field':'old_password'
					};					
	this.errors[3] = {
					'msg':'Incorrect email address or password, please try again',
					'field':'email'
					};
	if (o) {
		this.errors[4] = {
						'msg':'Email already exists in our database. <a href="' + o.href + '">Click here to login</a>',
						'field':'email'
						};
	
		this.errors[5] = {
						'msg':'The password you entered is incorrect. <a href="' + o.href + '">Forgot your password?</a>',
						'field':'password'
						};					
		this.errors[6] = {
						'msg':'The email address was not found. <a href="' + o.href + '">Click here to register</a>',
						'field':'email'
						};					
		this.errors[7] = {
						'msg': o.msg  + ' (' + o.code + ')',
						'field':['exp_month','exp_year']
						};					
		this.errors[8] = {
						'msg': o.msg + ' (' + o.code + ')',
						'field':'cvv'
						};					
		this.errors[9] = {
						'msg': o.msg + ' (' + o.code + ')',
						'field':'cvv'
						};					
		this.errors[10] = {
						'msg': o.msg + ' (' + o.code + ')',
						'field':'cc'
						};					

	}
	if (errorCode) {
		this.displayError(errorCode);	
	}
	
	//Select First Item
	if (focusFirst) { 
		this.i(focusFirst).focus(); 
	}
}
TRvalidator.prototype = {
	
	_initFields : function(ty) {
		var f = this.form.getElementsByTagName(ty);
		for(var i=0; i<f.length; i++) {
			if (f[i]) {
				var selfSet = this.self;
				f[i].onfocus = function() { selfSet.highlight(this, selfSet) }
			}
		}
	},
	
	/* --- */
	
	highlight : function(f, obj) {
		if (obj.curFocus != f) {
			if (obj.curFocus) {
				obj.curFocus.className = obj.curFocus.className.replace('tr_form_highlight', '');
			}
			f.className += ' tr_form_highlight';
			obj.curFocus = f;
		}
	},
	
	displayError : function(e) {		
		// add change event to field
		var selfSet = this.self;
		var fields = typeof this.errors[e].field == 'string' ? [this.errors[e].field] : this.errors[e].field;
		this.updateMsg( fields[0] , this.errors[e].msg );
		for(var i=0; i<fields.length; i++)
		{ 
			var field = this.i( fields[i] );	
			this.setClass( fields[i] , -1, true );	
		
			field[ field.tagName == 'SELECT' ? 'onchange' : 'onkeyup' ] = function(e)
			{
				if (this.getAttribute('custom_error')==1) {
					selfSet.setClass( this.id , 0 );		
				}
				this.onkeyup = null;
			};
		}
		
		this.i('tr_master_error').style.display = 'block';
	},
	
	/* --- */
	
	checkAll : function(justBool) {
		var okay = true;
		var s = false;
		for(id in this.fields) {
			s = this.check( id, null, justBool );
			if (!s) { okay = false; }
		}
		if (!justBool) {
			if (!okay ) { 
				this.i('tr_master_error').style.display = 'block'; 
				this.i('tr_master_error').innerHTML = ' Please fix the errors below. ';
			} else {
				this.i('tr_master_error').style.display = 'none';
			}
			if (okay) { this.form.submit(); }
		}
		if (this.o.checkAllEvent)
			this.o.checkAllEvent();
		
		return okay;
	},
	
	check : function( id , obj, justBool ) {
		obj = ( (obj) ? (obj):(this) );
		for(type in obj.fields[id]) {				
			okay = obj['v'+type]( id , obj.fields[id][type] );
			if (!justBool) { obj.setClass( id , ((okay)?(1):(-1)) ); }
			if (!okay) { return false; }			
		}
		return true;
	},
	
	checkMasterMsg : function() {
		if (this.i('tr_master_error').style.display == 'block') {
			for(var i in this.errorsOn) {
				if ( this.errorsOn[i] == '-1' ) {
					return false;	
				}
			}
			this.i('tr_master_error').style.display = 'none';
		}
	},
	
	updateMsg : function( id , msg ) {
		if ( !this.i( id+'_msg' ) ) {
			var n = document.createElement('div');
			n.setAttribute('id', id+'_msg');
			n.className = 'tr_form_msg';
			this.i( id ).parentNode.appendChild( n );
		}
		this.i( id+'_msg' ).innerHTML = msg;
	},	
	
	/* --- */
	
	apply : function( type, ids, vars) {
		if (!vars) { vars = new Object(); }
		for(i in ids) {
			id = ids[i];
			if ( this.i( id ) ) {
				if (!this.fields[ id ]) {
					this.fields[ id ] = new Object();
				}
				this.fields[ id ][type] = {'ids':ids, 'vars':vars};
				var selfSet = this.self;
				if (this.i( id ).type == 'checkbox') {
                	this.i( id ).onclick = function() { selfSet.check(this.id, selfSet); if (selfSet.o.onChange) { selfSet.o.onChange(); } }
				} else {
                	this.i( id ).onchange = function() { selfSet.check(this.id, selfSet); if (selfSet.o.onChange) { selfSet.o.onChange(); }  }                                                
				}
			}
		}
	},
	
	/* --- */
	
	setClass : function( id , which, custom_error ) {
		var classNames = {'-1':'tr_form_error' , '1':'tr_form_okay'};
		which += '';
		
		if (which == '0') { //reset
			this.i(id).parentNode.className = this.i(id).parentNode.className.replace(' ' + classNames[-1],'');
			this.i(id).parentNode.className = this.i(id).parentNode.className.replace(' ' + classNames[1],'');
		} else {
			this.i(id).parentNode.className = this.i(id).parentNode.className.replace(' ' + classNames[which*-1],'');
		}

		if ( !this.i(id).parentNode.className.match(classNames[which]) ) {
			this.i(id).parentNode.className += ' ' + classNames[which];
		}
		
		this.errorsOn[ id ] = which;
		
		if (which != '-1') { this.checkMasterMsg(); }
		
		this.i(id).setAttribute('custom_error', custom_error ? 1 : 0);			
	},
	
	/* --- */
	
	i : function(id) {
		return document.getElementById(id);
	},
	
	/* -- Validation Scripts -- */
	/* -- To add more, simply use the format vTYPE as the function name, don't forget the comma in between each function -- */
	/* -- Each script should return true or false.  To set the error message, use the this.updateMsg function -- */
	
	vrequired : function( id , field ) {
		var o = this.i(id);
		var okay = false;
		switch( o.getAttribute('type') ) {
			
			case('checkbox'):
				okay = o.checked;
				break;
				
			case('radio'):			
				okay = o.checked;
				break;
				
			default:
				okay = (this.i(id).value.length > 0);
				
		}
		if (!okay) {
			this.updateMsg( id , 'This field is required.' );
		}
		return okay;
	},
	
	vconfirm : function( id , field ) {
		var o = this.i(id);
		var okay = true;

		if ( this.i( field['vars']['compareTo'] ).value != o.value) {
			okay = false;
		} else {
			if (this.i(id).value.length > 0) {
				this.setClass( id , 1 );
			} else {
				okay = false;
			}
		}
		
		if (!okay) {
			this.updateMsg( id , ((field['vars']['what'])?(field['vars']['what']):('Fields')) + ' does not match' );
		}
		return okay;
	},	
	
	vemail : function( id , field ) {
		var o = this.i(id);
		var regEx = "^[0-9a-zA-Z\-_\+\.]+@[0-9a-zA-Z\-_\+]+[\.]{1}[0-9a-zA-Z\-_\+]+[\.]?[0-9a-zA-Z\-_\+]+$";
		
		okay = ((o.value.match( new RegExp( regEx ) ))?(true):(false));
		
		if (!okay) {
			this.updateMsg( id , 'Invalid email address' );
		}
		return okay;
	},
	vnumeric : function( id, field ) {
		var o = this.i(id);
		
		var regEx = "^[0-9]+$";
		
		okay = ((o.value.match( new RegExp( regEx ) ))?(true):(false));
		
		if (!okay) {
			this.updateMsg( id, 'The ' + field['vars']['what'] + ' must be numeric.' );
		}
		
		return okay;
	},
	vzip : function( id, field ) {
		var o = this.i(id);
		
		var regEx = "^[0-9]+$";
		
		okay = ((o.value.match( new RegExp( regEx ) ))?(true):(false));

		if (okay) {		
			if (field['vars']['min']) {
				if (o.value.length < field['vars']['min']) {
					okay = false;
				}
			}
			if (field['vars']['max']) {
				if (o.value.length > field['vars']['max']) {
					okay = false;
				}
			}
		}
		
		if (!okay) {
			this.updateMsg( id, 'The ' + field['vars']['what'] + ' must be 5 numbers.' );
		}
		
		return okay;
	},
	vcreditcard : function( id, field) {
		var o = this.i(id);
		
		var cardname = "none";
		var startNo = o.value.charAt(0);
		
		if (startNo == 4) {
			cardname = "Visa";
		} else if (startNo == 5) {
			cardname = "MasterCard";
		} else if (startNo == 3) {
			cardname = "AmEx";
		} else if (startNo == 6) {
			cardname = "Discover";
		}

		okay = checkCreditCard (o.value, cardname)

		if (!okay) {
			this.updateMsg( id, ccErrors[ccErrorNo]);
		}
		
		
		return okay;
	},
	
	vlimit : function( id , field ) {
		var o = this.i(id);
		var okay = true;
		
		if (field['vars']['min']) {
			if (o.value.length < field['vars']['min']) {
				okay = false;
			}
		}
		if (field['vars']['max']) {
			if (o.value.length > field['vars']['max']) {
				okay = false;
			}
		}

		if (!okay) {
			if ( field['vars']['min'] && field['vars']['max']) {
				msg = field['vars']['what'] + ' must be between ' + field['vars']['min'] + ' and ' + field['vars']['max'] + ' characters';
			} else if ( field['vars']['min'] ) {
				msg = field['vars']['what'] + ' at least ' + field['vars']['min'] + ' characters';					
			} else {					
				msg = field['vars']['what'] + ' has to be shorter than ' + field['vars']['max'] + ' characters';	
			}
			this.updateMsg( id , msg  );
		}
		return okay;
	}			
	
}