/*------------- [ VALIDATOR CLASS ] -------------*/

	var Validator = Class.create({
		initialize: function(className, error, test, options){
			if(typeof test == 'function'){
				this.options = $H(options);
				this._test = test;
			}
			else {
				this.options = $H(test);

				this._test = function(){
					return true;
				};
			}

			this.error = error || 'Validation Failed.';
			this.className = className;
		},

		test: function(v, elm){
			return(this._test(v,elm) && this.options.all(function(p){
				return Validator.methods[p.key] ? Validator.methods[p.key](v,elm,p.value) : true;
			}));
		},

		methods: {
			pattern: function(v,elm,opt){return Validation.get('IsEmpty').test(v) || opt.test(v)},
			minLength: function(v,elm,opt){return v.length >= opt},
			maxLength: function(v,elm,opt){return v.length <= opt},
			min: function(v,elm,opt){return v >= parseFloat(opt)},
			max: function(v,elm,opt){return v <= parseFloat(opt)},
			notOneOf: function(v,elm,opt){return $A(opt).all(function(value){return v != value;})},
			oneOf: function(v,elm,opt){return $A(opt).any(function(value){return v == value;})},
			is: function(v,elm,opt){return v == opt},
			isNot: function(v,elm,opt){return v != opt},
			equalToField: function(v,elm,opt){return v == $F(opt)},
			notEqualToField: function(v,elm,opt){return v != $F(opt)},
			include: function(v,elm,opt){return $A(opt).all(function(value){return Validation.get(value).test(v,elm);})}
		}
	});


