//
// Lazyness
//
function $( ID )
{
	return document.getElementById( ID );	
}


//
// Chan.Controls.Form
//

function Chan_Controls_Form_Validate( input_object , notify_object )
{
	var ii = 0;
	var ni = input_object.elements.length;
	var Valid = true;
	var ValidTemp = true;
	
	for( ii = 0 ; ii < ni ; ii ++ )
	{
		//need to fetch and validate all controls, not just fail out on
		//the first one we find. but we don't want the whole form to be
		//flagged as Valid if the very last control happens to be valid
		ValidTemp = Chan_Controls_Validate( input_object.elements[ ii ] );	
			
		if( !ValidTemp)
			Valid = false;
	}
	
	//notify the user if bad things happenned
	if( !Valid )
	{
		var s = "Could not send the form because it was invalid, please correct the highlighted entries before trying again.";
		
		if( notify_object != null )
			notify_object.innerHTML = s;
		else
			alert( s );
	}
	
	//DEBUG
	//alert( Valid );
	//return false;
	//DEBUG END
	
	return Valid;
}




//
//	SHARED / GENERIC FUNCTIONS
//

//
// Generic validation function, switches on object type
//
function Chan_Controls_Validate( input_object )
{
	var type = input_object.className;
	
	//multiple class names?! find the chan one in there
	if( type.indexOf( " " ) > -1 )
	{
		var a = type.split( " " );
		var ia = 0;
		var na = a.length;
		
		for( ia = 0 ; ia < na ; ia ++ )
			if( a[ia].indexOf( "Chan_Controls_" ) > -1 )
				type = a[ia];
	}
	
	//alert( type );
	
	switch( type )
	{
		case "Chan_Controls_Numeric":
			return Chan_Controls_Numeric_Validate( input_object );
			break;
	
		case "Chan_Controls_Upload":
			return Chan_Controls_Upload_Validate( input_object );
			break;
	
		case "Chan_Controls_TextBox":
			return Chan_Controls_TextBox_Validate( input_object );
			break;
	
		case "Chan_TextBox_Wide":
			return Chan_Controls_TextBox_Validate( input_object );
			break;
	
		case "Chan_Controls_Password":
			return Chan_Controls_TextBox_Validate( input_object );
			break;
	
		default:
			break;
	}	
	
	return true;
}


//
// Shows or hides a control's invalid image depending on the control's
// parameters, specifically it's Valid bool
//
function Chan_Controls_SetInvalidImage( Chan_Control )
{
	var IMG_ID = Chan_Control.ID + "_InvalidImage";
	var IMG = $( IMG_ID );
	
	//if the control is Valid remove any "invalid" image associated with it	
	if( Chan_Control.Valid )
	{
		//remove any old Invalid image from the DOM
		if( IMG )
			IMG.parentNode.removeChild( IMG );
	}
	else
	{
		//no image, spawn one
		if( !IMG )
		{
			IMG = document.createElement( "IMG" );
			IMG.id = IMG_ID;
			IMG.src = "/Chan/Invalid.gif";
			IMG.className = "Chan_Invalid";
			
			//i.e. insertAfter(this) !
			Chan_Control.DOMObject.parentNode.insertBefore( IMG , Chan_Control.DOMObject.nextSibling );	
		}

		IMG.setAttribute( "alt" , Chan_Control.InvalidReason );
		IMG.setAttribute( "title" , Chan_Control.InvalidReason );
	}
}

//
//	CLASSES
//
//	All should publicly expose
//
//	ID			(string)
//	Text		(string)
//	Value		(variant type)
//	Valid		(bool)
//	InvalidReason	(string)
//	DOMObject	(HTML DOM input handle)
//
//	Most will also have the following:
//
//	Mandatory	(bool)
//

//
// Chan.Controls.Numeric
//
// Allows the developer to specify a number-only textbox
//

