﻿
var char_lat_lo = 'abcdefghijklmnopqrstuvwxyz';
var char_lat_hi = char_lat_lo.toUpperCase();
var char_lat = char_lat_lo + char_lat_hi;
var char_rus_lo = 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя';
var char_rus_hi = char_rus_lo.toUpperCase();
var char_rus = char_rus_lo + char_rus_hi;
var char_digits = '1234567890';
var char_quotes = '"\'`';
var char_spaces = ' \t\n\r';
var char_signs_basic = '+-*/.,=%()';
var char_signs = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~';
var char_names = char_lat + char_rus + char_spaces + '_\'&.,';
var char_email = char_lat + char_digits + '@._-';
var char_phone = char_digits + '()[] +-';
var char_number = char_digits + '+- .,eE';
var char_integer = char_digits + '+- ';
var char_url = char_lat + char_digits + '_-';

var _check_err_empty = 0, _check_err_maxlen = 1, _check_err_invalid = 2;
var _check_err_atleast = 3, _check_err_inset = 4, _check_err_minlen = 5, _check_err_eqlen = 6;

function validateChars(str, chars)
{	var n;
	if (!str.length) return false; 	// Additional code!!! -- 24.11.2008 
	for(n = 0; n < str.length; n++)
		if(chars.indexOf(str.charAt(n)) < 0) return false;
	return true;
}

function trimString(ss)
{
	if(!ss) return ss;
	var n, spac = " \t\n\r";
	ss = ss.toString();
	for(n = 0; n < ss.length; n++)
		if(spac.indexOf(ss.charAt(n)) < 0) break;
	ss = ss.substring(n, ss.length);
	for(n = ss.length - 1; n >= 0; n--)
		if(spac.indexOf(ss.charAt(n)) < 0) break;
	ss = ss.substring(0, n + 1);
	return ss;
}


function DataChecker(sLang)
{
	this.err_count = 0;
	this.fld_count = 0;
	this.form = null;
	this.err = new Array();
	this.fld = new Array();
	this.lang = "en";
	this.dfmt = 'mm/dd/yy';
	this.err_templates = null;
	
	this.bild = FormChecker_Bild;
	this.add = FormChecker_Add;
	this.check = FormChecker_Check;
	this.message = FormChecker_Message;
	this.element = FormChecker_Element;
	this.field = FormChecker_Field;
	
	{
		if( sLang ) this.lang = sLang.toLowerCase();
		
		if( this.lang == "ru" )
		{
			this.err_templates = new Array(
				'Поле "--fieldDesc--" не может быть пустым',
				'Максимальным количеством символов в поле "--fieldDesc--" является --fieldMax--',
				'Поле "--fieldDesc--" заполнено некорректно',
				'В разделе "--fieldDesc--" должно быть выбрано хотя бы одно значение',
				'В разделе "--fieldDesc--" должно быть выбрано от 1 до --fieldLen-- значений',
				'Минимальным количеством символов в поле "--fieldDesc--" является --fieldMin--',
				'Количество символов в поле "--fieldDesc--" должно быть равно --fieldMax--'
			);
			
			this.dfmt = 'dd.mm.yy';
		}
		else {
			this.err_templates = new Array(
				'"--fieldDesc--" cannot be empty',
				'Maximum length of "--fieldDesc--" cannot be greater than --fieldMax--',
				'--fieldDesc-- is invalid',
				'"--fieldDesc--" section must have at least 1 value selected',
				'"--fieldDesc--" section must have 1 to --fieldLen-- values selected',
				'Minimum length of "--fieldDesc--" cannot be less than --fieldMin--',
				'The amount of characters in a field "--fieldDesc--" should be equal --fieldMin--'
			);
		
			this.dfmt = 'mm/dd/yy';
		}
	
	}
}

function DataChecker_Error(errfld,errtxt)
{
	this.fld = errfld;  // поле в котором возникла ошибка
	this.text = errtxt; // текст сообщения об ошибке
}

