<?php
/*
 * This file is part of Web Pro Manager.
 * 
 * Web Pro Manager is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Web Pro Manager is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Web Pro Manager.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * @author The Web Pro Miami, Inc. <info@thewebpro.com>
 * @copyright The Web Pro Miami, Inc. <info@thewebpro.com>, http://www.thewebpro.com/
 * @license http://www.gnu.org/licenses/gpl.html GNU GPL
 * @package WebProManager
*/

// ver 1.2.4
// 1.0.2 - added validation min/max length
// 1.0.3 - added static field type (non-editable, non-submittable item)
// 1.0.4 - completed email integration, fixed cancel redirect button bug
// 1.0.5 - fixed "checkbox" select bug
// 1.0.6 - added onBlur event for all fields
// 1.0.7 - added SQLNoQuotes to allow certain items to have no quotes in SQL string (i.e. integers)
// 1.0.8 - added class/style to form groups, added basic support for File input type with NO processing (must be included in DontProcess and processed separately)
// 1.0.9 - added "processed" notification to forms that do not use additional post-processing (db or email), added IDs to save/cancel buttons
// 1.1.0 - added "ClearAfter" to Group class, moved group div style up one level (to now include header) allowing for floating divs
// 1.1.0b - updated "onChange" to "onClick" for onBlue event linkup with checkboxes, added "editBoxInner" ID to hook style for grouped inner form elements as a whole, added "nClearFinal" at end of form
// 1.1.1 - added Caption to Form Group, updated "required" fields to show asterisk on caption if available and title is not
// 1.1.2 - added ItemStyle to Form Field, removed unneeded "<br>" from behind Checkbox field item
// 1.1.3 - added ID tag to SELECT field (was just NAME tag)
// 1.1.4 - added BeforeField and AfterField to place text before/after fields
// 1.1.5 - added ID tag to Form Group (for external calls like Tab Grouping)
// 1.1.6 - updated onBlur event on file upload field to onClick, updated code to use nCloseScript var
// 1.1.7 - added rich-text editor (FCKeditor) as new field type "rte", added OnSubmitScriptARRAY for script validation/usage before submitting form
// 1.1.8 - added MySQLInsertID to give access to mysql_insert_id of last added item to database
// 1.1.9 - added MailUseSendMail flag for email servers that require it
// 1.2.0 - added CleanMarkup flag to return forms without extra surrounding DIVs
// 1.2.1 - added "custom" validation handling
// 1.2.2 - bug fixes based on XAMPP 1.7.4 default install
// 1.2.3 - moved nPOST to global to allow custom function override of posted values
// 1.2.4 - added FieldTemplate, updated all field templates, added ButtonTemplate and GroupTemplate, RowID/Title/Rel (fields), submit/cancel button and label classes/styles

$nPOST = $_POST;

class Form {
	var $HasProcessed, $Action, $Encoding, $Method, $Name, $ClearAfter, $SubmitText, $CancelText, $FormClass, $SubmitClass, $CancelClass, $CancelRedirect, $Redirect, $DontProcess, $SQLNoQuotes, $InsertID, $DEBUG, $CleanMarkup, $FieldTemplate, $ButtonTemplate, $GroupTemplate;
	var $DBName,$DBLink,$AddToDBTable,$ModifyDBTable,$ModifyDBID,$ModifyDBField,$nUseADODB,$SubmitToJS;
	var $EncodeRC4ARRAY = array(), $GroupARRAY = array(), $ValReqARRAY = array(), $ValEmailARRAY = array(), $ValNumARRAY = array(), $ValPhoneARRAY = array(), $ValDateARRAY = array(), $ValCCARRAY = array(), $OnSubmitScriptARRAY = array();
	var $ValMaxLengthARRAY = array(), $ValMaxLengthParamARRAY = array(), $ValMinLengthARRAY = array(), $ValMinLengthParamARRAY = array(), $ValCustomARRAY = array(), $ValCustomParamARRAY = array();
	var $Action_email, $Action_email_bodyFile, $MailUseSendMail, $MailHost, $MailUser, $MailPass, $MailFrom, $EmailFromName, $EmailSubject;
	
