Error.prototype.show = function(label){
	alert('file: ' + this.fileName + '\n'+
		'line : ' + this.lineNumber+'\n'+
		'message : '+this.message+'\n'+
		'number : '+this.number+'\n'+
		'description : '+this.description+'\n'+
		'label : '+label);
}
//fom -> Form Object Model
//Suffixes in id of elements
var sfx = {
	BUTTON_MASK : '@buttonMask',
	MSG_HOLDER  : '@error_msg',
	NOTE_HOLDER : '@send_msg',
	SIGN 		: '@sign',
	MASK		: '@mask',
	CONTENT		: '@content'
}

var URL = "/sendmail.php";
//time when message is active
var ALIVE_TIME = 20;

var msg = {
	ru : { 
		BAD_MAIL_ : "Неверный email ",
		ERROR_IN_FIELD_ : "Ошибка в поле ",
		
		STRING_ : "Должна быть строка длиной минимум ",
		ALPHA_STRING_ : "Строка может содержать только буквы, числа, " +
				"символы '-','_' и ее длина минимум ",
		INT_ : "Должно быть целое число ",
		FLOAT_ : "Должно быть вещественное число ",
		
		_MIN_ : " минимум ",
		_MAX_ : " максимум ",
		_SYMB : " симв",
		
		DATE_FORMAT : "Дата должна соответствовать формату ДД.ММ.ГГГГ",
		MESSAGE_SENT : "Ваши данные успешно отправлены"
	},
	en : { 
		BAD_MAIL_ : "Incorrect email ",
		ERROR_IN_FIELD_ : "Error in field: ",
		
		STRING_ : "String length must be no less than ",
		ALPHA_STRING_ : "Строка может содержать только буквы, числа, " +
				"символы '-','_' и ее длина минимум ",
		INT_ : "Должно быть целое число ",
		FLOAT_ : "Должно быть вещественное число ",
		
		_MIN_ : " minimum ",
		_MAX_ : " maximum ",
		_SYMB : " chars",
		
		DATE_FORMAT : "Date must be in format YYYY-MM-DD",
		MESSAGE_SENT : "Your request is successfully sent" 
	}
}

var RE = {
	ru: {
		date : /^([\d]{1,2})\.([\d]{1,2})\.([\d]{4})$/
	},
	en: {
		date : /^([\d]{4})-([\d]{1,2})-([\d]{1,2})$/
	},
	alphastring : /^[а-яА-Я\s\w_-]+$/,
	email : /^(\w\.?)+\w@([\w-]+\.)+[\w-]{2,4}$/,
	'int' : /^[+-]?[\d]+$/,
	'float' : /^[+-]?[\d]+[\.]?[\d]*$/
}

var isIE = !!window.ActiveX;
var formValidator;


Event.observe(window, 'load', function(){
	if(typeof _form != 'undefined'){
		formValidator = new FormValidator();
		for(var i=0; i < _form.length; i++){
			formValidator.parse(_form[i]);
		}
	}
});

FormValidator = Class.create();
//img src of signs
FormValidator.SIGN_OK = "/img/icon-cheked.gif";
FormValidator.SIGN_ERROR = "/img/icon-error.gif";
FormValidator.CLASS = "form-block";
FormValidator.CLASS_OK = "form-block ok";
FormValidator.CLASS_ERROR = "form-block err";

