/*------------- [ 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.readAttribute('name') + '_parent'));
				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 ] -------------*/

	Event.observe(window, 'load', function(){
		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-9\.\-\(\) ]+$/.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|doc|docx|ppt|pptx)$/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);
			}]
		]);
	});