	function Form(){
		// set defaults
		$this->Method = "post";
		$this->SubmitText = "Submit";
		$this->CancelText = "Cancel";
		$this->HasProcessed = 0;
		$this->CleanMarkup = false;
		$this->DontProcess = "";
		$this->CancelRedirect = "";
		$this->CancelRedirectIsJS = "";
		$this->SubmitClass = "formSubmit";
		$this->CancelClass = "formCancel";
		$this->FormClass = "form";
		$this->FieldTemplate = "";
		$this->ButtonTemplate = "";
		$this->GroupTemplate = "";
	}
	function AddGroup($nGroupObj){
		$this->GroupARRAY[] = $nGroupObj;
	}
	function AddValidation($nValType,$nFieldObj,$nValParam=""){
		$nFieldObj->AddValidation($nValType,$nValParam);
		switch($nValType){
			case "required": $this->ValReqARRAY[] = $nFieldObj->ID; break;
			case "email": $this->ValEmailARRAY[] = $nFieldObj->ID; break;
			case "numeric": $this->ValNumARRAY[] = $nFieldObj->ID; break;
			case "phone": $this->ValPhoneARRAY[] = $nFieldObj->ID; break;
			case "date": $this->ValDateARRAY[] = $nFieldObj->ID; break;
			case "cc": $this->ValCCARRAY[] = $nFieldObj->ID; break;
			case "maxlength": if($nValParam){ $this->ValMaxLengthARRAY[] = $nFieldObj->ID; $this->ValMaxLengthParamARRAY[$nFieldObj->ID] = $nValParam; } break;
			case "minlength": if($nValParam){ $this->ValMinLengthARRAY[] = $nFieldObj->ID; $this->ValMinLengthParamARRAY[$nFieldObj->ID] = $nValParam; } break;
			case "custom": if($nValParam){ $this->ValCustomARRAY[] = $nFieldObj->ID; $this->ValCustomParamARRAY[$nFieldObj->ID] = $nValParam; } break;
		}
		return $nFieldObj;
	}
	function AddOnSubmitScript($nOnSubmitScript,$nFieldObj){
		$this->OnSubmitScriptARRAY[] = $nOnSubmitScript;
		return $nFieldObj;
	}
	function AddEncoding($nEncType,$nFieldObj){
		// encoding (done before final processing)
		switch($nEncType){
			case "RC4": $this->EncodeRC4ARRAY[] = $nFieldObj->ID; break;
		}
		return $nFieldObj;
	}
	function GetForm(){
		global $nPOST;
		// prepare scripts, if needed
		$nOnSubmitScriptCode = "";
		foreach($this->OnSubmitScriptARRAY AS $nOnSubmitScript){ $nOnSubmitScriptCode.= $nOnSubmitScript; }
		if($nOnSubmitScriptCode){
			if($this->SubmitToJS){ $this->SubmitToJS = "if(formOnSubmitScript()){ ".$this->SubmitToJS." }"; }
			$nOnSubmitScriptCode = "<script>formOnSubmitScript = function(){ $nOnSubmitScriptCode return true; }</script>";
		}
		// returns full form, with all groups and fields
		if($this->Encoding){ $nEncoding = "enctype=\"$this->Encoding\""; } else { $nEncoding = ""; }
		if($this->SubmitToJS){
			$Opener = "<form action=\"$this->Action\" method=\"$this->Method\" name=\"$this->Name\" id=\"$this->Name\" class=\"$this->FormClass\" style=\"margin:0px;\" onSubmit=\"$this->SubmitToJS\" $nEncoding>";
		} else {
			$Opener = "<form action=\"$this->Action\" method=\"$this->Method\" name=\"$this->Name\" id=\"$this->Name\" class=\"$this->FormClass\" style=\"margin:0px;\" $nEncoding>";
		}
		$Opener.="<input type=\"hidden\" name=\"nProcess\" id=\"nProcess\" value=\"1\">";
		$CloserButtons = "<input type=\"submit\" name=\"nSave\" id=\"nSave\" value=\"$this->SubmitText\" class=\"$this->SubmitClass\"> ";
		if(!$this->CancelRedirectIsJS && $this->CancelRedirect){ $this->CancelRedirect = "document.location.href='$this->CancelRedirect'"; }
		if($this->CancelRedirect){ $CloserButtons.= "<input type=\"button\" name=\"nCancel\" id=\"nCancel\" value=\"$this->CancelText\" class=\"$this->CancelClass\" onClick=\"$this->CancelRedirect\">"; }
		$Closer = "</form>";
		$nFormGroupCode = "";
		foreach ($this->GroupARRAY AS $nGroup){
			if(is_object($nGroup)){
				$nFormGroupCode.= $nGroup->GetFormGroup($this);
			}
		}
		// if form has been posted, process it
		if(isset($_POST["nProcess"])){ $nProcess = (isset($_POST["nProcess"]) ? $_POST["nProcess"] : NULL); } else { $nProcess = ""; }
		$nError = "";
		$nErrorCode = "";
		$nProcessRedirect = "";
		$nRequired = "";
		if($nProcess){
			$nDEBUG = $this->DEBUG; // turns off/on general debugging, including PHPMailer comprehensive debugging
			// Where the form goes after successful submission
			$nRedirect = $this->Redirect;
			// Required fields (multiple values accepted, comma-delimited)
			$nRequired = implode(",",$this->ValReqARRAY);
			// Fields to be validated (multiple values accepted, comma-delimited)
			$nValidate_email = implode(",",$this->ValEmailARRAY);
			$nValidate_numeric = implode(",",$this->ValNumARRAY);
			$nValidate_phone = implode(",",$this->ValPhoneARRAY);
			$nValidate_date = implode(",",$this->ValDateARRAY);
			$nValidate_cc = implode(",",$this->ValCCARRAY);
			$nValidate_maxlength = implode(",",$this->ValMaxLengthARRAY); $nValParam_maxlengthARRAY = $this->ValMaxLengthParamARRAY;
			$nValidate_minlength = implode(",",$this->ValMinLengthARRAY); $nValParam_minlengthARRAY = $this->ValMinLengthParamARRAY;
			$nValidate_custom = implode(",",$this->ValCustomARRAY); $nValParam_customARRAY = $this->ValCustomParamARRAY;
			// Fields to be encoded (multiple values accepted, comma-delimited)
			$nEncode_RC4 = implode(",",$this->EncodeRC4ARRAY);
			// Dont process these fields (multiple values accepted, comma-delimited)
			$nDontProcessARRAY[] = "nSave,nCancel,_";
			$nDontProcessARRAY[] = $this->DontProcess;
			$nDontProcess = implode(",",$nDontProcessARRAY);
			// Dont allow quotes around these items in the database SQL string
			$nSQLNoQuotes = $this->SQLNoQuotes;
			// Mail settings (leave everything blank if you don't want to send mail)
			$nAction_email = $this->Action_email; // (multiple values accepted, comma-delimited)
			$nAction_email_bodyFile = $this->Action_email_bodyFile;
			$nUseSendMail = $this->MailUseSendMail;
			$nMailHost = $this->MailHost;
			$nMailUser = $this->MailUser;
			$nMailPass = $this->MailPass;
			$nMailFrom = $this->MailFrom;
			$nEmailFromName = $this->EmailFromName;
			$nEmailSubject = $this->EmailSubject;
			// Database settings (leave each blank if not in use)
			$DBName = $this->DBName; $Link = $this->DBLink;
			$nAction_addtodb = $this->AddToDBTable;  // Adds data submitted to this table
			$nAction_modifydb = $this->ModifyDBTable; // Updates this table with data submitted (nAction_modifydb_id required)
			$nAction_modifydb_id = $this->ModifyDBID; // Set this to update an item (PHP can be used here)
			$nAction_modifydb_field = $this->ModifyDBField; // Set this to the field of the item to update (PHP can be used here)
			$nAction_use_adodb = $this->nUseADODB;
			// Translate these fields within a database (multiple values accepted, comma-delimited)
			// (field to be translated_db table name_db field name,...)
			$nTranslate ="";
			// Process...
			$nMySQLInsertID = "";
			$nFormProcessed = 0;
			include_once("form_process.php");
			$this->InsertID = $nMySQLInsertID;
			if($nFormProcessed){ $this->HasProcessed = 1; }
			if(!$nError && !$nAction_email && !$nAction_addtodb && !$nAction_modifydb){ $this->HasProcessed = 1; }
		}
		if($nError){ $nErrorCode = "<div id=\"errorBox\">$nError</div>"; }
		// if form processes requests this class to do the redirecting...
		if($nProcessRedirect){ return $nProcessRedirect; }
		
		// Button template
		$nFormButtonTemplate = "";
		if($this->CleanMarkup){
			$nFormButtonTemplate = "<span id=\"buttonBox\">[#Buttons#]</span>";
		} else {
			$nFormButtonTemplate = "<div align=\"center\" id=\"buttonBox\">[#Buttons#]</div>";
		}
		if($this->ButtonTemplate){ $nFormButtonTemplate = $this->ButtonTemplate; }
		if($CloserButtons){
			// Replace tags and build code
			$nTemplateTags = array("[#Buttons#]");
			$nTemplateReplacement = array($CloserButtons);
			$CloserButtons = str_replace($nTemplateTags,$nTemplateReplacement,$nFormButtonTemplate);
		}
		if(!$this->CleanMarkup){ $nClearFinal = "<div style=\"clear:both;\">&nbsp;</div>"; } else { $nClearFinal = ""; }
		return $nOnSubmitScriptCode.$nErrorCode.$Opener.$nFormGroupCode.$nClearFinal.$CloserButtons.$Closer;
	}
}