FormValidator.prototype = {
	initialize : function(){},
	parse : function(fom){
		try{
		if(fom){
			var field = $(fom[0].id);
			if(field){
				//add onsubmit function
				var that = this;
				var _id = (fom.dom = field.form).id;
				var notifier = new Notifier($(_id + sfx.MSG_HOLDER),$(_id + sfx.NOTE_HOLDER));

				fom.dom.onsubmit = function(e){
					var b = 1, r, f;
					for(var i = 0; i < fom.length; i++){
						f = fom[i].dom;
						r = f.validate['submit'](f.value, f.required, f.min, f.max);
						if(r.message){
							notifier.showMessage(f.id, msg[LANG].ERROR_IN_FIELD_ + f.caption + " : " + r.message);
							//that.showSign(f.signDom, FormValidator.SIGN_ERROR);
							f.parentNode.className = FormValidator.CLASS_ERROR;
							b = 0;
						}else{
							notifier.hideMessage(f.id);
							//that.showSign(f.signDom, FormValidator.SIGN_OK);
							f.parentNode.className = FormValidator.CLASS_OK;
						}
					}
					if(b){
						that.submit(fom, notifier);
					}
					e?e.preventDefault():(window.event.returnValue = false);
				};
				Event.observe(fom.dom['cancel'],'click', this.onFormCancel = function(event, leaveNotifiers){
					fom.dom.reset();
					var fff = fom;
					if(!leaveNotifiers) notifier.hideAll();
					for(var i = 0; i < fom.length; i++){
						//$(fom[i].id+sfx.SIGN).hide();
						fom[i].dom.parentNode.className = FormValidator.CLASS;	
					}
				}, false);
				
				for(var i = 0; i < fom.length; i++){
					
					field = fom[i].dom = $(fom[i].id);
					field.caption = fom[i].caption;
					field.min = fom[i].minVal;
					field.max = fom[i].maxVal;
					field.required = fom[i].required;
					field.signDom = $(fom[i].id+sfx.SIGN);
					field.validate = ValidatorFactory.createValidator(fom[i].type);
					
					if(isIE){
						field.onfocus = InputEvents.focus;
					}
					
					field.onkeyup = function(e){
						if ((e || window.event).keyCode == 9) return;
						if(this.value.strip().length){
							var r = this.validate['event'](this.value, this.min, this.max);
							if(r.message && r.message != '0'){
								//that.showSign(this.signDom, FormValidator.SIGN_ERROR);
								this.parentNode.className = FormValidator.CLASS_ERROR;
							}else{
								//that.showSign(this.signDom, FormValidator.SIGN_OK);
								this.parentNode.className = FormValidator.CLASS_OK;
							}
						}else{
							//this.signDom.hide();
							this.parentNode.className = FormValidator.CLASS;
						}
					};
					field.onblur = function(e){
						if(this.value.strip().length){
							var r = this.validate['event'](this.value, this.min, this.max);
							if(r.message && r.message != '0'){
								notifier.showMessage(this.id, msg[LANG].ERROR_IN_FIELD_ + this.caption + " : " + r.message);
								//that.showSign(this.signDom, FormValidator.SIGN_ERROR);
								this.parentNode.className = FormValidator.CLASS_ERROR;
								return;
							}
							notifier.hideMessage(this.id);
							//that.showSign(this.signDom, FormValidator.SIGN_OK);
							this.parentNode.className = FormValidator.CLASS_OK;
						}else{
							notifier.hideMessage(this.id);
							//this.signDom.hide();
							this.parentNode.className = FormValidator.CLASS;
						}
					};
				}
			
			}
		}
		}catch(ee){ee.show && ee.show('parse');}
	},
	submit : function(fom, notifier){
		try{
		var form = $(fom.dom.id);
		var mask = $(form.id + sfx.MASK), b;
		var self = this;
		mask.style.width = Element.getWidth(form) +"px";

		if(b = $(form.id + sfx.CONTENT)){
			b = b.lastChild;
			while(b.nodeType == 3 || b.style.display.toLowerCase() == 'none'){
				b = b.previousSibling;
			}
			mask.style.height = b.offsetTop + b.offsetHeight +'px';
//			mask.style.display = 'block';
		}
		$(fom.dom.id + sfx.BUTTON_MASK).show();
		//Send ajax request
		var request = new Ajax.Request(
			URL,
			{
//				method : 'POST',
//				parameters : Form.serialize(fom.dom) + '&url=' + escape(window.location) + '&lang=' + LANG ,
//				onSuccess : function(req){
//						console.log(eval("(" + req.responseText + ")"));
//						var r = eval("(" + req.responseText + ")");
//						if(r.status){
//							notifier.showNote(fom.dom.id, msg[LANG].MESSAGE_SENT);
//						}else{
//							notifier.showMessage(fom.dom.id, r.error.code + ' : ' + r.error.message);
//						}
//						$(fom.dom.id + sfx.BUTTON_MASK).hide();
//						mask.style.display = 'none';
//						//clear error or success message in TIME seconds
////						var executer = PeriodicalExecuter(function(){
////							fom.dom.onfocus = hideAllNotes();
////						}, ALIVE_TIME);
//				},
//				onFailure : function(req){
//					mask.style.display = 'none';
//					$(fom.dom.id + sfx.BUTTON_MASK).hide();
//					notifier.showMessage(fom.dom.id, req.responseText);
//				}
				method : 'POST',
				parameters : Form.serialize(fom.dom) + '&lang=' + LANG + '&url=' + escape(window.location) ,
				onComplete: function(req){
					if(req.readyState == 4){
						if(req.status == 200){
							var r = eval('('+req.responseText+')');
							if(r.status){
								notifier.showNote(fom.dom.id, msg[LANG].MESSAGE_SENT);
								self.onFormCancel(null, true);
//								self.hideAllNotes();
//								fom.dom.onfocus = hideAllNotes();
							}else{
								notifier.showMessage(fom.dom.id, r.error.code + ' : ' + r.error.message);
//								self.hideAllMessages();
//								fom.dom.onfocus = hideAllMessages();
							}
						}else{
							notifier.showMessage(fom.dom.id, req.responseText);
						}
						$(fom.dom.id + sfx.BUTTON_MASK).hide();
						mask.style.display = 'none';
					}
				}
			}
		); 
		}catch(err){(err.show && err.show('submit')) || alert('submit');}
	},
	showSign : function(sign, type){
		try{
		sign.src = type;
		sign.show();
		}catch(err){alert('showSign');}
	},
	onFormCancel: null
};
/** Show error messages and notes 
 *  */