/*------------- [ VALIDATION CLASS ] -------------*/

	var Validation = Class.create({
		initialize: function(form, options){
			Validation.options = Object.extend({
				onSubmit: true,
				stopOnFirst: false,
				immediate: false,
				focusOnError: true,
				useTitles: false,
				validationPassed: false,
				displayValidation: null,
				onFormValidate: function(result, form){},
				onElementValidate: function(result, elm){}
			}, options || {});

			Validation.form = $(form);

			if(Validation.options.onSubmit)
				Event.observe(Validation.form, 'submit', this.onSubmit.bind(this), false);

			if(Validation.options.immediate){
				var useTitles = Validation.options.useTitles;

				var callback = Validation.options.onElementValidate;

				Form.getElements(Validation.form).each(function(input){
					Event.observe(input, 'blur', function(ev){
						Validation.validate(Event.element(ev), {
							useTitle: useTitles,
							onElementValidate: callback
						});
					});
				});
			}
		},

		onSubmit:  function(ev){
			if(!this.validate())
				Event.stop(ev);
		},

		validate: function(){
			var result = false;
			var useTitles = Validation.options.useTitles;
			var callback = Validation.options.onElementValidate;

			if(Validation.options.stopOnFirst){
				result = Form.getElements(Validation.form).all(function(elm){
					return Validation.validate(elm, {
						useTitle: useTitles,
						onElementValidate : callback
					});
				});
			}
			else {
				result = Form.getElements(Validation.form).collect(function(elm){
					return Validation.validate(elm, {
						useTitle: useTitles,
						onElementValidate: callback
					});
				}).all();
			}

			if(!result && Validation.options.focusOnError){
				Form.getElements(Validation.form).findAll(function(elm){
					return $(elm).hasClassName('validation-failed');
				}).first().focus();
			}

			Validation.options.onFormValidate(result, Validation.form);

			return result;
		},

		reset: function() {
			Form.getElements(Validation.form).each(Validation.reset);
		}
	});

	Object.extend(Validation, {
		validate: function(elm, options){
			options = Object.extend({
				useTitle: false,
				onElementValidate: function(result, elm){}
			}, options || {});

			elm = $(elm);

			var cn = elm.classNames();

			return result = cn.all(function(value){
				var test = Validation.test(value,elm,options.useTitle);
				options.onElementValidate(test, elm);

				return test;
			});
		},

		getAlertElement: function(element){
			if(element.readAttribute('type') == 'checkbox' || element.readAttribute('type') == 'radio')
				return(element.up('div', 1));
			else
				if(element.tagName.toLowerCase() == 'textarea' && element.up('div').hasClassName('tinymce-textarea'))
					return(element.next('span'));
				else
					return(element);
		},

		test: function(name, elm, useTitle){
			var v = Validation.get(name);
			var prop = '__advice' + name.camelize();

			try {
				if((Validation.isVisible(elm) || elm.up('div').hasClassName('tinymce-textarea')) && !v.test($F(elm), elm)) {
					if(!elm[prop]){
						var advice = Validation.getAdvice(name, elm);

						if(advice == null){
							var errorMsg = useTitle ? ((elm && elm.title) ? elm.title : v.error) : v.error;
							advice = '<div class="validation-warning" id="advice-' + name + '-' + Validation.getElmID(elm) +'" style="display: none;"><span>' + errorMsg + '</span></div>';

							if(Validation.options.displayValidation)
								$(Validation.options.displayValidation).insert(advice);
							else
								Validation.form.insert({ before: advice });

							advice = Validation.getAdvice(name, elm);
						}

						if(typeof Effect == 'undefined')
							advice.style.display = 'block';
						else {
							new Effect.ScrollTo(Validation.form, { queue: 'end', offset: -100 });
							new Effect.Appear(advice, { queue: 'end', duration: 1 });
						}
					}

					elm[prop] = true;

					alertElement = Validation.getAlertElement(elm);

					if(Validation.options.validationPassed)
						alertElement.removeClassName('validation-passed');

					alertElement.addClassName('validation-failed');

					return false;
				}
				else {
					var advice = Validation.getAdvice(name, elm);

					if(advice != null)
						advice.hide();

					elm[prop] = '';

					alertElement = Validation.getAlertElement(elm);

					alertElement.removeClassName('validation-failed');

					if(Validation.options.validationPassed)
						alertElement.addClassName('validation-passed');

					return true;
				}
			}
			catch(e){
				throw(e);
			}
		},

		isVisible: function(elm){
			while(elm.tagName != 'BODY' && elm.tagName != 'body'){
				if(!$(elm).visible())
					return false;

				elm = elm.parentNode;
			}

			return true;
		},

		getAdvice: function(name, elm){
			return $('advice-' + name + '-' + Validation.getElmID(elm)) || $('advice-' + Validation.getElmID(elm));
		},

		getElmID: function(elm){
			return elm.id ? elm.id : elm.name;
		},

		reset: function(elm){
			elm = $(elm);

			var cn = elm.classNames();

			cn.each(function(value){
				var prop = '__advice'+value.camelize();

				if(elm[prop]){
					var advice = Validation.getAdvice(value, elm);

					advice.hide();

					elm[prop] = '';
				}

				alertElement = Validation.getAlertElement(elm);

				alertElement.removeClassName('validation-failed');

				if(Validation.options.validationPassed)
					alertElement.removeClassName('validation-passed');
			});
		},

		add: function(className, error, test, options){
			var nv = {};
			nv[className] = new Validator(className, error, test, options);
			Object.extend(Validation.methods, nv);
		},

		addAllThese: function(validators){
			var nv = {};

			$A(validators).each(function(value){
				nv[value[0]] = new Validator(value[0], value[1], value[2], (value.length > 3 ? value[3] : {}));
			});

			Object.extend(Validation.methods, nv);
		},

		get: function(name){
			return  Validation.methods[name] ? Validation.methods[name] : Validation.methods['_LikeNoIDIEverSaw_'];
		},

		methods: {
			'_LikeNoIDIEverSaw_' : new Validator('_LikeNoIDIEverSaw_', '', {})
		}
	});


