Form.Item.Validator = function (expression, message) {
	if (isFunction(expression)) {
		this.expression = expression;
	} else {
		this.expression = new Function('value', 'item', 'return (' + expression + ')');
	}
	this.message = message;
}

Form.Item.Validator.prototype.isValid = function (item) {
	return this.expression(item.value, item);
}



Validators = {};

Validators.isEmpty = function (val) {
	//var rx = new RegExp('^\\s*$', 'ig');
	//return ! isset(val) || rx.test(val);
	return ! isset(val) || ! val.trim();
}

Validators.isNotEmpty = function (val) {
	return ! Validators.isEmpty(val);
}

Validators.isSelected = function (val) {
	return val != '' /*&& val != '0'*/;
}

/**
* Available formats:
*
*	1. Just string
*
*		Validators.isString(value)
*
*	2. String with RegExp
*
*		Validators.isString(value, new RegExp('^[0-9a-f]+$', 'i'))
*
*	3. String with max length
*
*		Validators.isString(value, 50)
*
*	4. String with min and max length
*
*		Validators.isString(value, 4, 10)
*		Validators.isString(value, 10, 4)
*
*	5. String with different length and RegExp combinations
*
*		Validators.isString(value, 25, /^[XYZ]+$/)
*		Validators.isString(value, /^[XYZ]+$/, 25)
*		Validators.isString(value, 5, 15, /^[abc]+$/)
*		Validators.isString(value, /^[01]+$/, 4, 8)
*/
Validators.isString = function (val, expr1, expr2, expr3) {
	// Params testing
	if (val === '') {
		return true;
	}
	if (! isset(expr1) && ! isset(expr2) && ! isset(expr3)) {
		return true;
	}
	// RX testing
	expr = null;
	if (expr1 instanceof RegExp) {
		expr = expr1;
	} else if (expr2 instanceof RegExp) {
		expr = expr2;
	} else if (expr3 instanceof RegExp) {
		expr = expr3;
	}
	valid = true;
	if (expr !== null) {
		valid &= expr.test(val);
	}
	// MIN/MAX testing
	min = Number.POSITIVE_INFINITY; max = Number.NEGATIVE_INFINITY;
	if (isNumber(expr1)) {
		if (expr1 < min) {
			min = expr1;
		}
		if (expr1 > max) {
			max = expr1;
		}
	}
	if (isNumber(expr2)) {
		if (expr2 < min) {
			min = expr2;
		}
		if (expr2 > max) {
			max = expr2;
		}
	}
	if (isNumber(expr3)) {
		if (expr3 < min) {
			min = expr3;
		}
		if (expr3 > max) {
			max = expr3;
		}
	}
	if (max !== Number.NEGATIVE_INFINITY) {
		valid &= (val.length <= max);
		if (min !== max) {
			valid &= (val.length >= min);
		}
	}
	return Boolean(valid);
}

Validators.isStringVarName = function (val, expr1, expr2) {
	return Validators.isString(val, new RegExp('^[a-z0-9_]*$', 'i'), expr1, expr2);
}

Validators.isStringAlphas = function (val, expr1, expr2) {
	if (System.Language === 'lt') {
		expr = new RegExp('^[a-ząčęėį�šųūž]*$', 'i');
	} else if (System.Language === 'ru') {
		expr = new RegExp('^[абвгдеёжзийклмнопрст�уфхцчшщъы�ьэюя]*$', 'i');
	} else {
		expr = new RegExp('^[a-z]*$', 'i');
	}
	return Validators.isString(val, expr, expr1, expr2);
}

Validators.isStringAlphaSpaces = function (val, expr1, expr2) {
	if (System.Language === 'lt') {
		expr = new RegExp('^[a-ząčęėį�šųūž\\s]*$', 'i');
	} else if (System.Language === 'ru') {
		expr = new RegExp('^[абвгдеёжзийклмнопр�ст�уфхцчшщ�ъы�ьэюя\\s]*$', 'i');
	} else {
		expr = new RegExp('^[a-z\\s]*$', 'i');
	}
	return Validators.isString(val, expr, expr1, expr2);
}

Validators.isStringLatinAlphaSpaces = function (val, expr1, expr2) {
	return Validators.isString(val, new RegExp('^[a-z\\s]*$', 'i'), expr1, expr2);
}

