//- formChecker v0.3
//- JavaScript v1.1
//- Tested on: PC: ns3, ns4, gecko, ie4, ie5
//- Author: Pieter Van Waeyenberge - pvwaey@yahoo.com
//- Credits: Claude Iyi Dogan: Email validation

//// to do:
// * make prototypes
// * v1.0 add data type" stext = strict text, options: name, type, nice name, (excape st5ing, min, manx,)
// * validate argument input for check ?
// * reporting: cat 1 string and add in to report ?
// * make sorting poosible (orser of check's)
// * Clean up document.forms ... realForm

function container(mMaxOptions)
{
	this.params = new Array();
	this.maxOptions = mMaxOptions + 2; //-2 is min args
}
function form()
{
	//-Methods
	this.check = storeElement;
	this.valid = validateForm;
	//-Kids
	this.text = new container(2);
	this.num = new container(2);
	this.date = new container(2);
	this.email = new container(0);
	this.pwd = new container(0);
	this.radio = new container(0);
	this.select = new container(3);
	this.report = new Array();
	//- Properties
	this.pwd.checking = false;
	this.realForm = new Object();
	this.lang = 'en';
	this.date.delimiter = '/';
	this.reportIndex = 0;
}
function storeElement(mElementName, mType, mNiceName)
{
	var debugContext = ' in: ' + this.name + '.check(' + mElementName + ', ' + mType + ', ' + mNiceName + ')';
	var lArgLen = arguments.length;
	var paramKey;

	if (lArgLen < 3) {alert('Too few arguments' + debugContext);}
	else 
	{//-Store params
		if (mType == 'text'
			|| mType == 'num'
			|| mType == 'date'
			|| mType == 'email'
			|| mType == 'pwd'
			|| mType == 'radio'
			|| mType == 'select')
		{
			paramKey = this[mType].params.length;
			this[mType].params[paramKey] = new Array(mElementName, mNiceName);

			for (var i = 2; i < this[mType].maxOptions; i++) {if (lArgLen > (i + 1)) {this[mType].params[paramKey][i] = arguments[i + 1];}}
			if (mType == 'date' && lArgLen > 4) {this.date.delimiter = arguments[4];}
		}
		else {alert('\'Type\' invalid' + debugContext);}
	}
}

