var Validation = new Class({
		
		forms:			new Array(),
		groups:		{},
		
		options: {
			'class':							'validForm',
			onError:						Class.empty,
			onSuccess:					Class.empty,
			onResult:						Class.empty,
			onValidateStart:	Class.empty
		},
		
		initialize: function ( options ) {
			this.setOptions( options );
			$ES( '.validForm' ).each( function ( form ) {
				var oldF = form.onsubmit;
				this.forms.push( form );
				form.removeEvents( 'onsubmit' );
				form.onsubmit = this.validForm.bindAsEventListener( this, [form, oldF] );
				form.validating = false;
				$ES( '.validField', form ).each( function ( obj ) {
					if( obj.hasClass( 'validFieldRequiredGroup' ) )
						this.registerGroup( form, obj );
					if( obj.hasClass( 'validFieldRequired' ) )
						obj.addEvent( 'onvalidation', this.validRequired.bind( this, [form, obj] ) );
					if( obj.hasClass( 'validFieldNumber' ) )
						obj.addEvent( 'onvalidation', this.validNumber.bind( this, [form, obj] ) );
					if( obj.hasClass( 'validFieldPostcode' ) )
						obj.addEvent( 'onvalidation', this.validPostcode.bind( this, [form, obj] ) );
					if( obj.hasClass( 'validFieldEmail' ) )
						obj.addEvent( 'onvalidation', this.validEmail.bind( this, [form, obj] ) );
					if( obj.hasClass( 'validFieldPhone' ) )
						obj.addEvent( 'onvalidation', this.validPhone.bind( this, [form, obj] ) );
				}.bind( this ) );
			}.bind( this ) );
		},
		
		registerGroup: function( form, obj ) {
			var start = obj.className.indexOf( 'validFieldGroup[' );
			var stop  = obj.className.indexOf( ']', start );
			var groupName = obj.className.substring( start + 16, stop );
			if( !this.groups[groupName] ) {
				this.groups[groupName] = new Array();
				obj.addEvent( 'onvalidation', this.validGroup.bind( this, [form, groupName] ) );
			}
			this.groups[groupName].push( obj );
		},
		
		revalidate: function () {
			this.forms.each( function ( form ) {
				for( var i=0; i<form.elements.length; i++ ) {
					var field = form.elements[i];
					if( this.isVisible( field ) )
						$( field ).fireEvent( 'onvalidation' );
				}
			}.bind( this ) );
		},
		
		validForm: function ( event, form, oldF ) {
			var event = new Event( event );
			form.valid = true;
			form.validating = true;
			this.fireEvent( 'onValidateStart', form );
			for( var i=0; i<form.elements.length; i++ ) {
			//$$( form.elements ).each( function ( field ) {
				var field = form.elements[i];
				if( this.isVisible( field ) )
					$( field ).fireEvent( 'onvalidation' );
			}
			//}.bind( this ) );
			if( $defined( oldF ) && valid )
				oldF.attempt( form );
			form.validating = false;
			return form.valid;
		},
		
		validRequired: function ( form, field ) {
			var valid = false;
			if( field.tagname == 'select' )
				valid = field.options[field.selectedIndex].value != '';
			else {
				switch( field.type ) {
					case 'checkbox':
						valid = field.checked;
						break;
					case 'radio':
						for( var i=0; i<form.elements[field.name].length; i++ ) {
							if( form.elements[field.name][i].checked )
								valid = true;
						};
						break;
					default:
						valid = field.value != '';
						break;
				}
			}
			
			this.fireEvent( 'onResult', [field, valid] );
			if( valid )
				this.fireEvent( 'onSuccess', [field, ''] );
			else
				this.fireEvent( 'onError', [field, 'Above field is required'] );
			
			if( !valid )
				form.valid = false;
		},
		
		validGroup: function( form, group ) {
			var fvalid = form.valid;
			var valid = false;
			this.groups[group].each( function ( field ) {
					
					
					
				var tvalid = false;
				if( field.tagname == 'select' )
					tvalid = field.options[field.selectedIndex].value != '';
				else {
					switch( field.type ) {
						case 'checkbox':
							tvalid = field.checked;
							break;
						case 'radio':
							for( var i=0; i<form.elements[field.name].length; i++ ) {
								if( form.elements[field.name][i].checked )
									tvalid = true;
							};
							break;
						default:
							tvalid = field.value != '';
							break;
					}
				}
				if( tvalid )
					valid = true;
				
				
				
			}.bind( this ) );
			
			this.groups[group].each( function ( field ) {
				this.fireEvent( 'onResult', [field, valid] );
				if( valid )
					this.fireEvent( 'onSuccess', [field, ''] );
				else
					this.fireEvent( 'onError', [field, 'One telephone field is required'] );
			}.bind( this ) );
			
			form.valid = fvalid;
			if( !valid )
				form.valid = false;
		},
		
		validNumber: function ( form, field ) {
			var valid = true;
			var pattern = /^[0-9]+$/;
			valid = field.value.test( pattern, 'i' );
			
			start = field.className.indexOf( 'validFieldMin' );
			if( start != -1 ) {
				stop = field.className.indexOf( ' ', start );
				if( stop == -1 )
					stop = field.className.length;
				var val = parseFloat( field.className.substr( start+13, stop-start-13 ) );
				valid = valid && ( parseFloat( field.value ) >= val );
			}
			start = field.className.indexOf( 'validFieldMax' );
			if( start != -1 ) {
				stop = field.className.indexOf( ' ', start );
				if( stop == -1 )
					stop = field.className.length;
				var val = parseFloat( field.className.substr( start+13, stop-start-13 ) );
				valid = valid && ( parseFloat( field.value ) <= val );
			}
			this.fireEvent( 'onResult', [field, valid] );
			if( valid )
				this.fireEvent( 'onSuccess', [field, ''] );
			else
				this.fireEvent( 'onError', [field, 'Wrong Value'] );
			
			if( !valid )
				form.valid = false;
		},
		
		validPostcode: function ( form, field ) {
			var valid = true;
			var pattern = /^([A-PR-UWYZa-pr-uwyz0-9][A-HK-Ya-hk-y0-9][AEHMNPRTVXYaehmnprtvxy0-9]?[ABEHMNPRVWXYabehmnprvwxy0-9]? {1,2}[0-9][ABD-HJLN-UW-Zabd-hjln-uw-z]{2}|GIR 0AAgir 0aa)$/;
			valid = field.value.test( pattern, 'i' );
			this.fireEvent( 'onResult', [field, valid] );
			if( valid )
				this.fireEvent( 'onSuccess', [field, ''] );
			else
				this.fireEvent( 'onError', [field, 'Invalid Postcode'] );
			
			if( !valid )
				form.valid = false;
		},
		
		validEmail: function ( form, field ) {
			var valid = true;
			var pattern = /^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/;
			valid = field.value.test( pattern, 'i' );
			
			this.fireEvent( 'onResult', [field, valid] );
			if( valid )
				this.fireEvent( 'onSuccess', [field, ''] );
			else
				this.fireEvent( 'onError', [field, 'Invalid Email Address'] );
			
			if( !valid )
				form.valid = false;
		},
		
		validPhone: function ( form, field ) {
			var valid = true;
			if( field.value.trim() == '' )
				valid = true;
			else {
				value = field.value.trim();
				var pattern1 = /^0[0-9]{4}\s+[0-9]{6}$/;
				var pattern2 = /^0[0-9]{3}\s+[0-9]{7}$/;
				valid = ( value.test( pattern1 ) || value.test( pattern2 ) );
			}
			
			repExp = /[\s]+/gi;
			if( !valid ) {
				value.replace( repExp, '' );
				value = value.slice( 0, 5 ) + ' ' + value.slice( 5, value.length );
				var pattern1 = /^0[0-9]{4}\s+[0-9]{6}$/;
				var pattern2 = /^0[0-9]{3}\s+[0-9]{7}$/;
				valid = ( value.test( pattern1 ) || value.test( pattern2 ) );
				if( valid ) {
					field.value = value;
				}
			}
			
			this.fireEvent( 'onResult', [field, valid] );
			if( valid )
				this.fireEvent( 'onSuccess', [field, ''] );
			else
				this.fireEvent( 'onError', [field, 'Invalid Number'] );
			
			if( !valid )
				form.valid = false;
		},
		
		/* validPhone: function ( form, field ) {
			var valid = true;
			
			if( field.value.trim() == '' )
				valid = true;
			else {
				var pattern = /\s+/;
				var value = field.value.replace( pattern, '' );
				if( value.charAt(0) == '0' ) {
					if( value.length != 11 )
						valid = false;
					var pattern = /^[0-9]+$/;
					if( !value.test( pattern ) )
						valid = false;
				}
				else
					valid = false;
			}
			
			this.fireEvent( 'onResult', [field, valid] );
			if( valid )
				this.fireEvent( 'onSuccess', [field, ''] );
			else
				this.fireEvent( 'onError', [field, 'Wrong value'] );
			
			if( !valid )
				form.valid = false;
		}, */
		
		isVisible: function ( obj ) {
			while( obj.parentNode.tagName.toUpperCase() != 'HTML' && $(obj.parentNode).getStyle( 'display' ) != 'none' && $(obj.parentNode).getStyle( 'visibility' ) != 'hidden' ) {
				obj = obj.parentNode;
			}
			if( obj.parentNode.tagName.toUpperCase() == 'HTML' )
				return true;
			else
				return false;
		}
		
});

