/* form-based, get, post, ajax javascript routines*/
/* - Required dependancies: common.js 			 */
/*----------------------------------------------*/
function autoFill(theForm,answerid,ro){
	if(undefined == ro){
		//default to not read only
		ro=0;
        }
    //get the answers - 
	var answers=new Array();
	var slist=GetElementsByAttribute('div', 'id', answerid);
	for(i=0;i<slist.length;i++){
		var ename=slist[i].getAttribute('name');
		if(ename!='null'){
			var val=getText(slist[i]);
			answers[ename]=val;
			}
        }
    for(var i=0;i<theForm.length;i++){
		var etype=theForm[i].type;
		var ename=theForm[i].getAttribute('name');
		var aname=ename.replace(/\[/,"");
		aname=aname.replace(/\]/,"");
		var answer=answers[aname];
		if(ro){
			//set to read only mode
			theForm[i].style.backgroundColor='#FFFFFF';
			theForm[i].style.color='#000000';
			theForm[i].style.border='1px solid #7f9db9';
			if(etype == 'textarea'){
				theForm[i].readOnly=true;
				}
			else if(etype == 'text'){
				theForm[i].readOnly=true;
				}
			else{theForm[i].disabled=true;}
			}
		//alert('form:name='+ename+', aname='+aname+', answer='+answers[aname]);
		if(undefined != answers[aname]){
			if(etype == 'checkbox'){
				var vals=answers[aname].split(':');
				var evalue=theForm[i].getAttribute('value');
				for(s=0;s<vals.length;s++){
					if(evalue == vals[s]){theForm[i].checked=true;}
                    }
                }
			else{
				theForm[i].value=answers[aname];
				}
			}
		}
    }
//--------------------------
function ajaxAddEditForm(table,id,flds,userparams){
	var params='_action=editform&-table='+table;
	var xtitle='Add New Record';
	if(undefined != id && id > 0){
		params += '&_id='+id;
		xtitle='Edit Record';
		}
	if(undefined != flds){params += '&-fields='+flds;}
	if(undefined != userparams){params += '&'+userparams;}
	ajaxPopup('/php/index.php',params,{id:'addeditform',center:1,y:'-200',title:xtitle,mouse:1,x:'+50',drag:1});
	return false;
	}
//--------------------------
function autoGrow(box,maxheight) {
	//info: allows a textbox to grow as a person types
	//usage: <textarea onkeypress="autoGrow();"><textarea>
	if(undefined==maxheight){maxheight=400;}
	if (box.scrollHeight < maxheight && box.scrollHeight > box.clientHeight && !window.opera){box.style.height=box.scrollHeight+'px';}
	}
//--------------------------
function comboCompleteMatch (sText, arrValues) {
	sText=sText.toLowerCase();
	for (var i=0; i < arrValues.length; i++) {
		aval=arrValues[i].toLowerCase();
		if (aval.indexOf(sText) == 0) {
    		return i;
			}
   		}
	return -1;
	}