Validators.isStringNumbers = function (val, expr1, expr2) {
	return Validators.isString(val, new RegExp('^[0-9]*$', 'i'), expr1, expr2);
}

Validators.isStringAlphaNumbers = function (val, expr1, expr2) {
	if (System.Language === 'lt') {
		expr = new RegExp('^[0-9a-ząčęėį�šųūž]*$', 'i');
	} else if (System.Language === 'ru') {
		expr = new RegExp('^[0-9абвгдеёжзийклмнопр�ст�уфхцчшщ�ъы�ьэюя]*$', 'i');
	} else {
		expr = new RegExp('^[0-9a-z]*$', 'i');
	}
	return Validators.isString(val, expr, expr1, expr2);
}

Validators.isStringLatinAlphaNumbers = function (val, expr1, expr2) {
	return Validators.isString(val, new RegExp('^[0-9a-z]*$', 'i'), expr1, expr2);
}

//
// .int(value, 50)        // max
// .int(value, 50, true)  // max
// .int(value, 50, false) // min
// .int(value, 10, 50)    // min <= x <= max
//

Validators.isNumber = function (val, expr1, expr2) {
	number = Number(val);
	if (isNaN(number)) {
		return false;
	}

	if (! isset(expr1) && ! isset(expr2)) {
		return true;
	}

	// MIN/MAX testing
	min = Number.POSITIVE_INFINITY; max = Number.NEGATIVE_INFINITY;
	if (isNumber(expr1)) {
		if (expr1 < min) {
			min = expr1;
		}
		if (expr1 > max) {
			max = expr1;
		}
	}
	if (isNumber(expr2)) {
		if (expr2 < min) {
			min = expr2;
		}
		if (expr2 > max) {
			max = expr2;
		}
	}

	// MIN/MAX swich testing
	swc = null;
	if (isBool(expr1) && swc === null) {
		swc = expr1;
	}
	if (isBool(expr2) && swc === null) {
		swc = expr2;
	}
	swc = Boolean(swc);

	valid = true;
	if (max !== Number.NEGATIVE_INFINITY) {
		valid &= (min === max)
		? (swc ? (number <= max) : (number >= min))
		: ((number <= max) && (number >= min));
	}
	return Boolean(valid);
}

Validators.isNumeric = Validators.isNumber;

Validators.isInt = function (val, expr1, expr2) {
	if (! Validators.isNumber(val, expr1, expr2)) {
		return false;
	}
	number = Number(val);
	return (number == Math.ceil(number));
}

Validators.isInteger = Validators.isInt;

Validators.isFloat = Validators.isNumber;
Validators.isDouble = Validators.isFloat;

Validators.isDate = function (val) {
	if (val == '') {
		return true;
	}
	var s = val.split('-', 3), x, d = new Date(s[0], s[1] - 1, s[2]);
	s = d.getFullYear() + '-';
	x = d.getMonth() + 1;
	if (x < 10) {
		x = '0' + x;
	}
	s += x + '-';
	x = d.getDate();
	if (x < 10) {
		x = '0' + x;
	}
	s += x;
	return s == val;
}

Validators.isTime = function (val) {
	if (val == '') {
		return true;
	}
	var rx = new RegExp('^(([01]?\\d|2[0-3]):[0-5]\\d)|24:00$');
	return rx.test(val);
}

Validators.isUnlimitedTime = function (val) {
	if (val == '') {
		return true;
	}
	var rx = new RegExp('^\\d+:[0-5]\\d$');
	return rx.test(val);
}

Validators.isDateTime = function (val) {
	var dt = val.split(new RegExp('[ T]', 'i'), 2);
	// Whether no date...
	if (dt[0] === '') {
		return dt.length === 1 || dt[1] === '';
	}
	// Whether have date but no time...
	if (dt.length === 1 || dt[1] === '') {
		return false;
	}
	// Whether have date and time...
	return Boolean(Validators.isDate(dt[0]) && Validators.isTime(dt[1]));
}


Validators.isDateTimeEmpty = function (val) {
	var dt = val.split(new RegExp('[ tT]'), 2);
	return Validators.isEmpty(dt[0]) || Validators.isEmpty(dt[1]);
}

