/*
The SoftAd Group
Copyright (c) 2000-2004 The SoftAd Group, Inc.  All rights reserved
*/

//To use this object the following files must be also included.
// CNCommon.js
// CNString.js
// HTMLDom.js

// -------------------------------------------------------------------------------
// File name        : CNForm.js
// -------------------------------------------------------------------------------
// Author           : Scott Pennington
// Created on       : June 24, 2003
// 
// This file contains the the CNForm object that holds all the generic methods
// for Form handling and Submitting that are used in ChannelNet.  When this file is to be extended, create
// a new file with and add a suffix with the Context i.e. CNForm_Catalog.js  This way 
// it will be clear that the Catalog object will call the CNForm object for its basic 
// function and take advantage of any code that was writen generically.
// -------------------------------------------------------------------------------
// Last Updated     : November 6, 2003
// Updated by       : Ken Wimberley
// -------------------------------------------------------------------------------
// Copyright (c) 2004 The SoftAd Group, Inc.


// -------------------------------------------------------------------------------
// Function         : CNForm()
// -------------------------------------------------------------------------------
// Author           : Scott Pennington
// Created on       : June 23, 2003
// 
// This function creates the CNForm 
//
// -------------------------------------------------------------------------------
// Parameters
// -------------------------------------------------------------------------------
// NAME				TYPE        DESCRIPTION
// -------------------------------------------------------------------------------
// Last Updated     : November 6, 2003
// Updated by       : Ken Wimberley
// -------------------------------------------------------------------------------

