/* ************************************************************************************* *\
 * The MIT License
 * Copyright (c) 2007 Fabio Zendhi Nagao - http://zend.lojcomm.com.br
 * Copyright (c) 2008 Lukas Schulze - http://www.lukas-schulze.de
 * 
 * <version> 1.0
 * <date> 2008-08-26
 * <author> Lukas Schulze
 *
 * This class is based on the fValidator class of Fabio Zendhi Nagao
 * I removed the field validations and added the ajax-request validation.
 * Everything is going to be validated by a php-file
 *
 *
 *
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this
 * software and associated documentation files (the "Software"), to deal in the Software
 * without restriction, including without limitation the rights to use, copy, modify,
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies
 * or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * 
\* ************************************************************************************* */

var fValidate = new Class({
	options: {
		msgClass: "errormsg",
		url: "./ajax_checkInputs.php",
		form: "general",
		isValid: true,
		invalidField: false,
		dontSend: false,
		canEmpty: false,
		canSubmit: false,
		countErrors: 0,
		countElements: 0,
		styleNeutral: {"background-color": "#ffc", "border-color": "#cc0"},
		styleInvalid: {"background-color": "#fcc", "border-color": "#c00"},
		styleValid: {"background-color": "#cfc", "border-color": "#0c0"}
	},

	initialize: function(form, options) {
		this.form = $(form);
		this.setOptions(options);
		//this.options.form = this.form.get('name') || this.options.form;
		this.options.form = form;
		
		this.fields = this.form.getElements("*[class^=fValidate]");
		this.validations = [];

		this.fields.each(function(element) {
			element.cbErr = false;
			this.register(element, this.options);
		}.bind(this));
		
		this.form.removeEvents('submit');
		this.form.addEvents({
			"submit": this._onSubmit.bind(this),
			"reset": this._onReset.bind(this)
		});
		
		if(this.options.countErrors > 0) {
			this.options.countErrors = 0;
			this.options.dontSend = true;
			this.form.fireEvent('submit');
		}
	},

	register: function(field, options) {
		field = $(field);
		this.validations.push([field, options]);
		field.addEvent("blur", function() {
			this._validate(field, options);
		}.bind(this));
		if(field.hasClass('error')) {
			field.fireEvent('blur');
		}
	},
	
	_validate: function(field, options, isSubmit) {
		isSubmit = isSubmit || false;
		
		var value = '';
		if(field.get('tag') == 'input') value = field.get('value');
		else if(field.get('tag') == 'textarea') value = field.get('value');
		
		if(value == '' && !isSubmit && this.options.canEmpty) {
			this.options.countElements--;
			return false;
		}
		if(field.get('disabled')) {
			this.options.countElements--;
			return false;
		}
		
		//var this2 = this;
		
		var requestData = field.getParent('form');
		if ($type(requestData) == 'element') requestData = $(requestData).toQueryString();
		requestData += '&checkForm='+options.form+'&checkName='+field.get('name')+'&checkValue='+value;
		
		this.options.countErrors++;
		var req = new Request({
			method: 'post',
			url: options.url,
			data: requestData,
			onComplete: function(response) {
				options.code = response.substr(0, response.indexOf('|'));
				options.msg = response.substr(response.indexOf('|')+1);
				
				if(options.code == 'error') {
					this._msgInject(field, options);
					if(this.options.isValid) {
						this.options.isValid = false;
						this.options.invalidField = field;
					}
				}
				else if(options.code == 'good') {
					this.options.countErrors--;
					this._msgRemove(field, options);
				}
				
				if(isSubmit) {
					this.options.countElements--;
					if(this.options.countElements == 0 && this.options.countErrors <= 0) {
						if(this.options.dontSend) {
							this.options.dontSend = false;
						}
						else {
							this.form.submit();
						}
					}
					else if(this.options.countElements == 0) {
						if($defined(this.options.invalidField) && this.options.invalidField) this.options.invalidField.focus();
					}
					//$('debug').set('html', $('debug').get('html') + this.options.countElements + '<br />' + this.options.countErrors + '<hr />');
				}
			}.bind(this)
		});
		
		req.send();
	},

	_msgInject: function(owner, options) {
		if(!$defined($(owner.get("name") + "_msg"))) {
			var msgContainer = new Element('div', {"id": owner.get("name") + "_msg", "class": this.options.msgClass})
				.setStyle('width', owner.getSize().x - 4)
				.set('html', options.msg)
				.inject(owner.getParent(), 'bottom');
			$(owner.get("name") + "_msg").Slide = new Fx.Slide($(owner.get("name") + "_msg"), {duration: 400});
			$(owner.get("name") + "_msg").Slide.hide();
			$(owner.get("name") + "_msg").Slide.slideIn().chain(function() {
				owner.fireEvent('finishValidate');
			});
			owner.cbErr = true;
			this._chkStatus(owner, options);
		}
		else {
			var old = $(owner.get("name") + "_msg").get('html');
			$(owner.get("name") + "_msg").set('html', options.msg);
			if(old == $(owner.get("name") + "_msg").get('html')) {
				$(owner.get("name") + "_msg").highlight('#ffebeb', '#e00000');
			}
			else {
				$(owner.get("name") + "_msg").Slide.slideOut().chain(function() {
					$(owner.get("name") + "_msg").set('html', options.msg);
					$(owner.get("name") + "_msg").Slide.slideIn().chain(function() {
						owner.fireEvent('finishValidate');
					});
				});
			}
		}
	},

	_msgRemove: function(owner, options, isReset) {
		isReset = isReset || false;
		if($(owner.get("name") + "_msg")) {
			var el = $(owner.get("name") + "_msg");
			var parents = el.getParent('div');
			//el.set('tween', {duration: "300"}).tween('opacity', 0);
			var myFX = new Fx.Tween(el, {duration: 410});
			el.Slide.slideOut().chain(function() {
				owner.fireEvent('finishValidate');
			});
			myFX.start('opacity', 1, 0).chain(function(){parents.destroy();});
			
			owner.cbErr = false;
		}
		
		this._chkStatus(owner, options, isReset);
	},

	_chkStatus: function(field, options, isReset) {
		isReset = isReset || false;
		
		if(isReset) {
			field.removeClass('error');
			field.removeClass('good');
		}
		else if(field.cbErr == false) {
			field.removeClass('error');
			field.addClass('good');
			//field.effects({duration: 500, transition: Fx.Transitions.linear}).start(this.options.styleValid);
			//this.fireEvent("onValid", [field, options], 50);
		} else {
			field.removeClass('good');
			field.addClass('error');
			//field.effects({duration: 500, transition: Fx.Transitions.linear}).start(this.options.styleInvalid);
			//this.fireEvent("onInvalid", [field, options], 50);
		}
	},

	_onSubmit: function(/* event */) {
		//event = new Event(event).stop();
		
		if(this.options.canSubmit) {
			this.form.submit();
			return false;
		}
		
		//$('debug').set('html', '');
		this.options.isValid = true;
		this.options.invalidField = false;
		this.options.countErrors = 0;
		this.options.countElements = this.validations.length;
		
		this.validations.each(function(array) {
			this._validate(array[0], array[1], true);
		}.bind(this));
		
		/*
		if(!this.options.isValid) {
			event.stop();
			this.options.invalidField.focus();
		}
		*/
		return false;
	},

	_onReset: function() {
		this.validations.each(function(array) {
			array[0].cbErr = false;
			this._msgRemove(array[0], array[1], true);
		}.bind(this));
		this.validations[0][0].focus();
	}
});

fValidate.implement(new Events); // Implements addEvent(type, fn), fireEvent(type, [args], delay) and removeEvent(type, fn)
fValidate.implement(new Options);// Implements setOptions(defaults, options)
