function ErrorItem(num, msg, objEl)
{
	this.number		= num || -1;
	this.message	= msg || "";
	this.objRef		= objEl;
}

// ------------------------------------------------------------------

function ErrorContainer()
{
	this.list		= new Array();
	
	this.add		= _ErrorContainer_add;
	this.purge		= _ErrorContainer_purge;
}

function _ErrorContainer_add(num, msg, el)
{
	this.list[this.list.length] = new ErrorItem(num, msg, el);
	return;
}

function _ErrorContainer_purge()
{
	this.list = new Array();
	return;
}
// ------------------------------------------------------------------

function ClientError(noticeHeader, noticeFooter, sa)
{
	this.errorNoticeHeader		= "";
	this.errorNoticeFooter		= "";
    // changed to accomodate the french translations - should fix this perhaps at a later date.
	//this.errorNoticeHeader		= ((noticeHeader || "The following errors have been detected:") + "\n\n");
	//this.errorNoticeFooter		= ("\n" + (noticeFooter || "Please correct the described errors and try again."));
	this.initialized			= false;
	this.showAll				= sa || true;

	this.display				= _ClientError_display;	
	this.validate				= _ClientError_validate;
	this.processElement			= _ClientError_processElement;
	this.processList			= _ClientError_processElementList;
}

ClientError.prototype = new ErrorContainer;

function _ClientError_display(sa)
{
	var errorList		= "";
	var sa				= this.showAll;
	
	if(this.list.length == 0)
	{
		return true;
	}
	else
	{
		if(!sa)
		{
			alert(this.errorNoticeHeader + this.list[0].message + "\n" + this.errorNoticeFooter);
			
		}
		else
		{
			for(var i=0; i<this.list.length; i++)
			{
				errorList += (i+1) + ". " + this.list[i].message + "\n";
			}
			
			alert(this.errorNoticeHeader + errorList + this.errorNoticeFooter);
		}
		
		this.list[0].objRef.focus();
		return false;
	}
}

function _ClientError_validate(frm)
{
	var skipElAllowed		= new Array();  // elements allowed to have multiple instances but only process once
	var type				= "";
	var name				= "";
	var found				= false;

	this.purge(); // empty out any old error messages
	
	for(var i=0; i<frm.length; i++)
	{
		type = frm[i].type
		name = frm[i].name;

		for(var k=0; k < skipElAllowed.length; k++)
		{
			if(name == skipElAllowed[k])
			{
				found = true;
				break;
			}
		}
				
		if(found == true)
		{
			if(type == "checkbox" || type == "radio")
			{
				found = false;
				continue;
			}
			else
			{
				if(type != "button" && type != "submit" && type != "reset")
				{
					alert("Form element \"" + name + "\" named illegally [multiple instances].");
					return false;
				}
			}
		}
		else
		{
			if(!this.initialized)
			{
				if(type == "checkbox" || type == "radio")
				{
					if(frm[name][0])
					{
						if(frm[name].required) frm[name][0].required = frm[name].required;
						if(frm[name].required_errorMessage) frm[name][0].required_errorMessage = frm[name].required_errorMessage;
						
						if(frm[name].condition) frm[name][0].condition = frm[name].condition;
						if(frm[name].condition_errorMessage) frm[name][0].condition_errorMessage = frm[name].condition_errorMessage;
						
						if(type == "checkbox")
						{
							if(frm[i].maxSelections) frm[name][0].maxSelections = frm[name].maxSelections;
							if(frm[i].maxSelections_errorMessage) frm[name][0].maxSelections_errorMessage = frm[i].maxSelections_errorMessage;
						}
					}
				}
			}
			
			skipElAllowed[skipElAllowed.length] = name;
			
			// process elements
			if(type == "checkbox" || type == "radio")
				if(frm[name][0])
					this.processList(frm[name], type);
				else
					this.processElement(frm[i], type);
			else
				this.processElement(frm[i], type);
		}
	}
	
	this.initialized = true;
	return this.display();	
}

