Event.implement({
	getCharCode: function(){
		return (typeof(this.event.charCode) != 'undefined') ? this.event.charCode : this.event.keyCode;
	},
	
	getCharKey: function(){
		var code = this.getCharCode();
		return (code == 0) ? '' : String.fromCharCode(code);
	}
});

String.implement({
	isBlank: function(){
		return (this.trim() == '');
	},
	
	isAlpha: function(){
		var re = /^[a-zA-Z_]+$/;
		return re.test(this);
	},
		
	isAlphanumeric: function(){
		var re = /^[a-zA-Z0-9_]+$/;
		return re.test(this);
	},
	
	isNumber: function(){
		var re = /^[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?$/;
		return re.test(this);
	},
	
	isEmail: function(){
		var re = new RegExp('^\\w+((-\\w+)|(\\.\\w+))*\\@[A-Za-z0-9]+((\\.|-)[A-Za-z0-9]+)*\\.[A-Za-z0-9]{2,4}$');
		return re.test(this);
	},
	
	isEmails: function(){
		var re = new RegExp('[ ;,\n]');
	    var emailArr = this.split(re);
	    for (var i = 0; i < emailArr.length; i++) {
	        if (!emailArr[i].trim().isEmail()) {
				return false;
			}
	    }
	    return true;
	},
	
	isWebsite: function(){
		var re = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
		return re.test(this);
	},
	
	isWebsites: function(){
		var re = new RegExp('[;,]');
	    var websiteArr = this.split(re);
	    for (var i = 0; i < websiteArr.length; i++) {
	        if (!websiteArr[i].trim().isWebsite()) {
				return false;
			}
	    }
	    return true;
	},
	
	isImage: function(){
		var re = new RegExp('\\.(png|gif|bmp|jpg|jpeg|jpe)$', 'i');
		return re.test(this);
	},
	
	isVideo: function(){
		var re = new RegExp('\\.(avi|wmv)$', 'i');
		return re.test(this);
	},
	
	isAudio: function(){
		var re = new RegExp('\\.(mp3|wma|wav)$', 'i');
		return re.test(this);
	},
	
	isPhone: function(){
		var re = /^\+?1?([- ()\.]{0,3}\d){7,16}( *(x|ext)\.? *(\d{1,10}))?$/;
		return re.test(this);
	},
	
	isDate: function(format){
		var re = new RegExp('[.\/-]');
	    var arr = this.split(re);
	    if (arr.length != 3) {
			return false;
		}
	    var y = parseInt(arr[format.indexOf('y')], 10);
	    var m = parseInt(arr[format.indexOf('m')], 10);
	    var d = parseInt(arr[format.indexOf('d')], 10);
	    var date = new Date(y, m - 1, d);
	    return (y == date.getFullYear() && m == date.getMonth() + 1 && d == date.getDate());
	},
	
	isCompareDate: function(format, other){		
		var re = new RegExp('[.\/-]');
	    var a1 = this.split(re);
	    var y1 = parseInt(a1[format.indexOf('y')]);
	    var m1 = parseInt(a1[format.indexOf('m')]);
	    var d1 = parseInt(a1[format.indexOf('d')]);
	    
	    var a2 = other.split(re);
	    var y2 = parseInt(a2[format.indexOf('y')]);
	    var m2 = parseInt(a2[format.indexOf('m')]);
	    var d2 = parseInt(a2[format.indexOf('d')]);
	    
	    if (y2 > y1) { 
			return 1; 
		}
	    else if (y2 < y1) { 
			return -1; 
		}
	    else {
	        if (m2 > m1) { 
				return 1; 
			}
	        else if (m2 < m1) { 
				return -1; 
			}
	        else {
	            if (d2 > d1) { 
					return 1; 
				}
	            else if (d2 < d1) { 
					return -1; 
				}
	            else { 
					return 0;
				}
	        }
	    }
	},
	
	isCreditCard: function(cardname){
		// Define the cards we support. You may add addtional card types.
	    // Name:      As in the selection box of the form - must be same as user's
	    // Length:    List of possible valid lengths of the card number for the card
	    // prefixes:  List of possible prefixes for the card
	    // checkdigit Boolean to say whether there is a check digit
	    var cards = new Array({
	        name: "Visa",
	        length: "13,16",
	        prefixes: "4",
	        checkdigit: true
	    }, {
	        name: "MasterCard",
	        length: "16",
	        prefixes: "51,52,53,54,55",
	        checkdigit: true
	    }, {
	        name: "DinersClub",
	        length: "14,16",
	        prefixes: "300,301,302,303,304,305,36,38,55",
	        checkdigit: true
	    }, {
	        name: "CarteBlanche",
	        length: "14",
	        prefixes: "300,301,302,303,304,305,36,38",
	        checkdigit: true
	    }, {
	        name: "AmEx",
	        length: "15",
	        prefixes: "34,37",
	        checkdigit: true
	    }, {
	        name: "Discover",
	        length: "16",
	        prefixes: "6011,650",
	        checkdigit: true
	    }, {
	        name: "JCB",
	        length: "15,16",
	        prefixes: "3,1800,2131",
	        checkdigit: true
	    }, {
	        name: "enRoute",
	        length: "15",
	        prefixes: "2014,2149",
	        checkdigit: true
	    }, {
	        name: "Solo",
	        length: "16,18,19",
	        prefixes: "6334, 6767",
	        checkdigit: true
	    }, {
	        name: "Switch",
	        length: "16,18,19",
	        prefixes: "4903,4905,4911,4936,564182,633110,6333,6759",
	        checkdigit: true
	    }, {
	        name: "Maestro",
	        length: "16,18",
	        prefixes: "5020,6",
	        checkdigit: true
	    }, {
	        name: "VisaElectron",
	        length: "16",
	        prefixes: "417500,4917,4913",
	        checkdigit: true
	    });
	    // Establish card type
		var cardnumber = this;
	    var cardType = -1;
	    for (var i = 0; i < cards.length; i++) {
	        // See if it is this card (ignoring the case of the string)
	        if (cardname.toLowerCase() == cards[i].name.toLowerCase()) {
	            cardType = i;
	            break;
	        }
	    }
	    // If card type not found, report an error
	    if (cardType == -1) { return false; }
	    // Ensure that the user has provided a credit card number
	    if (cardnumber.length == 0) { return false; }
	    // Now remove any spaces from the credit card number
	    var re1 = new RegExp("\\s", "g");
	    cardnumber = cardnumber.replace(re1, "");
	    // Check that the number is numeric
	    var cardNo = cardnumber;
	    var cardexp = new RegExp("^[0-9]{13,19}$");
	    if (!cardexp.exec(cardNo)) { return false; }
	    // Now check the modulus 10 check digit - if required
	    if (cards[cardType].checkdigit) {
	        var checksum = 0; // running checksum total
	        var mychar = ""; // next char to process
	        var j = 1; // takes value of 1 or 2
	        // Process each digit one by one starting at the right
	        var calc;
	        for (i = cardNo.length - 1; i >= 0; i--) {
	            // Extract the next digit and multiply by 1 or 2 on alternative digits.
	            calc = Number(cardNo.charAt(i)) * j;
	            // If the result is in two digits add 1 to the checksum total
	            if (calc > 9) {
	                checksum = checksum + 1;
	                calc = calc - 10;
	            }
	            // Add the units element to the checksum total
	            checksum = checksum + calc;
	            // Switch the value of j
	            if (j == 1) {
	                j = 2;
	            }
	            else {
	                j = 1;
	            }
	                        }
	        // All done - if checksum is divisible by 10, it is a valid modulus 10.
	        // If not, report an error.
	        if (checksum % 10 != 0) { return false; }
	    }
	    // The following are the card-specific checks we undertake.
	    var LengthValid = false;
	    var PrefixValid = false;
	    // We use these for holding the valid lengths and prefixes of a card type
	    var prefix = new Array();
	    var lengths = new Array();
	    // Load an array with the valid prefixes for this card
	    prefix = cards[cardType].prefixes.split(",");
	    // Now see if any of them match what we have in the card number
	    for (i = 0; i < prefix.length; i++) {
	        var exp = new RegExp("^" + prefix[i]);
	        if (exp.test(cardNo)) PrefixValid = true;
	    }
	    // If it isn't a valid prefix there's no point at looking at the length
	    if (!PrefixValid) { return false; }
	    // See if the length is valid for this card
	    lengths = cards[cardType].length.split(",");
	    for (j = 0; j < lengths.length; j++) {
	        if (cardNo.length == lengths[j]) LengthValid = true;
	    }
	    // See if all is OK by seeing if the length was valid. We only check the 
	    // length if all else was hunky dory.
	    if (!LengthValid) { return false; };
	    // The credit card is in the required format.
	    return true;
	}
});

Element.implement({

	isVisible: function() {
		return this.getStyle('display') != 'none';
	},
	
	toggle: function() {
		return this[this.isVisible() ? 'hide' : 'show']();
	},
	
	hide: function() {
		var d;
		try {
			//IE fails here if the element is not in the dom
			d = this.getStyle('display');
		} catch(e){}
		this.store('originalDisplay', d||'block'); 
		this.setStyle('display','none');
		return this;
	},
	
	show: function(display) {
		original = this.retrieve('originalDisplay')?this.retrieve('originalDisplay'):this.get('originalDisplay');
		this.setStyle('display',(display || original || 'block'));
		return this;
	},

	swapClass: function(remove, add) {
		return this.removeClass(remove).addClass(add);
	}
});
function $FS(selector, filter){
	var selectorArray = new Array();
	var form = filter ? $(filter) || $(document.forms[filter]) : false;
	for (var i = 0; i < document.forms.length; i++){
		if (!form || form == document.forms[i]) {
			for (var j = 0; j < document.forms[i].elements.length; j++) {
				if (selector == document.forms[i].elements[j].name) {
					selectorArray.push(document.forms[i].elements[j]);
				}
			}
		}
	}
	return selectorArray;
}

function $F(selector, filter){
	return $FS(selector, filter)[0] || false;
}

/*
* class: MooForm
* version: 1.0
* description: Form Validation
* author: Len.Nguyen
* y!m: elesks
*/

var MooForm = new Class({
	
	Implements: [Events, Options],
	
	options: {	
		// layer
		layer: null,		
		layerType: 'inline',
		layerWidth: 170,
		layerOffset: '0, 0',
		zIndex: 999,
		timeHide: 3000,		
		iframe: null,		
		overlay: null,
		opacity: 0.8,
		fadeEffect: true,
						
		// variables
		mooForm: null,
		mooData: null,		
		timeWait: null,
		errorElement: null,
		delimeter: '|',
				
		// events
		onShow: $empty,
		onHide: $empty,	
		onChange: $empty,	
		onSubmit: $empty
	},

	initialize: function(form, data, options){	
		var that = this;			
		
		// merge options into MooForm options
		that.setOptions(options);
		
		// get form element
		var formObj = $(form || document.forms[form]);
		if (!formObj) {
			that.log(form + ' Form does not exists!');
			return;
		}
		
		// set values into MooForm options 
		that.options.mooForm = formObj;
		that.options.mooData = data;
		if (options.onSubmit) {			
			that.options.onSubmit = options.onSubmit;
		}
		
		that.log(form + ' - instance of MooFrom is starting...');
		
		// init functions
		that.initLayer();
		that.initMooForm();
		
		that.log(form + ' - instance of MooFrom is ready.');
	},
	
	initLayer: function(){
		var that = this;
		
		// get values from MooForm options 	
		var mooForm = that.options.mooForm;
		var layerId = mooForm.id || mooForm.name;
		// create layer
		that.options.layer = new Element('div', {
			'id': layerId + 'Layer',
			'class': 'layer'
		}).inject(document.body);
		
		// create 'x' close button
		var layerButton = new Element('a', {
			'href': 'javascript:void(0);',
			'html': 'x',
			'events': {
				'click': function(e){
					e.stop();
					that.hideLayer();
				}
			}
		}).inject(that.options.layer);
		
		// create the content of layer
		var layerContent = new Element('p').inject(that.options.layer);				
	},
	
	initMooForm: function(){
		var that = this;
		
		// get values from MooForm options 
		var mooForm = that.options.mooForm;
		var mooData = that.options.mooData;
		
		// init validate for elements		
		for (var i = 0; i < mooData.length; i++) {
			for (var j = 0; j < mooForm.elements.length; j++) {
				var element = $(mooForm.elements[j]);				
				if (element.name == mooData[i].name) {
					that.log(mooForm.name + ' - instance of MooFrom is initializing ' + mooData[i].name + ' element');				
					that.initElement(element, mooData[i]);					
				}
			}			
	    }
	    
	    // add event for Submit button
	    mooForm.removeEvents().addEvent('submit', function(e){
			that.log(mooForm.name + ' - instance of MooFrom fired event : onSubmit');
			if (that.isValidMooForm()) {				
				if(that.options.onSubmit){
					that.onSubmit();
					e.stop();
				}
			}
			else{
				e.stop();
			}
	    });
		
		// add event for Reset button
		var resetBtn = mooForm.getElement('input[class=reset]');
		if (resetBtn) {
			resetBtn.addEvent('click', function(e){
				that.log(mooForm.name + ' - instance of MooFrom fired event : onReset');
				e.stop();				
				that.hideLayer();
				that.resetMooForm();
			});
		}
	},
	
	isValidMooForm: function(){
		var that = this;
		
		// get values from MooForm options 
		var mooForm = that.options.mooForm;
		var mooData = that.options.mooData;		
		// validating elements
		for (var i = 0; i < mooData.length; i++) {
			for (var j = 0; j < mooForm.elements.length; j++) {
				var element = $(mooForm.elements[j]);								
				if (element.name == mooData[i].name) {					
					var validated = that.validElement(element);					
					element.store('validated', validated);
					that.log(mooForm.name + ' - instance of MooFrom is validating ' + mooData[i].name + ' element : ' + validated);
					if (!validated) {
						that.showLayer(element);
						return false;
					}				
				}
			}				
	    }		
	    return true;
	},
	
	resetMooForm: function(){
		var that = this;
		
		// get values from MooForm options 	
		var mooForm = that.options.mooForm;
		
		// fire event onReset
		mooForm.reset();				
		that.resetMooFormInEditMode();					
	},
	
	initMooFormInEditMode: function(){
		var that = this;
		
		// get values from MooForm options 
		var mooForm = that.options.mooForm;	
		
		// update init value for elements
		for (var i = 0; i < mooForm.elements.length; i++) {
			var element = $(mooForm.elements[i]);
			switch(element.type){
				case 'text':
				case 'textarea':
				case 'password':
					element.store('initValue', element.get('value').trim());
					break;
			}
			switch(element.type){
				case 'select-one':
					element.store('initValue', element.selectedIndex);	
					break;
				case 'select-multiple':
					element.store('initValue', true);
					for(var j = 0; j < element.options.length; j++){
						if(element.options[j].selected){
							element.store('initValue' + j, j);
						}						
					}					
					break;
			}
			switch(element.type){
				case 'radio':
				case 'checkbox':
					element.store('initValue', element.checked);					
			}			
		}		
	},
	
	resetMooFormInEditMode: function(){
		var that = this;
		
		// get values from MooForm options 
		var mooForm = that.options.mooForm;
		
		// reset mooForm in edit mode
		for (var i = 0; i < mooForm.elements.length; i++) {
			var element = $(mooForm.elements[i]);						
			var initValue = element.retrieve('initValue', false);
			if (initValue) {
				switch(element.type){
					case 'text':
					case 'textarea':
					case 'password':
						element.set('value', initValue);	
						break;
				}
				switch(element.type){
					case 'select-one':
						element.selectedIndex = initValue;
						break;
					case 'select-multiple':						
						for(var j = 0; j < element.options.length; j++){
							var _initValue = element.retrieve('initValue' + j, false);							
							if(_initValue){							
								element.options[j].selected = true;
							}
						}					
						break;
				}
				switch(element.type){
					case 'radio':
					case 'checkbox':
						element.checked = initValue;						
				}
			}
		}
	},
	
	initElement: function(element, data){
		var that = this;
		
		// store values
	    element.store('data', data);
		element.store('validated', true);
		
	    // apply init
	    if ($type(data.init) != false) {	    
			switch(element.type){
				case 'text':
				case 'textarea':
				case 'password':
					element.store('initValue', element.get('value').trim());
					element.set('value', data.init);
					element.addEvents({
						'focus': function(){
			                if (element.get('value').trim() == data.init) {
			                    element.set('value', '');
			                }
						},
						'blur': function(){
			                if (element.get('value').trim() == '') {
			                    element.set('value', data.init);
			                }
			            }
					});
					break;
				case 'select-one':
				case 'select-multiple':
					element.store('initValue', element.selectedIndex);
					element.selectedIndex = Number(data.init);
					break;
				case 'radio':					
				case 'checkbox':
					element.store('initValue', element.checked);
					element.form[element.name][Number(data.init)].checked = true;					
			}
			
	    }
		
		// apply maxLength		
		if ($type(data.maxLength) != false){
			switch(element.type){
				case 'text':
				case 'password':
					element.set('maxLength', data.maxLength);
					break;
				case 'textarea':
					element.addEvent('keypress', function(e){
			            var evt = new Event(e);
			            var code = evt.getCharCode();
			            if (element.get('value').trim().length >= data.maxLength && code != 0) { 
							evt.stop(); 
						}
			        });					
			}
		}
				    
		// apply restrict input characters
	    if ($type(data.restrict) != false){
			switch(element.type){
				case 'text':
				case 'password':					
				case 'textarea':
					element.addEvent('keypress', function(e){
			            var evt = new Event(e);
						var key = evt.getCharKey();
			            var re = new RegExp(data.restrict);
			            if (key != '' && !re.test(key)) { 
							evt.stop(); 
						}
			        });					
			}
		}
		
		// add event for element
		element.addEvents({
			'click': function(e){	
				that.onChange(element);	
				that.hideLayer();
			},
			'keyup': function(e){					
				that.onChange(element);
				that.hideLayer();
			},
			'change': function(e){							
				that.onChange(element);
				that.hideLayer();
			}
		});
		
		// add callback functions
		if ($type(data.events) != false) {
			element.addEvents(data.events);
		}
	},
	
	validElement: function(element){
		var that = this;
		
		// retrieve values
		var data = element.retrieve('data');
		switch ($type(data.valid)) {
	        case 'function':					
				element.store('message', data.message.trim());	
			    return data.valid();
	            break;	
			case 'boolean':				
				element.store('message', data.message.trim());	
				return data.valid;
				break;				
	        case 'string':
				var validate = data.valid.trim();
				var validateArray = validate.split(that.options.delimeter);
				var message = data.message.trim();
				var messageArray = message.split(that.options.delimeter);
				
				// no need to validate
				if(validateArray.length != messageArray.length){
					return true;
				}
				
				// validate elements
				for(var i = 0; i < validateArray.length; i++){					
					if(!that.isValidated(element, validateArray[i])){
						element.store('validated', false);
						element.store('message', messageArray[i]);	
						return false;
					}
				}											
		}	
		return true;
	},
	
	isValidated: function(element, valid){
	
		// retrieve values
		var data = element.retrieve('data');
		
		var value = $pick(element.get('value'), '').trim();
		
		// no need to validate
		var defaultValidated = value == $pick(data.init, '');
		
		switch(valid){			
			case 'range':
				switch(element.type){
					case 'text':
					case 'textarea':
						return defaultValidated || Number(value) >= $pick(data.minimum, 0) && Number(value) <= $pick(data.maximum, 0);					
				}
				break;
			case 'required':
				switch(element.type){
					case 'text':
					case 'textarea':
					case 'password':
					case 'file':
						return value.length > 0 && value != $pick(data.init, '');						
				}								
				break;
			case 'minimum':
				switch(element.type){
					case 'text':
					case 'textarea':
					case 'password':
					case 'file':
						return value.length >= $pick(data.minimum, 0) && value != $pick(data.init, '');						
				}								
				break;
			case 'maximum':
				switch(element.type){
					case 'text':
					case 'textarea':
					case 'password':
					case 'file':
						return value.length <= $pick(data.maximum, 0) && value != $pick(data.init, '');						
				}								
				break;
			case 'number':
				switch(element.type){
					case 'text':
					case 'textarea':
					case 'password':
						return defaultValidated || value.isNumber();							
				}				
				break;
			case 'email':
				switch(element.type){
					case 'text':
					case 'textarea':
						return defaultValidated || value.isEmail();							
				}				
				break;
			case 'emails':
				switch(element.type){
					case 'text':
					case 'textarea':
						return defaultValidated || value.isEmails();							
				}				
				break;
			case 'website':
				switch(element.type){
					case 'text':
					case 'textarea':
						return defaultValidated || value.isWebsite();							
				}				
				break;
			case 'websites':
				switch(element.type){
					case 'text':
					case 'textarea':
						return defaultValidated || value.isWebsites();							
				}				
				break;
			case 'phone':
				switch(element.type){
					case 'text':
					case 'textarea':
						return defaultValidated || value.isPhone();							
				}				
				break;
			case 'date':
				switch(element.type){
					case 'text':
					case 'textarea':
					case 'label':
						return defaultValidated || value.isDate($pick(data.format, 'dmy'));							
				}		
				break;
			case 'future':
				switch(element.type){
					case 'text':
					case 'textarea':
						var other = $(element.form[data.other]);
						var format = $pick(data.format, 'dmy');
						if(!other){
							var date = new Date();
							var _date = date.getDate();
							var _month = date.getMonth() + 1;
							var _year = date.getFullYear();
							switch(format){
								case 'dmy':
									other = new Array(_date, _month, _year).join('/');
									break;
								case 'mdy':
									other = new Array(_month, _date, _year).join('/');
									break;
								case 'ymd':
									other = new Array(_year, _month, _day).join('/');																	
							}
							
						}
						else{
							other = other.get('value').trim();
						}						
						return defaultValidated || value.isCompareDate(format, other) == -1;						
				}
				break;
			case 'compare':
				switch(element.type){
					case 'text':
					case 'textarea':
					case 'password':
						var other = $(element.form[data.other]);
						var format = $pick(data.format, 'dmy');
						if(!other){
							switch($pick(data.type, '')){
								case 'string':
									other = '';		
									break;
								case 'number':
									other = 0;	
									break;
								case 'date':										
									var date = new Date();
									var _date = date.getDate();
									var _month = date.getMonth() + 1;
									var _year = date.getFullYear();
									switch(format){
										case 'dmy':
											other = new Array(_date, _month, _year).join('/');
											break;
										case 'mdy':
											other = new Array(_month, _date, _year).join('/');
											break;
										case 'ymd':
											other = new Array(_year, _month, _day).join('/');																				
									}							
							}														
						}
						else{
							other = other.get('value').trim();
						}	
						switch($pick(data.operator, '=')){
							case '=':
								switch($pick(data.type, '')){
									case 'string':
										return defaultValidated || value == other;												
									case 'number':
										return defaultValidated || Number(value) == Number(other);											
									case 'date':										
										return defaultValidated || value.isCompareDate(format, other) == 0;										
								}								
								break;
							case '!=':
								switch($pick(data.type, '')){
									case 'string':
										return defaultValidated || value != other;												
									case 'number':
										return defaultValidated || Number(value) != Number(other);											
									case 'date':										
										return defaultValidated || value.isCompareDate(format, other) != 0;																			
								}							
								break;
							case '>':
								switch($pick(data.type, '')){
									case 'string':
										return defaultValidated || value > other;												
									case 'number':
										return defaultValidated || Number(value) > Number(other);											
									case 'date':										
										return defaultValidated || value.isCompareDate(format, other) == -1;								
								}								
								break;
							case '>=':
								switch($pick(data.type, '')){
									case 'string':
										return defaultValidated || value >= other;												
									case 'number':
										return defaultValidated || Number(value) >= Number(other);											
									case 'date':										
										return defaultValidated || value.isCompareDate(format, other) == -1 || value.isCompareDate(format, other) == 0;								
								}								
								break;
							case '<':
								switch($pick(data.type, '')){
									case 'string':
										return defaultValidated || value < other;											
									case 'number':
										return defaultValidated || Number(value) < Number(other);										
									case 'date':										
										return defaultValidated || value.isCompareDate(format, other) == 1;									
								}	
								break;
							case '<=':
								switch($pick(data.type, '')){
									case 'string':
										return defaultValidated || value <= other;											
									case 'number':
										return defaultValidated || Number(value) <= Number(other);										
									case 'date':										
										return defaultValidated || value.isCompareDate(format, other) == 1 || value.isCompareDate(format, other) == 0;									
								}									
						}												
				}
				break;			
			case 'file':
				switch(element.type){
					case 'text':
					case 'textarea':
					case 'file':
						switch($pick(data.type, '')){
							case 'image':
								return defaultValidated || value.isImage();									
							case 'video':
								return defaultValidated || value.isVideo();							
							case 'audio':
								return defaultValidated || value.isAudio();							
							case 'other': 
								return defaultValidated || value.test(new RegExp($pick(data.extension, ''), 'i'));							
						}						
				}		
				break;
			case 'checked':
				switch(element.type){
					case 'checkbox':						
					case 'radio':					
						var group = element.form[element.name];						
						if(!group.length){
							return group.checked;
						}
						else{									
							for(var i = 0; i < group.length; i++){								
								if(group[i].checked){
									return true;
								}
							}
						}			
						return false;						
				}		
				break;
			case 'selected':
				switch(element.type){
					case 'select-one':							
						return element.selectedIndex != $pick(data.init, (element.size == 0) ? 0 : -1);						
					case 'select-multiple':							
						return element.selectedIndex != $pick(data.init, -1);											
				}
				break;
			default:
				if($type(eval('data.' + valid)) != false){
					return eval('data.' + valid + '()');
				}				
		}
		return true;
	},
	
	showLayer: function(element){	    
		var that = this;
		
		// retrieve values
		var data = element.retrieve('data');
		
		// get 
		var layer = that.options.layer;
		
		// set values into MooForm options 
		that.options.errorElement = element;
		
		that.onShow(element);
		
		// set error message for layer
		layer.getElement('p').set('html', element.retrieve('message'));
		var layerType = data.layerType || that.options.layerType;		
		var layerOffset = (data.layerOffset) ? data.layerOffset.split(',') : ['0', '0'];
		var layerWidth = data.layerWidth || that.options.layerWidth;				
		switch (layerType) {
			case 'inline':	
				var coords = element.getCoordinates();					
				// show inline layer	
				layer.set('styles', {
					'visibility': 'visible',
					'display': 'block',
					'position': 'absolute',
					'top': coords.top + coords.height + layerOffset[1].toInt() + 'px',
					'left': coords.left + layerOffset[0].toInt() + 'px',
					'width': layerWidth + 'px',
					'zIndex': that.options.zIndex + 3
				}).swapClass('popup', 'inline');
				
				// if IE6 then show Iframe	
				if(Browser.Engine.trident4){
					that.showIframeIE6Fix(layer);
				}
				break;
					
			case 'popup':
			
				// show popup layer								
				var coords = layer.getCoordinates();									
				layer.set('styles', {
					'visibility': 'visible',
					'display': 'block',					
					'position': Browser.Engine.trident4 ? 'absolute' : 'fixed',
					'top': Browser.Engine.trident4 ? window.getScrollTop() : 0 + window.getHeight() / 2 - coords.height / 2 + 'px',
					'left': window.getWidth() / 2 - layerWidth / 2 + 'px',
					'width': layerWidth + 'px',
					'zIndex': that.options.zIndex + 3
				}).swapClass('inline', 'popup');		
				if(Browser.Engine.trident4){	
					window.addEvent('scroll', function(){
						layer.set('styles', {						
							'top': window.getScrollTop() + window.getHeight() / 2 - coords.height / 2 + 'px',
							'left': window.getWidth() / 2 - layerWidth / 2 + 'px'						
						});
					});
				}
				var fadeEffect = $pick(data.fadeEffect, that.options.fadeEffect);
				if(fadeEffect){
					that.showOverlay();
				}			
				
				break;		
			case 'alert':
				
				// show alert
				window.alert(element.retrieve('message'));
				break;			
		}
		
		// focus on error element
		
		switch(element.type){
			case 'file':
				break;
			case 'select-one':
			case 'select-multiple':
				element.focus();
				break;
			default:					
				element.select();
				element.focus();
				break;
		}
		
		// auto hide layer
		$clear(that.options.timeWait);
		that.options.timeWait = that.hideLayer.periodical(that.options.timeHide, that);	
	},
	
	hideLayer: function(){
		var that = this;
		
		$clear(that.options.timeWait);
		
		// get values from MooForm options 
		var layer = that.options.layer;
		var element = that.options.errorElement;
		var data = null;
		if(element){
			data = element.retrieve('data');		
			that.onHide(element);		
		}
		// hide layer
		layer.set('styles', {
			'visibility': 'hidden'			
		});
		
		// if IE6 then hide Iframe	
		if(Browser.Engine.trident4){
			that.hideIframeIE6Fix(layer);
		}
		if(element){
			var fadeEffect = $pick(data.fadeEffect, that.options.fadeEffect);
			if(fadeEffect){
				that.hideOverlay();			
			}
		}
	},
	
	showIframeIE6Fix: function(layer){
		var that = this;
		
		var dim = layer.getCoordinates();
		if (!that.options.iframe) {
			that.options.iframe = new IFrame({
				'id': layer.id + 'Iframe',
				'src': 'javascript:false;',
				'frameBorder': 0,
				'scrolling': 'no',
				'styles': {
					'border': '0 none',
					'margin': 0,
					'padding': 0,
					'zIndex': that.options.zIndex + 2,
					'visibility': 'hidden',
					'display': 'none',
					'position': 'absolute',
					'filter': 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)'
				}
			}).inject(layer, 'before');
		}
		
		that.options.iframe.set('styles', {
			'visibility': 'visible',
			'display': 'block',
			'top': dim.top,
			'left': dim.left,
			'width': dim.width,
			'height': dim.height			
		});
	},
	
	hideIframeIE6Fix: function(layer){
		var that = this;
		
		if (that.options.iframe) {
			that.options.iframe.set('styles', {
				'visibility': 'hidden',
				'display': 'none'
			});
		}
	},
	
	showOverlay: function(){
		var that = this;		
		if(!that.options.overlay){
			that.options.overlay = new IFrame({
				'id': 'overlayIframe',
				'src': 'javascript:false;',
				'frameBorder': 0,
				'scrolling': 'no',
				'styles': {					
					'margin': 0,
					'padding': 0,
					'top': 0,
					'left': 0,
					'width': Math.max(window.getWidth(), document.body.offsetWidth) + 'px',
					'height': Math.max(window.getHeight(), document.body.offsetHeight) + 'px',
					'zIndex': that.options.zIndex + 1,
					'visibility': 'hidden',
					'display': 'none',
					'position': 'absolute',					
					'opacity': that.options.opacity					
				}
			}).inject(document.body);
			
			var _document = $pick(that.options.overlay.contentDocument, that.options.overlay.contentWindow.document);					
			_document.open();
			_document.write('<html><body bgColor="#000"></body></html>');
			_document.close();
				
			new Element('div', {
				'id': 'overlayDiv',
				'styles': {					
					'margin': 0,
					'padding': 0,
					'top': 0,
					'left': 0,
					'width': Math.max(window.getWidth(), document.body.offsetWidth) + 'px',
					'height': Math.max(window.getHeight(), document.body.offsetHeight) + 'px',
					'zIndex': that.options.zIndex + 2,
					'visibility': 'hidden',
					'display': 'none',
					'display': 'none',
					'position': 'absolute',					
					'opacity': that.options.opacity					
				}				
			}).inject(document.body);
			
		}
		
		$('overlayIframe').setStyle('display', 'block');
		$('overlayDiv').setStyle('display', 'block');	
		if(Browser.Engine.trident4){
			$$('select').each(function(element){
				element.setStyle('visibility', 'hidden');
			});
		}		
	},
	
	hideOverlay: function(){
		var that = this;
		if($('overlayIframe') && $('overlayDiv')){
			$('overlayIframe').setStyle('display', 'none');
			$('overlayDiv').setStyle('display', 'none');		
			if(Browser.Engine.trident4){
				$$('select').each(function(element){
					element.setStyle('visibility', 'visible');
				});
				window.removeEvents();
			}
			
		}
	},
	
	onShow: function(element){
		var that = this;
		that.fireEvent('onShow', element);
	},
	
	onHide: function(element){
		var that = this;
		that.fireEvent('onHide', element);
	},
	
	onChange: function(element){
		var that = this;
		that.fireEvent('onChange', element);
	},
				
	onSubmit: function(element){
		var that = this;
		that.fireEvent('onSubmit', element);
	},

	log: function(text, args){
		if (window.console){
			console.log(text.substitute(args || {}));
		}
	}	
});