function FormChecker_Add(cfg_str)
{
	this.fld[this.fld_count++] = new DataChecker_Field(this,cfg_str);
}

function FormChecker_Bild(form_obj, cfg_line)
{
	if(cfg_line.substr(cfg_line.length-2,2)==';;')
		cfg_line=cfg_line.substr(0,cfg_line.length-2);

	if( !form_obj ) return false;
	if(typeof(form_obj) == 'string') this.form = eval("document." + form_obj);
	else this.form = form_obj
	if(!cfg_line) return false;
	
	var m;
	var cfg = cfg_line.split(';;');
	for(m = 0; m < cfg.length; m++)	this.add(cfg[m]);

	return true;
}

function FormChecker_Check()
{
	var n;
	for(n = 0; n < this.fld_count; n++)
		if( this.fld[n].isused )
				this.fld[n].check();
		
	return (this.err_count == 0);
}

function FormChecker_Message(msg_delimeter)
{
	var n, ret = "";
	if(!msg_delimeter) msg_delimeter = "\n";
	for(n = 0; n < this.err_count; n++)
	{
		if( n > 0 ) ret += msg_delimeter;
		ret +=  this.err[n].text;
	}
	return ret;
}

function FormChecker_Element(index)
{
	if(!index) index = 0;
	if(index < this.err_count)
	{
		var obj = this.form.elements[this.err[index].fld.name];
		if(obj.type) return obj; 
		else return obj[0];
	}
	return null;
}

function FormChecker_Field(index)
{
	var m;
	if( typeof(index) == 'string' )
	{
		for( m=0; m < this.fld_count; m++ )
			if( this.fld[m].name == index)
				return this.fld[m];
	}
	else if( index < this.fld_count)
	{
		return this.fld[index];
	}
	return null;
}


function DataChecker_Field(oParent,sDetail)
{
	this.name;	// имя поля на форме
	this.desc;	// название поля
	this.attrs; // тип поля, регулярка, функция
	this.req= false;	// необходимость заполнения
	this.isused= true;  // проводить проверку
	this.maxlen = Number.MAX_VALUE; // максимальная длинна текста
	this.minlen = 0; // минимальная длинна
	this.focus = null; // поле на которое устанавливается фокус
	this.type = null; // тип поля
	this.value = null; // значение поля после проверки
	this.collection = null; // коллекция полей формы
	this.element = null; // поле формы
	this.fld_set = null; // случай набора полей
	this.parent = oParent; // ссылка на DataChecker
	this.iserror = false; // обнаружена ошибка
	

	this.check = FieldChecker_Check;
	this.error = FieldChecker_Error;
	
	{
		var cfg_detail = sDetail.split("::");
		this.name = cfg_detail[0];
        this.fld_set = this.name.split(",");
		this.desc = cfg_detail[1];
		this.attrs = cfg_detail[2];
		this.req = (cfg_detail[3] == 'req'); 
		
		if( cfg_detail[4] )
		{
			var cfg_size = cfg_detail[4].split(",");
			if( cfg_size.length > 1 )
			{
				this.minlen = parseInt(cfg_size[0]);
				this.maxlen = parseInt(cfg_size[1]);
			}
			else if( cfg_size.length == 1 )
			{
				this.maxlen = parseInt(cfg_size[0]);
			}
		}
	}
}


function FieldChecker_Error(errType)
{
	this.iserror = true;
	if( arguments.length == 0 ) errType = _check_err_invalid;
	var errtxt = ( typeof(errType) == 'string' ) ? errType : new String(this.parent.err_templates[errType]);
	errtxt = errtxt.replace('--fieldDesc--', this.desc);
	errtxt = errtxt.replace('--fieldMax--', this.maxlen);
	errtxt = errtxt.replace('--fieldMin--', this.minlen);
	this.parent.err[this.parent.err_count++] = new DataChecker_Error(this,errtxt);		
}