Validation.implement( new Options, new Events );

var ValidationDisplay = {
	
	success: function ( field, msg ) {
		if( field.hasClass( 'validFieldError' ) )
			field.removeClass( 'validFieldError' );
		
		this.label( field ).each( function ( label ) {
			if( label.hasClass( 'validFieldLabelError' ) )
				label.removeClass( 'validFieldLabelError' );
		} );
	},
	
	error: function ( field, msg ) {
		if( !field.hasClass( 'validFieldError' ) )
			field.addClass( 'validFieldError' );
		
		this.label( field ).each( function ( label ) {
			if( !label.hasClass( 'validFieldLabelError' ) )
				label.addClass( 'validFieldLabelError' );
		} );
	},
	
	label: function ( field ) {
		id = false;
		start = field.className.indexOf( 'validFieldId' );
		if( stop != -1 ) {
			stop = field.className.indexOf( ' ', start );
			if( stop == -1 )
				stop = field.className.length;
			id = field.className.substr( start+12, stop-start-12 );
		}
		
		if( id )
			return $ES('.validFieldLabel' + id);
		else
			return new Array();
	}
	
}

var ValidationAdvancedDisplay = {
	
	success: function ( field, msg ) {
		if( field.hasClass( 'validFieldError' ) )
			field.removeClass( 'validFieldError' );
		
		$ES('.validFieldLabel' + this.label( field ) ).each( function ( label ) {
			if( label.hasClass( 'validFieldLabelError' ) )
				label.removeClass( 'validFieldLabelError' );
			$ES('.validField' + this.label( field ) + 'ErrorMsg').each( function ( tmsg ) {
				tmsg.parentNode.remove( tmsg );
			} );
		}.bind( this ) );
	},
	
	error: function ( field, msg ) {
		if( !field.hasClass( 'validFieldError' ) )
			field.addClass( 'validFieldError' );
		
		$ES('.validFieldLabel' + this.label( field ) ).each( function ( label ) {
			if( !label.hasClass( 'validFieldLabelError' ) ) {
				label.addClass( 'validFieldLabelError' );
				var msgObj = new Element( 'span' ).addClass( 'validFieldLabelErrorMsg' ).addClass( 'validField' + this.label( field ) + 'ErrorMsg' ).setHTML( msg ).injectInside( new Element( 'span' ).addClass( 'base_size' ).injectInside( label ) );
			}
		}.bind( this ) );
	},
	
	validateStart: function ( form ) {
		$ES( '.validFieldError', form ).each( function ( field ) {
			field.removeClass( 'validFieldError' );
		} );
		$ES( '.validFieldLabelError', form ).each( function ( field ) {
			field.removeClass( 'validFieldLabelError' );
		} );
		$ES( '.validFieldLabelErrorMsg', form ).each( function ( tmsg ) {
			tmsg.parentNode.remove( tmsg );
		} );
	},
	
	label: function ( field ) {
		id = false;
		start = field.className.indexOf( 'validFieldId' );
		if( start != -1 ) {
			stop = field.className.indexOf( ' ', start );
			if( stop == -1 )
				stop = field.className.length;
			id = field.className.substr( start+12, stop-start-12 );
		}
		
		return id;
	}
	
}

window.addEvent( 'domready', function () {
		var v = new Validation( {
				onValidateStart: ValidationAdvancedDisplay.validateStart.bind( ValidationAdvancedDisplay ),
				onError: ValidationAdvancedDisplay.error.bind( ValidationAdvancedDisplay )
		} );
		if( new String( document.location ).indexOf( '+error=validation' ) != -1 )
			v.revalidate();
} );