function _ClientError_processElementList(objList, type)
{
	// ============================================================================================================================
	// PROPERTY								PROPERTY SETTING						APPLIES TO
	// ============================================================================================================================
	// 1. required*							: true || false							: All
	//    required_errorMessage*			: string value							: All
	//
	// 2. maxSelections*					: integer								: checkbox
	//    maxSelections_errorMessage*		: string value							: checkbox
	//
	// 3. condition*						: expression that returns a boolean		: All
	//    condition_errorMessage*			: string value							: All
	//
	// *Optional
	// ============================================================================================================================
	
	var el;
	var defaultErrorMessage;
	
	if(objList.length > 0)  // radio/checkbox collection
	{
		el = objList[0];
	
		switch(type)
		{
		case "radio":
			if(el.required == true)
			{
				var checked = false;
				for(var i=0; i<objList.length; i++)
					if(checked = objList[i].checked)
						break;
					
				if(!checked)
				{
					defaultErrorMessage = "Selection required for radio button collection [" + el.name + "]";
					this.add(null, (el.required_errorMessage || defaultErrorMessage), el);
				}
			}

			break;

		case "checkbox":
			var cnt = 0;

			for(var i=0; i<objList.length; i++)
				if(checked = objList[i].checked)
					cnt++;
				
			if(el.required == true && 0 == cnt)
			{
				defaultErrorMessage = "Selection required checkbox collection [" + el.name + "]";
				this.add(null, (el.required_errorMessage || defaultErrorMessage), el);
			}
			
			if(el.maxSelections)
			{
				if(cnt > el.maxSelections)
				{
					defaultErrorMessage = "Number of selected checkboxes exceeds maximum of " + el.maxSelections + " [" + el.name + "]";
					this.add(null, (el.maxSelection_errorMessage || defaultErrorMessage), el);
				}
			}
			
			break;
		}
		
		if(el.condition)
		{
			if(!el.condition())
			{
				defaultErrorMessage = "An internal test condition has failed [" + el.name + "]";
				this.add(null, (el.condition_errorMessage || defaultErrorMessage), el);
			}
		}
	}
}