function comboComplete(oTextbox, oEvent, vid) {
	var comboSelectionText=getText(vid);
	//alert(comboSelectionText);
	var selectionLines=comboSelectionText.split("\n");
	var arrayValues=new Array();
	for(var i=0;i<selectionLines.length;i++){
		var cline=trim(selectionLines[i]);
		if(cline.length ==0){continue;}
		var matches = cline.match(/tval=\"(.+?)\"/ig);
		for(m in matches){
			var val=matches[m].replace('tval="','');
			val=val.replace(/\"$/,'');
			arrayValues.push(val);
			}
    	}
	//showProperties(arrayValues,null,1);
	var code=parseInt(oEvent.keyCode)
	switch (code) {
		case 38: //up arrow
			if(undefined != oTextbox.getAttribute('last_index')){
				var mi=parseInt(oTextbox.getAttribute('last_index'));
				if(mi > 0){
					mi=mi-1;
					if(undefined != arrayValues[mi]){
						oTextbox.value = arrayValues[mi].replace('&amp;','&');;
						oTextbox.setAttribute('last_index',mi);
    					textboxSelect(oTextbox, iLen, oTextbox.value.length);
    					//window.status='M1:'+arrayValues.length+','+mi+','+oEvent.keyCode;
    					return false;

						}
					}
            	}
            break;
		case 40: //down arrow
		//window.status='M2-A:'+arrayValues.length+','+mi+','+oEvent.keyCode;
		if(undefined != oTextbox.getAttribute('last_index')){
				var mi=parseInt(oTextbox.getAttribute('last_index'));
				//window.status='M2-B:'+arrayValues.length+','+mi+','+oEvent.keyCode;
				if(mi < arrayValues.length){
					mi=mi+1;
					if(undefined != arrayValues[mi]){
						oTextbox.value = arrayValues[mi].replace('&amp;','&');;
						oTextbox.setAttribute('last_index',mi);
    					textboxSelect(oTextbox, iLen, oTextbox.value.length);
    					//window.status='M2:'+arrayValues.length+','+mi+','+oEvent.keyCode;
    					return false;
    					break;
						}
					}
            	}
            break;
		case 37: //left arrow
		case 39: //right arrow
		case 33: //page up
		case 34: //page down
		case 36: //home
		case 35: //end
		case 13: //enter
		case 9: //tab
		case 27: //esc
		case 16: //shift
		case 17: //ctrl
		case 18: //alt
		case 20: //caps lock
		case 8: //backspace
		case 46: //delete
			//window.status='Keycode:'+arrayValues.length+','+oEvent.keyCode;
			return true;
			break;
		default:
			textboxReplaceSelect(oTextbox, String.fromCharCode(isIE?oEvent.keyCode:oEvent.charCode));
			var iLen = oTextbox.value.length;
			var mi = comboCompleteMatch(oTextbox.value, arrayValues);
			if (mi > -1) {
				oTextbox.value = arrayValues[mi].replace('&amp;','&');;
				oTextbox.setAttribute('last_index',mi);
    			textboxSelect(oTextbox, iLen, oTextbox.value.length);
    			//window.status='M4:'+arrayValues.length+','+mi+','+oEvent.keyCode;
				}
			return false;
   		}
	}
//--------------------------
function filemanagerEdit(id,page,param){
	//build an html for for changing the name and description of file
	var obj=getObject(id);
	var fname=obj.getAttribute('filename');
	var desc=getText(obj);
	var htm='';
	htm += '<form class="w_form" method="post" action="/'+page+'" onSubmit="return submitForm(this);">'+"\n";
	htm += '<table border="0">'+"\n";
	htm += '<tr><th>Name</th><td><input type="text" name="file_name" value="'+fname+'" style="width:300px;"></td></tr>'+"\n";
	htm += '<tr><th>Desc</th><td><textarea name="file_desc" style="width:300px;height:60;" onkeypress="autoGrow(this,200);">'+desc+'</textarea></td></tr>'+"\n";
	htm += '<tr><td align="right" colspan="2"><input type="submit" value="Save Changes"></td></tr>'+"\n";
	htm += '</table>'+"\n";
	if(param){
		htm += '<div style="display:none" id="params">'+"\n";
		for (var key in param){
			htm += '<textarea name="'+key+'">'+param[key]+'</textarea>'+"\n";
			}
		htm += '</div>'+"\n";
		}
	htm += '</form><br />'+"\n";
	//alert(htm);
	popUpDiv(htm,{title:'filemanager Edit',drag:1,center:'x',y:'-100',width:350});
	return false;
	}
//--------------------------
function dynamicSelect(fld,v,p){
	//info: allows a user to enter "other" values in a select box
	//usage: <select name="color" onChange="dynamicSelect(this,'other')>
	if(undefined == fld){return false;}
	if(undefined == v){v='other';}
	var dname=fld.name;
	if(fld.getAttribute('displayname')){dname=fld.getAttribute('displayname');}
	if(undefined == p){p='Enter '+v+' "'+dname+'" below and click OK.';}
	if(fld.value.toLowerCase()==v.toLowerCase()){
		var other=prompt(p);
		if(undefined != other && other.length > 0){
			for(var i=0;i<fld.options.length;i++){
				if(fld.options[i].value == other){
					fld.value=fld.options[i].value;
					return false;
                	}
            	}
			fld.options[fld.length]=new Option(other.toLowerCase(),other);
			fld.value=other;
        	}
    	}
    return false;
	}
//--------------------------
function remindMeForm(){
	var frm='';
	frm +=	'<div style="padding:5px;">'+"\n";
	frm +=	'<form method="POST" name="remindMe" action="/php/index.php" onSubmit="ajaxSubmitForm(this,\'remindMePopup_Body\');return false;">'+"\n";
	frm +=  '	<input type="hidden" name="_remind" value="1">'+"\n";
	frm +=  '	<input type="hidden" name="tname" value="remind me">'+"\n";
	frm +=	'	<div class="w_lblue">Enter your email address and we will send you a reminder.</div>'+"\n";
	frm +=	'	<b>Email Address</b><br>'+"\n";
	frm +=	' 	<input type="text" name="email" maxlength="255" name="email" mask=".+@.+..{2,6}" maskmsg="Invalid Email Address" required="1" requiredmsg="Enter the email address you registered with." value="" onFocus="this.select();" style="width:200px;font-size:8pt;font-family:arial;">'+"\n";
	frm +=	'	<div align="right" style="margin-right:2px;margin-top:5px;"><input type="submit" class="w_formsubmit" value="Remind Me"></div>'+"\n";
	frm +=  '</form>';
	frm +=	'</div>'+"\n";
	//frm +=  '</textarea>'+"\n";
	popUpDiv(frm,{title:'Remind Me Form',id:'remindMePopup',drag:1,width:220,x:'+10',y:'+10'});
	document.remindMe.email.focus();
	//alert(frm);
	return false;
	}
//--------------------------
function setProcessing(id,msg){
	if(undefined == msg){msg='Processing ...';}
	var str='<div class="w_lblue"><img src="/wfiles/loading_blu.gif" border="0"> '+msg+'</div>';
	setText(id,str);
	return;
	}
//--------------------------
function submitRemindMeForm(frm){
	setProcessing('reminderMessage');
	ajaxSubmitForm(frm,'remindMeForm_Body');
	return false;
	}
//--------------------------
function setDateTimeBox(id,d,h,m,ap){
	if(undefined == d || d.length==0){
		var cdate=new Date();
		d=cdate.getMonth()+'-'+cdate.getDate()+'-'+cdate.getFullYear();
		}
	var dparts=d.split('-',3);
	h=parseInt(h*1);
	if(ap=='PM'){h=h+12;}
	if(h < 10){h='0'+h;}
	if(m.length==1){m='0'+m;}
	var t=dparts[2]+'-'+dparts[0]+'-'+dparts[1]+' '+h+':'+m+':00';
	setText(id,t);
	return 1;
	}
//--------------------------
function setTimeBox(id,h,m,ap){
	h=parseInt(h*1);
	if(ap=='PM'){h=h+12;}
	if(h.length==1){h='0'+h;}
	if(m.length==1){m='0'+m;}
	var t=h+':'+m+':00';
	setText(id,t);
	return 1;
	}
//--------------------------
function showColors(color,hexbox,colorbox){
	window.status=color+","+hexbox+","+colorbox;
	var setEl = document.getElementById(hexbox);
	setEl.innerHTML=color;
	setEl = document.getElementById(colorbox);
	setEl.style.backgroundColor=color;
	}
//--------------------------
function showColor(color){
	showColors(color,'show_hex','show_color');
	}
//--------------------------
var setHexObj;
var setHexDiv;
var setHexImg;
function selectColor(divid,frmObj,imgid){
	setHexObj=frmObj;
	setHexDiv=divid;
	setHexImg=imgid;
	ajaxGet('/wfiles/colortable.html',divid);
	}
//--------------------------
function setHex(hex){
	setText(setHexObj,hex);
	setText(setHexDiv,'');
	setStyle(setHexImg,'backgroundColor',hex);
    }
//--------------------------
function showToolbar(field,cat){
	var list=GetElementsByAttribute('div','id','toolbar');
	for(var i=0;i<list.length;i++){
		var cfield = list[i].getAttribute('field');
		var ccat = list[i].getAttribute('category');
		if(cfield == field && ccat == cat){
			list[i].style.display='block';
			}
		else {
			list[i].style.display='none';
			}
		}
	}
//--------------------------
function setLabelChecked(att,val,ck){
    //info:decorate labels associated with a checkbox value that have an attribute of value
    //info: returns number of items checked
    var cust=GetElementsByAttribute('label',att,'^'+val+'$');
    var cnt = 0;
    for(var i=0;i<cust.length;i++){
		if(ck){cust[i].style.borderBottom='1px solid #000';}
		else{cust[i].style.borderBottom='';}
    	}
	return true;
    }
//--------------------------
function checkAllElements(att,val,ck){
    //info:check/toggle all checkboxes that have an attribute of value
    //info: returns number of items checked
    var cust=GetElementsByAttribute('input',att,'^'+val+'$');
    var cnt = 0;
    for(var i=0;i<cust.length;i++){
		if(cust[i].type=='checkbox'){cust[i].checked=ck;cnt++;}
    	}
    if (ck){return cnt;}
	return 0;
    }
//--------------------------
function setTimeField(frmname,fldname){
	var dt = new Date();
    var h=dt.getHours();
    var m=dt.getMinutes();
    //get the m that is closest
    if(m<10){m="0"+m;}
    var p="am";
    if(h > 12){h=h-12;p="pm";}
    if(h<10){h="0"+h;}
    var obj=getObject(frmname+'_'+fldname+'_hour');
    obj.value=h;
    obj=getObject(frmname+'_'+fldname+'_minute');
    obj.value=m;
    obj=getObject(frmname+'_'+fldname+'_ampm');
    obj.value=p;
	}
//--------------------------
function insertAtCursor(myField, myValue) {
	var obj=getObject(myField);
	//usage: insertAtCursor(document.formName.fieldName, 'this value');
	//IE support
	if (document.selection) {
		obj.focus();
		sel = document.selection.createRange();
		sel.text = myValue;
		}
	//MOZILLA/NETSCAPE support
	else if (obj.selectionStart || obj.selectionStart == '0') {
		var startPos = obj.selectionStart;
		var endPos = obj.selectionEnd;
		obj.value = obj.value.substring(0, startPos) + myValue + obj.value.substring(endPos, obj.value.length);
		}
	else {
		obj.value += myValue;
		}
	}
//--------------------------
function isCreditCardNumber(ccNumb) {
	var valid = "0123456789"  // Valid digits in a credit card number
	var len = ccNumb.length;  // The length of the submitted cc number
	var iCCN = parseInt(ccNumb);  // integer of ccNumb
	var sCCN = ccNumb.toString();  // string of ccNumb
	sCCN = sCCN.replace (/^\s+|\s+$/g,'');  // strip spaces
	var iTotal = 0;  // integer total set at zero
	var bNum = true;  // by default assume it is a number
	var temp;  // temp variable for parsing string
	var calc;  // used for calculation of each digit
	// Determine if the ccNumb is in fact all numbers
	for (var j=0; j<len; j++) {
		temp = "" + sCCN.substring(j, j+1);
  		if (valid.indexOf(temp) == "-1"){return false;}
		}
	// ccNumb is a number and the proper length - let's see if it is a valid card number
  	if(len >= 15 && len <= 20){
	// 15 or 16 for Amex or V/MC
    	for(var i=len;i>0;i--){  // LOOP throught the digits of the card
      		calc = parseInt(iCCN) % 10;  // right most digit
     		calc = parseInt(calc);  // assure it is an integer
      		iTotal += calc;  // running total of the card number as we loop - Do Nothing to first digit
      		i--;  // decrement the count - move to the next digit in the card
      		iCCN = iCCN / 10;                               // subtracts right most digit from ccNumb
      		calc = parseInt(iCCN) % 10 ;    // NEXT right most digit
      		calc = calc *2;                                 // multiply the digit by two
      		// Instead of some screwy method of converting 16 to a string and then parsing 1 and 6 and then adding them to make 7,
      		// I use a simple switch statement to change the value of calc2 to 7 if 16 is the multiple.
      		switch(calc){
        		case 10: calc = 1; break;       //5*2=10 & 1+0 = 1
        		case 12: calc = 3; break;       //6*2=12 & 1+2 = 3
        		case 14: calc = 5; break;       //7*2=14 & 1+4 = 5
        		case 16: calc = 7; break;       //8*2=16 & 1+6 = 7
        		case 18: calc = 9; break;       //9*2=18 & 1+8 = 9
        		default: calc = calc;           //4*2= 8 &   8 = 8  -same for all lower numbers
      			}
    		iCCN = iCCN / 10;  // subtracts right most digit from ccNum
    		iTotal += calc;  // running total of the card number as we loop
  			}
  		// check to see if the sum Mod 10 is zero
  		var m=iTotal%10;
  		if (m==0){
    		return true;  // This IS (or could be) a valid credit card number.
  			}
		else {
    		return false;  // This could NOT be a valid credit card number
    		}
  		}
  	return false;
	}
//--------------------------
function textboxSelect (oTextbox, iStart, iEnd) {
	switch(arguments.length) {
		case 1:
			oTextbox.select();
			break;
		case 2:
			iEnd = oTextbox.value.length;
			/* falls through */
		case 3:
			if (isIE) {
               	var oRange = oTextbox.createTextRange();
               	oRange.moveStart("character", iStart);
               	oRange.moveEnd("character", -oTextbox.value.length + iEnd);
               	oRange.select();
           		} 
			else if (isMoz){
            	oTextbox.setSelectionRange(iStart, iEnd);
           		}
           	break;
   		}
	oTextbox.focus();
	}
function textboxReplaceSelect (oTextbox, sText) {
	if (isIE) {
		var oRange = document.selection.createRange();
		oRange.text = sText;
		oRange.collapse(true);
		oRange.select();
		} 
	else if (isMoz) {
		var iStart = oTextbox.selectionStart;
		oTextbox.value = oTextbox.value.substring(0, iStart) + sText + oTextbox.value.substring(oTextbox.selectionEnd, oTextbox.value.length);
		oTextbox.setSelectionRange(iStart + sText.length, iStart + sText.length);
		}
   	oTextbox.focus();
	}
//--------------------------
//submitForm -- parses through theForm and validates input based in additonal field attributes
// Possible attributes are: required="1" requiredmsg="" mask="^[0-9]" maskmsg="Age must begin with a number" maxlength="23"
function submitForm(theForm,popup,debug){
	if(undefined == debug){debug==0;}
	if(undefined == theForm){
		alert("No form object passed to submitForm");
		return false;
		}
	/*If action is delete then just return true*/
	if(undefined != theForm._action){
		if(theForm._action.value == 'Delete'){return true;}
    	}
    //Define some quickmasks
    var quickmask=new Array();
	quickmask['alpha'] = '^[a-zA-Z_-\\?\\ \\\']+$';
	quickmask['alphanumeric'] = '^[0-9a-zA-Z_-\\.\\?\\ \\\']+$';
	quickmask['calendar'] = '^[0-9]{1,4}-[0-9]{1,2}-[0-9]{1,4}$';
	quickmask['email'] = '.+@.+\\..{2,6}';
	quickmask['integer'] = '^[0-9]+$';
	quickmask['hexcolor'] = '^#[abcdef0-9]{6,6}$';
	quickmask['decimal'] = '^[0-9]*\\.[0-9]+$';
	quickmask['number'] = '(^[0-9]+$)|(^[0-9]+\\.[0-9]+$)';
	quickmask['phone'] = '^([0-9]{3,3}[\\-\\.][0-9]{3,3}[\\-\\.][0-9]{4,4}|\\([0-9]{3,3}\\)\\ [0-9]{3,3}[\\-][0-9]{4,4})$';
	quickmask['time'] = '^[0-9]{1,2}\\:[0-9]{2}$';
	quickmask['ssn'] = '^[0-9]{3,3}-[0-9]{2,2}-[0-9]{4,4}$';
	quickmask['zipcode'] = '^[0-9]{5,5}(\\-[0-9]{4,4})*$';
	//alert("theForm type="+typeof(theForm));
	if(theForm.length ==0){return false;}
	if(debug==1){alert("Form length: "+theForm.length);}
	for(var i=0;i<theForm.length;i++){
		if(debug==1){alert("Checking "+theForm[i].name+" of type "+theForm[i].type);}
	  	/* Password confirm */
	  	if(theForm[i].name == 'password'  && undefined != theForm.password_confirm){
	  		if(theForm[i].value.length == 0 || theForm.password_confirm.value.length == 0){
				submitFormAlert('Password is required',popup,5);
                theForm[i].focus();
                return false;
            	}
            if(theForm[i].value != theForm.password_confirm.value){
				submitFormAlert('Passwords do not match.  Please retype password.',popup,5);
                theForm[i].focus();
                return false;
            	}
			}
		var dname=theForm[i].name;
		if(theForm[i].getAttribute('displayname')){dname=theForm[i].getAttribute('displayname');}

        //check for required attribute
        var required=0;
		if(undefined != theForm[i].getAttribute('required')){required=theForm[i].getAttribute('required');}
		if(debug==1){
        	alert(dname+' type='+theForm[i].type+', required='+required+', value=['+theForm[i].value+']');
			}
        if(required == 1){
			//checkboxes
			if(theForm[i].type=='checkbox'){
				var checkname='name';
				if(theForm[i].getAttribute('checkname')){checkname=theForm[i].getAttribute('checkname');}
				var checkval=theForm[i].getAttribute(checkname);
				//alert(checkname+'='+checkval);
				var checkboxlist=GetElementsByAttribute('input', checkname, checkval);
				//alert(checkboxlist.length+' elements found with a '+checkname+' of '+checkval);
				var isChecked=0;
				for(var c=0;c<checkboxlist.length;c++){
					if(checkboxlist[c].type=='checkbox' && checkboxlist[c].checked){isChecked++;}
					else if(checkboxlist[c].type=='text' && checkboxlist[c].value != ''){isChecked++;}
                	}
                if(isChecked==0){
					var msg=dname+" is required";
		            if(theForm[i].getAttribute('requiredmsg')){msg=theForm[i].getAttribute('requiredmsg');}
				 	submitFormAlert(msg,popup,5);
		            theForm[i].focus();
		            return false;
                	}
            	}
            else if(theForm[i].type=='radio'){
				var checkboxlist=GetElementsByAttribute('input', 'name', theForm[i].name);
				var isChecked=0;
				for(var c=0;c<checkboxlist.length;c++){
					if(checkboxlist[c].type=='radio' && checkboxlist[c].checked){isChecked++;}
					else if(checkboxlist[c].type=='text' && checkboxlist[c].value != ''){isChecked++;}
                	}
                if(isChecked==0){
					var msg=dname+" is required";
		            if(theForm[i].getAttribute('requiredmsg')){msg=theForm[i].getAttribute('requiredmsg');}
				 	submitFormAlert(msg,popup,5);
		            theForm[i].focus();
		            return false;
                	}
            	}
			else if(theForm[i].value == ''){
	            var msg=dname+" is required";
	            if(theForm[i].getAttribute('requiredmsg')){msg=theForm[i].getAttribute('requiredmsg');}
			 	submitFormAlert(msg,popup,5);
	            theForm[i].focus();
	            return false;
				}
            }
        //check for mask attribute - a filter to test input against
        if(theForm[i].getAttribute('mask') && theForm[i].getAttribute('mask').value != '' && theForm[i].value != ''){
            var mask=theForm[i].getAttribute('mask');
            if(mask == 'ccnumber'){
				//credit card number
				if(isCreditCardNumber(theForm[i].value) == false){
					//invalid card number
                    var msg = dname+" must be of valid credit card number ";
                    if(theForm[i].getAttribute('maskmsg')){msg=theForm[i].getAttribute('maskmsg');}
                    submitFormAlert(msg,popup,5);
                    theForm[i].focus();
                    return false;
                    }
                }
            else if(mask == 'intlphone'){
				//international phone check
				if(checkInternationalPhone(theForm[i].value) == false){
					//invalid card number
                    var msg = dname+" must be a valid phone number";
                    if(theForm[i].getAttribute('maskmsg')){msg=theForm[i].getAttribute('maskmsg');}
                    submitFormAlert(msg,popup,5);
                    theForm[i].focus();
                    return false;
                    }
                }
            else if(mask != 'searchandreplace'){
				var rmask=mask;
                if(undefined != quickmask[mask]){rmask=quickmask[mask]+'';}
                var re = new RegExp(rmask, 'i');
                if(re.test(theForm[i].value) == false){
                    var msg = dname+" must be of type "+mask;
                    if(theForm[i].getAttribute('maskmsg')){msg=theForm[i].getAttribute('maskmsg');}
                    submitFormAlert(msg,popup,5);
                    theForm[i].focus();
                    return false;
                    }
           		}
            }
        //check for length attribute on textarea fields
        if(theForm[i].type == 'textarea' && theForm[i].getAttribute('maxlength')){
            var len=theForm[i].value.length;
            var max=Math.abs(theForm[i].getAttribute('maxlength'));
            if(len > max){
                var msg = dname+" must be less than "+max+" characters\nYou entered "+len+" characters.";
                submitFormAlert(msg,popup,5);
                theForm[i].focus();
                return false;
                }
            }
        //min length
        if(theForm[i].getAttribute('minlength')){
            var len=theForm[i].value.length;
            var minlength=Math.abs(theForm[i].getAttribute('minlength'));
            if(len < minlength){
                var msg = dname+" must be at least "+minlength+" characters\nYou entered "+len+" characters.";
                submitFormAlert(msg,popup,5);
                theForm[i].focus();
                return false;
                }
            }
        //check for allow for file types
        if(theForm[i].type == 'file' && theForm[i].getAttribute('accept') && theForm[i].value.length){
			var allow=theForm[i].getAttribute('accept');
			if(debug==1){
				alert(" -- File type allowed exts:"+allow);
            	}
			var exts=allow.split(',');
			var valid=0;
			for(s=0;s<exts.length;s++){
				if(theForm[i].value.lastIndexOf(exts[s])!=-1){valid++;}
                }
            if(valid==0){
            	var msg = dname+" must be of valid file type:  "+allow;
                if(theForm[i].getAttribute('acceptmsg')){msg=theForm[i].getAttribute('acceptmsg');}
                submitFormAlert(msg,popup,5);
                theForm[i].focus();
                return false;
                }
            }
        }
    return true;
	}
//--------------------------
function imposeMaxlength(obj, max){
	return (obj.value.length <= max);
	}
//--------------------------
//submitSurveyForm appends additional info to the form 
//  like question, section, etc
//	usage: onSubmit="return submitSurveyForm(this,{question:1,section:1,group:1,order:1});"
function submitSurveyForm(theForm,opts){
	if(undefined == theForm){
		alert('submitSurveyForm Error: No Form');
		return false;
    	}
	//validate first
	if(!submitForm(theForm)){return false;}
	//lets make an array of form element names
	var enames=new Array();
	for(var i=0;i<theForm.length;i++){
		var fname=theForm[i].name;
		enames[fname]=1;
		}
	for(var i=0;i<theForm.length;i++){
		if(undefined == theForm[i].name){continue;}
		var fname=theForm[i].name;
		if(fname.length==0){continue;}
		//check for opts
		if(undefined != opts){
			for (var optkey in opts){
				if(opts[optkey]!=1){continue;}
				if(theForm[i].getAttribute(optkey)){
					var optval=theForm[i].getAttribute(optkey);
					if(optval.length){
						var fieldname=optkey+'_'+fname;
						if(undefined == enames[fieldname]){
							enames[fieldname]=1;
							var addfield=document.createElement("textarea");
							addfield.setAttribute('NAME',fieldname);
							addfield.style.display='none';
							addfield.value=optval;
							theForm.appendChild(addfield);
							}
		   				}
		  			}
	            }
	        }
        }
    return true;
    }
//--------------------------
function checkInternationalPhone(strPhone){
	// Declaring required variables
	var digits = "0123456789";
	// non-digit characters which are allowed in phone numbers
	var phoneNumberDelimiters = ".()- ";
	// characters which are allowed in international phone numbers
	// (a leading + is OK)
	var validWorldPhoneChars = phoneNumberDelimiters + "+";
	// Minimum no of digits in an international phone no.
	var minDigitsInIPhoneNumber = 10;
	var bracket=3;
	strPhone=trim(strPhone);
	if(strPhone.indexOf("+")>1) return false;
	if(strPhone.indexOf("-")!=-1){bracket=bracket+1;}
	if(strPhone.indexOf("(")!=-1 && strPhone.indexOf("(")>bracket){return false;}
	var brchr=strPhone.indexOf("(");
	if(strPhone.indexOf("(")!=-1 && strPhone.charAt(brchr+2)!=")"){return false;}
	if(strPhone.indexOf("(")==-1 && strPhone.indexOf(")")!=-1){return false;}
	s=stripCharsInBag(strPhone,validWorldPhoneChars);
	return (isInteger(s) && s.length >= minDigitsInIPhoneNumber);
	}
//--------------------------
function isInteger(s){   
	var i;
    for (i = 0; i < s.length; i++){
        // Check that current character is number.
        var c = s.charAt(i);
        if (((c < "0") || (c > "9"))) return false;
    	}
    // All characters are numbers.
    return true;
	}
//--------------------------
function trim(value){
	if (null != value && undefined != value && "" != value){
		var rval=value.replace(/^[\ \s\0\r\n\t]*/g,"");
		rval=rval.replace(/[\ \s\0\r\n\t]*$/g,"");
	    return rval;
		}
	else{return "";}
	}
//--------------------------
function stripCharsInBag(s, bag){   
	var i;
    var returnString = "";
    // Search through string's characters one by one.
    // If character is not in bag, append to returnString.
    for (i = 0; i < s.length; i++){
        // Check that current character isn't whitespace.
        var c = s.charAt(i);
        if (bag.indexOf(c) == -1) returnString += c;
    	}
    return returnString;
	}
//--------------------------
function submitFormAlert(msg,popup,timer){
	if(undefined == popup){popup=0;}
	if(popup){
		html='';
		html+= '<div style="padding:10px;font-size:12pt;width:300px;background:#FFF;z-index:600">'+"\n";
		html+= '	<div>'+"\n";
		html+= '		<h4 style="margin:2px;padding:2px;"><img src="/wfiles/warn.gif" border="0"> '+msg+'</h4>'+"\n";
		html+= '	</div>'+"\n";
		html+= '	<div style="margin-top:10px;" align="right"><a href="#" class="w_red w_link w_bold" onClick="removeId(\'submitFormAlertBox\');return false;"><img src="/wfiles/x_red.gif" border="0"> Close</a></div>'+"\n";
		html+= '</div>'+"\n";
		if(undefined != timer && timer > 0){
			popUpDiv(html,{id:'submitFormAlertBox',title:'Attention!',drag:1,width:300,height:300,center:1,timout:timer});
        	}
		else{
			popUpDiv(html,{id:'submitFormAlertBox',title:'Attention!',drag:1,width:300,height:300,center:1});
			}
    	}
    else{alert(msg);}
    return false;
	}
//--------------------------
function showFormData(theForm,id){
	if(undefined == theForm){
		alert("No form object passed to formData");
		return false;
		}
	//alert("theForm type="+typeof(theForm));
	if(theForm.length ==0){return false;}
	var str='';
	for(var i=0;i<theForm.length;i++){
		var dname=theForm[i].name;
		var type=typeof(theForm[i]);
		alert(theForm[i]);
		//if(type == 'object'){showProperties(theForm[i],'info',1);}
		str += 'Name: '+ dname + "<br>\r\n";
		str += 'Type: '+ type + "<br>\r\n";
		}
	if(!id){
		alert(str);
		}
	else{
		setText(id,str);
    	}
	}
//--------------------------
function checkPerl(field,value){
	if(undefined == document._perlcheck){
		alert('document._perlcheck does not exist.');
		return false;
		}
	var pfield=field+"_perlcheck";
	if(undefined == value){
		alert('Nothing to check.');
		return false;
		}
	if(value.length ==0){
		alert('Nothing to check.');
		return false;
		}
	document.getElementById(pfield).innerHTML ='<img src="/wfiles/busy.gif" title="checking Perl syntax" border="0" width="12" height="12">';
	document._perlcheck.perlcheck.value=value;
	ajaxSubmitForm(document._perlcheck,pfield,5);
	return false;
	}
//--------------------------
/*
	cloneObj - clones a row, div, ect.  Use for adding another file input type or another item in a form
	if a input field is a button and is named _clone then it will hide that field on cloned objects
	incriments field names for input, select, and textarea fields cloned . name, name_1, name_2, ...
*/
function cloneObj(c){
	var obj=getObject(c);
	var inc=obj.getAttribute('inc');
	if(undefined == inc){inc=1;}
  	else{
		inc=parseFloat(inc);
		inc++;
	  	}
	obj.setAttribute('inc',inc);
	/* clone the object */
	var cloneObj = obj.cloneNode(true);
	/*Gen any input elements in the cloned object*/
	var clonedInputs = cloneObj.getElementsByTagName('input');
	/*Incriment the names of any inputs found*/
	for(var i=0;i<clonedInputs.length;i++){
		var cname=clonedInputs[i].getAttribute('name');
		/* skip inputs without a name attribute*/
		if(undefined == cname){continue;}
		/*get input type*/
		var ctype=clonedInputs[i].getAttribute('type');
		/* hide buttons named _clone */
		if(cname == '_clone' && ctype.toLowerCase() == 'button'){
			clonedInputs[i].style.display='none';
			}
		//alert(cname+','+ctype);
		/* set the value to zero unless it is a button or hidden */
		if(ctype.toLowerCase() != 'button' && ctype.toLowerCase() != 'hidden'){clonedInputs[i].value='';}
		/* get and set the newname */
		var newname=cname+'_'+inc;
		/* treat _path field differently since they need to match their corresponding field */
		if(cname.indexOf('_path') != -1){
			newname=cname.replace(/path/, "");
			newname+=inc+'_path';
        	}
        if(cname.indexOf('_autonumber') != -1){
			newname=cname.replace(/autonumber/, "");
			newname+=inc+'_autonumber';
        	}
		clonedInputs[i].setAttribute('name',newname)
		}
	/*Gen any select elements in the cloned object*/
	var clonedSelects = cloneObj.getElementsByTagName('select');
	/*Incriment the names of any selects found*/
	for(var i=0;i<clonedSelects.length;i++){
		var cname=clonedSelects[i].getAttribute('name');
		/* skip inputs without a name attribute*/
		if(undefined == cname){continue;}
		/* get and set the newname */
		var newname=cname+'_'+inc;
		clonedSelects[i].setAttribute('name',newname)
		}
	/*Gen any textarea elements in the cloned object*/
	var clonedTextareas = cloneObj.getElementsByTagName('textarea');
	/*Incriment the names of any textareas found*/
	for(var i=0;i<clonedTextareas.length;i++){
		var cname=clonedTextareas[i].getAttribute('name');
		/* skip inputs without a name attribute*/
		if(undefined == cname){continue;}
		/* set the value to zero */
		clonedTextareas[i].value='';
		/* get and set the newname */
		var newname=cname+'_'+inc;
		//alert(newname);
		clonedTextareas[i].setAttribute('name',newname)
		}
	obj.parentNode.appendChild(cloneObj);
	}
//--------------------------
function ajaxSubmitForm(theform,sid,tmeout,callback) {
	ajaxPost(theform,sid,tmeout,callback);
	}
//--------------------------
function ajaxPopup(url,params,useropts){
	/* set default opt values */
	var pid='ajaxPopupDiv';
	var opt={
        id: pid,
        drag:1
		}
	/* allow user to override default opt values */
	if(useropts){
		for (var key in opt){
			if(undefined != useropts[key]){opt[key]=useropts[key];}
			}
		/* add additonal user settings to opt Object */
		for (var key in useropts){
			if(undefined == opt[key]){opt[key]=useropts[key];}
			}
		}
	popUpDiv('<div class="w_bold w_lblue w_big"><img src="/wfiles/loading_blu.gif" border="0"> loading...please wait.</div>',opt);
	ajaxGet(url,opt['id']+'_Body',params);
	}
//--------------------------
//--Submit form using ajax
function ajaxPost(theform,sid,tmeout,callback,var1,var2,var3,var4,var5) {
	if(undefined == theform){
		alert("No form object passed to submitForm");
		return false;
		}
	//alert('Here: callback='+callback);
	//Pass form through validation before calling ajax
	var ok=submitForm(theform);
	if(!ok){
		//alert("Not ok. Length="+theform.length);
		//showProperties(theform);
		return false;
		}
	if(undefined == tmeout || tmeout < 60000){tmeout=60000;}
	if(sid.toLowerCase()=='centerpop'){sid='centerpop';}
	if(callback=='centerpop' || sid=='centerpop'){
		var val='<div class="w_centerpop w_whiteback w_bigger w_bold w_lblue"><img src="/wfiles/loading_blu.gif" border="0"> Processing. Please wait...</div>';
		popUpDiv(val,{id:"centerpop",width:300,height:50,drag:1,notop:1,nobot:1,noborder:1,nobackground:1,bodystyle:"padding:0px;border:0px;background:none;"});
		centerObject('centerpop');
		}
	var AJUid=new Date().getTime() + "";
	var status = AjaxRequest.submit(
		theform,{
			'groupName':sid
			,'timeout':tmeout
			,'callback':callback
			,'var1':var1
			,'var2':var2
			,'var3':var3
			,'var4':var4
			,'var5':var5
			,'AjaxRequestUniqueId':AJUid
			,'onGroupBegin':function(req){
				var dname = this.groupName;
				if(this.callback=='centerpop' || dname=='centerpop'){
					}
				else{
					setProcessing(dname);
					}
				}
          	,'onGroupEnd':function(req){
				//setText('ajaxstatus',' ');
				}
          	,'onTimeout':function(req){
				var dname = this.groupName;
				var val="<b style=\"color:red\">ajaxPost Timed Out Error</b>";
				if(this.callback=='centerpop' || dname=='centerpop'){
					setText('centerpop',val);
					centerObject(dname);
                    }
				else{setText(dname,val);}
				}
			,'onError':function(req){
				var dname = this.groupName;
				var val=req.responseText;
				if(this.callback=='centerpop' || dname=='centerpop'){
					setText('centerpop',val);
					centerObject(dname);
                    }
				else{setText(dname,val);}
				}
			,'onComplete':function(req){
				var dname=this.groupName;
				if(undefined != this.callback){
					if(this.callback=='popUpDiv'){
						var val=req.responseText;
						popUpDiv(val,{center:1,drag:1});
                    	}
                    else if(this.callback=='centerpop' || dname=='centerpop'){
						var val=req.responseText;
						setText('centerpop',val);
						centerObject(dname);
                    	}
					else{
						var str=this.callback+'(req);';
						eval(str);
						}
                	}
				else if(undefined != dname){
					var val=req.responseText;
					if(this.callback=='centerpop' || dname=='centerpop'){
						setText(dname,val);
						centerObject(dname);
                    	}
					else if(document.getElementById(dname)){
						document.getElementById(dname).style.display='inline';
						setText(dname,val);
						}
					else{alert('ajaxPost could not find object id:'+dname);}
					}
				else{alert('ajaxPost could not find object id:'+dname);}
				}
  			}
	  	);
	return status;
	}
//--------------------------
function callWaSQL(id,name,params){
	var url='/cgi-bin/wasql.pl';
	ajaxGet(url,name,'&_view='+id+'&'+params);
	}
//--------------------------
function ajaxGet(url,sid,params,callback){
	//get GUID cookie and pass it in
	var guid=getCookie('GUID');
	var tmeout=60000;
	if(sid.toLowerCase()=='centerpop'){sid='centerpop';}
	if(sid.toLowerCase()=='centerpop2'){sid='centerpop2';}
	if(callback=='centerpop' || sid=='centerpop'){
		var val='<div class="w_centerpop w_whiteback w_bigger w_bold w_lblue"><img src="/wfiles/loading_blu.gif" border="0"> Processing. Please wait...</div>';
		popUpDiv(val,{id:"centerpop",width:300,height:50,drag:1,notop:1,nobot:1,noborder:1,nobackground:1,bodystyle:"padding:0px;border:0px;background:none;"});
		centerObject('centerpop');
		}
	else if(callback=='centerpop2' || sid=='centerpop2'){
		}
	else if(undefined == document.getElementById(sid)){
		if(undefined==callback || callback != 'popUpDiv'){
			alert('Error in ajaxGet\n'+sid+' is not defined as a valid object id');
			return;
			}
    	}
	//document.getElementById(name).innerHTML = "Processing AJAX Request ...";
	AjaxRequest.get(
 		{
    		'url':url+'?'+params,
    		'callback':callback,
    		'timeout':tmeout,
			'groupName':sid,
			'onGroupBegin':function(req){
				var dname=this.groupName;
				if(this.callback=='centerpop' || dname=='centerpop' || this.callback=='centerpop2' || dname=='centerpop2'){}
				else{setProcessing(dname);}
				},
			'onError':function(req){
				var dname = this.groupName;
				var val=req.responseText;
				if(this.callback=='centerpop' || dname=='centerpop'){
					setText('centerpop',val);
					centerObject(dname);
                    }
                else if(this.callback=='centerpop2' || dname=='centerpop2'){
					var val=req.responseText;
					popUpDiv(val,{id:"centerpop2",drag:1,notop:1,nobot:1,noborder:1,nobackground:1,bodystyle:"padding:0px;border:0px;background:none;"});
					centerObject('centerpop2');
                    }
				else{setText(dname,val);}
				},
			'onTimeout':function(req){
				var dname = this.groupName;
				var val="<b style=\"color:red\">ajaxGet Timed Out Error</b>";
				if(this.callback=='centerpop' || dname=='centerpop'){
					setText('centerpop',val);
					centerObject(dname);
                    }
				else if(this.callback=='centerpop2' || dname=='centerpop2'){
					var val=req.responseText;
					popUpDiv(val,{id:"centerpop2",drag:1,notop:1,nobot:1,noborder:1,nobackground:1,bodystyle:"padding:0px;border:0px;background:none;"});
					centerObject('centerpop2');
                    }
				else{setText(dname,val);}
				},
    		'onComplete':function(req){
				var dname=this.groupName;
				if(undefined != this.callback){
					if(this.callback=='popUpDiv'){
						var val=req.responseText;
						popUpDiv(val,{id:dname,center:1,drag:1});
						centerObject(dname);
                    	}
                    else if(this.callback=='centerpop'){
						var val=req.responseText;
						setText(dname,val);
						centerObject(dname);
                    	}
                    else if(this.callback=='centerpop2'){
						var val=req.responseText;
						popUpDiv(val,{id:"centerpop2",drag:1,notop:1,nobot:1,noborder:1,nobackground:1,bodystyle:"padding:0px;border:0px;background:none;"});
						centerObject('centerpop2');
                    	}
					else{
						var str=this.callback+'(req);';
						eval(str);
						}
                	}
				else if(undefined != dname){
					var val=req.responseText;
					if(dname=='centerpop'){
						setText(dname,val);
						centerObject(dname);
                    	}
                    else if(dname=='centerpop2'){
						var val=req.responseText;
						popUpDiv(val,{id:"centerpop2",drag:1,notop:1,nobot:1,noborder:1,nobackground:1,bodystyle:"padding:0px;border:0px;background:none;"});
						centerObject('centerpop2');
                    	}
					else if(document.getElementById(dname)){
						document.getElementById(dname).style.display='inline';
						setText(dname,val);
						}
					else{alert('ajaxPost could not find object id:'+dname);}
					}
				else{alert('ajaxPost could not find object id:'+dname);}
				}
  		}
		);
	return false;
	}
//--------------------------
function newXmlHttpRequest(){
	if (window.XMLHttpRequest) {return new XMLHttpRequest();}
	else if (window.ActiveXObject) {
		// Based on http://jibbering.com/2002/4/httprequest.html
		/*@cc_on @*/
		/*@if (@_jscript_version >= 5)
		try {
			return new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				return new ActiveXObject("Microsoft.XMLHTTP");
			} catch (E) {
				return null;
			}
		}
		@end @*/
	}
	else {
		return null;
	}
}
//--------------------------
// Parts Taken from  http://www.AjaxToolbox.com/
function AjaxRequest() {
	var req = new Object();
	
	// -------------------
	// Instance properties
	// -------------------

	/**
	 * Timeout period (in ms) until an async request will be aborted, and
	 * the onTimeout function will be called
	 */
	req.timeout = null;
	
	/**
	 *	Since some browsers cache GET requests via XMLHttpRequest, an
	 * additional parameter called AjaxRequestUniqueId will be added to
	 * the request URI with a unique numeric value appended so that the requested
	 * URL will not be cached.
	 */
	req.generateUniqueUrl = true;
	
	/**
	 * The url that the request will be made to, which defaults to the current 
	 * url of the window
	 */
	req.url = window.location.href;
	
	/**
	 * The method of the request, either GET (default), POST, or HEAD
	 */
	req.method = "GET";
	
	/**
	 * Whether or not the request will be asynchronous. In general, synchronous 
	 * requests should not be used so this should rarely be changed from true
	 */
	req.async = true;
	
	/**
	 * The username used to access the URL
	 */
	req.username = null;
	
	/**
	 * The password used to access the URL
	 */
	req.password = null;
	
	/**
	 * Generic fields for user to pass through data
	 */
	req.xAttribute = null;
	req.xValue = null;
	req.xName = null;
	req.xAction = null;
	req.xId = null;

	/**
	 * The parameters is an object holding name/value pairs which will be 
	 * added to the url for a GET request or the request content for a POST request
	 */
	req.parameters = new Object();
	
	/**
	 * The sequential index number of this request, updated internally
	 */
	req.requestIndex = AjaxRequest.numAjaxRequests++;
	
	/**
	 * Indicates whether a response has been received yet from the server
	 */
	req.responseReceived = false;
	
	/**
	 * The name of the group that this request belongs to, for activity 
	 * monitoring purposes
	 */
	req.groupName = null;
	req.callback = null;
	req.var1 = null;
	req.var2 = null;
	req.var3 = null;
	req.var4 = null;
	req.var5 = null;
	
	/**
	 * The query string to be added to the end of a GET request, in proper 
	 * URIEncoded format
	 */
	req.queryString = "";
	
	/**
	 * After a response has been received, this will hold the text contents of 
	 * the response - even in case of error
	 */
	req.responseText = null;
	
	/**
	 * After a response has been received, this will hold the XML content
	 */
	req.responseXML = null;
	
	/**
	 * After a response has been received, this will hold the status code of 
	 * the response as returned by the server.
	 */
	req.status = null;
	
	/**
	 * After a response has been received, this will hold the text description 
	 * of the response code
	 */
	req.statusText = null;

	/**
	 * An internal flag to indicate whether the request has been aborted
	 */
	req.aborted = false;
	
	/**
	 * The XMLHttpRequest object used internally
	 */
	req.xmlHttpRequest = null;

	// --------------
	// Event handlers
	// --------------
	
	/**
	 * If a timeout period is set, and it is reached before a response is 
	 * received, a function reference assigned to onTimeout will be called
	 */
	req.onTimeout = null; 
	
	/**
	 * A function reference assigned will be called when readyState=1
	 */
	req.onLoading = null;

	/**
	 * A function reference assigned will be called when readyState=2
	 */
	req.onLoaded = null;

	/**
	 * A function reference assigned will be called when readyState=3
	 */
	req.onInteractive = null;

	/**
	 * A function reference assigned will be called when readyState=4
	 */
	req.onComplete = null;

	/**
	 * A function reference assigned will be called after onComplete, if 
	 * the statusCode=200
	 */
	req.onSuccess = null;

	/**
	 * A function reference assigned will be called after onComplete, if 
	 * the statusCode != 200
	 */
	req.onError = null;
	
	/**
	 * If this request has a group name, this function reference will be called 
	 * and passed the group name if this is the first request in the group to 
	 * become active
	 */
	req.onGroupBegin = null;

	/**
	 * If this request has a group name, and this request is the last request 
	 * in the group to complete, this function reference will be called
	 */
	req.onGroupEnd = null;

	// Get the XMLHttpRequest object itself
	req.xmlHttpRequest = AjaxRequest.getXmlHttpRequest();
	if (req.xmlHttpRequest==null) { return null; }
	
	// -------------------------------------------------------
	// Attach the event handlers for the XMLHttpRequest object
	// -------------------------------------------------------
	req.xmlHttpRequest.onreadystatechange = 
	function() {
		if (req==null || req.xmlHttpRequest==null) { return; }
		if (req.xmlHttpRequest.readyState==1) { req.onLoadingInternal(req); }
		if (req.xmlHttpRequest.readyState==2) { req.onLoadedInternal(req); }
		if (req.xmlHttpRequest.readyState==3) { req.onInteractiveInternal(req); }
		if (req.xmlHttpRequest.readyState==4) { req.onCompleteInternal(req); }
	};
	
	// ---------------------------------------------------------------------------
	// Internal event handlers that fire, and in turn fire the user event handlers
	// ---------------------------------------------------------------------------
	// Flags to keep track if each event has been handled, in case of 
	// multiple calls (some browsers may call the onreadystatechange 
	// multiple times for the same state)
	req.onLoadingInternalHandled = false;
	req.onLoadedInternalHandled = false;
	req.onInteractiveInternalHandled = false;
	req.onCompleteInternalHandled = false;
	req.onLoadingInternal = 
		function() {
			if (req.onLoadingInternalHandled) { return; }
			AjaxRequest.numActiveAjaxRequests++;
			if (AjaxRequest.numActiveAjaxRequests==1 && typeof(window['AjaxRequestBegin'])=="function") {
				AjaxRequestBegin();
			}
			if (req.groupName!=null) {
				if (typeof(AjaxRequest.numActiveAjaxGroupRequests[req.groupName])=="undefined") {
					AjaxRequest.numActiveAjaxGroupRequests[req.groupName] = 0;
				}
				AjaxRequest.numActiveAjaxGroupRequests[req.groupName]++;
				if (AjaxRequest.numActiveAjaxGroupRequests[req.groupName]==1 && typeof(req.onGroupBegin)=="function") {
					req.onGroupBegin(req.groupName);
				}
			}
			if (typeof(req.onLoading)=="function") {
				req.onLoading(req);
			}
			req.onLoadingInternalHandled = true;
		};
	req.onLoadedInternal = 
		function() {
			if (req.onLoadedInternalHandled) { return; }
			if (typeof(req.onLoaded)=="function") {
				req.onLoaded(req);
			}
			req.onLoadedInternalHandled = true;
		};
	req.onInteractiveInternal = 
		function() {
			if (req.onInteractiveInternalHandled) { return; }
			if (typeof(req.onInteractive)=="function") {
				req.onInteractive(req);
			}
			req.onInteractiveInternalHandled = true;
		};
	req.onCompleteInternal = 
		function() {
			if (req.onCompleteInternalHandled || req.aborted) { return; }
			req.onCompleteInternalHandled = true;
			AjaxRequest.numActiveAjaxRequests--;
			if (AjaxRequest.numActiveAjaxRequests==0 && typeof(window['AjaxRequestEnd'])=="function") {
				AjaxRequestEnd(req.groupName);
			}
			if (req.groupName!=null) {
				AjaxRequest.numActiveAjaxGroupRequests[req.groupName]--;
				if (AjaxRequest.numActiveAjaxGroupRequests[req.groupName]==0 && typeof(req.onGroupEnd)=="function") {
					req.onGroupEnd(req.groupName);
				}
			}
			req.responseReceived = true;
			req.status = req.xmlHttpRequest.status;
			req.statusText = req.xmlHttpRequest.statusText;
			req.responseText = req.xmlHttpRequest.responseText;
			req.responseXML = req.xmlHttpRequest.responseXML;
			if (typeof(req.onComplete)=="function") {
				req.onComplete(req);
			}
			if (req.xmlHttpRequest.status==200 && typeof(req.onSuccess)=="function") {
				req.onSuccess(req);
			}
			else if (typeof(req.onError)=="function") {
				req.onError(req);
			}

			// Clean up so IE doesn't leak memory
			delete req.xmlHttpRequest['onreadystatechange'];
			req.xmlHttpRequest = null;
		};
	req.onTimeoutInternal = 
		function() {
			if (req!=null && req.xmlHttpRequest!=null && !req.onCompleteInternalHandled) {
				req.aborted = true;
				req.xmlHttpRequest.abort();
				AjaxRequest.numActiveAjaxRequests--;
				if (AjaxRequest.numActiveAjaxRequests==0 && typeof(window['AjaxRequestEnd'])=="function") {
					AjaxRequestEnd(req.groupName);
				}
				if (req.groupName!=null) {
					AjaxRequest.numActiveAjaxGroupRequests[req.groupName]--;
					if (AjaxRequest.numActiveAjaxGroupRequests[req.groupName]==0 && typeof(req.onGroupEnd)=="function") {
						req.onGroupEnd(req.groupName);
					}
				}
				if (typeof(req.onTimeout)=="function") {
					req.onTimeout(req);
				}
			// Opera won't fire onreadystatechange after abort, but other browsers do. 
			// So we can't rely on the onreadystate function getting called. Clean up here!
			delete req.xmlHttpRequest['onreadystatechange'];
			req.xmlHttpRequest = null;
			}
		};

	// ----------------
	// Instance methods
	// ----------------
	/**
	 * The process method is called to actually make the request. It builds the
	 * querystring for GET requests (the content for POST requests), sets the
	 * appropriate headers if necessary, and calls the 
	 * XMLHttpRequest.send() method
	*/
	req.process = 
		function() {
			if (req.xmlHttpRequest!=null) {
				// Some logic to get the real request URL
				if (req.generateUniqueUrl && req.method=="GET") {
					req.parameters["AjaxRequestUniqueId"] = new Date().getTime() + "" + req.requestIndex;
				}
				var content = null; // For POST requests, to hold query string
				for (var i in req.parameters) {
					if (req.queryString.length>0) { req.queryString += "&"; }
					req.queryString += encodeURIComponent(i) + "=" + encodeURIComponent(req.parameters[i]);
				}
				if (req.method=="GET") {
					if (req.queryString.length>0) {
						req.url += ((req.url.indexOf("?")>-1)?"&":"?") + req.queryString;
					}
				}
				req.xmlHttpRequest.open(req.method,req.url,req.async,req.username,req.password);
				if (req.method=="POST") {
					if (typeof(req.xmlHttpRequest.setRequestHeader)!="undefined") {
						req.xmlHttpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
					}
					content = req.queryString;
				}
				if (req.timeout>0) {
					setTimeout(req.onTimeoutInternal,req.timeout);
				}
				req.xmlHttpRequest.send(content);
			}
		};

	/**
	 * An internal function to handle an Object argument, which may contain
	 * either AjaxRequest field values or parameter name/values
	 */
	req.handleArguments = 
		function(args) {
			for (var i in args) {
				// If the AjaxRequest object doesn't have a property which was passed, treat it as a url parameter
				if (typeof(req[i])=="undefined") {
					req.parameters[i] = args[i];
				}
				else {
					req[i] = args[i];
				}
			}
		};

	/**
	 * Returns the results of XMLHttpRequest.getAllResponseHeaders().
	 * Only available after a response has been returned
	 */
	req.getAllResponseHeaders =
		function() {
			if (req.xmlHttpRequest!=null) {
				if (req.responseReceived) {
					return req.xmlHttpRequest.getAllResponseHeaders();
				}
				alert("Cannot getAllResponseHeaders because a response has not yet been received");
			}
		};

	/**
	 * Returns the the value of a response header as returned by 
	 * XMLHttpRequest,getResponseHeader().
	 * Only available after a response has been returned
	 */
	req.getResponseHeader =
		function(headerName) {
			if (req.xmlHttpRequest!=null) {
				if (req.responseReceived) {
					return req.xmlHttpRequest.getResponseHeader(headerName);
				}
				alert("Cannot getResponseHeader because a response has not yet been received");
			}
		};

	return req;
}

// ---------------------------------------
// Static methods of the AjaxRequest class
// ---------------------------------------

/**
 * Returns an XMLHttpRequest object, either as a core object or an ActiveX 
 * implementation. If an object cannot be instantiated, it will return null;
 */
AjaxRequest.getXmlHttpRequest = function() {
	if (window.XMLHttpRequest) {
		return new XMLHttpRequest();
	}
	else if (window.ActiveXObject) {
		// Based on http://jibbering.com/2002/4/httprequest.html
		/*@cc_on @*/
		/*@if (@_jscript_version >= 5)
		try {
			return new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				return new ActiveXObject("Microsoft.XMLHTTP");
			} catch (E) {
				return null;
			}
		}
		@end @*/
	}
	else {
		return null;
	}
};

/**
 * See if any request is active in the background
 */
AjaxRequest.isActive = function() {
	return (AjaxRequest.numActiveAjaxRequests>0);
};

/**
 * Make a GET request. Pass an object containing parameters and arguments as 
 * the second argument.
 * These areguments may be either AjaxRequest properties to set on the request 
 * object or name/values to set in the request querystring.
 */
AjaxRequest.get = function(args) {
	AjaxRequest.doRequest("GET",args);
};

/**
 * Make a POST request. Pass an object containing parameters and arguments as 
 * the second argument.
 * These arguments may be either AjaxRequest properties to set on the request 
 * object or name/values to set in the request querystring.
 */
AjaxRequest.post = function(args) {
	AjaxRequest.doRequest("POST",args);
};

/**
 * The internal method used by the .get() and .post() methods
 */
AjaxRequest.doRequest = function(method,args) {
	if (typeof(args)!="undefined" && args!=null) {
		var myRequest = new AjaxRequest();
		myRequest.method = method;
		myRequest.handleArguments(args);
		myRequest.process();
	}
}	;

/**
 * Submit a form. The requested URL will be the form's ACTION, and the request 
 * method will be the form's METHOD.
 * Returns true if the submittal was handled successfully, else false so it 
 * can easily be used with an onSubmit event for a form, and fallback to 
 * submitting the form normally.
 */
AjaxRequest.submit = function(theform, args) {
	var myRequest = new AjaxRequest();
	if (myRequest==null) { return false; }
	var serializedForm = AjaxRequest.serializeForm(theform);
	myRequest.method = theform.method.toUpperCase();
	myRequest.url = theform.action;
	myRequest.handleArguments(args);
	myRequest.queryString = serializedForm;
	myRequest.process();
	return true;
};

/**
 * Serialize a form into a format which can be sent as a GET string or a POST 
 * content.It correctly ignores disabled fields, maintains order of the fields 
 * as in the elements[] array. The 'file' input type is not supported, as 
 * its content is not available to javascript. This method is used internally
 * by the submit class method.
 */
AjaxRequest.serializeForm = function(theform) {
	var els = theform.elements;
	if(undefined==els){alert('Ajax Request serializeForm failed');return false;}
	var len = els.length;
	var queryString = "";
	this.addField = 
		function(name,value) { 
			if (queryString.length>0) { 
				queryString += "&";
			}
			queryString += encodeURIComponent(name) + "=" + encodeURIComponent(value);
		};
	for (var i=0; i<len; i++) {
		var el = els[i];
		if (!el.disabled) {
			switch(el.type) {
				case 'text': case 'password': case 'submit': case 'hidden': case 'textarea':
					this.addField(el.name,el.value);
					break;
				case 'select-one':
					if (el.selectedIndex>=0) {
						this.addField(el.name,el.options[el.selectedIndex].value);
					}
					break;
				case 'select-multiple':
					for (var j=0; j<el.options.length; j++) {
						if (el.options[j].selected) {
							this.addField(el.name,el.options[j].value);
						}
					}
					break;
				case 'checkbox': case 'radio':
					if (el.checked) {
						this.addField(el.name,el.value);
					}
					break;
			}
		}
	}
	return queryString;
};

// -----------------------
// Static Class variables
// -----------------------

/**
 * The number of total AjaxRequest objects currently active and running
 */
AjaxRequest.numActiveAjaxRequests = 0;

/**
 * An object holding the number of active requests for each group
 */
AjaxRequest.numActiveAjaxGroupRequests = new Object();

/**
 * The total number of AjaxRequest objects instantiated
 */
AjaxRequest.numAjaxRequests = 0;