class FormGroup {
	var $Name, $Style, $Class, $Caption, $ID;
	var $FieldARRAY = array();
	
	function FormGroup (){
		// set defaults
		$this->ClearAfter = false;
	}
	function AddField($nFieldObj){
		$this->FieldARRAY[] = $nFieldObj;
	}
	function GetFormGroup($nFrmObj){
		$nGroupName = $this->Name;
		$nCaption = $this->Caption;
		$nFormFieldCode = "";
		foreach ($this->FieldARRAY AS $nField){
			if(is_object($nField)){
				$nFormFieldCode.= $nField->GetFormField($nFrmObj);
			}
		}
		if($nGroupName){
			if($nFrmObj->CleanMarkup){
				$nGroupName = "<span id=\"fieldGrpTitle\">$nGroupName</span><BR>$nCaption";
			} else {
				$nGroupName = "<div id=\"editBoxHdr\"><span id=\"fieldGrpTitle\">$nGroupName</span><BR>$nCaption</div>";
			}
		}
		
		// Form group template
		$nFormGroupTemplate = "";
		if($nFrmObj->CleanMarkup){
			$nFormGroupTemplate = "<span id=\"[#ID#]\" style=\"[#Style#]\" class=\"[#Class#]\">[#Name#][#FieldCode#]</span>";
		} else {
			$nFormGroupTemplate = "<div id=\"[#ID#]\" style=\"[#Style#]\" class=\"[#Class#]\">[#Name#]<div id=\"editBoxInner\">[#FieldCode#]</div></div>";
		}
		if($nFrmObj->GroupTemplate){ $nFormGroupTemplate = $nFrmObj->GroupTemplate; }
		// Replace tags and build code
		$nTemplateTags = array("[#ID#]","[#Style#]","[#Class#]","[#Name#]","[#FieldCode#]");
		$nTemplateReplacement = array($this->ID,$this->Style,$this->Class,$nGroupName,$nFormFieldCode);
		$nFormFieldCode = str_replace($nTemplateTags,$nTemplateReplacement,$nFormGroupTemplate);
		
		if($this->ClearAfter){ $nFormFieldCode.= "<div style=\"clear:both;\">&nbsp;</div>"; }
		
		return $nFormFieldCode;
	}
}

