
	/* System.Xml.Forms.js													*/
	/* By Cory Dambach 														*/
	/* Enumeration of Form Input Types										*/
	/* Reference Material: HTML 4.01 W3C Recommendation 24-December-1999	*/
	
	/* Input Types - Refer to Section 17.4.1 */
	/* Reason it is uppercase is because Node.nodeName returns all Uppercase letters */
	/* Fixes */
	/* Form.GetTextAreaValue() incorrectly returned innerHTML instead of value - Fixed 12:20 PM 6/21/2006 By Cory Dambach
	
	/* The Static Form Class */
	function Form( FormObj )
	{
		/* private HTMLFormElement */
		this.FormObj				= FormObj;

		/* Setting the internal Use FormInput Getters */
		this.GetRadioGroupValue		= RadioGroup.GetValue;
		this.GetCheckGroupValue		= CheckBoxGroup.GetValue;
		this.GetSimpleInputValue	= function ( InputObj ) { return InputObj.value; } 
		this.GetSelectValue			= function ( InputObj ) { return InputObj.value; }
		this.GetTextAreaValue		= function ( InputObj ) { return InputObj.value; }
		/* End Internal Use Getters */
				
		this.InputValueLookupCol = new NameValueCollection(); //TODO: rename InputValueLookupCol
		with(this.InputValueLookupCol )
		{
			Add( Form.InputType.Text,		this.GetSimpleInputValue );
			Add( Form.InputType.Password,	this.GetSimpleInputValue );
			Add( Form.InputType.CheckBox,	this.GetCheckGroupValue	 );
			Add( Form.InputType.Radio,		this.GetRadioGroupValue	 );
			Add( Form.InputType.Submit,		this.GetSimpleInputValue );
			Add( Form.InputType.Image,		this.GetSimpleInputValue );
			Add( Form.InputType.Reset,		this.GetSimpleInputValue );
			Add( Form.InputType.Button,		this.GetSimpleInputValue );
		    Add( Form.InputType.Hidden,		this.GetSimpleInputValue );
		    Add( Form.InputType.File,		this.GetSimpleInputValue );
		}	
		
		this.GetControlValue = function( ControlObj )
		{
			switch( ControlObj.nodeName )
			{
				case Form.ControlType.Input:
					return this.GetInputValue( ControlObj );
				case Form.ControlType.Button:
					return this.GetInputValue( ControlObj );
				case Form.ControlType.Select:
					return this.GetSelectValue( ControlObj );
				case Form.ControlType.TextArea:
					return this.GetTextAreaValue( ControlObj );
				default:
					throw ("The parameter 'ControlObj' is not a W3C Recognized Form Control");
			}
		}
		
		this.GetInputValue = function( InputObj )
		{
			return this.InputValueLookupCol.Get( InputObj.type )( InputObj );
		}
		
		this.Validate = function( optionalHandler, optionalSuccessHandler ) /* params: ValidationHandler( FormInputObj, Form.ExceptionType, */
		{
			if( arguments.length == 2 )
				{ return Form.Validate( this.FormObj, optionalHandler, optionalSuccessHandler ); }
			else if( arguments.length == 1 )
				{ return Form.Validate( this.FormObj, optionalHandler );	}
			else
				{ return Form.Validate( this.FormObj ); }
		}
		
		this.ToNVC = function() //Cory Dambach - May 19, 2005 - June 1, 2006
		{			
			var ArrInputs		= this.FormObj.elements;
			var outNVC			= new NameValueCollection();			
			for( var i = 0; i < ArrInputs.length; i++ )
			{
				if( i > 0 && ArrInputs[i-1].name == ArrInputs[i].name )
					continue; //avoids iterating multiple times through single radiogroups and checkboxgroups
				outNVC.Add( ArrInputs[i].name, this.GetControlValue( ArrInputs[i] ) );
			}
			return outNVC;
		}
		
		this.ToString = function()
		{
			return this.ToNVC( this.FormObj ).ToString();
		}

		//Optimized by Cory Dambach - 1:39 PM 6/19/2006 
		this.Fill = function( inNVC )
		{
			var Inputs	= this.FormObj.elements;
			for( var i = 0; i < Inputs.length; i++ )
			{				
				if( Inputs[i].name != null && inNVC.Get( Inputs[i].name ) != null && Inputs[i].type != null ) //text, radio, checkbox, button, hidden
				{						
					switch( Inputs[i].type )
					{
						case Form.InputType.Radio:
						case Form.InputType.CheckBox:
							var CheckVals = inNVC.GetValues( Inputs[i].name );
							for( var j = 0; j < CheckVals.length; j++ )
							{
								if( Inputs[i].value == CheckVals[j] )
								{
									Inputs[i].checked = true;
								}
							}
							break;
						
						default:
							Inputs[i].value = inNVC.Get( Inputs[i].name );
							break;
					}
				}
				else
				{
					Inputs[i].value = inNVC.Get( Inputs[i].name );
				}
			}
		}
		this.Populate = this.Fill; /* [Deprecated] */
	}
	
	Form.ToNVC = function( FormObj )
	{
		var FrmObj = new Form( FormObj );
		//I know I know, at first it appears terrible, but I'll go ahead and argue that it is better
		//The efficiency that one realizes by using the Form() constructor's ToNVC method exists only because
		//the constructs needed to use it are not initialized until we need them ie: at the moment the Form() constructor is
		//called.  If we were to instead place the LookupNameValueCollection outside of the constructor, we would incur  an overhead on
		//every page, initializing it, regardless of whether or not that particular page needed ToNVC() or not.
		//Also in the static Form scope we would have a NameValueCollection just sitting there.
		return FrmObj.ToNVC();
	}
	
	Form.ControlType = {			//W3C Canonical Uppercase
		Input		: "INPUT",		//See Form.InputType
		Button		: "BUTTON",		//See Form.ButtonType
		Select		: "SELECT",
		TextArea	: "TEXTAREA"
	};
	Form.InputType = {
		Text		: "text",		// Simple
		Password	: "password",   // Simple
		CheckBox	: "checkbox",   // CheckBoxGroup.GetValue	( CheckBoxObj.name );
		Radio		: "radio",      // RadioGroup.GetValue		( RadioObj.name );
		Submit		: "submit",     // Simple
		Image		: "image",      // Not sure about this one
		Reset		: "reset",      // Not sure if this should be used for its value
		Button		: "button",     // Simple
		Hidden		: "hidden",     // Simple
		File		: "file"		// Simple
	};                           
	Form.ButtonType = { /* <button type="submit"><img src="fubar.gif"/></button> */
		Button		: "button",
		Submit		: "submit", 	
		Reset		: "reset"
	};

	/* Exception Enumerations */
	Form.RequiredException			= 1;
	Form.LengthException			= 2;
	Form.TypeException				= 3;
	Form.CustomException			= 4;	
	/* Class Methods */
	Form.Validate = function( MyForm, ValidationHandler, ValidatedInputHandler ) //Cory Dambach - May 19, 2005 - June 1, 2006
	{
		var ErrorNum		= 0;
		var ErrorHandler	= null;
		var SuccessHandler	= null;
		
		if( ValidationHandler != null )		
			ErrorHandler = ValidationHandler; //they want to use their own...
		else
			ErrorHandler = Form.ValidateExceptionHandler; //Just use the default event handler
		
		if( ValidatedInputHandler != null )			
			SuccessHandler = ValidatedInputHandler;
		else
			SuccessHandler = Form.ValidateSuccessHandler;
			
		var ArrInputs	= MyForm.elements;
		var CheckNVC	= new Form.ToNVC( MyForm );		
		for( var i = 0; i < ArrInputs.length; i++ )
		{
			var InputErrors = 0;
			if( i > 0 && ArrInputs[i-1].name == ArrInputs[i].name )
				continue; //avoids iterating multiple times through single radiogroups and checkboxgroups 
			if( ArrInputs[i].getAttribute("required") == "true" && CheckNVC.Get(ArrInputs[i].name) == "" && CheckNVC.Get(ArrInputs[i].value) == "")
			{
				ErrorHandler( ArrInputs[i], Form.RequiredException, "is a required field." );
				InputErrors++;
			}
			if( ArrInputs[i].getAttribute("dtype") != null && ArrInputs[i].value != "" )
			{	//<input name="fubar" id="fubar" type="text" dbtype="int" />
				switch( ArrInputs[i].getAttribute("dtype") )
				{
					case "int": case "double": case "single": case "float": case "long": case "decimal":
						if( isNaN( CheckNVC.Get(ArrInputs[i].name) ) )
						{
							ErrorHandler( ArrInputs[i], Form.TypeException, "is not a valid number." );
							InputErrors++;
						}
						break;						
					case "date": case "datetime": case "smalldatetime":
						if( !IsDate( CheckNVC.Get(ArrInputs[i].name) ) )
						{
							ErrorHandler( ArrInputs[i], Form.TypeException, "should be of the format: mm/dd/yyyy." );
							InputErrors++;
						}
						break;
				}
			}
			if( ArrInputs[i].getAttribute("dlength") != null && CheckNVC.Get(ArrInputs[i].name).length > ArrInputs[i].getAttribute("dlength") )
			{
				ErrorHandler( ArrInputs[i], Form.LengthException, "exceeds the maximum length of " + ArrInputs[i].getAttribute("dlength") + " for this field" );
				InputErrors++;
			}
			if( InputErrors == 0 ) //call successful validation Handler! or Increment Total Error Number
				SuccessHandler( ArrInputs[i] );
			else
				ErrorNum++;
		}
		if( ErrorNum == 0 )
			return true;
		else
			return false;
	}		
	
	/* Default Exception Handler for Form.Validate */
	Form.ValidateExceptionHandler = function( InputObj, ExceptionType, Msg )
	{
		switch( ExceptionType )
		{
			case Form.RequiredException:								
			case Form.TypeException:								
			case Form.LengthException:
			default:
				alert( PascalToEnglish( InputObj.name + " " + Msg ) );
				InputObj.focus();
				break;
		}
		return;
	}
	/* Default Input Succes Handler for Form.Validate */
	Form.ValidateSuccessHandler = function( InputObj )
	{
		InputObj.style.backgroundColor = "";
	}
	
	/* Converts PascalCaseIdentifiers to User Friendly English */
	function PascalToEnglish(str)
	{
		str = str.replace( /(.*?[a-z])([A-Z].*?)/g, "$1 $2"				);
		str = str.replace( /([A-Z][A-Z].*?)([A-Z][a-z].*?)/g, "$1 $2"	);
		return str;
	}
	
	/* Depends: System.Collections.Specialized */
	Form.Fill = function( FormObj, inNVC )
	{
		var TempForm = new Form( FormObj );
		TempForm.Fill( inNVC );
		return;
	}	
	
	//string LookingForID
	Form.FindLabelTextFor = function(LookingForID)
	{
		var labelElements = document.getElementsByTagName("label");
		for(var a=0; a<labelElements.length; a++)
		{
			if(labelElements[a].htmlFor == LookingForID)
			{
				return labelElements[a].innerText;
			}
		}
		return null;
	}
		
	Form.EnableAllFormElements = function( bEnabled )
	{
		var	selectBoxes=document.getElementsByTagName("select");
		for	(var i=0; i<selectBoxes.length;	i++)
		{
			selectBoxes[i].disabled	= !bEnabled;
		}	
		var	inputBoxes=document.getElementsByTagName("input");
		for	(var i=0; i<inputBoxes.length; i++)
		{
			inputBoxes[i].disabled = !bEnabled;
			
		}
		var	buttonBoxes=document.getElementsByTagName("button");
		for	(var i=0; i<buttonBoxes.length;	i++)
		{
			buttonBoxes[i].disabled	= !bEnabled;
		}
	}
	
