var Validator_Element = new Class({
	valid: true,
	validate_input: true,
	params: {},
	validators	:	{
		min_length	: function( v, param )	{
			v	= String( v );
			if( v.length < parseInt( param ) )	{
				return false;
			}
			return true;
		},
		max_length	: function( v, param )	{
			v	= String( v );
			if( v.length > parseInt( param ) )	{
				return false;
			}
			return true;
		},
		exact_length	: function( v, param )	{
			v	= String( v );
			if( v.length != parseInt( param ) )	{
				return false;
			}
			return true;
		},
		alpha	: function( v, param )	{
			v	= String( v );
			if( v.match( /[^a-zA-Z]/ ) )	{
				return false;
			}
			return true;
		},
		alpha_dash	: function( v, param )	{
			v	= String( v );
			if( v.match( /[^a-zA-Z0-9_\-]/ ) )	{
				return false;
			}
			return true;
		},
		alpha_numeric	: function( v, param )	{
			v	= String( v );
			if( v.match( /[^a-zA-Z0-9]/ ) )	{
				return false;
			}
			return true;
		},
		numeric	: function( v, param )	{
			v	= parseFloat( v );
			if( isNaN( v ) )	{
				return false;
			}
			return true;
		},
		integer	: function( v, param )	{
			v	= parseInt( v );
			if( isNaN( v ) )	{
				return false;
			}
			return true;
		},
		is_natural	: function( v, param )	{
			if( v.match( /[^0-9]/ ) )	{
				return false;
			}
			return true;
		},
		is_natural_no_zero	: function( v, param )	{
			var v	= String( that.getValue() );
			if( v.match( /[^1-9]/ ) )	{
				return false;
			}
			return true;
		},
		allowed_charset	: function( v, param )	{
			var v	= String( that.getValue() );
			var re	= new RegExp( "[^" + param + "]" );
			if( v.match( re ) )	{
				return false;
			}
			return true;
		},
		required	: function( v, param )	{
			if( '' == v )	{
				return false;
			}
			return true;
		},
		terms	: function( v, param )	{
			if( '' == v )	{
				return false;
			}
			return true;
		},	
		house	: function( v, param )	{
			if( '' == v )	{
				return false;
			}
			return true;
		},			
		email	: function( v )	{
			v	= String( v );
			if( !v.match( /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i ) )	{
				return false;
			}
			return true;
		},	
		valid_mgm_email: function(){
			//need to vaildate this email
		},	
		mobile	: function( v )	{
			v	= String( v );
			str = v.replace(/ /g,'');
			// Added by Marius so that we can use required/not-required in PHP
			// However this needs to be re-added so that when the mobile is required
			//  is being checked if it has the correct format			
			if( str != '' ){
				if( !str.match( /^\+?(?:44|0|44 0)\s?7[5789][\s\d]{8}$/i ) )	{
					return false;
				}
			}

			return true;
		},	
		valid_emails	: function( v )	{
			v	= String( v ).split( ',' );
			for( var i=0,i2=v.length; i<i2; i++ )	{
				v[i]	= v[i].replace( /\n/g, "" );
				if( !v[i].match( /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i ) )	{
					return false;
				}
			}
			return true;
		},		
		//:TODO: these are not implemented yet
		valid_url	: function( v, param )	{
			return true;
		},
		valid_ip	: function( v, param )	{
			return true;
		},
		matches	: function( v, param )	{
			return true;
		}
	},
	initialize: function(element, form_validator, type, params) {
		this.params = Object.extend({
				initial_status: '',
				initial_error: '',
				validated: false
			},
			params || {}
		);
		this.form = form_validator;
		this.type = type;
		this.validation_url = window.location.href.replace(/#.*$/ig, ' ');
		this.element = $(element);
		this.element.validator = this;
		this.setupElementNodes();
		this.setupErrorNodes();
		this.setupLabelNode();
		this.setupObservers();				
	
		this.validators.valid_email	= this.validators.email;
		this.validators.isset		= this.validators.required;
		this.validators.is_numeric	= this.validators.numeric;	
	},
	setupElementNodes: function() {
		if (this.type == 'radio') {
			this.element_container = this.element;
			this.element_group = $(this.element.parentNode);
		}
		else {
			this.element_container = $(this.element.parentNode);
			this.element_group = $(this.element.parentNode.parentNode);
		}
	},
	setupErrorNodes: function() {
		//TODO: Set these values when form is prefilled
		this.error_group = this.element_group.getElements('.errorInput');
		if (this.error_group) {
			this.error = $(this.error_group.firstChild);
		}
		else {
			this.error_group = null;
			this.error = null;
		}
	},
	setupLabelNode: function() {
		this.label = $$('label[for=' + this.element.id + '], #' + this.element.id + '_label_');
		if (this.label[0]) {
			this.label = this.label[0];
			this.label_required = this.label.getElements('.required');
			var aSpans = this.label.getElements('span');

			for (var i = 0; i < aSpans.length; i++) {
				var span = aSpans[i];
				if (span.innerHTML == '!') {
					this.label_mark = span;
				}
			}
		}
	},
	setupObservers: function() {
		if (this.type == 'checkbox') {//TODO: Fix Safari Bug, no focus onblur...
			this.element.addEvent('click', this.validate.bind(this));
		}
		else if (this.type == 'radio') {
			//No need to do anything as radio buttons will always be valid
			/*
			 var aRadioGroup = this.form.form.getInputs('radio',this.element.id);
			 for( var i = 0; i < aRadioGroup.length; i++ )
			 {
			 aRadioGroup[i].addEvent('click',this.validate.bind(this));
			 }
			 */
		}
		else {
			this.element.addEvent('blur', this._validate.bind(this));
		}
		if (this.type != 'radio' && this.type != 'checkbox') {
			this.element.addEvent('focus', this.setFocus.bind(this));
		}
	},
	removeObservers: function() {
		//TODO: Only remove observers I've created		
		this.validate_input = false;
	},
	_validate: function() {
		if (this.validate_input) {
			this.validate();
		}
	},		
	validate: function( params, onSuccess ) {	
				
		var method = 'post';
		if (!params) {
			var params = 'ajax=true' + '&' + '_submitted=' + this.form.form.id + '&' + this.element.id + '=' + this.getValue();
		}
		if (!onSuccess) {
			var onSuccess = this._parseXML.bind(this);
		}
		this.trimValue();
		
		//[fs] extracts validation tests + parameters from class names
		var aClasses	= this.element.get( 'class' ).toLowerCase().split( ' ' );
		var oClasses	= {};
		var aClass, v, sErr;
		
		while( aClass	= aClasses.shift() )	{
			aClass	= aClass.split( '-' );
			if( 1 < aClass.length && 'js' == aClass[0] )	{
				aClass.push( 1 );

				oClasses[aClass[1]]	= aClass[2];
			}
		}		
		
		//[fs]
		for( var k in oClasses ){
			if( typeof this.validators[k] == 'undefined' ){
				continue;
			}
			
			v	= this.getValue();
			
			if(k == 'valid_mgm_email'){
				var request = new Request(
				{
					method:method,
					url:'/tools/mgm_lookup/',
					data: params,
					onComplete: this.valid_mgm_email.bind(this)
				}).send();
				
				return;
			}else if( !this.validators[k]( v, oClasses[k] )){
				if( $defined( this.form.aErrorTxt[k] ) ){
					sErr	= this.form.aErrorTxt[k].replace( /%s/, this.getLabel() );
					sErr	= sErr.replace( /%s/, oClasses[k] );
				}else{
					sErr	= 'There is an error';
				}
				
				this.setInvalid( sErr, params );
				
				return;
			}
			
		}
		this.setValid();
		this.form.validationRequested = true;
	},
	valid_mgm_email: function(transport){
		response = JSON.decode(transport);
		
		// ORIGINAL line - Changed by Marius on 09.05.2011 for Tinie Tempah campaign
		//if(response.valid == true){
		if(response == null || response.valid == true){
			this.setValid('mgm');
			this.form.validationRequested = true;
		}else{
			this.setInvalid(this.form.aErrorTxt[response.error], 'mgm');
		}
	},	
	getLabel	: function()	{
		if( 1 == this.label.nodeType
			&& 0 < this.label.childNodes.length )	{
				return this.label.firstChild.nodeValue;
			}	else	{
				return '';
			}
			
	},
	getValue: function() {
		if (this.type == 'checkbox') {
			if (this.element.checked) { return 'on'; }
			else { return ''; }
		}
		else if (this.type == 'radio') {
			var checked = this.form.form.getInputs('radio', this.element.id).find(function(re) {
				if (re.checked) return re;
			});
			if (checked && checked.checked) { return checked.value; }
			else { return ''; }
		}
		else if (this.type == 'select-one') {
			if (this.element.value == "0") { return ''; }
			else { return this.element.value; }
		}
		else { return this.element.value; }
	},
	setFocus: function() {
		this.element_container.removeClass('iconFail');
		this.element_container.removeClass('iconPass');
		this.element_container.addClass('iconFocus');
		this.element.addClass('focus');
	},
	trimValue: function( v ) {
		if( 'text' != this.type )	{
			return;
		}
		this.element.value	= this.element.value.replace( /^\s+/, "" ).replace( /\s+$/, "" );
	},
	setValue: function( v ) {
		switch( this.type )	{
			case	'select':
			case	'select-one':
				
				//[fs] not sure whether .value = v will work for this 
				//if it doesn't, uncomment the break and write code here
				//break;
				
			case	'select-multiple':
				//break;
			
			case	'text':
			default:
				this.element.value	= v;
				break;
		}
	},
	setValid: function(v) {
		this.valid = true;
		if (this.type != 'checkbox' && this.type != 'radio') {
			this.element_container.removeClass('iconFail');
			this.element_container.removeClass('iconFocus');
			this.element_container.addClass('iconPass');
			this.element.removeClass('invalid');
			this.element.removeClass('focus');
			this.element.addClass('valid');
		}
		
		if(v == 'mgm'){
			elements = $$('.line');
			for(var i = 2; i<elements.length; i++){
				elements[i].setStyle('display','');
			}			
		}
		
		this.removeErrors();
	},
	setInvalid: function(error, v) {
		this.valid = false;
		if (this.type != 'checkbox' && this.type != 'radio') {
			this.element_container.removeClass('iconFocus');
			this.element_container.removeClass('iconPass');
			this.element_container.addClass('iconFail');
			this.element.removeClass('valid');
			this.element.removeClass('focus');
			this.element.addClass('invalid');
		}
		this._setErrorMarks();

		if(v == 'mgm'){
			elements = $$('.line');
			for(var i = 2; i<elements.length; i++){
				elements[i].setStyle('display','none');
			}			
		}
		
		this._setErrorMessage(error, v);
	},
	removeErrors: function() {
		if(this.error_group && this.slideError && this.slideError.open){
			this.slideError.toggle();
		}			
		if (this.label_required) {
			this.label_required.set({"html":'*',"class":'required'});
		}
	},
	removeRequired: function() {
		if (this.label_required) {
			this.label_required.setStyle('display', 'none');
		}
	},
	addRequired: function() {
		if (this.label_required) {
			this.label_required.setStyle('display', '');
		}
	},
	isValid: function() {
		this.validate();
		return this.valid;
	},
	_removeError: function(event) {
		if (this.error) {
			this.error.remove();
			this.error = null;
		}
		if (this.error_group) {
			this.error_group.remove();
			this.error_group = null;
		}
	},
	_setErrorMarks: function() {
		if (this.label && !this.label_mark) {
			if(this.label_required)
			{
				this.label_required.set({"html":'*!', "class":'required error'});
			}
		}
	},
	_setErrorMessage: function(error, v) {
		if (error && this.error && this.error_group) {
			if(error.length != this.error.innerHTML.length){
				this.slideError.hide();
				if(v == 'mgm'){
					this.error_group.set({html:'<p class="errorMgmInput">'+error+'</p>','styles':{'display':''}});
				}else{
					this.error_group.set({html:'<p>'+error+'</p>','styles':{'display':''}});
				}
				this.error.innerHTML = error;
				this.slideError.toggle();	
			}else{
				if(!this.slideError.open){
					this.slideError.toggle();
				}	
			}	
		} else if( error ) {
			this.error_group = new Element('div', {
				'class': 'errorInput error'
			});
				
			if(v == 'mgm'){
				this.error = new Element('p', {
					'class': 'error errorMgmInput'
				});
			}else{
				this.error = new Element('p', {
					'class': 'error'
				});
			}	
			
			this.error.innerHTML = error;
			this.error_group.appendChild(this.error);
			
			this.element_group.appendChild(this.error_group);
			this.slideError = new Fx.Slide(this.error_group).hide();
			this.slideError.toggle();
		}
	},
	_parseXML: function(transport) {
		if (transport.responseXML) {
			var response = transport.responseXML;
			validated = response.getElementsByTagName('validated');
			if (validated[0].firstChild.nodeValue == 'true') {
				this.setValid();
			}
			else {
				var aError = response.getElementsByTagName('error');
				for (var i = 0; i < aError.length; i++) {
					if (aError[i].firstChild) {
						var error = aError[i].firstChild.nodeValue;
					}
					else {
						var error = '';
					}
					this.setInvalid(error);
				}
			}
			this._removeValidationFlag();
		}
		else {
			this._error();
		}
	},
	_removeValidationFlag: function() {
		this.form.validationRequested = false;
	},
	_error: function() {
		this._removeValidationFlag();
		this.setInvalid('Sorry, an error occured');
		//alert('An error occured')
	}
});

var Validator_Form = new Class({
	aErrorTxt: {},
	elements: [],
	params: {
		initial_state: {}
	},
	validationRequested: false,
	initialize: function(form_id, params) {

		this.params = Object.extend(this.params, params || {} );
		this.form = $(form_id);
		this.form.validator = this;
		this.valid = true;
		this.create();
	},
	loadErrors	: function( oMessages )	{
		this.aErrorTxt	= oMessages;
	},
	create: function() {
		var aElements = this.form.getElements('input');
		var aSelects = this.form.getElements('select');
		aElements = aElements.combine(aSelects);
		var aRadioGroups = [];
		for (var i = 0; i < aElements.length; i++) {
			var element = aElements[i];
			if (element.getAttribute('type') == 'radio') {
				aRadioGroups.push(element.name);
			}
			else if (element.getAttribute('type') == 'radio') {
				aRadioGroups.push(element.name);
			}
			else if (element.getAttribute('type') != 'submit' && element.getAttribute('type') != 'hidden' && element.getAttribute('type') != 'image' && element.getAttribute('type') != 'file') {
				this.addElement(element, element.type);
			}
		}
		//uniq is not valid in mootools, may break the form
		//aRadioGroups = aRadioGroups.uniq();
		for (var i = 0; i < aRadioGroups.length; i++) {
			this.addElement($(aRadioGroups[i]), 'radio');
		}
		this.form.addEvent('submit', this.submitForm.bind(this));
	},
	addElement: function(element, type) {
		if (null === element) { return; }
		var initial_state = Object.extend({
			validated: this.params.form_validated || false
		}, this.params.initial_state[element.id] ||
		{});
		this.elements.push(new Validator_Element(element, this, type, initial_state));
	},
	submitForm: function(event) {
		this.error_fields = [];
		this.pass_fields = [];
		this.validateForm();
		//If an ajax request has taken place, submit the form without waiting
		if (this.valid == true) {
			//alert('Pass:'+this.pass_fields);
			//return false;
			this.form.submit();
			event.stop();
			//
		} else {			
			var errorElement = this.error_fields.pop();
			if (errorElement.element) {
				$(errorElement.element).scrollTo();
			}
			event.stop();
			
			return false;
		}
	},
	validateForm: function() {
		this.valid = true;
		for (var i = 0; i < this.elements.length; i++) {
			element = this.elements[i];
			if (element.type != 'radio' && !element.isValid()) {
				this.error_fields.push(element);
				//this.error_fields.push(element.element.type);
				this.valid = false;
			} else {
				this.pass_fields.push(element);
			}
		}
	}
});