/*------------- [ VALIDATION CLASSES DEFINITION ] -------------*/

	Validation.add('IsEmpty', '', function(v){
		return  ((v == null) || (v.length == 0)); // || /^\s+$/.test(v));
	});

	Validation.addAllThese([
		['required', getLanguageString('VALIDATE_REQUIRED'), function(v){
			return !Validation.get('IsEmpty').test(v);
		}],

		['validate-digits', getLanguageString('VALIDATE_DIGITS'), function(v){
			return Validation.get('IsEmpty').test(v) ||  !/[^\d]/.test(v);
		}],

		['validate-alpha', getLanguageString('VALIDATE_ALPHA'), function(v){
			return Validation.get('IsEmpty').test(v) ||  /^[a-zA-Z]+$/.test(v);
		}],

		['validate-alphanumeric', getLanguageString('VALIDATE_ALPHANUMERIC'), function(v){
			return Validation.get('IsEmpty').test(v) ||  !/\W/.test(v);
		}],

		['validate-phone', getLanguageString('VALIDATE_PHONE'), function(v){
			return Validation.get('IsEmpty').test(v) || /^(?:(?:[\(\)]?[\.\- ]?|[\.\- ]?[\(\)]?)\+{0,2}\d+)+$/.test(v);
		}],

		['validate-date', getLanguageString('VALIDATE_DATE'), function(v){
			var test = new Date(v);
			return Validation.get('IsEmpty').test(v) || !isNaN(test);
		}],

		['validate-email', getLanguageString('VALIDATE_EMAIL'), function(v){
			return Validation.get('IsEmpty').test(v) || /\w{1,}[@][\w\-]{1,}([.]([\w\-]{1,})){1,3}$/.test(v);
		}],

		['validate-url', getLanguageString('VALIDATE_URL'), function(v){
			return Validation.get('IsEmpty').test(v) || /^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i.test(v);
		}],

		['validate-date-au', getLanguageString('VALIDATE_DATE_AU'), function(v){
			if(Validation.get('IsEmpty').test(v))
				return true;

			var regex = /^(\d{2})\/(\d{2})\/(\d{4})$/;

			if(!regex.test(v))
				return false;

			var d = new Date(v.replace(regex, '$2/$1/$3'));

			return ( parseInt(RegExp.$2, 10) == (1+d.getMonth()) ) && (parseInt(RegExp.$1, 10) == d.getDate()) && (parseInt(RegExp.$3, 10) == d.getFullYear() );
		}],

		['validate-currency-dollar', getLanguageString('VALIDATE_CURRENCY_DOLLAR'), function(v){
			// [$]1[##][,###]+[.##]
			// [$]1###+[.##]
			// [$]0.##
			// [$].##
			return Validation.get('IsEmpty').test(v) ||  /^\$?\-?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/.test(v);
		}],

		['validate-selection', getLanguageString('VALIDATE_SELECTION'), function(v, elm){
			return elm.options ? elm.selectedIndex > 0 : !Validation.get('IsEmpty').test(v);
		}],

		['validate-one-required', getLanguageString('VALIDATE_ONE_REQUIRED'), function(v, elm){
			var p = elm.parentNode;

			var options = p.getElementsByTagName('INPUT');

			return $A(options).any(function(elm){
				return $F(elm);
			});
		}],

		['validate-max-date', getLanguageString('VALIDATE_MAX_DATE'), function(v, elm){
			dateStart = $$('[name="' + elm.readAttribute('title') + '"]')[0].getValue().split('/');
			dateEnd = v.split('/');

			for(cont = 0; cont < dateEnd.size(); cont++)
				if(dateStart[cont] > dateEnd[cont])
					return(false);

			return(true);
		}],

		['validate-min', getLanguageString('VALIDATE_MIN'), function(v, elm){
			return Validation.get('IsEmpty').test(v) || /^.{8,}$/i.test(v);
		}],

		['validate-jpeg', getLanguageString('VALIDATE_JPEG'), function(v, elm){
			return Validation.get('IsEmpty').test(v) || /\.(jpg|jpeg)$/i.test(v);
		}],

		['validate-document', getLanguageString('VALIDATE_DOCUMENT'), function(v, elm){
			return Validation.get('IsEmpty').test(v) || /\.(pdf|swf|doc|docx|ppt|pptx|pps|ppsx|xls|xlsx|mpp|zip|rar)$/i.test(v);
		}],

		['validate-equal-to-field', getLanguageString('VALIDATE_EQUAL_TO_FIELD'), function(v, elm){
			if(elm.up('form').down('[name="' + elm.readAttribute('title') + '"]').getValue() != v)
				return(false);
			else
				return(true);
		}],

		['validate-unique', getLanguageString('VALIDATE_UNIQUE'), function(v, elm){
			errors = false;

			new Ajax.Request('../php/main.php', {
				asynchronous: false,

				parameters: {
					JSONRequest: Object.toJSON({
						rowExists: 1,
						sourceData: [elm.readAttribute('name'), v],
						table: elm.readAttribute('title')
					})
				},

				onSuccess: function(transport){
					if(transport.responseText == 1)
						errors = true;
				}
			});

			if(errors)
				return(false);
			else
				return(true);
		}],

		['validate-availability', getLanguageString('VALIDATE_AVAILABILITY'), function(v, elm){
			availability = parseInt(changeContent(elm.readAttribute('title'), {
				asynchronous: false,
				requestAddress: '../products/control-ajax.php',
				changeElement: {
					action: 'return'
				},
				parameters: {
					id: elm.readAttribute('name')
				}
			}));

			if(v <= availability)
				return(true);
			else
				return(false);
		}]
	]);