/*Begin Class*/
function CNForm() {
	//	********************** Public properties *******************
	//	************************************************************
	this.value = null;
	this.length = null;
	this.CNForm = null;					// Pointer to main ChannelNet HTML form
	this.form = null;					// Pointer back to the HTML form
	this.bSubmitted = false;
	this.cn = "";
	this.act = "";
	this.crt = "";
	this.lang = "";
	this.style = "";
	this.pageID = "";
	this.debug = "";
	this.xml = "";
	this.bValidate = true;
	this.sCrtElementName = "";
	this.sCharIgnore = "_";
	this.sBlueMartiniCharIgnore = "bm";
	this.mValueHash = new Object();		//contains the named values managed by this instance of CNForm. 
	this.mDefaultValueHash = new Object();		//contains the named default values managed by this instance of CNForm. 
	this.mNames     = new Array();		//an Array of all of the names managed by the object. 
	this.mValidatorHash = new Object();	//contains the validation functions for each named value. 
	this.debugMode = false;
	
	//	********************** Public methods **********************
	//	************************************************************
	this.setForm = setForm;
	this.submitGrammar = submitGrammar;
	this.submitEnvironment = submitEnvironment;
	this.submitMultiActionGrammar = submitMultiActionGrammar;
	this.submitMultiActionWithArray = submitMultiActionWithArray;
	this.submitAndClose = submitAndClose;
	this.compare = null;
	this.remove = null;
	
	this.getValue = getValue;
	this.setValue = setValue;
	this.setValueFromInput = setValueFromInput;
	this.setValidator = setValidator;
	this.getMessage = getMessage;
	this.getNames = getNames;
	this.fromString = fromString;
	this.fromForm = fromForm;
	this.toString = toString;
	this.toForm = toForm;
	this.validateField = validateField;
	this.getCriteria = getCriteria;
	this.handleSubmit = handleSubmit;
	this.isValidForm = isValidForm;
		
	//	********************** Private methods **********************
	//	************************************************************	
	this._clearForm = _clearForm;
	this._getForm = _getForm;
	this._toFormValue = _toFormValue;
	this._getValidationArgs = _getValidationArgs;
	this._getRegEx = _getRegEx;
	this._createCNElements = _createCNElements;
	this._hasFormChanged = _hasFormChanged;
	this._getDefaultValue = _getDefaultValue;
	this._isValidCNForm = _isValidCNForm;
	this._setOnBlurHandler = _setOnBlurHandler;
	this._isIgnoredField = _isIgnoredField;
	this._trimMessage = _trimMessage;
	this._isCNField = _isCNField;
	//	************************** Globals *******************//******
	//	************************************************************
	var bReturn;
	var iReturn;
	var sReturn = "";
	var sErrors = "";
	var oReturn = null;
	
	
	// -------------------------------------------------------------------------------
	// Method	        : setForm(oHTMLForm)
	// -------------------------------------------------------------------------------
	// Author           : Scott Pennington
	// Created on       : June 24, 2003
	// 
	// This function sets an HTML Form into the form property
	//
	// -------------------------------------------------------------------------------
	// Parameters
	// Returns true if oHTMLForm is a Form object
	// -------------------------------------------------------------------------------
	// NAME				TYPE        DESCRIPTION
	// -------------------------------------------------------------------------------
	// Last Updated     : 
	// Updated by       : 
	// -------------------------------------------------------------------------------
	function setForm(oHTMLForm) {   
		var bReturn = false;
		if(oHTMLForm.nodeName == 'FORM'){
			this.CNForm = oHTMLForm;
			bReturn =  true;
		}
		return bReturn;
	}
	
	// -------------------------------------------------------------------------------
	// Method	        : _clearForm()
	// -------------------------------------------------------------------------------
	// Author           : Ken Wimberley
	// Created on       : August 1, 2003
	// 
	// This function clears the ChannelNet form element values and sets to "".
	// -------------------------------------------------------------------------------
	// Last Updated     : November 12, 2003
	// Updated by       : Ken Wimberley
	// -------------------------------------------------------------------------------		
	function _clearForm(){
		this.CNForm = this._getForm();
		bReturn = false;
		try {
			this.CNForm.cn.value		= "";
			this.CNForm.act.value		= "";
			this.CNForm.crt.value		= "";
			this.CNForm.lang.value		= "";
			//this.CNForm.pageID.value		= "";
			//this.CNForm.debug.value		= "";
			this.CNForm.xml.value		= "";
			bReturn = true;
		}
		catch(e) {
			if(this.debugMode)
				alert("The channelnet form on this page does not adhere to ChannelNet grammar rules.");
		}
		finally {
			return bReturn;
		}
	}
	
	// -------------------------------------------------------------------------------
	// Method	        : _getForm()
	// -------------------------------------------------------------------------------
	// Author           : Ken Wimberley
	// Created on       : November 5, 2003
	// 
	// This function finds and returns the main ChannelNet submittal form.
	// -------------------------------------------------------------------------------
	// Last Updated     : 
	// Updated by       : 
	// -------------------------------------------------------------------------------
	function _getForm(){
		oReturn = null;
		var iLen = document.forms.length;
		for(var i=0; i<iLen; i++){
			if(document.forms && document.forms[i].name.toString().toLowerCase() == "channelnet"){
				oReturn = document.forms[i];
				break;
			}			
		}
		return oReturn;
	}

	// -------------------------------------------------------------------------------
	// Method	        : submitGrammar(oCNGrammar)
	// -------------------------------------------------------------------------------
	// Author           : Ken Wimberley
	// Created on       : August 1, 2003
	// 
	// This function is the final step in posting a form to ChannelNet with a single action grammar.
	// -------------------------------------------------------------------------------
	// Returns true if oHTMLForm is a Form object
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME				TYPE        DESCRIPTION
	// oCNGrammar		object		CNGrammar object
	// -------------------------------------------------------------------------------
	// Last Updated     : 
	// Updated by       : 
	// -------------------------------------------------------------------------------
	function submitGrammar(oCNGrammar){		
		if(this._clearForm()){
			this.CNForm.cn.value		= oCNGrammar.cn;
			this.CNForm.act.value		= oCNGrammar.act;
			this.CNForm.crt.value		= oCNGrammar.crt;
			this.CNForm.lang.value		= oCNGrammar.lang;
			this.CNForm.style.value		= oCNGrammar.style;
			this.CNForm.pageID.value	= oCNGrammar.pageID;
			this.CNForm.debug.value		= oCNGrammar.debug;
			this.CNForm.submit();
		}
	}

	// -------------------------------------------------------------------------------
	// Method	        : submitEnvironment(oCNEnvironment)
	// -------------------------------------------------------------------------------
	// Author           : Ken Wimberley
	// Created on       : August 1, 2003
	// 
	// This function is the final step in submitting a form to ChannelNet with 
	// a mult-action cnenvironment.
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME				TYPE        DESCRIPTION
	// oCNEnvironment	object		CNEnvironment object
	// -------------------------------------------------------------------------------
	// Last Updated     : 
	// Updated by       : 
	// -------------------------------------------------------------------------------	
	function submitEnvironment(oCNEnvironment){
		if(this._clearForm()){
			this.CNForm.xml.value = oCNEnvironment.getXML();
			this.CNForm.submit();
		}
	}
	
	function submitMultiActionGrammar(){
		var args = submitMultiActionGrammar.arguments;
		var argLen = args.length;
		var oCNGrammar = null;
		var oForm;
		try{			
			if(this._clearForm()){
				var aryCNGrammars = new Array();
				for(var i=0; i<argLen; i++){
					oForm = document.getElementById(args[i]);
					oForm.crt.value = oForm.oCNForm.getCriteria();					
					oCNGrammar = oCNFormHandler.getGrammar(args[i],false);
					if(oCNGrammar){
						aryCNGrammars[i] = oCNGrammar;					
					}
				}
				var CNGrammarsLen = aryCNGrammars.length;
				if(this._createCNElements(CNGrammarsLen)){
					var iIndex;
					for(var i=0; i<CNGrammarsLen; i++){
						iIndex = i+1;
						oCNGrammar = aryCNGrammars[i];
						
						// Have to use document.getElementById because we added these
						// elements dynamically						
						document.getElementById('cn' + iIndex).value	= oCNGrammar.cn;
						document.getElementById('act' + iIndex).value	= oCNGrammar.act;
						document.getElementById('crt' + iIndex).value	= oCNGrammar.crt;
						document.getElementById('lang' + iIndex).value	= oCNGrammar.lang;
						if(document.getElementById('style' + iIndex)){
							document.getElementById('style' + iIndex).value	= oCNGrammar.style;
						}
						document.getElementById('label' + iIndex).value	= oCNGrammar.label;
					}
					this.CNForm.submit();
				}
			}
		}
		catch(e){
			if(this.debugMode)
				alert("Error: CNForm.submitMultiActionGrammar()");
		}		
	}	
	
	function submitMultiActionWithArray(aryOForms){
		var oFormsLen = aryOForms.length;
		var oCNGrammar = null;
		var oForm;
		try{			
			if(this._clearForm()){
				var aryCNGrammars = new Array();
				for(var i=0; i<oFormsLen; i++){
					oForm = aryOForms[i];
					oForm.crt.value = oForm.oCNForm.getCriteria();
					oCNGrammar = oCNFormHandler.getGrammar(oForm.id,false);
					if(oCNGrammar){
						aryCNGrammars[aryCNGrammars.length] = oCNGrammar;					
					}
				}
				var CNGrammarsLen = aryCNGrammars.length;
				if(this._createCNElements(CNGrammarsLen)){
					var iIndex;
					for(var i=0; i<CNGrammarsLen; i++){
						iIndex = i+1;
						oCNGrammar = aryCNGrammars[i];
						
						// Have to use document.getElementById because we added these
						// elements dynamically						
						document.getElementById('cn' + iIndex).value	= oCNGrammar.cn;
						document.getElementById('act' + iIndex).value	= oCNGrammar.act;
						document.getElementById('crt' + iIndex).value	= oCNGrammar.crt;
						document.getElementById('lang' + iIndex).value	= oCNGrammar.lang;
						if(document.getElementById('style' + iIndex)){
							document.getElementById('style' + iIndex).value	= oCNGrammar.style;
						}
						document.getElementById('label' + iIndex).value	= oCNGrammar.label;
					}
					this.CNForm.submit();
				}
			}
		}
		catch(e){
			if(this.debugMode)
				alert("Error: CNForm.submitMultiActionWithArray()");
		}		
	}
	
	function _createCNElements(iNum){
		bReturn = false;
		var oInput;
		var aryCNParamNames = new Array('cn','act','crt','lang','style','label');
		try{
			// Remove existing CNParameter elements
			// Netscape has issues with removeNode
			// IE has issues with removeChild
			if(document.removeNode){
				this.CNForm.cn.removeNode(true);
				this.CNForm.act.removeNode(true);
				this.CNForm.crt.removeNode(true);
				this.CNForm.lang.removeNode(true);
				this.CNForm.style.removeNode(true);
				this.CNForm.xml.removeNode(true);
			} else {
				this.CNForm.removeChild(this.CNForm.cn);
				this.CNForm.removeChild(this.CNForm.act);
				this.CNForm.removeChild(this.CNForm.crt);
				this.CNForm.removeChild(this.CNForm.lang);
				this.CNForm.removeChild(this.CNForm.style);
				this.CNForm.removeChild(this.CNForm.xml);
			}
			
			for(var i=1; i<=iNum; i++){
				for(var j=0; j<aryCNParamNames.length; j++){
					oInput = document.createElement('INPUT');
					oInput.name = new String(aryCNParamNames[j] + i);
					oInput.id = new String(aryCNParamNames[j] + i);
					oInput.type = "hidden";
					this.CNForm.appendChild(oInput);
				}
			}
			bReturn = true;
		}
		catch(e){
			if(this.debugMode)
				alert("Error: CNForm._createCNElements()");
		}
		finally{
			return bReturn;
		}
	}
	
	
	// -------------------------------------------------------------------------------
	// Function         : submitAndClose(oForm)
	// -------------------------------------------------------------------------------
	// This function submits a form and then closes the window
	// -------------------------------------------------------------------------------
	// Returns true if the form has been submitted and false otherwise.
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME			TYPE			DESCRIPTION
	// oForm        form object     The form to validate and submit
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 02/06/2001   Chad Peck		Created
	// 08/05/2003	Ken Wimberley	Updated

	function submitAndClose(oForm) {		
		var bReturn = false;		
		if(oForm) {
			if(window.opener) {
				window.opener.name = "mainWindow";
				form.target = "mainWindow";
			}
			
			if(submitCNForm(oForm)) {
				self.close();
				bReturn = true;
			}
		}		
		return bReturn;
	}
	
	// -------------------------------------------------------------------------------
	// Function         : getValue(sName)
	// -------------------------------------------------------------------------------
	// This function gets the value from the mValueHash obj associated with sName
	// -------------------------------------------------------------------------------
	// Returns null, '', or value
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME			TYPE		DESCRIPTION
	// sName        string		Name property associated with name of form element
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 11/10/2003   Ken Wimberley	Created	
	function getValue(sName){
		var oValues = this.mValueHash[sName];
		
		if (typeof(oValues) == 'undefined'){
			return null;
		}
		
		if (!oValues || oValues.length == 0){
			return '';
		}
		
		if (oValues.length == 1){
			return oValues[0];
		}
		
		return oValues;
	}
	
	// -------------------------------------------------------------------------------
	// Function         : _getDefaultValue(sName)
	// -------------------------------------------------------------------------------
	// This function gets the default value from the mDefaultValueHash obj associated with sName
	// -------------------------------------------------------------------------------
	// Returns null, '', or value
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME			TYPE		DESCRIPTION
	// sName        string		Name property associated with name of form element
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 11/10/2003   Ken Wimberley	Created		
	function _getDefaultValue(sName){
		var oValues = this.mDefaultValueHash[sName];
		
		if (typeof(oValues) == 'undefined'){
			return null;
		}
		
		if (!oValues || oValues.length == 0){
			return '';
		}
		
		if (oValues.length == 1){
			return oValues[0];
		}
		
		return oValues;
	}	
	
	
	// -------------------------------------------------------------------------------
	// Function         : setValue(sName, vValue)
	// -------------------------------------------------------------------------------
	// This function sets the name and value to the mValueHash obj
	// Assigns the default isValid function.
	// Initializes this.crt and this.sCrtElementName property if the sName.toLowerCase() == 'crt'
	// Manages the HTML form.element values
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME			TYPE						DESCRIPTION
	// sName        string						Name property associated with name of form element
	// vValue		variant (string or array)	Value property associated with value of named form element
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 01/06/2005   Ken Wimberley	Added logic to manage this.CNForm.element values.
	function setValue(sName, vValue){
		if (!this.mValueHash[sName]){
			this.mNames[this.mNames.length] = sName;
			this.mValidatorHash[sName] = { isValid: function() { return true; }, message: ''};
		}
		
		if (typeof(vValue) != 'string' && typeof(vValue.length) == 'number'){
			this.mValueHash[sName] = vValue.slice(0);
			if(this.mDefaultValueHash[sName] == null){
				this.mDefaultValueHash[sName] = vValue.slice(0);
			}
		} else {
			this.mValueHash[sName] = [ vValue ];
			// Logic to manage this.form.element values.
			this.form.elements[sName].value = vValue;
			
			if(this.mDefaultValueHash[sName] == null){
				this.mDefaultValueHash[sName] = [ vValue ];
			}
		}
				
		switch(sName.toLowerCase()){
			case "cn":
				this.cn = vValue;
				break;
			
			case "act":
				this.act = vValue;
				break;
			
			case "crt":
				this.crt = vValue;
				this.sCrtElementName = sName;
				break;				
			
			case "lang":
				this.lang = vValue;
				break;
			
			case "style":
				this.style = vValue;
				break;
			
			case "pageid":
				this.pageID = vValue;
				break;
			
			case "debug":
				this.debug = vValue;
				break;
		}
	}
		
	// -------------------------------------------------------------------------------
	// Function         : setValueFromInput(oInput)
	// -------------------------------------------------------------------------------
	// This function prepares the this.setValue function call
	// Sets the value to the mValueHash obj associated with oInput.name
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME			TYPE		DESCRIPTION
	// oInput		object		Form element
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 11/10/2003   Ken Wimberley	Created	
	function setValueFromInput(oInput){
		var aryValues = new Array();
		var colInputs = oInput.form[oInput.name];
		if (colInputs.options){
			colInputs = colInputs.options; // for opera
		}
		
		if (typeof(colInputs.length) != 'number'){
			aryValues[0] = oInput.value;
		} else {
			var iLen = colInputs.length;
			for (var i=0; i<iLen ; ++i){
				if (colInputs[i].checked || colInputs[i].selected){
					aryValues[aryValues.length] = colInputs[i].value;
				}
			}
		}
		this.setValue(oInput.name, aryValues);
	}
	
	// -------------------------------------------------------------------------------
	// Function         : setValidator(sName, funcValidator, sRegEx, sMessage)
	// -------------------------------------------------------------------------------
	// This function sets the name, function pointer, regular expression and error message 
	//  to the mValidatorHash obj
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME				TYPE				DESCRIPTION
	// sName			string				Name property associated with name of form element
	// funcValidator	function pointer	Function pointer for field validation
	// sRegEx			string				Regular expression for validation
	// sMessage			string				Error message
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 11/10/2003   Ken Wimberley	Created
	function setValidator(sName, funcValidator, sRegEx, sMessage){
		var isValid = funcValidator;
		this.mValidatorHash[sName] = { isValid: isValid, re: sRegEx, message: sMessage };
	}
	
	// -------------------------------------------------------------------------------
	// Function         : validateField(sName)
	// -------------------------------------------------------------------------------
	// This function calls the function defined (function pointer) for the associated sName
	// in the mValidatorHash obj.
	// -------------------------------------------------------------------------------
	// Returns true/false if valid
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME				TYPE				DESCRIPTION
	// sName			string				Name property associated with name of form element
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 11/10/2003   Ken Wimberley	Created
	function validateField(sName){		
		var validator = this.mValidatorHash[sName];
		
		if (validator){
			var re = this._getRegEx(sName);
			var sMessage = this.getMessage(sName);
			
			return validator.isValid(this, re, sName, sMessage);
		}
		return true;
	}
	
	// -------------------------------------------------------------------------------
	// Function         : _getRegEx(sName)
	// -------------------------------------------------------------------------------
	// This helper function gets the regular expression for the associated sName
	// in the mValidatorHash obj.
	// -------------------------------------------------------------------------------
	// Returns regular expression or null
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME				TYPE				DESCRIPTION
	// sName			string				Name property associated with name of form element
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 11/10/2003   Ken Wimberley	Created	
	function _getRegEx(sName){
		var validator = this.mValidatorHash[sName];
		if (validator){
			return validator.re;
		}
		return null;
	}
	
	// -------------------------------------------------------------------------------
	// Function         : getMessage(sName)
	// -------------------------------------------------------------------------------
	// This helper function gets the error message string for the associated sName
	// in the mValidatorHash obj.
	// -------------------------------------------------------------------------------
	// Returns error message or null
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME				TYPE				DESCRIPTION
	// sName			string				Name property associated with name of form element
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 11/10/2003   Ken Wimberley	Created		
	function getMessage(sName){
		var validator = this.mValidatorHash[sName];
		if (validator){
			var sMsg = this._trimMessage(validator.message);
			if(this.debugMode) sMsg = sName + ': ' + sMsg;
			return sMsg;
		}
		return null;
	}
	
	function _trimMessage(sMsg){
		sMsg = oCNString.Trim(sMsg)
		if(sMsg.charAt(0) == "'" || sMsg.charAt(0) == '"') sMsg = sMsg.substring(1, sMsg.length);
		if(sMsg.charAt(sMsg.length-1) == "'" || sMsg.charAt(sMsg.length-1) == '"') sMsg = sMsg.substring(0, sMsg.length-1);
		return sMsg
	}
	
	// -------------------------------------------------------------------------------
	// Function         : getNames()
	// -------------------------------------------------------------------------------
	// Returns an array containing the names of all values contained in the object. 
	// -------------------------------------------------------------------------------
	// Returns an array
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME				TYPE				DESCRIPTION
	// sName			string				Name property associated with name of form element
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 11/10/2003   Ken Wimberley	Created
	function getNames(){
		var aryNames = this.mNames.slice(0);
		return aryNames;
	}
	
	// -------------------------------------------------------------------------------
	// Function         : fromString(sQueryString)
	// -------------------------------------------------------------------------------
	// Loads an instance of CNForm from the query string into the object. 
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME				TYPE		DESCRIPTION
	// sQueryString		string		HTML document query string (document.location.search)
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 11/10/2003   Ken Wimberley	Created	
	function fromString(sQueryString){
		if (!sQueryString){
			return;
		}
		
		if (sQueryString.indexOf('?') == 0);{
			sQueryString = sQueryString.substring(1);
		}
		sQueryString = sQueryString.replace(/[\&]amp;/g, '&');
		var aryParmList = sQueryString.split('&');
		var iLen = aryParmList.length;
		for (var i=0; i<iLen ; i++){
			var a     = aryParmList[i].split('=');
			var sName  = unescape(a[0]);
			var value;
			if (a.length == 1){
				value = true;
			} else {
				value = a[1].replace(/\+/g, ' ');
				value = unescape(value);
			}
			if (!this.mValueHash[sName]){
				this.mValueHash[sName] = [ value ];
				this.mDefaultValueHash[sName] = [ value ];
				this.mNames[this.mNames.length] = sName;
			} else {
				this.mValueHash[sName][this.mValueHash[sName].length] = value;
				this.mDefaultValueHash[sName][this.mValueHash[sName].length] = value;
			}
		}
	}
	
	// -------------------------------------------------------------------------------
	// Function         : fromForm(oForm)
	// -------------------------------------------------------------------------------
	// Loads an instance of CNForm from the inputs of the specified ChannelNet form
	// Sets the validation handlers for all inputs that have an ONCHANGE event handler
	// 
	// NOTE:	only "validate" calls are assigned to this object's internal error handling
	//			Other onchange error handling is ignored by this object but can be put in
	//			to handle custom error handling.
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME		TYPE		DESCRIPTION
	// oForm	object		HTML form object
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 11/10/2003   Ken Wimberley	Created	
	function fromForm(oForm){
		// First reset the form to insure that values are defaulted.
		oForm.reset();
		
		var values;
		var aryArgs;
		var iLen = oForm.elements.length;
		for (var i=0; i<iLen ; ++i){
			var oInput = oForm.elements[i];
			if(oInput.name.toLowerCase() == "_dontvalidate"){
				this.bValidate = false;
			}
			if (!oInput.name || typeof(oInput.value) == 'undefined'){
				continue; // skip non values
			}
			this.setValueFromInput(oInput);
			// Set the event handler to keep input and object in synch:
			this._setOnBlurHandler(oInput);
			if (!oInput.disabled		&& 
				oInput.type != "hidden"	&& 
				oInput.onchange			&& 
				oInput.onchange != "") {
					aryArgs = this._getValidationArgs(oInput);	
					if(aryArgs){
						// aryArgs[1] = regular expression string
						// aryArgs[2] = message string
						this.setValidator(oInput.name, validate, eval(aryArgs[1]), aryArgs[2]);
					}
			}
		}
		// Set the pointer to the oCNForm object as an expando property of the HTML form
		oForm.oCNForm = this;
		// Set the pointer to the HTML form as a property of the oCNForm object.
		this.form = oForm;
		// Set the pointer to the main ChannelNet HTML form
		this.setForm(oForm);
	}
	
	// -------------------------------------------------------------------------------
	// Function         : _getValidationArgs(oInput)
	// -------------------------------------------------------------------------------
	// Identifies and returns the arguments associated with the "validate()"  function
	// "validate" calls are assigned to this object's internal error handling.
	// -------------------------------------------------------------------------------
	// Returns aryArgs array with:
	// aryArgs[1] = regular expression string
	// aryArgs[2] = message string
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME		TYPE		DESCRIPTION
	// oInput	object		Form element object
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 11/10/2003   Ken Wimberley	Created
	function _getValidationArgs(oInput){
		var sFunction, sArgs;		
		var sFunction = oInput.onchange.toString();		
		var bSpecialValidation = (sFunction.indexOf(' validate(',0) == -1);
		if(bSpecialValidation){
			return false;
		} else {
					
			var iStart, iEnd, iCount;
			var bInString = false;
			var sThisChar, sLastChar;
			var sSpace = " ";
			var sEscape = "\\";
			var sComma = ",";
			var sSingle = "'";
			var sDouble = '"';
			var aryArgs = new Array();
						
			iStart = sFunction.indexOf("(",22);
			iEnd = sFunction.lastIndexOf(")",sFunction.length);		
			sArgs = sFunction.substring(iStart+1, iEnd);
			/*
				Loop through sArgs characters and build array of arguments.
				1.)  Begin iStart at 0
				2.)  Check for commas and quotes, double and/or single
				3.)  Make sure the character immediately preceding isn't an escape character "\"
				4.)  If not, take substring from iStart to iEnd as argument.
				5.)  Move iStart to iEnd+1
				6.)  If a quote exists set bInsString to true
				7.)  If an occurence of a quote occurs and bInsString is true and quote not preceded by escape character
					 then take substring from iStart to iEnd as string argument.
			*/
			iStart = 0;
			iEnd = 0;
			iCount = 0;
			
			var iLen = sArgs.length;
			for(iEnd=1; iEnd<iLen; iEnd++){
				sThisChar = sArgs.charAt(iEnd);
				sLastChar = sArgs.charAt(iEnd -1);
				if(!bInString){
					((sThisChar == sSingle || sThisChar == sDouble) && sLastChar != sEscape) ? bInString = true : bInString = false;
				}
							
				if(sThisChar == sComma && sLastChar != sEscape){
					if(bInString && (sLastChar == sSingle || sLastChar == sDouble)){	// End of String argument
						aryArgs[iCount] = sArgs.substring(iStart, iEnd);
						iCount++;
						iStart = iEnd+1;
					} 
					
					if (!bInString) {		// End of Object argument
						aryArgs[iCount] = sArgs.substring(iStart, iEnd);
						iCount++;
						iStart = iEnd+1;
					}
				}						
			}
			(bInString)? aryArgs[iCount] = sArgs.substring(iStart, iEnd +1): aryArgs[iCount] = sArgs.substring(iStart, iEnd +1); 
			return aryArgs;
		}
	}
	
	// -------------------------------------------------------------------------------
	// Function         : toString()
	// -------------------------------------------------------------------------------
	// The toString returns a string representing a specified object.  The toString method 
	// (which comes with every object) is automatically called.
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 11/10/2003   Ken Wimberley	Created	
	function toString(){
		var parms = '';
		for (var name in this.mValueHash){
			for (var j = 0; j < this.mValueHash[name].length; ++j){
				if (parms){
					parms += '&';
				}
				var value = this.mValueHash[name][j];
				value = escape(value);
				value = value.replace(/\+/g, '%2B');
				parms += name + '=' + value;
			}
		}
		parms = '?' + parms;
		return parms;
	}
	
	// -------------------------------------------------------------------------------
	// Function         : getCriteria()
	// -------------------------------------------------------------------------------
	// Returns an escaped string representing ChannelNet criteria
	// Ignores form elements whose names begin are prefixed with the "_" (underscore character)
	// Ignores 'cn', act', 'crt', 'lang', 'style', 'pageid', and 'debug' form elements.
	// 'crt' is ignored because 'crt' is already stored internally within this object
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 11/10/2003   Ken Wimberley	Created
	// 03/22/2004	Ken Wimberley	Removed bEscape param, enforcing encodeURIComponent
	// 01/31/2006	Ken Wimberley	Added this.sBlueMartiniCharIgnore check
	// 02/03/2006	Ken Wimberley	Added this._isCNField check
	function getCriteria(aryIgnoreFields){
		var crt = this.crt;
		for (var name in this.mValueHash){
			var iLen = this.mValueHash[name].length;
			for (var j=0; j<iLen ; ++j){
				if(this._isCNField(name)){
					if(aryIgnoreFields){
						if(	name.toLowerCase() != 'cn' &&
							name.toLowerCase() != 'act' &&
							name.toLowerCase() != 'crt' &&
							name.toLowerCase() != 'lang' &&
							name.toLowerCase() != 'style' &&						
							name.toLowerCase() != 'pageid' &&
							name.toLowerCase() != 'debug' &&
							name.toLowerCase() != 'xml' &&
							!this._isIgnoredField(name.toLowerCase(),aryIgnoreFields) ){
								var value = this.mValueHash[name][j];
								while(value.indexOf('\r\n') >=0){
									value = value.replace('\r\n', '<br/>');
								}
								value = encodeURIComponent(value);
								while(value.indexOf(/\+/g) >=0){
									value = value.replace(/\+/g, '%2B');
								}
								//if(crt && crt != "") crt += '%26';
								if(crt && crt != "") crt += '&';
								crt += name + '=' + value;						
						}
					} else {
						if(	name.toLowerCase() != 'cn' &&
							name.toLowerCase() != 'act' &&
							name.toLowerCase() != 'crt' &&
							name.toLowerCase() != 'lang' &&
							name.toLowerCase() != 'style' &&						
							name.toLowerCase() != 'pageid' &&
							name.toLowerCase() != 'debug' ){
								var value = this.mValueHash[name][j].toString();
								while(value.indexOf('\r\n') >=0){
									value = value.replace('\r\n', '<br/>');
								}
								value = encodeURIComponent(value);
								while(value.indexOf(/\+/g) >=0){
									value = value.replace(/\+/g, '%2B');
								}
								//if(crt && crt != "") crt += '%26';
								if(crt && crt != "") crt += '&';
								crt += name + '=' + value;						
						}
					}	
				}
			}
		}
		return crt;
	}
	
	// -------------------------------------------------------------------------------
	// Function         : toForm(oForm)
	// -------------------------------------------------------------------------------
	// Loads the values from the CNForm object into the specified form. 
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME		TYPE		DESCRIPTION
	// oForm	object		HTML form object
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 11/10/2003   Ken Wimberley	Created	
	function toForm(oForm){
		var iLen = oForm.elements.length;
		for (var i=0; i<iLen; ++i){
			var oInput = oForm.elements[i];
			if (typeof(oInput.checked) == 'boolean'){
				oInput.checked = false;
			} else if (typeof(oInput.selected) == 'boolean'){
				oInput.selected = false;
			}
			this._setOnBlurHandler(oInput);
		}
		for (var name in this.mValueHash){
			var jLen = this.mValueHash[name].length;
			for (var j=0; j<jLen; ++j){
				if (typeof(oForm[name].length) != 'number'){
					this._toFormValue(oForm[name], this.mValueHash[name][j]);
				} else {
					var kLen = oForm[name].length;
					for (var k=0; k<kLen; ++k){
						this._toFormValue(oForm[name][k], this.mValueHash[name][j]);
					}
				}
			}
		}
		// Set the pointer to the oCNForm object as an expando property of the HTML form
		oForm.oCNForm = this;
	}
	
	// -------------------------------------------------------------------------------
	// Function         : _toFormValue(oInput, sValue)
	// -------------------------------------------------------------------------------
	// Helper function that loads a values from the CNForm object into the form element
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME		TYPE		DESCRIPTION
	// oInput	object		Form element object
	// sValue	string		String used to assign value to form element
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 11/10/2003   Ken Wimberley	Created	
	function _toFormValue(oInput, sValue){
		if (typeof(oInput.type) != 'undefined' && oInput.type.indexOf('text') != -1){
			oInput.value = sValue;
		} else if (typeof(oInput.selected) == 'boolean'){
			if (oInput.value == sValue){
				oInput.selected = true;
			}
		} else if (oInput.type == 'checkbox' || oInput.type == 'radio'){
			if (oInput.value == sValue){
				oInput.checked = true;
			}
		}		
		this._setOnBlurHandler(oInput);
	}
	
	// -------------------------------------------------------------------------------
	// Function         : handleSubmit(oForm)
	// -------------------------------------------------------------------------------
	// Function that handles the form submittal process
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME		TYPE		DESCRIPTION
	// oForm	object		HTML form object
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 11/10/2003   Ken Wimberley	Created		
	function handleSubmit(oForm, sMessage, escapeStrings, setcursor, dontValidate, aryIgnoreFields, bIgnoreCheck){
		bReturn = false;		
		var bEscapeStrings = (escapeStrings != null && escapeStrings != "")? escapeStrings : false;
		if(oForm.oCNForm && !oForm.oCNForm.bSubmitted){
			var bFormChanged = this._hasFormChanged(oForm.oCNForm);
			if(!this.bValidate) dontValidate = true;
			
			if(!bIgnoreCheck)	{
				if (!bFormChanged && !dontValidate) {
					if (!sMessage || sMessage == '') {
						sMessage =  "No changes have been made to the information on this page.  The page will not be saved!";
					}
					alert(sMessage);
					return false;				
				} 
			}
			if(this.isValidForm(oForm)){
				if(aryIgnoreFields){
					oForm.elements[this.sCrtElementName].value = this.getCriteria(aryIgnoreFields);
				} else {
					oForm.elements[this.sCrtElementName].value = this.getCriteria();
				}
				bReturn = true;
				oForm.oCNForm.bSubmitted = true;
				
				// setcursor is ignored
				/*					
				if(!setcursor){
					if(parent && parent.frames && parent.frames.length) {
						var frameLength = parent.frames.length;
						for(i=0; i < frameLength; i++) {
							parent.frames[i].document.body.style.cursor = 'wait';
						}
					}
				}
				*/
				document.body.style.cursor = 'wait';
			}			
		}
		return bReturn;
	}
	
	function _hasFormChanged(oCNForm) {
		var myBReturn = false;
		if (oCNForm) {
			var aryFieldNames = oCNForm.getNames();
			var iLen = aryFieldNames.length;
			for (var i=0; i<iLen; ++i){
				var sField = aryFieldNames[i];
				if(oCNForm.getValue(sField) != oCNForm._getDefaultValue(sField)) myBReturn = true;
			}
		}
		return myBReturn;
	}
	
	function _isValidCNForm(oCNForm){
		var myBReturn = true;
		if (oCNForm.cn==null) {
			alert('The form does not adhere to ChannelNet grammar rules.\nMust have a context(cn)');
			myBReturn = false;
		} else if (oCNForm.cn=='') {
			alert('The form does not adhere to ChannelNet grammar rules.\nMust have a context value');
			myBReturn = false;
		} else if (oCNForm.act==null) {
			alert('The form does not adhere to ChannelNet grammar rules.\nMust have an action(act)');
			myBReturn = false;
		} else if (oCNForm.act=='') {
			alert('The form does not adhere to ChannelNet grammar rules.\nMust have an action value');
			myBReturn = false;
		} else if (oCNForm.debug==null) {
			alert('The form does not adhere to ChannelNet grammar rules.\nMust have a debug value');
			myBReturn = false;
		} else if (oCNForm.debug!='0' && oCNForm.debug!='1' && oCNForm.debug!='2'&& oCNForm.debug!='3') {
			alert('The form does not adhere to ChannelNet grammar rules.\nMust have a debug value of 0,1, 2, or 3');
			myBReturn = false;
		} else if (oCNForm.crt==null) {
			alert('The form does not adhere to ChannelNet grammar rules.\nMust have a criteria(crt)');
			myBReturn = false;
		}
		return myBReturn;
	}
	
	function _setOnBlurHandler(oInput){
		if (oInput.type != 'hidden' &&
			oInput.type != 'button' &&
			oInput.type != 'submit' &&	
			oInput.type != 'reset'	&&
			!oInput.readOnly){
			oInput.onblur = handleFormInputChange;
		}
	}
	
	// Form specific array that contains field names to ignore
	function _isIgnoredField(sName,aryIgnoreFields){
		var myBReturn = false;
		if(aryIgnoreFields){
			var iLen = aryIgnoreFields.length;
			for(var fldNum=0; fldNum<iLen; fldNum++){
				if(aryIgnoreFields[fldNum].toLowerCase() == sName){
					myBReturn = true;
				}
			}
		} else {
			myBReturn = true;
		}
		return myBReturn;
	}	
	
	// -------------------------------------------------------------------------------
	// Function         : isValidForm(oForm)
	// -------------------------------------------------------------------------------
	// Function that checks to see if the form is valid and ready for submittal
	// -------------------------------------------------------------------------------
	// Parameters
	// -------------------------------------------------------------------------------
	// NAME		TYPE		DESCRIPTION
	// oForm	object		HTML form object
	// -------------------------------------------------------------------------------
	// History
	// -------------------------------------------------------------------------------
	// DATE			NAME			DESCRIPTION
	// 12/16/2004   Ken Wimberley	Created	
	
	function isValidForm(oForm){
		var myBReturn = false;
		if(this._isValidCNForm(oForm.oCNForm)){
			var iInvalidFieldCount = 0;
			var aryFieldNames = this.getNames();
			var sMessage = '';
			var iLen = aryFieldNames.length;
			for (var i=0; i<iLen; ++i){
				var sField = aryFieldNames[i];
				if (!this.validateField(sField)){
					++iInvalidFieldCount;
					sMessage += this.getMessage(sField) + '\n';
				}
			}
			if (iInvalidFieldCount > 0){
				//alert("We have problems");
				alert(sMessage);
			} else {
				myBReturn = true;
			}
		}
		return myBReturn;
	}
	
	function _isCNField(sName){
		var bReturn = true;		
		if (sName.charAt(0) == this.sCharIgnore) bReturn = false;
		
		// Saks specific checks
		if (sName.indexOf(this.sBlueMartiniCharIgnore) == 0) bReturn = false;
		if (sName.indexOf("<") > -1) bReturn = false;
		if (sName.indexOf(">") > -1) bReturn = false;
		
		return bReturn;
	}
	
}
/*End Class*/
var oCNForm = new CNForm();

function handleFormInputChange(e){
	var oInput;
	if(e && e.target){	//For Netscape
		oInput = e.target;
	} else {
		oInput = event.srcElement;
	}
	if(oInput.form.oCNForm){
		oInput.form.oCNForm.setValueFromInput(oInput);
		if(e && e.target){	//For Netscape
			if(e.type != 'blur' && oInput.value != ""){
				// onBlur allows for empty strings, onChange has problems with this.
				oInput.form.oCNForm.validateField(oInput.name);
			}
		} else {
			if(event.type != 'blur' && oInput.value != ""){
				oInput.form.oCNForm.validateField(oInput.name);
			}
		}
	}
}

function handleOnReset(oForm){
	oForm.reset();
	if(oForm.oCNForm){
		oForm.oCNForm.fromForm(oForm);
	}
}
