String.prototype.trim = function() {
	a = this.replace(/^\s+/, '');
	return a.replace(/\s+$/, '');
};

var pageNavigator = new Object();
pageNavigator.currentPageId = 0;

//--------------
//- jsValidate class -
//--------------
var JSValidate = Class.create();
JSValidate.prototype = {
	initialize: function(){
		this.valid_form = false;
		this.visible_errorHeader = false;
		this.js_options = {
			errorTag: 'span', // which tag do you want to use for error container. it must be one that opens and closes (div,span,p,b)
			errorClass: 'jsvalidation', // this is the css class name given to the tag above
			errorLocation: 'afterEnd', // only accepts beforeBegin or afterEnd (either before or after the input element)
			//note: if you choose "none" for the above attribute, you must create the error yourself and give the element an ID consisting of the option below + the name of the field to validate.
			errorIDPrefix: 'jsvalidator', // prefix of the id of the element above that will attach to the name or id of the form element. don't use spaces or special characters.
			startGone: false, //couldn't think of another name for this, but if true, it will apply "display:none", otherwise, the element is just invisible.
			useBR: 'none', // accepts before, after, both or none; This will add a new line (<br />) before and/or after the above element.
			useBlur: true, // this will attach an onBlur validator to each form element.
			submitClass: 'submit_action', // apply this class inside any form to let this element submit the form.
			highlightColor: '#FFFF99', //default color should be:  #FFFF99
			endColor: '#FFFFFF', //this is what you generally want to set to the background color behind the form elements.
			extMessage: true, // if true, and you have accept value on file input, it tells user what extensions are accepted.
			message: 'There was a validation error!'
		}
		this.js_validators = {
			number: {
				className: 'jsvalidate_number',
				defaultMessage: 'This field must have a numerical value.',
				regExp: /^[-]?\d+(\.\d+)?$/
			},
			digits: {
				className: 'jsvalidate_digits',
				defaultMessage: 'This field can only contain numbers.',
				regExp: /^[-]?\d+(\.\d+)?$/
			},
			email: {
				className: 'jsvalidate_email',
				defaultMessage: 'The email address you entered appears to be incorrect. Email addresses must contain an "at" sign (@) and a period (.) somewhere to the right of the @, with no spaces or commas. (Example: yourscreenname@aol.com)',
				regExp: /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/
			},
			cemail:{
				className: 'jsconfirm_email',
				defaultMessage: 'The confirmation email appears to be incorrect. Please try again.'
			},
			uscanzip: {
				className: 'jsvalidate_uscanzip',
				defaultMessage: 'This field must contain a valid US or Canada zip code.',
				regExp: /^((\d{5}([- ])\d{4})|(\d{5})|([AaBbCcEeGgHhJjKkLlMmNnPpRrSsTtVvXxYy]\d[A-Za-z]\s?\d[A-Za-z]\d))$/
			},
			alpha: {
				className: 'jsvalidate_alpha',
				defaultMessage: 'This field must contain only letters.',
				regExp: /^[a-zA-z\s]+$/
			},
			alphanum: {
				className: 'jsvalidate_alphanum',
				defaultMessage: 'This field must contain only letters or numbers.',
				regExp: /^[a-zA-Z0-9\s]+$/
			},
			required: {
				className: 'jsrequired',
				defaultMessage: 'This field is required.'
			},
			names: {
				className: 'jsvalidate_name',
				defaultMessage: 'This field must contain only letters.',
				regExp: /^[a-zA-Z-.''\s]*$/
			},
			iso88591: {
				className: 'jsvalidate_iso88591',
				defaultMessage: 'This field cannot accept accented characters, please use an alternate spelling.',
				regExp: /^[a-zA-Z0-9_\x20-\x7E\x0a\x0d]*$/
			},
			zipcode: {
				className: 'jsvalidate_zipcode',
				defaultMessage: 'Please enter a valid zip or postal code.',
				regExp: /^[a-zA-Z0-9-\s]*$/
			},
			phoneno: {
				className: 'jsvalidate_phoneno',
				defaultMessage: 'This field must contain a valid phone number with area code.',
				regExp: /^[0-9.()\s-+]*$/
			},
			passrequired: {
				className: 'jspassrequired',
				defaultMessage: 'Password must contain at least 5 characters, cannot be the same as the username and cannot contain accented characters.',
				regExp: /^[a-zA-Z0-9_\x20-\x7E]*$/
			},
			cpass:{
				className: 'jsconfirm_pass',
				defaultMessage: 'The confirmation password appears to be incorrect. Please try again.',
				regExp: /^[a-zA-Z0-9_\x20-\x7E]*$/
			},
			cardexp_year: {
				className: 'jsvalidate_exp_year',
				defaultMessage: 'Select a valid expiration date.'
			},
			cardcvv: {
				className: 'jsvalidate_cvv',
				defaultMessage: 'This field must contain 3 or 4 digits.',
				regExp: /^[0-9]*$/
			},
			cardno: {
				className: 'jsvalidate_cardno',
				defaultMessage: 'Please enter a valid credit card number.',
				regExp: /^[0-9\s-]*$/
			},
			cardno_checksum: {
				className: 'jsvalidate_cc_checksum',
				defaultMessage: 'Please enter a valid credit card number.'
			},
			jsvalidate_4digits: {
				className: 'jsvalidate_4digits',
				defaultMessage: 'Please enter four digits.'
			},			
			jsvalidate_mmyy: {
				className: 'jsvalidate_mmyy',
				defaultMessage: 'Please enter a correct date in the MM/YY format.'
			},			
			select_notempty: {
				className: 'jsselect_notempty',
				defaultMessage: 'Please select a value.'
			},
			incorrect_value: {
				className: 'jsincorrect_value',
				defaultMessage: 'This value does not match with our records.'
			}
					
		}
	},
	formValidate: function(form_id){
		var form_obj = $(form_id); 

		var thisCls = this;
		thisCls.valid_form = true;

		if( form_obj )
		{
			// remove error messages
			form_obj.descendants().each( function(element) {
				if(element.tagName.toLowerCase() == 'div') {
					if(element.hasClassName('purchaseError')) {
						element.remove();
					}
					 
				}
				
			});
			form_obj.getElements().each( function(element){
				// clear the errorBorder class
				element.removeClassName('errorBorder');

				var classes = element.className;
				if( classes && classes != '' ){

					classes.trim();
					classes = classes.split(' ');
		
					var index = '';
					for( var i=0; i < classes.length; i++ ) {

						result = true;
						index = jsValidate.getValidatorIndex( classes[i] );

						if( index != '' ){
							result = thisCls.fieldValidate(element, index);						
							thisCls.hideErrorMessage(element);
							if ( !result ){
								thisCls.displayErrorMessage(element, index);
								thisCls.displayErrorHeader();
								thisCls.valid_form = false;
							}
						}
						if( !result ){
							return;
						}
					}
				}	
			});
		}
		return thisCls.valid_form;
	},
	
	getValidatorIndex: function( className )
	{
		for(items in this.js_validators) {
			if ( className == this.js_validators[items]['className']){
				return items;
			}
		}
		return '';
	},

	fieldValidate: function (element, cls){

		var cls_name = this.js_validators[cls]['className'];
		var reg_exp = this.js_validators[cls]['regExp'];		
		
		var el_type = '';
		var el_tag = '';		 
		if(typeof element == 'undefined'){
			el_type = element[0].type.toLowerCase();
			el_tag = element[0].tagName.toLowerCase();
		} else {
			el_type = element.type.toLowerCase();
			el_tag = element.tagName.toLowerCase();
		}
		switch (cls_name) {
			case 'jsrequired':			
				switch (el_tag){
					case 'input':
					case 'select':				
					case 'textarea':
						if( element.value.trim() == '' ){
							return false;
						}
					break;
				}
			break;
			case 'jsselect_notempty':			
				switch (el_tag){
					case 'select':
						if( element.value.trim() == '' ){
							return false;
						}
					break;
				}
			break;
			case 'jspassrequired':			
				switch (el_tag){
					case 'input':				
						if( element.value == '' ){
							return false;
						}
						else{
							var js_field = $(element.accessKey);
							if( element.value == js_field.value || element.value.length < 5 ){
								return false;
							}						
						}
						if( reg_exp && !reg_exp.test(element.value) ){
							return false;
						}
					break;
				}
			break;
			case 'jsconfirm_email':			
			case 'jsconfirm_pass':			
				switch (el_tag){
					case 'input':
						if( element.accessKey ){
							var js_field = $(element.accessKey);
							if( element.value != js_field.value ){
								return false;
							}
						}
						else{
							return false;
						}
					break;
					if( reg_exp && !reg_exp.test(element.value) ){
						return false;
					}
				}
			break;
			default:
				if( reg_exp && !reg_exp.test(element.value) ){
					return false;
				}
				else{
					switch (cls_name){
						case 'jsvalidate_cardno':
							if( element.accessKey ) {
								var ccType = creditCard.type(element.value);
								if(ccType != $(element.accessKey).value) {
									return false;
								}
							}
							// test if a test number
							if(creditCard.isTestNumber(element.value)) {
								return false;
							}
						break;
						case 'jsvalidate_cc_checksum':
							if(!creditCard.verifyLuhn10(element.value))
								return false;
						break;
						case 'jsvalidate_phoneno':
							if( element.value.length > 0 && element.value.length < 10 ){
								return false;
							}
						break;
						case 'jsvalidate_exp_year':
							var formMonth = element.form['cc_exp_month'].value;
							var curDate = new Date();
							var formDate = new Date();
							formDate.setMonth(formMonth - 1);
							formDate.setYear(element.value);
							if(curDate.getTime() > formDate.getTime())
								return false;
						break; 
						case 'jsvalidate_4digits':
							if( element.value.length != 4 ){
								return false;
							}						
						break;
						case 'jsvalidate_mmyy':

							var value = element.value;

							if( value.length != 5 )	return false;
							if( value.indexOf("/") != 2 ) return false;

							var month = value.substr(0,2);
							var year = value.substr(3,2);
							var reg_exp = /^[0-9]*$/;
							if (!reg_exp.test(month) || !reg_exp.test(year)) return false;
							
							month = Number(month);
							year = "20"+year;
							year = parseInt(year);
							
							if (month<1 || month>12) return false;

							var formDate = new Date();
							formDate.setMonth(month);
							formDate.setYear(year);
							var curDate = new Date();
							if(curDate.getTime() > formDate.getTime()) return false;
							
						break;
						case 'jsvalidate_cvv':
							if( element.value.length != 3 && element.value.length != 4 ){
								return false;
							}
						break;
						default:
						break;
					}
				}
			break;
		}
		return true;
	},
	
	isFirstInRow: function(element) {
		return ( element.readAttribute('firstinrow') == '1' );
	},
	
	getRowParent: function(element) {
		var elm = $(element.id);
		var lastRowParent = elm.parentNode;
		if( !this.isFirstInRow(element) ) {
			var previousElms = $(elm.parentNode).previousSiblings();
    		for (var i = 0, length = previousElms.length; i < length; i++) {
				var first_elm = this.checkFirstRow(previousElms[i]);
				if( first_elm != false ) {
					lastRowParent = first_elm;
					break;
				}
			}
		}
		return lastRowParent;
	},
	
	checkFirstRow: function(element) {
		var thisCls = this;
		var result = false;
		element.immediateDescendants().each( function(inside_elm) {
			var el_tag = inside_elm.tagName.toLowerCase();		
			if( el_tag == 'input' || el_tag == 'select' || el_tag == 'textarea' )
				if( thisCls.isFirstInRow(inside_elm) ) {
					result = element;
				}
				 
		});
		return result;
	},
	
	displayErrorMessage: function(element, cls){
		var message = this.getValidatorMessage(element, cls);
		var container = $(element.id);
		
		// find the first element in row
		var row_element = this.getRowParent(element);

		if( row_element ) {
			row_element.addClassName("err");
			
			var err_element =  $('err_' + element.id);
			if( err_element ){
				err_element.innerHTML = message;
				err_element.style.display = 'block';
			} else {
				var html = Builder.node(
							  this.js_options.errorTag,  
							  {'id': 'err_' + element.id},
							  message
						   );
				$(row_element).insert( html ); 		
			}
		}
		
	},
	
	hideErrorMessage: function(element){
		var row_element = this.getRowParent(element);
		if( row_element ) {
			row_element.removeClassName("err");
			var err_element =  $('err_' + element.id);
			if( err_element ) {
				err_element.innerHTML = '';
				err_element.style.display = 'none';
			}
		}
	},
	
	displayErrorHeader: function(){

		var thisCls = this;
		if( thisCls.visible_errorHeader == false ) {	
			var err_header = $('errorHeader' + pageNavigator.currentPageId);
			if( err_header ) {
				err_header.innerHTML = 'There are some problems with your entry.<br />Please fix the fields highlighted below.';
				err_header.style.position = 'static';
				err_header.style.visibility = 'visible';
				err_header.style.height = 'auto';
				thisCls.visible_errorHeader = true;
			}
		}			
		
	},
	
	hideErrorHeader: function(){
		if( pageNavigator.currentPageId != null ) {
			var thisCls = this;
			var err_header = $('errorHeader' + pageNavigator.currentPageId);
			if( err_header ) {
				err_header.innerHTML = '';
				err_header.style.position = 'absolute';
				err_header.style.visibility = 'hidden';
				err_header.style.height = '0px';
				thisCls.visible_errorHeader = false;
			}
		}
		
	},
		
	getValidatorMessage: function( element, cls )
	{
		if ( element.accept && cls == 'required'){
			return element.accept;
		}
		for(items in this.js_validators) {
			if ( items == cls ){ 
				return this.js_validators[items]['defaultMessage'];
			}
		}
		return this.js_options['message'];
	}
}
var jsValidate = new JSValidate();