Validators.isDateTimeNotEmpty = function (val) {
	var dt = val.split(new RegExp('[ tT]'), 2);
	return ! Validators.isEmpty(dt[0]) && ! Validators.isEmpty(dt[1]);
}


Validators.isDateTimeDateEmpty = function (val) {
	var dt = val.split(new RegExp('[ tT]'), 2);
	return Validators.isEmpty(dt[0]);
}

Validators.isDateTimeDateNotEmpty = function (val) {
	var dt = val.split(new RegExp('[ tT]'), 2);
	return ! Validators.isEmpty(dt[0]);
}


Validators.isDateTimeTimeEmpty = function (val) {
	var dt = val.split(new RegExp('[ tT]'), 2);
	return Validators.isEmpty(dt[1]);
}

Validators.isDateTimeTimeNotEmpty = function (val) {
	var dt = val.split(new RegExp('[ tT]'), 2);
	return ! Validators.isEmpty(dt[1]);
}

//Validators.Custom.FirstLevelDomains='(';
//Validators.Custom.FirstLevelDomains+='a[c-gil-oq-uwz]|';		//ac,ad,ae,af,ag,ai,al,am,an,ao,aq,ar,as,at,au,aw,az
//Validators.Custom.FirstLevelDomains+='b[a-bd-jm-or-tvwyz]|';	//ba,bb,bd,be,bf,bg,bh,bi,bj,bm,bn,bo,br,bs,bt,bv,bw,by,bz
//Validators.Custom.FirstLevelDomains+='c[acdf-ik-orsuvx-z]|';	//ca,cc,cd,cf,cg,ch,ci,ck,cl,cm,cn,co,cr,cs,cu,cv,cz,cy,cz
//Validators.Custom.FirstLevelDomains+='d[ejkmoz]|';			//de,dj,dk,dm,do,dz
//Validators.Custom.FirstLevelDomains+='e[ceghr-u]|';			//ec,ee,eg,eh,er,es,et,eu
//Validators.Custom.FirstLevelDomains+='f[i-kmorx]|';			//fi,fj,fk,fm,fo,fr,fx
//Validators.Custom.FirstLevelDomains+='g[abd-ilmnp-uwy]|';		//ga,gb,gd,ge,gf,gg,gh,gi,gl,gm,gn,gp,gq,gr,gs,gt,gu,gw,gy
//Validators.Custom.FirstLevelDomains+='h[kmnrtu]|';			//hk,hm,hn,hr,ht,hu
//Validators.Custom.FirstLevelDomains+='i[delm-oq-t]|';			//id,ie,il,im,in,io,iq,ir,is,it
//Validators.Custom.FirstLevelDomains+='j[emop]|';				//je,jm,jo,jp
//Validators.Custom.FirstLevelDomains+='k[eg-imnprwyz]|';		//ke,kg,kh,ki,km,kn,kp,kr,kw,ky,kz
//Validators.Custom.FirstLevelDomains+='l[a-cikr-vy]|';			//la,lb,lc,li,lk,lr,ls,lt,lu,lv,ly
//Validators.Custom.FirstLevelDomains+='m[acdghk-z]|';			//ma,mc,md,mg,mh,mk,ml,mm,mn,mo,mp,mq,mr,ms,mt,mu,mv,mw,mx,my,mz
//Validators.Custom.FirstLevelDomains+='n[ace-giloprtuz]|';		//na,nc,ne,nf,ng,ni,nl,no,np,nr,nt,nu,nz
//Validators.Custom.FirstLevelDomains+='om|';					//om
//Validators.Custom.FirstLevelDomains+='p[ae-hk-nrtwy]|';		//pa,pe,pf,pg,ph,pk,pl,pm,pn,pr,pt,pw,py
//Validators.Custom.FirstLevelDomains+='qa|';					//qa
//Validators.Custom.FirstLevelDomains+='r[eouw]|';				//re,ro,ru,rw
//Validators.Custom.FirstLevelDomains+='s[a-eg-ort-vyz]|';		//sa,sb,sc,sd,se,sg,sh,si,sj,sk,sl,sm,sn,so,sr,st,su,sv,sy,sz
//Validators.Custom.FirstLevelDomains+='t[cdf-hjkm-prtvwz]|';	//tc,td,tf,tg,th,tj,tk,tm,tn,to,tp,tr,tt,tv,tx,tz
//Validators.Custom.FirstLevelDomains+='u[agkmsyz]|';			//ua,ug,uk,um,us,uy,uz
//Validators.Custom.FirstLevelDomains+='v[aceginu]|';			//va,vc,ve,vg,vy,vn,vu
//Validators.Custom.FirstLevelDomains+='w[fs]|';				//wf,ws
//Validators.Custom.FirstLevelDomains+='y[etu]|';				//ye,yt,yu
//Validators.Custom.FirstLevelDomains+='z[admrw]|';				//za,zd,zm,zr,zw
//Validators.Custom.FirstLevelDomains+='aero|';					//aero
//Validators.Custom.FirstLevelDomains+='biz|';					//biz
//Validators.Custom.FirstLevelDomains+='co(m|op)|';				//com,coop
//Validators.Custom.FirstLevelDomains+='edu|';					//edu
//Validators.Custom.FirstLevelDomains+='gov|';					//gov
//Validators.Custom.FirstLevelDomains+='in(fo|t)|';				//info,int
//Validators.Custom.FirstLevelDomains+='m(il|useum)|';			//mil,museum
//Validators.Custom.FirstLevelDomains+='n(ame|et)|';			//name,net
//Validators.Custom.FirstLevelDomains+='org|';					//org
//Validators.Custom.FirstLevelDomains+='pro';					//pro
//Validators.Custom.FirstLevelDomains+=')';