class FormField {
	var $Type, $ID, $Label, $Caption, $Value, $Style, $Class, $Title, $Rel, $RowSize, $RowID, $RowStyle, $RowClass, $LabelStyle, $LabelClass, $ItemStyle, $onBlur, $BeforeField, $AfterField;
	var $DataARRAY = array(),$SelectedARRAY = array(),$ValidationARRAY = array(),$ValParamARRAY = array();
	
	function FormField ($nType="text",$nID="",$nLabel=""){
		// set defaults
		$this->Type = trim($nType);
		$this->ID = trim($nID);
		$this->Label = trim($nLabel);
		$this->RowSize = "Full";
		$this->RowID = "";
	}
	function AddValidation($nValType,$nValParam=""){
		$this->ValidationARRAY[] = $nValType;
		$this->ValParamARRAY[$nValType] = $nValParam;
	}
	function GetFormField($nFrmObj){
		// validation
		$nReqCode = "";
		$nLabel = "";
		$nRequired = "";
		$nValidateEmail = "";
		$nValidateNum = "";
		$nValidatePhone = "";
		$nValidateDate = "";
		$nValidateCC = "";
		$nValidateMaxlength = ""; $nValMaxLengthParam = "";
		$nValidateMinlength = ""; $nValMinLengthParam = "";
		foreach($this->ValidationARRAY AS $nValType){
			switch($nValType){
				case "required":	$nRequired = 1; $nReqCode = "<span class=\"r\">*</span>"; break;
				case "email":		$nValidateEmail = 1; break;
				case "numeric":		$nValidateNum = 1; break;
				case "phone":		$nValidatePhone = 1; break;
				case "date":		$nValidateDate = 1; break;
				case "cc":			$nValidateCC = 1; break;
				case "maxlength":	$nValidateMaxlength = 1; $nValMaxLengthParam = $this->ValParamARRAY[$nValType]; break;
				case "minlength":	$nValidateMinlength = 1; $nValMinLengthParam = $this->ValParamARRAY[$nValType];break;
			}
		}
		if($this->Label){ $this->Label = $this->Label."$nReqCode"; }
		if(!$this->Label && $this->Caption){ $this->Caption = $this->Caption."$nReqCode"; }
		if($this->Label){
			if($nFrmObj->CleanMarkup){ $nLabel = "<label for=\"$this->ID\" id=\"fieldTitle\" style=\"[#LabelStyle#]\" class=\"[#LabelClass#]\">$this->Label</label>"; } else { $nLabel = "<div id=\"fieldTitle\">$this->Label</div>"; }
		}
		if($nFrmObj->CleanMarkup){ $nCaption = "<span class=\"caption\">$this->Caption</span>"; } else { $nCaption = "<label for=\"$this->ID\" style=\"[#LabelStyle#]\" class=\"[#LabelClass#] caption\">$this->Caption</label>"; }
		if($this->RowSize=="Full"){ $nRowID = "fieldRowFull"; } else { $nRowID = "fieldRowDualCols"; }
		if($this->RowID){ $nRowID = $this->RowID; }
		// if form has been posted, use posted values
		if(isset($_POST["nProcess"])){ $nProcess = (isset($_POST["nProcess"]) ? $_POST["nProcess"] : NULL); } else { $nProcess = ""; }
		$nAddTrigger=0;
		if(isset($_POST[$this->ID])){ $nPostVal = trim($_POST[$this->ID]); } else { $nPostVal = ""; }
		if($nProcess){
			if($this->Type!="static"){ $this->Value = $nPostVal; }
			
			// required fields
			switch($this->Type){
				case "checkbox":
					$nSelectedAmt = 0;
					foreach($this->DataARRAY AS $Key => $Item){
						if(isset($_POST[$Key])){ $nPostKey = trim($_POST[$Key]); } else { $nPostKey = ""; }
						if($nPostKey==$Key){ $nSelectedAmt++; }
					}
					if($nRequired && !$nSelectedAmt){ $this->Style = "border:1px solid #FF0000;".$this->Style; $nAddTrigger=1; }
					break;
				default: if($nRequired && !$this->Value){ $this->Style = "border:1px solid #FF0000;".$this->Style; }
			}
			// other validation
			if($this->Value){
				if($nValidateEmail && !validate_email($this->Value)){ $this->Style = "border:1px solid #FF0000;".$this->Style; }
				if($nValidateNum && !validate_num($this->Value)){ $this->Style = "border:1px solid #FF0000;".$this->Style; }
				if($nValidatePhone && !validate_phone($this->Value)){ $this->Style = "border:1px solid #FF0000;".$this->Style; }
				if($nValidateDate && !validate_date($this->Value)){ $this->Style = "border:1px solid #FF0000;".$this->Style; }
				if($nValidateCC && !validate_cc($this->Value)){ $this->Style = "border:1px solid #FF0000;".$this->Style; }
				if($nValidateMaxlength && !validate_maxlength($this->Value,$nValMaxLengthParam)){ $this->Style = "border:1px solid #FF0000;".$this->Style; }
				if($nValidateMinlength && !validate_minlength($this->Value,$nValMinLengthParam)){ $this->Style = "border:1px solid #FF0000;".$this->Style; }
			}
		}
		// JS Events
		$nCloseScript = "</script>";
		if($this->onBlur){ $this->onBlur = "onBlur=\"$this->onBlur\""; }
		$nOptionCode = "";
		
		// Field template
		$nFormFieldTemplate = "";
		if($nFrmObj->CleanMarkup){
			$nFormFieldTemplate = "<span id=\"fieldGrpBox\" style=\"[#RowStyle#]\" class=\"[#RowClass#]\">[#Label#]<span id=\"[#RowID#]\" style=\"[#ItemStyle#]\">[#BeforeField#][#Field#][#AfterField#][#Caption#]</span></span>\n";
		} else {
			$nFormFieldTemplate = "<div id=\"fieldGrpBox\" style=\"[#RowStyle#]\" class=\"[#RowClass#]\">[#Label#]<div id=\"[#RowID#]\" style=\"clear:both;\"><div id=\"fieldItem\" style=\"[#ItemStyle#]\">[#BeforeField#][#Field#][#AfterField#][#Caption#]</div></div></div>\n";
		}
		if($nFrmObj->FieldTemplate){ $nFormFieldTemplate = $nFrmObj->FieldTemplate; }
		
		switch($this->Type){
			case "text":
				$nField = "<input type=\"text\" name=\"$this->ID\" id=\"$this->ID\" value=\"$this->Value\" class=\"$this->Class\" style=\"$this->Style\" title=\"$this->Title\" rel=\"$this->Rel\" $this->onBlur>";
				break;
			case "date":
				$nField = "<input type=\"text\" name=\"$this->ID\" id=\"$this->ID\" value=\"$this->Value\" class=\"$this->Class\" title=\"$this->Title\" rel=\"$this->Rel\" style=\"$this->Style\" size=\"10\" maxlength=\"10\" class=\"format-m-d-y divider-slash highlight-days-12 no-transparency\" $this->onBlur>$this->";
				$nField.= "<script>datePickerController.create(document.getElementById(\"$this->ID\"));</script>";
				break;
			case "hidden":
				$nFormFieldTemplate = "[#Field#]"; // clear template
				$nField = "<input type=\"hidden\" name=\"$this->ID\" id=\"$this->ID\" value=\"$this->Value\" class=\"$this->Class\" style=\"$this->Style\" title=\"$this->Title\" rel=\"$this->Rel\">";
				break;
			case "textarea":
				$nField = "<textarea cols=\"20\" rows=\"2\" name=\"$this->ID\" id=\"$this->ID\" class=\"$this->Class\" style=\"$this->Style\" title=\"$this->Title\" rel=\"$this->Rel\" $this->onBlur>$this->Value</textarea>";
				break;
			case "rte":
				$nRTEInitCode = nGetFCKEditorCode($this->ID);
				$nField = "<textarea cols=\"20\" rows=\"2\" name=\"$this->ID\" id=\"$this->ID\" class=\"$this->Class\" style=\"$this->Style\" title=\"$this->Title\" rel=\"$this->Rel\" $this->onBlur>$this->Value</textarea>$nRTEInitCode";
				break;
			case "static":
				$nField = "<span $this->onBlur>$this->Value</span>";
				break;
			case "password":
				$nField = "<input type=\"password\" name=\"$this->ID\" id=\"$this->ID\" value=\"$this->Value\" class=\"$this->Class\" title=\"$this->Title\" rel=\"$this->Rel\" style=\"$this->Style\" $this->onBlur>";
				break;
			case "radio":
				// if field is required and no default selection is set, add a blank item to trigger validation
				if($nRequired && !count($this->SelectedARRAY)){ $nOptionCode.= "<input type=\"radio\" name=\"".$this->ID."\" id=\"".$this->ID."\" value=\"\" checked style=\"border:none;width:auto;display:none;\" $this->onBlur>"; }
				foreach($this->DataARRAY AS $Key => $Item){
					// if form has not been posted, use default selections, otherwise use posted
					if(!$nProcess){
						if(isset($this->SelectedARRAY[$Key])){ $nSel="checked"; } else { $nSel=""; }
					} else {
						if($nPostVal==$Key){ $nSel="checked"; } else { $nSel=""; }
					}
					$nOptionCode.= "<label for=\"$this->ID$Key\" style=\"[#LabelStyle#]\" class=\"[#LabelClass#] hand\"><input type=\"radio\" name=\"$this->ID\" id=\"$this->ID$Key\" value=\"$Key\" $nSel class=\"$this->Class\" title=\"$this->Title\" rel=\"$this->Rel\" style=\"border:none;width:auto;$this->Style\">$Item</label>";
				}
				$nField = "$nCaption $nOptionCode";
				$nFormFieldTemplate = str_replace("[#Caption#]","",$nFormFieldTemplate); // force caption to appear in (before) field
				break;
			case "select":
			case "multiSelect":
				$this->onBlur = str_replace("onBlur","onChange",$this->onBlur);
				foreach($this->DataARRAY AS $Key => $Item){
					// if form has not been posted, use default selections, otherwise use posted
					if(!$nProcess){
						if(isset($this->SelectedARRAY[$Key])){ $nSel="SELECTED"; } else { $nSel=""; }
					} else {
						if($nPostVal==$Key){ $nSel="SELECTED"; } else { $nSel=""; }
					}
					$nOptionCode.= "<option value=\"$Key\" $nSel $this->onBlur>$Item</option>";
				}
				if($this->Type=="multiSelect"){ $nMultiSelect = " mulitple"; } else { $nMultiSelect = ""; }
				$nField = "<select$nMultiSelect name=\"$this->ID\" id=\"$this->ID\" class=\"$this->Class\" title=\"$this->Title\" rel=\"$this->Rel\" style=\"$this->Style\" $this->onBlur>$nOptionCode</select>";
				break;
			case "checkbox":
				$this->onBlur = str_replace("onBlur","onClick",$this->onBlur);
				foreach($this->DataARRAY AS $Key => $Item){
					if(isset($_POST[$Key])){ $nPostKey = trim($_POST[$Key]); } else { $nPostKey = ""; }
					// if form has not been posted, use default selections, otherwise use posted
					if(!$nProcess){
						if(isset($this->SelectedARRAY[$Key])){ $nSel="checked"; } else { $nSel=""; }
					} else {
						if($nPostKey){ $nSel="checked"; } else { $nSel=""; }
					}
					$nOptionCode.= "<label for=\"$Key\" style=\"[#LabelStyle#]\" class=\"[#LabelClass#] hand\"><input type=\"checkbox\" name=\"$Key\" id=\"$Key\" value=\"X\" $nSel style=\"border:none;width:auto;$this->Style\" $this->onBlur>$Item</label>";
				}
				// if field is required, add a blank item to trigger validation
				if($nAddTrigger){ $nOptionCode.= "<input type=\"hidden\" name=\"$this->ID\" id=\"$this->ID\" value=\"\">"; }
				$nField = "$nCaption $nOptionCode";
				$nFormFieldTemplate = str_replace("[#Caption#]","",$nFormFieldTemplate); // force caption to appear in (before) field
				break;
			case "file":
				$this->onBlur = str_replace("onBlur","onChange",$this->onBlur);
				$nField = "<input type=\"file\" name=\"$this->ID\" id=\"$this->ID\" style=\"$this->Style\" $this->onBlur>";
		}
		// Replace tags and build code
		$nTemplateTags = array("[#RowStyle#]","[#RowClass#]","[#Label#]","[#LabelRaw#]","[#ItemStyle#]","[#BeforeField#]","[#AfterField#]","[#Caption#]","[#Field#]","[#RowID#]","[#LabelStyle#]","[#LabelClass#]");
		$nTemplateReplacement = array($this->RowStyle,$this->RowClass,$nLabel,$this->Label,$this->ItemStyle,$this->BeforeField,$this->AfterField,$nCaption,$nField,$nRowID,$this->LabelStyle,$this->LabelClass);
		$nFormFieldCode = str_replace($nTemplateTags,$nTemplateReplacement,$nFormFieldTemplate);
		
		return $nFormFieldCode;
	}
}