//
// Converts a DOM input into a local Chan Numeric Control
//
function Chan_Controls_Numeric_New( input_object )
{
	this.DOMObject	= input_object;
	this.ID			= String( input_object.id );
	this.Text		= String( input_object.value );
	this.Value		= parseFloat( input_object.value );	
	this.Valid		= true;						//assume valid
	this.InvalidReason = "";

	this.Mandatory	= (input_object.getAttribute( "mandatory" ) == "true");
	
	//
	// Attributes / parameters - may be supported by html5 one day
	//
	
	this.Min		= parseFloat( input_object.getAttribute( "min" ) );
	this.Max		= parseFloat( input_object.getAttribute( "max" ) );

	//decimal places, default is integer
	this.Places		= parseInt( input_object.getAttribute( "places" ) );
	if( isNaN( this.Places ) )
		this.Places = 0;
		
	return this;
	
	//functions:
	//void ...OnBlur( input )       - actual HTML embedded event
	//bool ...OnBlur_Ctl( Control )
	//bool ...Validate( input )
}



//
// Converts a DOM input into a local Chan TextBox Control
//
function Chan_Controls_TextBox_New( input_object )
{
	this.DOMObject	= input_object;
	this.ID			= String( input_object.id );
	this.Text		= String( input_object.value );
	this.Value		= this.Text;	
	this.Valid		= true;						//assume valid
	this.InvalidReason = "";
	
	this.Mandatory	= (input_object.getAttribute( "mandatory" ) == "true");
	
	//input.text will have this natively handled but textarea will not
	this.MaxLength	= parseInt( input_object.getAttribute( "maxlength" ) );
	
	//mainly needed for Password subtype
	this.MinLength	= parseInt( input_object.getAttribute( "minlength" ) );
		
	return this;
	
	//functions:
	//bool ...Validate( input )		
}


//
// Converts a DOM input into a local Chan TextBox Control
//
function Chan_Controls_Upload_New( input_object )
{
	this.DOMObject	= input_object;
	this.ID			= String( input_object.id );
	this.Text		= String( input_object.value );
	this.Value		= this.Text;	
	this.Valid		= true;						//assume valid
	this.InvalidReason = "";
	
	this.Mandatory	= (input_object.getAttribute( "mandatory" ) == "true");
		
	return this;
	
	//functions:
	//bool ...Validate( input )		
}


//
// Generic Event container
//
/*
function EventArgs( e )
{

	if (!e) 
		var e = window.event;
		
	this.Event = e;
	
	
	
	if (e.target) 
		this.Target = e.target;
	else 
	if (e.srcElement) 
		this.Target = e.srcElement;
		
	if (this.Target.nodeType == 3) // defeat Safari bug
		this.Target = this.Target.parentNode;


	return this;
}
*/



//
//	EVENTS AND VALIDATION
//
//	CLIENT EVENTS SUCH AS ONKEYDOWN AND ONBLUR CAN PERFORM SUPERFICIAL REFORMATTING
//	OF AN INPUT'S CONTENTS, BUT MUST NOT SET/UNSET THE INVALID IMAGE
//
//	VALIDATION SHOULD ALSO PERFORM THE SAME CLEANUP FIRST AND WARN THE USER (SO
//	CLEANUP NOT CAUGHT IN ONBLUR CAN BE ADDRESSED). ONLY THE FORM SUBMIT VALIDATION
//	FUNCTION MAY SET/UNSET THE INVALID IMAGE
//

//  ----------------------------------------------------------------------------
//
//  Numeric
//
//  ----------------------------------------------------------------------------

//
// Validate function, invoked from parent form
//
function Chan_Controls_Numeric_Validate( input_object )
{
	var ctl = Chan_Controls_Numeric_New( input_object );
	
	//call the onblur first, which will autoformat any min/max/dp settings for us
	//it will return false if it made changes to the value
	if( !Chan_Controls_Numeric_OnBlur_Ctl( ctl ) )
	{
		ctl.InvalidReason = "This field has been reformatted to meet its Min,Max and Decimal Places, please check the new value before re-submitting.";
		ctl.Valid = false;
	}

	if( ctl.Valid && ctl.Mandatory && ctl.Text == "" )
	{
		ctl.InvalidReason = "This field is mandatory.";
		ctl.Valid = false;
	}

	//basic negateable numeric test
	if( ctl.Valid && isNaN( ctl.Value ) )
	{
		ctl.InvalidReason = "Entered value is not Numeric";
		ctl.Valid = false;
	}

	
	//show (or hide) our invalid marker image
	Chan_Controls_SetInvalidImage( ctl );

	return ctl.Valid;
}