Validators.isEmail = function (val) {
//
//	// Params testing
//	if (typeof item !== 'object') return false;
//	if (item.value === '') return true;
//
//	var rx = '^(.+)@(.+)$';
//
//	// The following pattern is used to check if the entered e-mail address
//	// fits the user@domain format. It also is used to separate the username
//	// from the domain.
//	var emailPat=new RegExp('^(.+)@(.+)$');
//
//	// The following string represents the pattern for matching all special
//	// characters. We don't want to allow special characters in the address.
//	// These characters include ( ) < > @ , ; : \ ' . [ ]
//	var specialChars='\\(\\)<>@,;:\\\\\\\'\\.\\[\\]';
//
//	// The following string represents the range of characters allowed in a
//	// username or domainname.  It really states which chars aren't allowed.
//	// var validChars='\\[^\\s' + specialChars + '\\]';
//	// var validChars='[^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]';
//	var validChars='\\w';
//
//	// The following pattern applies if the 'user' is a quoted string (in
//	// which case, there are no rules about which characters are allowed
//	// and which aren't; anything goes). E.g. 'jiminy cricket'@disney.com
//	// is a legal e-mail address.
//	var quotedUser='(\'[^\']*\')';
//
//	// The following pattern applies for domains that are IP addresses,
//	// rather than symbolic names.  E.g. joe@[123.124.233.4] is a legal
//	// e-mail address. NOTE: The square brackets are required.
//	// var ipDomainPat=new RegExp('^\\[(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\]$');
//	// var ipDomainPat=new RegExp('^\\[([1-9]|1\\d)?\\d|2([0-4]\\d|5[0-5])(\\.([1-9]|1\\d)?\\d|2([0-4]\\d|5[0-5])){3}\\]$');
//	// \[([1-9]|1\d)?\d|2([0-4]\d|5[0-5])(\.([1-9]|1\d)?\d|2([0-4]\d|5[0-5])){3}\]
//
//	// The following string represents an atom (basically a series of
//	// non-special characters.)
//	// var atom=validChars + '+';
//	var atom='[^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]+';
//
//	// The following string represents one word in the typical username.
//	// For example, in john.doe@somewhere.com, john and doe are words.
//	// Basically, a word is either an atom or quoted string.
//	// var word='(' + atom + '|' + quotedUser + ')';
//	var word='([^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]+|(\'[^\']*\'))';
//
//	// The following pattern describes the structure of the user
//	// var userPat=new RegExp('^' + word + '(\\.' + word + ')*$');
//	var userPat=new RegExp('^([^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]+|(\'[^\']*\'))(\\.([^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]+|(\'[^\']*\')))*$');
//
//
//
//	// The following pattern describes the structure of a normal symbolic
//	// domain, as opposed to ipDomainPat, shown above.
//	// var domainPat=new RegExp('^' + atom + '(\\.' + atom +')*$');
//	// var domainPat=new RegExp('^[^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]+(\\.[^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]+)*$');
//	var domainPat=new RegExp('^[^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]+(\\.[^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]+)*$');
//
//	var emailPat=new RegExp('^(.+)@(.+)$');
//
//	(\'[^\']*\'|\w+([\.\-]\w+)*)@(\w+(\.\w+)|\[\d{1,3}(\.\d{1,3}){3}\])
//
//	// Finally, let's start trying to figure out if the supplied address is valid.
//
//	// Begin with the coarse pattern to simply break up user@domain into
//	// different pieces that are easy to analyze.
//	var matchArray=item.value.match(emailPat);
//	if (null===matchArray)
//	{
//		// Too many/few @'s or something; basically, this address doesn't
//		// even fit the general mould of a valid e-mail address.
//		// alert('Email address seems incorrect (check @ and .'s)')
//		return false;
//	}
//	var user=matchArray[1];
//	var domain=matchArray[2];
//
//	// See if 'user' is valid
//	if (null===user.match(userPat))
//	{
//		// The username doesn't seem to be valid.
//		return false;
//	}
//
//	// if the e-mail address is at an IP address (as opposed to a symbolic
//	// host name) make sure the IP address is valid.
//	var IPArray=domain.match(ipDomainPat);
//	if (null!==IPArray)
//	{
//		// this is an IP address
//		for (var i=1; i<=4; i++)
//		{
//			if (IPArray[i]>255)
//			{
//				// Destination IP address is invalid!
//				return false;
//			}
//		}
//		return true;
//	}
//
//	// Domain is symbolic name
//	var domainArray=domain.match(domainPat);
//	if (null===domainArray)
//	{
//		// The domain name doesn't seem to be valid.
//		return false;
//	}
//
//	// domain name seems valid, but now make sure that it ends in a
//	// three-letter word (like com, edu, gov) or a two-letter word,
//	// representing country (uk, nl), and that there's a hostname preceding
//	// the domain or country.
//
//	// Now we need to break up the domain to get a count of how many atoms
//	// it consists of.
//	var atomPat=new RegExp(atom,'g');
//	var domArr=domain.match(atomPat);
//	var len=domArr.length;
//	var country=new RegExp(Validators.Custom.FirstLevelDomains);
//	if (null==domArr[domArr.length-1].match(country))
//	{
//		// The address must end with valid first level domain
//		return false;
//	}
//
//	// Make sure there's a host name preceding the domain.
//	if (len<2)
//	{
//		// This address is missing a hostname!
//		return false;
//	}
//
//	// If we've gotten this far, everything's valid!
//	return true;
//

	return Validators.isString(val, new RegExp('^\\s*(\'[^\']*\'|\\w+([\\.\\-]\\w+)*)@(\\w+([\\.\\-]\\w+)*|\\[\\d{1,3}(\\.\\d{1,3}){3}\\])\\s*$', 'i'));
}

