/**********************************
Javascript Form Validation - Usage:
===================================

1) Each form should state the onsubmit event handler, eg:
<form name="form_fanclub" method="post" action="http://contest.omy.sg/cgi-bin/cnt/quiz6.pl" onsubmit="return submitForm();">

2) Each form should have its own customised "validateForm()" function and form name (identical to <form> name), eg:
var gFrmName = "form_fanclub";
function validateForm() {
	if (!getTFValue(gFrmName,"fname")) 										addError("Name: Please enter your name");
	if (!getTFValue(gFrmName,"email")) 										addError("Email: Please enter your email");
	else if (!chkEmail(getTFValue(gFrmName,"email"))) 						addError("Email: Invalid email address");
	// etc.
}

3) Each form should have a submit button, eg.
<a onclick="javascript:submitForm();">Submit</a>

**********************************/

var errorNum, errorMsg;

function submitForm() {
	//reset
	errorNum = 0;
	errorMsg = "The following fields require your attention:\n";
	errorMsg += "操作未完成。详细原因如下。\n";	
	errorMsg += "---------------------------------------------------\n";
		
	validateForm(); //calls the custom validation function defined for each form
	if (errorNum>0) {
		alert(errorMsg);
		return false;
	}
	else {
		eval("document."+gFrmName+".submit();"); //performs the <form> action
		return true;
	} 
}
function addError(msg) {
	errorMsg += ++errorNum + ") " + msg + "\n";
}

/********************
* Validation Processing methods
*********************/
var frmEl;
//can be used to return the form element OR just populate frmEl for page use
function getFrmEl(gFrmName,fldName) {
	frmEl= new Object(eval("document."+gFrmName+"."+fldName));
	return frmEl;
}

//called onfocus and clears the TF of its current value
function emptyTF(fldName) {
	if (getTFValue(gFrmName,fldName)=='(Please specify)') frmEl.value='';
}

/********************
* Population methods
*********************/
//populates TF with 'value'
function setTFValue(gFrmName,fldName,value) {
	getFrmEl(gFrmName,fldName);
	frmEl.value=unescape(value);
}
//populates CB group with values from 'ary'
function setCBValue(gFrmName,fldName,value) {
	if (value.length==0) return; //if no values were recorded for this CB group
	if (typeof(value)=='string') ary = value.split("%2C"); //split by %2C, the escaped code for commas
	else ary = value;
	getFrmEl(gFrmName,fldName);
	resetCBRBValue(gFrmName,fldName);
	if (!frmEl.length) { //this is a single CB, only one value was recorded
		if (frmEl.value==unescape(ary[0])) frmEl.checked=true;
	}
	else { //group of CBs
		for (var j=0;j<ary.length;j++) {	
			for (var i=0;i<frmEl.length;i++) {
				if (frmEl[i].value==unescape(ary[j])) frmEl[i].checked=true;
			}
		}
	}
}
//selects RB group with value 'value'
function setRBValue(gFrmName,fldName,value) {
	if (value=='') return; //if no value was recorded for this RB
	getFrmEl(gFrmName,fldName);
	for (var i=0;i<frmEl.length;i++) {
		if (frmEl[i].value==unescape(value)) {
			frmEl[i].checked=true;
			return;
		}
	}
}
function resetCBRBValue(gFrmName,fldName) {
	getFrmEl(gFrmName,fldName);
	for (var i=0;i<frmEl.length;i++) {
		frmEl[i].checked=false;
	}
}
//set DL to item with value 'value'
function setDLValue(gFrmName,fldName,value) {
	if (value=='') return; //if no value was recorded for this DL
	getFrmEl(gFrmName,fldName);
	for (var i=0;i<frmEl.length;i++) {
		if (frmEl.options[i].text==unescape(value)) { //use 'text' cos 'value' wont work in IE
			frmEl[i].selected=true;
			return;
		}
	}
}
//set DL to item with index 'index'
function setDLIndex(gFrmName,fldName,index) {
	getFrmEl(gFrmName,fldName);
	frmEl[index].selected=true;
}

function getDLselectedIndex(gFrmName, elementName){
	dlFrmEl = eval("document."+gFrmName+"."+elementName);
	return dlFrmEl.selectedIndex;
}

function setDLselectedIndex(gFrmName, elementName, index){
	dlFrmEl = eval("document."+gFrmName+"."+elementName);
	dlFrmEl.selectedIndex = index;
}