//- V A L I D A T I O N
function validateForm()
{

	this.realForm = document.forms[this.name];

	//- set language
	var lang = trim(this.lang);
	if (lang == 'en') {lang = 0;}
	else if (lang == 'fr') {lang = 1;}
	else if (lang == 'es') {lang = 2;}
	else if (lang == 'de') {lang = 3;}
	else if (lang == 'nl') {lang = 4;}
	else {lang = 0; alert('Language not supported in :' + this.name + '.\nDefault : \'en\'');}

	var f = document.forms[this.name];
	var ev;
	var myE, r;
	var i, l, a, b;
	var reportMsg='';
	var el, fev, fe;

	//- Text
	el = this.text.params.length;
	for (i = 0; i < el; i++)
	{
		myE = this.text.params[i];
		l = myE.length;

		if (f[myE[0]])
		{
			fev = trim(f[myE[0]].value);
			if (fev == '') {this.report[this.reportIndex++] = '- ' + myE[1] + ' (Required)\n';}
			else if ((l > 2 && fev.length < myE[2]) || (l > 3 && fev.length > myE[3]))
			{
				this.report[this.reportIndex++] = '- ' + myE[1] + ' (Min ' + myE[2];
				if (l > 3) {this.report[this.reportIndex - 1] += ', Max ' + myE[3];}
				this.report[this.reportIndex - 1] += ' charachters)\n';
			}
		}
		else {reportMsg='foo';alert('Invalid form element reference in:\n' + this.name + '.check(' + myE/*.toString()*/ + ')');}
	}
	//- Num //dfoo: revize
	el = this.num.params.length;
	for (i = 0; i < el; i++)
	{
		myE = this.num.params[i];
		l = myE.length;

		if (f[myE[0]])
		{
			fev = trim(f[myE[0]].value);
	
			if (izNaN(fev)) {this.report[this.reportIndex++] = '- ' + myE[1] + ' (Number required)\n';}
			else if ((l > 2 && parseInt(fev) < parseInt(myE[2])) || (l > 3 && parseInt(fev) > parseInt(myE[3])))
			{
				this.report[this.reportIndex++] = '- ' + myE[1] + ' (Min' + myE[2];
				if (l > 3) {this.report[this.reportIndex - 1] += ', Max' + myE[3];}
				this.report[this.reportIndex - 1] += ')\n';
			}
		}
		else {reportMsg='foo';alert('Invalid form element reference in:\n' + this.name + '.check(' + myE/*.toString()*/ + ')');}
	}
	//- Date
	el = this.date.params.length;
	for (i = 0; i < el; i++)
	{
		myE = this.date.params[i];
		l = myE.length;

		if (f[myE[0]])
		{
			fev = trim(f[myE[0]].value);
			
//			qlert(fev, myE[2])
//			qlert(isValidDate(fev,myE[2]))

			if (fev == '' || l < 2 || !isValidDate(fev,myE[2]))
			{
				this.report[this.reportIndex++] = '- ' + myE[1] + ' (Format: \'';
				if (l > 2) {this.report[this.reportIndex - 1] += myE[2];}
				else {this.report[this.reportIndex - 1] += 'mdy';}
				this.report[this.reportIndex - 1] += '\')\n';
			}
			else /* replace delimiter */
			{
				var delim, newDateVal = '';
				if (l > 3) {delim = myE[3];}
				else {delim = this.date.delimiter;}

				for (var j = 0; j < fev.length; j++)
				{
					if (izNaN(fev.charAt(j))) {newDateVal += delim;}
					else {newDateVal += fev.charAt(j);}
				}
				f[myE[0]].value = newDateVal;
			}
		}
		else {reportMsg='foo';alert('Invalid form element reference in:\n' + this.name + '.check(' + myE/*.toString()*/ + ')');}
	}
	//- Email
	el = this.email.params.length;
	for (i = 0; i < el; i++)
	{
		myE = this.email.params[i];

		if (f[myE[0]])
		{
			fev = trim(f[myE[0]].value);
			if (fev == '') {this.report[this.reportIndex++] = '- ' + myE[1] + ' (Required)\n';}
			else if (!isValidEmail(fev)) {this.report[this.reportIndex++] = '- ' + myE[1] + ' (Invalid)\n';}
//			if (!(fev != '' && isValidEmail(fev))) {this.report[this.reportIndex++] = '- ' + myE[1] + ' (Invalid)\n';}
		}
		else {reportMsg='foo';alert('Invalid form element reference in:\n' + this.name + '.check(' + myE/*.toString()*/ + ')');}
	}
	//- Radio
	el = this.radio.params.length;
	for (i = 0; i < el; i++)
	{
		myE = this.radio.params[i];
		if (f[myE[0]]) {fe = f[myE[0]]; if (!radioChecked(fe)) {this.report[this.reportIndex++] = '- ' + myE[1] + ' (Nothing checked)\n';}}
		else {reportMsg='foo';alert('Invalid form element reference in:\n' + this.name + '.check(' + myE/*.toString()*/ + ')');}
	}
	//- Password
	el = this.pwd.params.length;
	for (i = 0; i < el; i++)
	{
		myE = this.pwd.params[i];
		if (f[myE[0]])
		{
			fev = trim(f[myE[0]].value);
			if (fev == '') {this.report[this.reportIndex++] = '- ' + myE[1] + ' (Required)\n';}
			else
			{
				if (!this.pwd.checking) {this.pwd.params[i][2] = fev;}
			}
//			else if (!dubbleCheckStrOK(fev)) {this.report[this.reportIndex++] = '- ' + myE[1] + ' (Confirmation doesn\'t match.)\n';}
		}
		else {reportMsg='foo';alert('Invalid form element reference in:\n' + this.name + '.check(' + myE/*.toString()*/ + ')');}
	}
	//- Select
	el = this.select.params.length;
	for (i = 0; i < el; i++)
	{
		myE = this.select.params[i];
		l = myE.length;
		if (f[myE[0]])
		{
			fe = f[myE[0]];
			var sis = getNrOfSeletedItems(fe);
			if (sis == 0 || (l > 2 && sis < myE[2]) || (l > 3 && sis < myE[3]))
			{
				this.report[this.reportIndex++] = '- ' + myE[1];
				if (l > 2)
				{
					this.report[this.reportIndex - 1] += ' (Min '+ myE[2];
					if (l > 3) {this.report[this.reportIndex - 1] += ', max ' + myE[3];}
					this.report[this.reportIndex - 1] += ' items)';
				}
				else {this.report[this.reportIndex - 1] += ' (Required)';}
				this.report[this.reportIndex - 1] += '\n';
			}
		}
		else {reportMsg='foo';alert('Invalid form element reference in:\n' + this.name + '.check(' + myE/*.toString()*/ + ')');}
	}

	//- Report
	for (i = 0; i < this.report.length; i ++) {
		if (!isEmpty(this.report[i])) {reportMsg += this.report[i]}
	}
	if (reportMsg != '') {
		if (reportMsg != 'foo' && reportMsg.indexOf("foo") == -1) {
			this.report.length = 0;
			alert('Some form fields have not been filled in properly:\n\n' + reportMsg);
		}
		this.pwd.checking = false;
		return false;
	}
	if (this.pwd.params.length > 0 && this.pwd.checking == false)
	{
		//reconcept validate .. valid ?
		repMsg = 'Please *re-type* the following and submit again:\n';
		for (i = 0; i < this.pwd.params.length; i++)
		{
			repMsg += '\n - ' + this.pwd.params[i][1];
			this.realForm[this.pwd.params[i][0]].value = '';
		}
		this.pwd.checking = true;
		alert(repMsg);
		return false;
	}
	repMsg = '';
	for (i = 0; i < this.pwd.params.length; i++)
	{//trim ?
//			qlert(this.pwd.params[i][2], this.realForm[this.pwd.params[i][0]].value)
		if (this.pwd.params[i][2] != this.realForm[this.pwd.params[i][0]].value)
		{
			repMsg += '\n - ' + this.pwd.params[i][1];
			this.realForm[this.pwd.params[i][0]].value = '';
		}
	}
	if (repMsg != '')
	{
		alert('*No correct match*, please re-type:\n' + repMsg);
		return false;
	}
	return true;
}