// Validators
function validate_email($email) { 
	$nIsValid = TRUE;
	if(preg_match("/^[_\.0-9a-zA-Z-]+@([0-9a-zA-Z][0-9a-zA-Z-]+\.)+[a-zA-Z]{2,6}$/i", $email)) {
		$nIsValid = TRUE;
	} else {
		$nIsValid = FALSE;
	}
	return $nIsValid; 
}
function validate_num($nValue) { 
	$nIsValid = TRUE;
	if(!is_numeric($nValue)){ $nIsValid = FALSE; }
	return $nIsValid; 
}
function validate_phone($nValue){
	// removes all allowed characters and validates rest as numeric
	$nStripThese = array("(",")"," ",".","-","+");
	$nValue = str_replace($nStripThese,"",$nValue);
	return validate_num($nValue);
}
function validate_date($nValue){
	// date must be in this format: 00/00/0000
	$nRemoveMe = array("/");
	$nFormattedDate = str_replace($nRemoveMe,"",$nValue);
	if(strlen($nFormattedDate)<6 || strlen($nFormattedDate)>8){ return 0; }
	if(!is_numeric($nFormattedDate)){ return 0; }
	return 1;
}
function validate_cc($nValue){
    if(!validate_num($nValue)){ return 0; }
	$GoodCard = true;
//  Get rid of any non-digits
    $nValue = ereg_replace("[^0-9]", "", $nValue);
//  The Luhn formula works right to left, so reverse the nValueber.
    $nValue = strrev($nValue);
    $Total = 0;
    for ($x=0; $x<strlen($nValue); $x++) {
      $digit = substr($nValue,$x,1);
//    If it's an odd digit, double it
      if ($x/2 != floor($x/2)) {
        $digit *= 2;
//    If the result is two digits, add them
        if (strlen($digit) == 2)
          $digit = substr($digit,0,1) + substr($digit,1,1);
      }
//    Add the current digit, doubled and added if applicable, to the Total
      $Total += $digit;
    }
//  If it passed (or bypassed) the card-specific check and the Total is
//  evenly divisible by 10, it's cool!
    if ($GoodCard && $Total % 10 == 0) return true; else return false;
}
function validate_maxlength($nValue,$nLength){
	if(strlen($nValue)>$nLength){ return 0; }
	return 1;
}
function validate_minlength($nValue,$nLength){
	if(strlen($nValue)<$nLength){ return 0; }
	return 1;
}
function validate_custom($nValue,$nFunctionName){
	$nSuccessful = 0;
	eval("\$nSuccessful = $nFunctionName('$nValue');");
	return $nSuccessful;
}
function nGetFCKEditorCode($nFieldID){
	if(!$nFieldID){ return; }
	$nRTEID = "oFCKeditor".$nFieldID;
	$nCloseScript = "</script>";
	$nFCKEditorCode = <<<CODE
		<script type="text/javascript">
		//window.onload = function(){
			FCKeditorAPI = null;
			__FCKeditorNS = null;
			var $nRTEID = new FCKeditor( '$nFieldID' ) ;
			$nRTEID.BasePath	= 'rte/';
			$nRTEID.Config['SkinPath'] = 'skins/office2003/';
			$nRTEID.Height	= 250;
			$nRTEID.ToolbarSet = "Normal";
			$nRTEID.ReplaceTextarea();
		//}
		// function FCKeditor_OnComplete( editorInstance ){ editorInstance.Events.AttachEvent( 'OnAfterLinkedFieldUpdate', DoSomething ) ; }
		$nCloseScript
CODE;
	return $nFCKEditorCode;
}
?>