/********************
* Validation/Retrieval methods
*********************/
//returns the value entered in the textfield
//returns false if no value entered
function getTFValue(gFrmName,fldName) {
	getFrmEl(gFrmName,fldName);
	if (frmEl.value!=='') return strim(frmEl.value);
	else return false; //no value entered
}
//returns the VALUE of the selected radio button in the group where name=fldName
//returns false if none selected
function getRBValue(gFrmName,fldName) {
	getFrmEl(gFrmName,fldName);
	for (var i=0;i<frmEl.length;i++) {
		if (frmEl[i].checked)
			return frmEl[i].value;
	}
	return false; //no radio selected
}
//returns the VALUE of the selected item in the DDL fldName
//returns false if default value selected, thus A DEFAULT VALUE MUST BE SET AT FIRST POSITION
function getDLValue(gFrmName,fldName) {
	getFrmEl(gFrmName,fldName);
	var index = frmEl.selectedIndex;
	if (index!=0) return frmEl.options[index].value;
	else return false; //default value selected
}
//returns as an array the VALUES of the selected checkboxes in the group where name=fldName
//returns false if none selected
function getCBValue(gFrmName,fldName) {
	getFrmEl(gFrmName,fldName);
	var aryCBValue= new Array();
	if (!frmEl.length && frmEl.checked) aryCBValue = frmEl.value; //this is a single CB
	else { //this is a group CB
		for (var i=0;i<frmEl.length;i++) {
			if (frmEl[i].checked) aryCBValue.push(frmEl[i].value);
		}
	}
	if (aryCBValue.length>0) return aryCBValue;
	else return false; //no checkbox selected
}


/********************
* Misc Validation methods
*********************/
//checks that email is of the format a@b.c
//returns false otherwise
function chkEmail(str) {
	/*var at="@";
	var dot=".";
	var lat=str.indexOf(at);
	var lstr=str.length;
	var ldot=str.indexOf(dot);
	if ((str.indexOf(at)==-1) ||
		(str.indexOf(at)==-1 || str.indexOf(at)==0 || str.indexOf(at)==lstr) ||
		(str.indexOf(dot)==-1 || str.indexOf(dot)==0 || str.indexOf(dot)==lstr) ||
		(str.indexOf(at,(lat+1))!=-1) ||
		(str.substring(lat-1,lat)==dot || str.substring(lat+1,lat+2)==dot) ||
		(str.indexOf(dot,(lat+2))==-1) ||
		(str.indexOf(" ")!=-1)) {
			return false;
	}
	return true;*/

	var regex = /^[\w-]+([\.]?[\w-]+)*@([\w-]+\.)+[\w]{2,4}$/i;
	if (!regex.test(str)){
		return false;
	}
	return true;

}
//checks that the value in the DL/RB/CB fldName equals reqValue
//1. called onkeypress in 'Others' textfield: onkeypress="chkValueSpecific(this.form.name,fldName,'[O] Others',eventFldName);"
//   otherwise prompts user and doesnt allow any values to be entered in the textfield
//2. called onchange of DL, or onclick of RB/CB: onchange/onclick="chkValueSpecific(this.form.name,this.name,'[O] Others',resetFldName);"
//   otherwise empties value in the textfield
function chkValueSpecific(gFrmName,fldName,reqValue,eventOrResetFldName) {
	switch (getFrmElType(fldName)) { //retrieve form element type
		case 'RB':
			if (getRBValue(gFrmName, fldName)==reqValue) return true;
			break;
		case 'DL':
			if (getDLValue(gFrmName, fldName)==reqValue) return true;
			break;
		case 'CB':
			var ary=getCBValue(gFrmName,fldName);
			for (var i=0; i<ary.length; i++) {
				if (ary[i]==reqValue) return true;
			}
			break;
	}
	if (typeof(eventOrResetFldName)=='object') { //parameter passed is the onkeypress event
		alert("Please choose '"+reqValue+"' to enter data");
		cancelIllegal(eventOrResetFldName);
	}
	else setTFValue(gFrmName,eventOrResetFldName,''); //parameter passed is the name of the TF to reset
}
function insertAfter(parent, node, referenceNode) {
  parent.insertBefore(node, referenceNode.nextSibling);
}
function chkValueOthers(gFrmName,fldName,reqValue,eventOrResetFldName) {
	var droplist = getFrmEl(gFrmName,fldName);
	otherTF = "frmTF"+fldName.substring(5).split("_")[0]+"_"+fldName.split("_")[1]+"_dscp";
	index = eval("document."+gFrmName+"."+fldName+".selectedIndex");
	if (eval("document."+gFrmName+"."+fldName+".options.length")==(index+1)){
		droplist.parentNode.innerHTML += '<input type="text" name="'+otherTF+'" id="'+otherTF+'" onFocus="emptyTF(this.name)" value="(Please specify)" id="'+fldName+'_dscp">'; //frmDLfixedOthers_1 fldName.substring(5)split("_")[0];
		dropdown = eval("document."+gFrmName+"."+fldName); 
		dropdown.selectedIndex = dropdown.options.length-1;
	}
	else {
		//alert(document.getElementById(otherTF).innerHTML);
		if (eval("document."+gFrmName+"."+otherTF))//if there is a matching TF
			droplist.parentNode.removeChild(document.getElementById(otherTF)); //remove the TF
	}
}
//checks that the value in fldName is numeric
//prevents user input from being displayed otherwise
function chkNumeric(e) {
	var keyCode = (e.keyCode) ? e.keyCode : e.which;
	var target = (e.target) ? e.target : e.srcElement;
	//allows numbers and the following:
	//keyCode==8 - backspace
	//keyCode==9 - tab
	//keyCode==13 - enter
	//keyCode==46 - dot/delete
	if ((keyCode<48 || keyCode>57) && keyCode!=8 && keyCode!=9 && keyCode!=13 && keyCode!=46) { 
		alert("Only digits to be entered");
		cancelIllegal(e);
	}
}
function chkExtension(filepath) {
	var filename = filepath.substring(filepath.lastIndexOf("\\")+1);
	var fileext = filename.substring(filename.lastIndexOf(".")).toLowerCase();
	if (fileext!=".gif" && fileext!=".jpg" && fileext!=".jpeg") return false;
	else return true;
}
//checks onkeypress that element is not more than maxLength, else cancels keypress
function chkLength(value, e, maxLength) {
	if (value.length>maxLength) {
		if (e=='') return false; //called by button-click validation
		else cancelIllegal(e); //called onkeypress
	}
	else return true;
}