function Select() { /* useless constructor for now */ }
Select.GetValue = function( InputObj ) /* static */ { return InputObj.value; }

function RadioGroup( RadioInputName ) /* constructor */
{	
	/* Members */
	this.RadioItems = new Array(); 	//HTMLElement Array
	this.Value		= new String(); //Currently Selected RadioButton's Value
	this.OnChange	= null;			//EventHandler( object Sender, EventArgs e );
	
	/* Member Methods */
	with( this ) //event handler, is not called with the context of the RadioGroup object...So I used With!
	{
		OnValueChanged = function()
		{
			for( var i = 0; i < RadioItems.length; i++ )
			{
				if( RadioItems[i].checked == true )
				{
					Value = RadioItems[i].value;
				}
			}
			if( OnChange != null )
			{
				OnChange( this, Value );
			}
		}
	}

	/* Initialization Code */
	var AllInputs = TagsByName( "input" ); //AllRadioButtons is an Html-Node-List	
	for( var i = 0; i < AllInputs.length; i++ )
	{
		if( AllInputs[i].type == "radio" && AllInputs[i].name == RadioInputName )
		{
			this.RadioItems.push( AllInputs[i] );
			AllInputs[i].onclick = OnValueChanged; //My own event handler, so that Value is always correct
			OnValueChanged(); //get the initial value for the group
		}
	}
}//End Class RadioGroup
RadioGroup.GetValue = function( RadioInputObj ) /* Utility Function for use by the Form Object */
{
	var AllInputs = TagsByName( "input" ); //AllRadioButtons is an Html-Node-List	
	for( var i = 0; i < AllInputs.length; i++ )
	{
		if( AllInputs[i].type == Form.InputType.Radio && AllInputs[i].name == RadioInputObj.name && AllInputs[i].checked == true )
		{	//if its a radiobutton && it is in the desired group && its selected
			return AllInputs[i].value; //return the singly selected radiobutton's value
		}
	}
	return "";
}
function CheckBoxGroup() { /* useless constructor for now */ }
CheckBoxGroup.GetValue = function( InputObj )
{
	var CheckGroupValue = new String();
	var AllInputs = TagsByName( "input" ); //AllRadioButtons is an Html-Node-List	
	for( var i = 0; i < AllInputs.length; i++ )
	{
		if( AllInputs[i].type == Form.InputType.CheckBox && AllInputs[i].name == InputObj.name && AllInputs[i].checked == true )
		{	/* if its a checkbox && it is in the desired group && its checked */
			if( CheckGroupValue.length > 0 )//we want it like val1,val2,val3
				{ CheckGroupValue += ","; }
			CheckGroupValue += AllInputs[i].value;
		}
	}
	return CheckGroupValue;
}