Validators.isURL = function (val) {
//
//	var expression1 = new RegExp('index\\.php\\?','i');
//
//	var expression2 = new RegExp('^(((ht|f)tp(s?))\://)?(www.|[a-zA-Z].)[a-zA-Z0-9\-\.]+\.(com|edu|gov|mil|net|org|biz|info|name|museum|us|ca|uk)(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\;\?\\\\+&%\$#\=~_\-]+))*$', 'i');
//
//	var protocol = '';
//	var servername =  '(\w+\.)*'+Validators.Custom.FirstLevelDomains+' (www.|[a-zA-Z].)[a-zA-Z0-9\-\.]+\.(com|edu|gov|mil|net|org|biz|info|name|museum|us|ca|uk)';
//
//	// Validators.Custom.FirstLevelDomains
//

	return Validators.isString(val, new RegExp('^\\s*(((ht|f)tp(s?))\\://)?\\w+(\\.\\w+)+(\\:\\d{1,5})?(/.*)?\\s*$','i'));
}

Validators.isPhone = function (val) {
	return Validators.isString(val, new RegExp('^\\s*((\\+\\d+(\\s*-?\\s*\\d+)*|[08])\\s*)?(\\(\\d+(\\s*-?\\s*\\d+)*\\)\\s*)?\\d+(\\s*-?\\s*\\d+)*\\s*$', 'i'));
}