function chkNRIC(nric) {
	if (nric.length != 9) return false;
	nric = nric.toUpperCase();
	var nricPrefix = nric.charAt(0);
	
	if (nricPrefix=='S' || nricPrefix=='F') var sum = 0;
	else if (nricPrefix=='T' || nricPrefix=='G') var sum = 4;
	else return false;
	
	var aryWeight = new Array(2, 7, 6, 5, 4, 3, 2);
	if (nricPrefix=='S' || nricPrefix=='T') var aryAlpha = new Array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'Z', 'J');
	else if (nricPrefix=='F' || nricPrefix=='G') var aryAlpha = new Array('K', 'L', 'M', 'N', 'P', 'Q', 'R', 'T', 'U', 'W', 'X');
	else return false;
	
	for (var i=1; i<=7; i++) {
		var currDigit = Number(nric.charAt(i));
		sum += currDigit*aryWeight[i-1];
	}
	
	var chkDigit = 11 - (sum%11);
	if (aryAlpha[chkDigit-1]==nric.charAt(8)) return true;
	else return false;
}

//takes values from 3 separate textfields, returns a single string of date in the format DD/MM/YYYY
//given the generic term 'frmTFdob', this function will autom check values from the textfields - 'frmTFdobD', 'frmTFdobM', 'frmTFdobY'
//checks that the day/month/year entries are valid values: correct num days for each month incl feb for leap years, year must be between 1900 and current year inclusive
function chkDate(gFrmName,fldName) {
	var usrDay = Number(eval("document."+gFrmName+"."+fldName+"D.value"));
	var usrMonth = Number(eval("document."+gFrmName+"."+fldName+"M.value"));
	var usrYear = Number(eval("document."+gFrmName+"."+fldName+"Y.value"));
	if (usrDay.toString().length>2 || usrMonth.toString().length>2 || usrYear.toString().length!=4) return false;
	
	var currDate = new Date();
	var currYear = currDate.getFullYear();
	
	var dateValid=false;
	if (usrYear>=1900 && usrYear<=currYear) { //valid year (between 1900 and current year inclusive)
		if (usrMonth>=1 && usrMonth<=12) { //valid month
			if (usrMonth==2) {
				if (chkLeapYear(usrYear) && usrDay<=29) dateValid=true; //valid day of leap year
				else if (usrDay<=28) dateValid=true; //valid day of non-leap year
			}
			else if ((usrMonth==1 || usrMonth==4 || usrMonth==6 || usrMonth==9 || usrMonth==11) && usrDay<=30) dateValid=true; //valid day
			else if (usrDay<=31) dateValid=true; //valid day
		}
	}

	if (dateValid) return usrDay+"/"+usrMonth+"/"+usrYear; //returns dob in the format DD/MM/YYYY
	else return false;
}
//checks if year is a leap year
//A year will be a leap year if it is divisible by 4 but not by 100. 
//If a year is divisible by 4 and by 100, it is not a leap year unless it is also divisible by 400.
//eg. 1996, 1992, 1988 are leap years (divisible by 4 but not by 100)
//century years eg. 1900, 1800 and 1700 are not leap years (divisible by 4 and 100 but not by 400)
//called from chkDate()
function chkLeapYear(year) {
	if (year%4==0) { //divisible by 4
		if (year%100==0) { //divisible by 100
			if (year%400==0) return true; //divisible by 400 too, therefore is leap year
			else return false; //divisible by 4 and 100, not leap year
		}
		else return true; //divisible by 4 but not by 100, therefore is leap year
	}
	else return false;
}