Notifier = Class.create();
Notifier.prototype = {
	initialize : function(alertHolder, notificationHolder){
		try{
		this._alertHolder = alertHolder;
		this._noteHolder = notificationHolder;
		(this._messages = {}).length = 0;
		(this._notes = {}).length = 0;
		}catch(err){alert('Notifier constructor')}
	},
	showMessage : function(invokerId, message){
		try{
		if(this._messages[invokerId+'@_error']){
			this._messages[invokerId+'@_error'].innerHTML = message;
		}else{
			var span = document.createElement('div');
			span.innerHTML = message;
			this._messages[invokerId+'@_error'] = span;
			this._alertHolder.appendChild(span);
			if(this._messages.length++ == 0){
				this._alertHolder.show();
			}
		}
		}catch(err){alert('showMessage')}
	},
	hideMessage : function(invokerId){
		try{
		if(this._messages[invokerId+'@_error']){
			if(--this._messages.length == 0){
				this._alertHolder.hide();
			}
			this._alertHolder.removeChild(this._messages[invokerId+'@_error']);
			delete this._messages[invokerId+'@_error'];
		}
		}catch(err){alert('hideMessage')}
	},
	hideAllMessages : function(){
		try{
		this._alertHolder.hide().innerHTML = '';
		(this._messages = {}).length = 0;
		}catch(err){alert('hideAllMessages')}
	},
	
	showNote : function(invokerId, message){
		try{
		if(this._notes[invokerId+'@send_msg']){
			this._notes[invokerId+'@send_msg'].innerHTML = message;
		}else{
			var span = document.createElement('div');
			span.innerHTML = message;
			this._notes[invokerId+'@send_msg'] = span;
			this._noteHolder.appendChild(span);
			if(this._notes.length++ == 0){
				this._noteHolder.show();
			}
		}		
		}catch(err){alert('showNote')}
	},
	hideNote : function(invokerId){
		try{
		if(this._notes[invokerId+'@send_msg']){
			if(--this._notes.length == 0){
				this._noteHolder.hide();
			}
			this._noteHolder.removeChild(this._notes[invokerId+'@send_msg']);
			delete this._notes[invokerId+'@send_msg'];
		}
		}catch(err){alert('hideNode')}
	},
	hideAllNotes : function(){
		try{
		this._noteHolder.hide().innerHTML = "";
		(this._notes = {}).length = 0;
		}catch(err){alert('hideAllNotes')}
	},
	
	hideAll : function(){
		try{
		this.hideAllMessages();
		this.hideAllNotes();
		}catch(err){alert('hideAll')}
	}
};
/** Validator factory 
 * four types supported - (type) : (rules)
 * string : min, max
 * int	  : min, max, /^[\d]+$/
 * float  : min, max, /^[+-]?[\d]+[\.]?[\d]*$/
 * mail   : /^[\w\._]+@[\w\.]+\.[\w]{2,4}$/ 
 * * * * * * * 
 * submit method has "r" parameter - required flag
 * */