//- L I B
//- Text
function isLongEnough(mStr, mMin) {return (trim(mStr).length >= mMin);}
function isNotTooLong(mStr, mMax) {return (trim(mStr).length <= mMax);}
function isEmpty(mStr) {return ((mStr == null) || (mStr == '') || (isBlank(mStr)));}
function isBlank(mStr) {for (var i=0; i<mStr.length; i++) {var lChar = mStr.charAt(i); if ((lChar != ' ') && (lChar != '\n') && (lChar != '\t')) {return false;}} return true;}
function trim(s) {var j=s.length; while (s.charAt(j-1) == ' ' || s.charAt(j-1) == '\t' || s.charAt(j-1) == '\n') {j--;}	if (j != 0) {var i=0; while (s.charAt(i) == ' ' || s.charAt(i) == '\t' || s.charAt(i) == '\n') {i++;} return s.substring(i,j);} return '';}
//- Num
function isBigEnough(mNum, mMin) {return (trim(mNum) >= mMin);}
function isNotTooBig(mNum, mMax) {return (trim(mNum) <= mMax);}
//- Date
function isValidDate(d, f)
{
	var md = trim(d);
	if (md.length > 4)
	{
		var dp = new Array();
		//- Get presumable date parts delimiter
		var dlm = ((izNaN(md.charAt(1))) ? md.charAt(1) : md.charAt(2));
		//- Set date format keys
		var dy, mn, yr;
		if (arguments.length == 2)
		{
			yr = f.indexOf('y');
			mn = f.indexOf('m');
			dy = f.indexOf('d');
			if (yr == -1 || mn == -1 || dy == -1)
			{//redundant check
				alert('Date format not supported in ' + this.name);
				return false;
			}
		}
		else {yr=2; mn=0; dy=1;}
		//- Validate; Delimiter may not be an Number
		if (izNaN(dlm))
		{
			dp = md.split(dlm);
			
			dp[mn] = trimLeadingZeros(dp[mn]);
			dp[dy] = trimLeadingZeros(dp[dy]);

			if ( dp.length != 3 || izNaN(dp[yr]) || izNaN(dp[mn]) || izNaN(dp[dy]) ) {return false;}
			return ( isMonth(parseInt(dp[mn])) && isDay( parseInt( dp[yr]), parseInt(dp[mn]), parseInt(dp[dy]) ) );

		}
	}
	return false;
}
function isMonth(m) {return (m > 0 && m < 13);}
function isDay(y,m,d) {return (d > 0 && d <= getDaysInMonth(y,m));}
function getDaysInMonth(y,m)
{
	var feb = (((y % 4)==0) && ((y % 100)!=0) || ((y % 400)==0)) ? 29 : 28;
	var daysInMonth = new Array(/*j*/'31',/*f*/feb,/*m*/'31',/*a*/'30',/*m*/'31',/*j*/'30',/*j*/'31',/*a*/'31',/*s*/'30',/*o*/'31',/*n*/'30',/*d*/'31');
	return daysInMonth[m-1];
}
//- Email
function cleanEmail(mStr)
{
	var newStr = '';
	for (var i = 0; i<mStr.length; i++)
	{
		var ch = mStr.charAt(i).toLowerCase();
		if ((ch >= "a" && ch <= "z") || (ch == "@") || (ch == ".") || (ch == "_") || (ch == "-") || (ch >= "0" && ch <= "9")) {newStr += ch;}
	}
	return newStr;
}
function isValidEmail(mStr)
{
	if ((mStr.indexOf('@@') == -1) && (mStr.indexOf('..') == -1) && (mStr.indexOf('.@') == -1) && (mStr.indexOf('@.') == -1))
	{
		var at = mStr.indexOf('@',1);
		if (at != -1)
		{
			var dot = mStr.indexOf('.', at+3);
			if (dot != -1)
			{
				dot = mStr.lastIndexOf('.');
				if (dot+2 < mStr.length) {if (mStr == cleanEmail(mStr)) {return true;}}
			}
		}
	}
	return false;
}
//- Password
function dubbleCheckStrOK(mStr)
{
	return (prompt("As a confirmation,\nplease type your password again.","") == mStr);
}
//- Radio
function radioChecked(mRadio) {for (i=0; i< mRadio.length; i++) {if (mRadio[i].checked) {return true;}} return false;}
//- Select
function getNrOfSeletedItems(so) {var j = 0; for (var i = ((isEmpty(so[0].value)) ? 1 : 0); i < so.length; i++) {if (so[i].selected) {j++;}} return j;}

//- T R A N S L A T I O N S

//- M I S C
function izNaN(s) {
	for (var i=0; i < s.length; i++) {
		if ( isNaN(parseInt(s.charAt(i))) ) {return true;}
	}
	return false;
}
function trimLeadingZeros(s) {
	var i = 0;
	while (s.charAt(i) == '0' && i < (s.length - 1)) {i++;}
	return s.substring(i, s.length)
}

//-debug
function qlert()
{
	var foo = '';
	for (i=0; i<arguments.length; i++) {foo+='-\''+arguments[i]+'\'\n';}
	alert(foo);
}