function _ClientError_processElement(el, type)
{
	// ============================================================================================================================
	// PROPERTY								PROPERTY SETTING						APPLIES TO
	// ============================================================================================================================
	// 1. required*							: true || false							: All
	//    required_errorMessage*			: string value							: All
	//
	// 2. pattern*							: function pointer						: text, textarea
	//    pattern_errorMessage*				: string value							: text, textarea
	//
	// 3. maxStringLength*					: integer								: text, textarea, file, password
	//    maxStringLength_errorMessage*		: string value							: text, textarea, file, password
	//
	// 4. minStringLength*					: integer								: text, textarea, file, password
	//    minStringLength_errorMessage*		: string value							: text, textarea, file, password
	//
	// 5. condition*						: expression that returns a boolean		: All
	//    condition_errorMessage*			: string value							: All
	//
	// 6. regexp*							: regular expression object				: text, textarea
	//    regexp_errorMessage*				: string value							: text, textarea
	//
	// 7. maxSelections*					: integer								: select, checkbox
	//    maxSelections_errorMessage*		: string value							: select, checkbox
	//
	// 8. minSelections*					: integer								: select, checkbox
	//    minSelections_errorMessage*		: string value							: select, checkbox
	//
	// 9. upperNumberLimit*					: integer || float						: text, textarea
	//    upperNumberLimit_errorMessage*	: string value							: text, textarea
	//
	// 10. lowerNumberLimit*				: integer || float						: text, textarea
	//    lowerNumberLimit_errorMessage*	: string value							: text, textarea
	//
	// *Optional
	// ============================================================================================================================
	
	var defaultErrorMessage = "";
	
	switch(type)
	{
		case "text":
		case "textarea":
			if(el.required == true)
			{
				var tmp = el.value;
				
				if(tmp.length == 0)
				{
					defaultErrorMessage = "Text element requires input [" + el.name + "]";
					this.add(null, (el.required_errorMessage || defaultErrorMessage), el);
				}
			}
			
			if(el.pattern)
			{
				if(!el.pattern())
				{
					defaultErrorMessage = "Text input malformed [" + el.name + "]";
					this.add(null, (el.pattern_errorMessage || defaultErrorMessage), el);
				}
			}
			
			if(el.maxStringLength)
			{
				if(el.value.length > el.maxStringLength)
				{
					defaultErrorMessage = "Text length exceeds maximum allowed [" + el.name + "]";
					this.add(null, (el.maxStringLength_errorMessage || defaultErrorMessage), el);
				}
			}
			
			if(el.minStringLength)
			{
				if(el.value.length > el.minStringLength)
				{
					defaultErrorMessage = "Text length is less than the required minimum [" + el.name + "]";
					this.add(null, (el.minStringLength_errorMessage || defaultErrorMessage), el);
				}
			}
			
			if(el.regexp)
			{
				if(!el.regexp.test(el.value))
				{
					defaultErrorMessage = "Text input malformed (regexp) [" + el.name + "]";
					this.add(null, (el.regexp_errorMessage || defaultErrorMessage), el);
				}
			}
			
			if(el.upperNumberLimit)
			{
				if(parseFloat(el.value) > parseFloat(el.upperNumberLimit))
				{
					defaultErrorMessage = "Number larger maximum allowed [" + el.name + "]";
					this.add(null, (el.upperNumberLimit_errorMessage || defaultErrorMessage), el);
				}
			}
			
			if(el.lowerNumberLimit)
			{
				if(parseFloat(el.value) < parseFloat(el.lowerNumberLimit))
				{
					defaultErrorMessage = "Number smaller than minimum required [" + el.name + "]";
					this.add(null, (el.lowerNumberLimit_errorMessage || defaultErrorMessage), el);
				}
			}
			
			break;

		case "password":
		case "file":
			if(el.required == true)
			{
				var tmp = el.value;
				
				if(tmp.length == 0)
				{
					defaultErrorMessage = "Text element requires input [" + el.name + "]";
					this.add(null, (el.required_errorMessage || defaultErrorMessage), el);
				}
			}

			if(el.maxStringLength)
			{
				if(el.value.length > el.maxStringLength)
				{
					defaultErrorMessage = "Text length exceeds maximum allowed [" + el.name + "]";
					this.add(null, (el.maxStringLength_errorMessage || defaultErrorMessage), el);
				}
			}
			
			if(el.minStringLength)
			{
				if(el.value.length > el.minStringLength)
				{
					defaultErrorMessage = "Text length is less than the required minimum [" + el.name + "]";
					this.add(null, (el.minStringLength_errorMessage || defaultErrorMessage), el);
				}
			}
			
			break;

		case "select-one":
			//alert("name: " + el.name + "\nrequired: " + el.required);
			if(el.required == true)
			{
				var selected = false;
				for(var i=0; i<el.length; i++)
				{
					if(selected = el[i].selected)
					{
						if("" == el[i].value)
						{
							selected = false;
						}
						break;
					}
				}
					
				if(!selected)
				{
					defaultErrorMessage = "Selection required for select box [" + el.name + "]";
					this.add(null, (el.required_errorMessage || defaultErrorMessage), el);
				}
			}
			
			break;

		case "select-multiple":
			var cnt = 0;
			for(var i=0; i<el.length; i++)
			{
				if(selected = el[i].selected)
				{
					if("" != el[i].value)
					{
						cnt++;
					}
				}
			}

			if(el.required == true)
			{
				if(cnt == 0)
				{
					defaultErrorMessage = "Selection required for checkboxes [" + el.name + "]";
					this.add(null, (el.required_errorMessage || defaultErrorMessage), el);
				}
			}

			if(el.maxSelections)
			{
				if(cnt > el.maxSelections)
				{
					defaultErrorMessage = "Selection exceeds maximum allowed [" + el.name + "]";
					this.add(null, (el.maxSelections_errorMessage || defaultErrorMessagenull), el);
				}
			}
			
			break;

		case "radio":
			if(el.required == true)
			{
				if(!el.checked)
				{
					defaultErrorMessage = "Selection required for radio button [" + el.name + "]";
					this.add(null, (el.required_errorMessage || defaultErrorMessage), el);
				}
			}
			
			break;
		
		case "checkbox":
			if(el.required == true)
			{
				if(!el.checked)
				{
					defaultErrorMessage = "Selection required for checkbox [" + el.name + "]";
					this.add(null, (el.required_errorMessage || defaultErrorMessage), el);
				}
			}

			break;
	}
	if(el.condition)
	{
		if(!el.condition())
		{
			defaultErrorMessage = "An internal test condition has failed [" + el.name + "]";
			this.add(null, (el.condition_errorMessage || defaultErrorMessage), el);
		}
	}
}