//
// onblur, reformat according to validation rules
//
function Chan_Controls_Numeric_OnBlur( input_object )
{
	var ctl = Chan_Controls_Numeric_New( input_object );
	
	Chan_Controls_Numeric_OnBlur_Ctl( ctl );
	
	//Chan_Controls_SetInvalidImage( ctl );
}

//
// overload of above - accepts custom control object
//
function Chan_Controls_Numeric_OnBlur_Ctl( ctl )
{
	var Clean = true;
	
	//set decimal places
	if( !isNaN(Value) )
	{
		//floor to min value
		if( !isNaN(ctl.Min) && Value < ctl.Min )
		{
			Value = ctl.Min;
			Clean = false;
		}

		//ceiling to max value
		if( !isNaN(ctl.Max) && Value > ctl.Max )
		{
			Value = ctl.Max;
			Clean = false;
		}
		
		//fixed number of decimal places
		//BUG : should truncate not round!
		if( Value.toFixed )
		{
			Value = Value.toFixed( ctl.Places );	//places is defaulted to zero in the constructor
			
			if( String(Value) != ctl.Text )
				Clean = false;
		}
	
		//write the value back into the document
		ctl.DOMObject.value = Value;
	}
	
	return Clean;
}





//  ----------------------------------------------------------------------------
//
//	TEXTBOX FUNCTIONS
//
//  ----------------------------------------------------------------------------

function Chan_Controls_TextBox_Validate( input_object )
{
	var ctl = Chan_Controls_TextBox_New( input_object );
	
	//alert( ctl.Text.length + " / " + ctl.MaxLength );

	//basic mandatory check
	if( ctl.Mandatory && ctl.Text == "" )
	{
		ctl.InvalidReason = "This field is mandatory.";
		ctl.Valid = false;
	}
		
	//need to handle this for textarea
	if( ctl.Valid && ctl.Text.length > ctl.MaxLength )
	{
		ctl.Valid = false;
		ctl.InvalidReason = "Entered text is too long, currently: " + ctl.Text.length + " chars, Max: " + ctl.MaxLength;
	}
	//	ctl.DOMObject.value = ctl.Text.substr( 0 , ctl.MaxLength );
	
	//need to handle this for textarea
	if( ctl.Valid && ctl.Text.length < ctl.MinLength )
	{
		ctl.Valid = false;
		ctl.InvalidReason = "Entered text is too short, currently: " + ctl.Text.length + " chars, Min: " + ctl.MinLength;
	}

	Chan_Controls_SetInvalidImage( ctl );
	
	return ctl.Valid;
}


//  ----------------------------------------------------------------------------
//
//	UPLOAD FUNCTIONS
//
//  ----------------------------------------------------------------------------

function Chan_Controls_Upload_Validate( input_object )
{
	var ctl = Chan_Controls_Upload_New( input_object );
	
	//alert( ctl.Text.length + " / " + ctl.MaxLength );

	//basic mandatory check
	if( ctl.Mandatory && ctl.Text == "" )
	{
		ctl.InvalidReason = "This field is mandatory.";
		ctl.Valid = false;
	}

	Chan_Controls_SetInvalidImage( ctl );
	
	return ctl.Valid;
}


//
// onblur, reformat according to validation rules
//
//function Chan_Controls_TextBox_OnBlur( input_object )
//{
//
//}
//
//
// overload of above - accepts custom control object
//
//function Chan_Controls_TextBox_OnBlur_Ctl( ctl )
//{
//	
//}