function FieldChecker_Check()
{
	var m;	
	var char_test;
	var form_obj = this.parent.form;
	
    if (!( this.fld_set.length-1))
	{
		if(!form_obj.elements[this.name])
		{ 
			this.error('INTERNAL ERROR. There is no field "' + this.name + '"'); 
			return;
		}
		if(form_obj.elements[this.name].type)
		{
			this.element = form_obj.elements[this.name];
			this.focus = this.element;
			this.type = this.element.type;
		}
		else
		{
	        this.collection = form_obj.elements[this.name];
			this.focus = this.collection[0];
			this.type = this.focus.type;
		}
		
		// Чтение данных

	    this.value = ''; 
		switch(this.type)
		{
			case 'radio': 
	            if(this.collection)
					for (oo = 0; oo < this.collection.length; oo++)
					{
						if(this.collection[oo].checked) this.value += this.collection[oo].value + ', ';
					}
					else
						if(this.element.checked) this.value += this.element.value + ', ';
				break;

			case 'checkbox':
				if(this.collection)
					for (oo = 0; oo < this.collection.length; oo++)
					{
						if(this.collection[oo].checked) this.value += this.collection[oo].value + ', ';
					}
				else
					if(this.element.checked) this.value += this.element.value + ', ';
				break;
			
			case 'select-one': 
				if(this.element.selectedIndex >= 0)
					this.value = this.element.options[this.element.selectedIndex].value;
				break;
				
			case 'select-multiple':
				this.value = '';
				this.collection = this.element.options;
				for (oo = 0; oo < this.collection.length; oo++)
				{
					var el = this.collection[oo].value;
					if(this.collection[oo].selected && el) this.value += el + ', ';
				}
				break;
				
			default:
				this.value = this.element.value;
		}

		// Проверка размера данных

		var val = trimString(this.value);
		
		// TEST	alert(this.name + "=" + this.value);
		// alert(this.name + "=" +this.minlen+","+this.maxlen);
		if(val) 
		{
			if( this.maxlen == this.minlen && this.value.length != this.maxlen )
			{
				this.error(_check_err_eqlen);
				return;
			}
			if(this.value.length > this.maxlen)
			{
				this.error(_check_err_maxlen);
				return;
			}
			else if(this.value.length < this.minlen)
			{
				this.error(_check_err_minlen);
				return;
			}
		}	

		if(this.req && val == '')
		{
			if( this.attrs == 'file' )
			{
				this.name = this.name.substring(3);
				val = form_obj.elements[this.name].value;
			}
				
			if( val == '' )
			{
				this.error(_check_err_empty);
				return;
			}
		}

		// Проверка формата

		if(val == '') 
			return; 

		switch(this.attrs)
		{	
			
			case 'email':
				{
					//alert ("1 datacheck.js");
					//var re = /^([\w-.]+@)((\w|-){2,}\.)+(\w{2,4})$/ig;
					//var re = /^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/ig; // 22 dec 2008
					//var re = /^[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/ig;
					var re = /^[a-zA-Z0-9]+([a-zA-Z0-9\._-]+)*@[a-zA-Z]+([a-zA-Z0-9\._-]+)*\.[a-zA-Z]{2,6}$/i;
					if (re.test(this.value) == false)
					{
						this.error();
					}
				}
				break;
			case 'emailLatin':
				{
					var re = /^[a-zA-Z0-9]+([a-zA-Z0-9\._-]+)*@[a-zA-Z0-9]+([a-zA-Z0-9\._-]+)*\.[a-zA-Z]{2,6}$/i;
					if (re.test(this.value) == false)
					{
						this.error();
					}
				}
				break;
			case 'url':
			
			case 'http':
				{
					var url = new URL();
					var ret = url.read(this.value);
					
					if( ret == 0 && this.attrs == 'http' )
						ret = url.protocols('http,https');
						
					if( ret != 0 ) this.error( url.error(ret,this.parent.lang) );
				}
				break;
				
			case 'phone':
			case 'fax':
				if( ! validateChars(this.value, char_phone) ) this.error();
				break;
				
			case 'number':
				if( ! validateChars(this.value, char_number) ) this.error();
				break;
				
			case 'integer':
				if( ! validateChars(this.value, char_integer)) this.error();
				break;
				
			case 'string':
				if( ! validateChars(this.value, char_names + char_digits + char_signs_basic)) this.error();
				break;
				
			case 'file':
				break;
				
			case 'date':
				var dfmt = this.parent.dfmt + ' [hh:mm]';
				if(check_date(this.value, dfmt) != 0) this.error();
				break;
				
	        case 'longdate':
				var dfmt = this.parent.dfmt + ' [hh:mm]';
				if(check_date(this.value, dfmt, 'long') != 0) this.error();
				break;
				
	        case 'shortdate':
				var dfmt = this.parent.dfmt + ' [hh:mm]';
				if(check_date(this.value, dfmt, 'short') != 0) this.error();
				break;
				
			case 'datetime':
				var dfmt = this.parent.dfmt + ' hh:mm';
				if(check_date(this.value, dfmt) != 0) this.error();
				break;
				
			default:
				if(this.attrs.substring(0, 1) == '+')
				{
					var m;
					var attrs_sub = this.attrs.split('+');
					
					for(m = 1, char_test = ''; m < attrs_sub.length; m++)
						if(attrs_sub[m].substring(0, 1) == '#')
							char_test += String.fromCharCode(parseInt(attrs_sub[m].substring(1, attrs_sub[m].length)));
						else if(eval('char_' + attrs_sub[m]))
							char_test += eval('char_' + attrs_sub[m]);
							
					if( ! validateChars(this.value, char_test) ) this.error();
				}
				else if(this.attrs.substring(0, 1) == '/')
				{
					var re = eval(this.attrs);
					if( !re.test(this.value) ) this.error();
				}
				else if(this.attrs.substring(0, 1) == '=')
				{
					eval( this.attrs.substring(1)+"(this)" );
				}
				else if(this.attrs != "any") 
				{
					this.error('INTERNAL ERROR. Invalid type format for "' + this.name + '". Founded "' + this.attrs + '"'); 
				}
				break;
		}
    }
    else
    {
		var _any_checked = 0;
		for(i=0;i<this.fld_set.length;i++)
		{ 
			if(form_obj.elements[this.fld_set[i]].length)
				if(form_obj.elements[this.fld_set[i]][0].type.toLowerCase().indexOf('text')<0)
				{ 
					for(j=0;j<form_obj.elements[this.fld_set[i]].length;j++) 	
						if(form_obj.elements[this.fld_set[i]][j].checked) _any_checked++;
				}
				else
				{
					if(form_obj.elements[this.fld_set[i]][0].value.length)
						_any_checked++;
				}
			else
			    if(form_obj.elements[this.fld_set[i]].type.toLowerCase().indexOf('text')<0)
				{ 
					if(form_obj.elements[this.fld_set[i]].checked) _any_checked++;
				}
				else
				{
					if(form_obj.elements[this.fld_set[i]].value.length)
						_any_checked++;
		        }
        }
        
        
		if(_any_checked < 1 || _any_checked > this.maxlen)
		{
			if(this.maxlen==Number.MAX_VALUE) this.error(_check_err_atleast);
			else this.error(_check_err_inset);
		}
		
		if(this.attrs != "any" ) 
		{
			for( m=0; m < this.fld_set.length; m++)
			{
				char_test = this.fld_set[m]+'::'+this.desc+'::'+this.attrs;
				var f = new DataChecker_Field(this.parent,char_test);
				f.check();
			}
		}
		
	}

		

}