//checks that age is between minAge and maxAge (inclusive), ie. age>=minAge and age<=maxAge
function chkAge(gFrmName,fldName,minAge,maxAge) {
	var usrDay = Number(eval("document."+gFrmName+"."+fldName+"D.value"));
	var usrMonth = Number(eval("document."+gFrmName+"."+fldName+"M.value"));
	var usrYear = Number(eval("document."+gFrmName+"."+fldName+"Y.value"));
	var today = new Date();
	
	var usrDOB = new Date();
	usrDOB.setDate(usrDay);
	usrDOB.setMonth(usrMonth-1);
	usrDOB.setYear(usrYear);
	
	var oneDayMs = 1000 * 60 * 60 * 24;// The number of milliseconds in one day
	var usrDOBdays=Math.abs(usrDOB.getTime())/oneDayMs; //convert to number of days
	var tdyDOBdays=Math.abs(today.getTime())/oneDayMs;
	
	var diffYears = (tdyDOBdays-usrDOBdays)/365; //difference in years
	if (diffYears>=minAge && diffYears<=maxAge) valid = true;
	else valid = false;
	
	/*alert('usrDOBms : '+usrDOBdays +'\n' + 
		  'tdyDOBms : '+tdyDOBdays +'\n' + 
		  'diffYears : '+diffYears +'\n' +
		  'valid : '+valid +'\n');*/
	
	return valid;
}
//converts value of fldName into uppercase
function convertUppercase(gFrmName,fldName) {
	getFrmEl(gFrmName,fldName);
	frmEl.value=frmEl.value.toUpperCase();
}
//strips string of all whitespace
function trim(str) {
	return str.replace(/\s/g, '');
}
//strips string of left and right whitespace
function strim(str) {
	return str.replace(/(^\s*)|(\s*$)/g, '');
}
//prevents illegal character from appearing
function cancelIllegal(e) {
	e.returnValue = (e.keyCode) ? false : e.preventDefault(); //for IE & Netscape respectively
}

//prevents user input from being displayed otherwise
function chkNegative(e) {
	var keyCode = (e.keyCode) ? e.keyCode : e.which;
	if (keyCode==45) { 
		alert("No negative figures allowed");
		cancelIllegal(e);
	}
}

document.onkeydown = checkKey;
//cancels event when user presses 'enter' key (instead of submitting form)
function checkKey(oEvent){
	var oEvent = (oEvent)? oEvent : event;
	var oTarget =(oEvent.target)? oEvent.target : oEvent.srcElement;
	if(oEvent.keyCode==13) {
		//oEvent.keyCode = 9; //only works in IE
		return false;
	}
}



//populates value into main form element (used when loading existing article)
function setElementValue(elName, elValue) {
	var frmEl2 = getFrmEl(gFrmName,elName);
	
	if (frmEl2.type) var frmElType = frmEl2.type; //retrieve textfield type attribute
	else if (frmEl2[0]) var frmElType = frmEl2[0].type; //retrieve RB/CB type attribute
	else var frmElType = 'none!'; // *** tmp
	
	switch (frmElType) {
		case "text": case "textarea": case "hidden":
			setTFValue(gFrmName,elName,elValue);
			break;
		case "radio":
			setRBValue(gFrmName,elName,elValue);
			break;
		case "checkbox":
			setCBValue(gFrmName,elName,elValue);
			break;
		case "select-one":
			setDLValue(gFrmName,elName,getCatName(elValue));
			break;
		default:
			break;
	}
}