(ValidatorFactory = {}).validators = {
	date : {
		submit : function(v, r){
			try{
			if(r || v.strip().length){
				var d = RE[LANG]['date'].exec(v.strip());
				if(!d || d[1] > 31 || d[1] < 1 || d[2] > 12 || d[2] < 1 || d[3] > 2100 || d[3] < 2001){
					return {message:msg[LANG].DATE_FORMAT}
				}				
			}
			return {'message':0};
			}catch(err){alert('date submit')}
		},
		event : function(v){
			try{
			var d = RE[LANG]['date'].exec(v.strip());
			}catch(err){err.show && err.show('date event')}
			if(!d || d[1] > 31 || d[1] < 1 || d[2] > 12 || d[2] < 1 || d[3] > 2100 || d[3] < 2001){
				return {message:msg[LANG].DATE_FORMAT}
			}		
			return {'message':0};
		}
	},	
	alphastring : {
		submit : function(v, r, min, max){
			v = v.strip();
			if(r || v.length){
				if(!RE['alphastring'].test(v) || (max && v.length > max) || (min && v.length < min)){
					return {message:msg[LANG].ALPHA_STRING_ + (min || 1) 
							+ ((max && (msg[LANG]._MAX_ + max)) || "")
							+ msg[LANG]._SYMB};
				}
			}
			return {'message':0};
		},
		event : function(v, min, max){
			if(!RE['alphastring'].test(v) || (max && v.length > max) || (min && v.length < min)){
				return {message:msg[LANG].ALPHA_STRING_ + (min || 1) 
							+ ((max && (msg[LANG]._MAX_ + max)) || "") 
							+ msg[LANG]._SYMB};
			}
			return {'message':0};
		}
	},	
	'string' : {
		submit : function(v, r, min, max){
			try{
			v = v.strip();
			if(r || v.length){
				if(!v.length || (min && v.length < min) || (max && v.length > max)){
					return {message:msg[LANG].STRING_ + (min || 1) 
							+ ((max && (msg[LANG]._MAX_ + max)) || "") 
							+ msg[LANG]._SYMB};
				}
			}
			return {'message':0};
			}catch(err){ alert('On string submit error occured: ' + err); }
		},
		event : function(v, min, max){
			try{
			if((min && v.length < min) || (max && v.length > max)){
				return {message:msg[LANG].STRING_ + (min || 1) 
						+ ((max && (msg[LANG]._MAX_ + max)) || "") 
						+ msg[LANG]._SYMB};
			}
			return {'message':0};
			}catch(err){alert('string event')}
		}
	},	
	text : {
		'submit' : function(v, r, min, max){
			try{
			v = v.strip();
			if(r || v.length){
				if(!v.length || (min && v.length < min) || (max && v.length > max)){
					return {message:msg[LANG].STRING_ + (min || 1) 
							+ ((max && (msg[LANG]._MAX_ + max)) || "") 
							+ msg[LANG]._SYMB};
				}					
			}
			return {'message':0};
			}catch(err){alert('text submit')}
		},
		event : function(v, min, max){
			try{
			if((min && v.length < min) || (max && v.length > max)){
				return {message:msg[LANG].STRING_ + (min || 1) 
						+ ((max && (msg[LANG]._MAX_ + max)) || "") 
						+ msg[LANG]._SYMB};
			}
			return {'message':0};
			}catch(err){alert('text event')}
		}
	},	
	'int' : {
		submit : function(v, r, min, max){
			try{
			v = v.strip();
			if(r || v.length){
				if(!RE['int'].test(v) || (max && v > max) || (min && v < min)){
					return {message:msg[LANG].INT_ 
							+ ((min && (msg[LANG]._MIN_ + min)) || "")
							+ ((max && (msg[LANG]._MAX_ + max)) || "")};
				}
			}
			return {'message':0};
			}catch(err){alert('int submit')}
		},
		event : function(v, min, max){
			try{
			if(!RE['int'].test(v) || (max && v > max) || (min && v < min)){
				return {message:msg[LANG].INT_ 
						+ ((min && (msg[LANG]._MIN_ + min)) || "") 
						+ (max && (msg[LANG]._MAX_ + max)) || ""};
			}
			return {'message':0};
			}catch(err){alert('int event')}
		}
	},	
	'float' : {
		submit : function(v, r, min, max){
			try{
			if(r || v.strip().length){
				if(!(RE['float']).test(v) || (max && v > max) || (min && v < min)){
					return {message:msg[LANG].FLOAT_ 
							+ ((min && (msg[LANG]._MIN_ + min)) || "") 
							+ ((max && (msg[LANG]._MAX_ + max)) || "")};
				}
			}
			return {'message':0};
			}catch(err){alert('float submit')}
		},
		event : function(v, min, max){
			try{
			if(!(RE['float']).test(v) || (max && v > max) || (min && v < min)){
				return {message:msg[LANG].FLOAT_ 
						+ ((min && (msg[LANG]._MIN_ + min) || "")) 
						+ ((max && (msg[LANG]._MAX_ + max)) || "")};
			}
			return {message:0};
			}catch(err){alert('float event')}		
		}			
	},
	email : {
		submit : function(v, r, min, max){
			try{
			v = v.strip();
			if(r || v.length){
				if(!RE['email'].test(v)){
					return {message:msg[LANG].BAD_MAIL_};
				}
			}
			return {'message':0};
			}catch(err){alert('mail submit')}
		},
		event : function(v, min, max){
			try{
			if(!RE['email'].test(v)){
				return {message:msg[LANG].BAD_MAIL_};
			}
			return {'message':0};
			}catch(err){alert('mail event')}			
		}
	}		
};

ValidatorFactory.createValidator = function(type){
	return ValidatorFactory.validators[type];
};

ValidatorFactory.addValidator = function(type, validator){
	try{
	if(validator && validator['submit'] && validator['event']){
		ValidatorFactory.validators[type] = validator;
	}
	}catch(err){alert('addValidator')}
};

ValidatorFactory.removeValidator = function(type){
	try{
	if(ValidatorFactory.validators[type]){
		delete ValidatorFactory.validators[type];
	}
	}catch(err){alert('removeValidator')}
};

//for ie 
(InputEvents = {}).focus = function(e){
	this.className = 'input-txt-focus';
};
InputEvents.blur = function(){
	this.className = 'input-txt'
};
InputEvents.mouseover = function(){
	this.className = 'input-txt-hover';
};
InputEvents.mouseout = function(){
	this.className = 'input-txt'
};
