function injectFormControls( formNode ) {
    if( formNode != null && formNode.nodeName.toLowerCase() == "form" ) {
        var formName = formNode.getAttributeNode( "name" ).value;

        if( formName != null && formName.length > 0 ) {

            var hierachicalGroups = lookUpHierachicalGroupNames( formName );
            if( hierachicalGroups != null ) {

                var groupNames = hierachicalGroups.call( this, formNode );
                for( var index=0; groupNames != null && index < groupNames.length; index++ ) {
                    injectOnClickHierachyCheck( formNode, groupNames[ index ], 5 );
                }
            }
            injectOnSubmitFormEvents( formNode );
            injectOnChangeFormEvents( formNode );
        }
    }
};


function injectOnSubmitFormEvents( formNode ) {
    if( formNode != null ) {
        var formName = formNode.getAttributeNode( "name" ).value;
        //alert( "Injecting onsubmit handlers for " + formName );
        if( formName != null && formName.length > 0 ) {
            formNode.onsubmit = function() {
                return invokeOnsubmitFormEvent( formNode );
            };
        }
    }
};

function injectOnChangeFormEvents( formNode ) {
    if( formNode != null ) {

        var formName = formNode.getAttributeNode( "name" ).value;

	//alert( "Injecting onchange handlers for " + formName );
        var onChangeCandidateNodes = new Array();
        var onChangeCandidatesFunction = lookUpOnChangeCandidates( formName );
        if( onChangeCandidatesFunction != null ) {
            onChangeCandidateNodes = onChangeCandidatesFunction.call( this, formNode );
        }

        var dateComponents = null;
        var dateComponentsFunction = lookUpDateWatchers( formName );
        if( dateComponentsFunction != null ) {
            dateComponents = dateComponentsFunction.call( this, formNode );
        }


        var dateRangeComponents = null;
        var dateRangeComponentsFunction = lookUpDateRangeWatchers( formName );
        if( dateRangeComponentsFunction != null ) {
            dateRangeComponents = dateRangeComponentsFunction.call( this, formNode );
        }

        var dateDurationComponents = null;
        var dateDurationComponentsFunction = lookUpDateAndDurationWatchers( formName );
        if( dateDurationComponentsFunction != null ) {
            dateDurationComponents = dateDurationComponentsFunction.call( this, formNode );
        }



        if( onChangeCandidateNodes != null && onChangeCandidateNodes.length > 0 ) {
	    //alert( "Starting injection for " + onChangeCandidateNodes.length + " candidates " );
            for( var index=0; index < onChangeCandidateNodes.length; index++ ) {
                var nextFormNode = onChangeCandidateNodes[ index ];
                if( nextFormNode != null ) {
                    var nextDateComponent = null;
                    if( dateComponents != null ) {
                        nextDateComponent = dateComponents[ nextFormNode.getName() ];
                    }

                    var nextDateRangeComponent = null;
                    if( dateRangeComponents != null ) {
                        nextDateRangeComponent = dateRangeComponents[ nextFormNode.getName() ];
                    }
        		    //alert( "For " + nextFormNode.getName() + " found " + nextDateComponent + " / " + nextDateRangeComponent );

                    var nextDateDurationComponent = null;
                    if( dateDurationComponents != null ) {
                        nextDateDurationComponent = dateDurationComponents[ nextFormNode.getName() ];
                    }
                    //alert( "Injecting for " + nextFormNode.getName() + " found " + nextDateComponent + " / " + nextDateRangeComponent +  " / " + nextDateDurationComponent);

                    if( nextDateComponent != null || nextDateRangeComponent != null || nextDateDurationComponent != null ) {

                        nextFormNode.getFormElementNode().onchange = function() {

                			    //alert( "onchange for " + this.name );
                                if( dateComponents != null ) {
                                    var myDateComponent = dateComponents[ this.name ];
	                                if( myDateComponent != null ) {
                                        //alert( "Invoking max correction... " + myDateComponent  );
                                        myDateComponent.Accept( new VisitorDateMaxDayCorrection() );
                                    }
                                }

                                if( dateRangeComponents != null ) {
                                    var myDateRangeComponent = dateRangeComponents[ this.name ];
                                    //alert( "Invoking range correction..." + myDateRangeComponent );
                                    if( myDateRangeComponent != null ) {
                                        //alert( "Invoking range correction..." + myDateRangeComponent );
                                        myDateRangeComponent.Accept( new VisitorDateRangeWatcher() );
                                    }
                                }

                                if( dateDurationComponents != null ) {
                                    var myDateDurationComponent = dateDurationComponents[ this.name ];
                                    if( myDateDurationComponent != null ) {
                                        //alert( "Invoking duration correction..." + myDateDurationComponent );
                                        myDateDurationComponent.Accept( new VisitorDateAndDuration() );
                                    }
                                }
                        };
                    }
                }
            }
        }
    }
}

function invokeOnsubmitFormEvent( formNode ) {
    var invokationState = false;
    if( formNode != null ) {
        var formName = formNode.getAttributeNode( "name" ).value;

        if( formName != null && formName.length > 0 ) {

            var componentGroups = lookUpComponentGroupNames( formName );
            if( componentGroups != null ) {

                var groups = componentGroups.call( this, formNode  );

                for( var index=0; groups != null && index < groups.length; index++ ) {

                    var nextGroup = groups[ index ];
                    nextGroup.Accept( new ComponentGroupExtender() );
                }
            }

            var errorHandler = lookupFunctionByName( formName, "errorHandler_");
            var formObjectFactoryHandler = lookupFunctionByName( formName, "createFormObjects_");
            if( errorHandler != null && formObjectFactoryHandler != null ) {
                invokationState = invokeFormValidation( formNode, formObjectFactoryHandler, errorHandler, false );
            } else {
                //alert( "No formhandlers found, error = " + (errorHandler != null) + " formh " + (formObjectFactoryHandler != null ) );
                invokationState = true;
            }

        }
    }
    return invokationState;
};


function injectOnClickHierachyCheck( formNode, hierachyName, maxLevel ) {
    var hierachyNodes = getNodesWithNameAndAttributeValue( formNode, FormNodeMetadata.ELEMENT_INPUT, "name", hierachyName );

    if( hierachyNodes != null && hierachyNodes.length > 0 ) {
        var hierachy = new HierachicalNodeScanner( formNode, hierachyName, maxLevel );
        for( var index = 0; index < hierachyNodes.length; index++ ) {

            hierachyNodes[ index ].onclick = function() {
                var correspondingHierachy = hierachy.getComponentForNode( this );
                if( correspondingHierachy != null ) {
                    correspondingHierachy.Accept( new VisitorHierachyTree() );
                }
            };

        }
    }
}

function injectOnsubmitValidation( formNode ) {
    var formName = formNode.getAttributeNode( "name" ).value;
    if( formName != null && formName.length > 0 ) {

        var errorHandler = lookupFunctionByName( formName, "errorHandler_");
        var formObjectFactoryHandler = lookupFunctionByName( formName, "createFormObjects_");
        if( errorHandler != null && formObjectFactoryHandler != null ) {
            formNode.onsubmit = function() {
                return invokeFormValidation( this, formObjectFactoryHandler, errorHandler, false );
            }
        }

    }
}

function injectOnsubmitComponentGroup( formNode, componentGroup ) {
    var formName = formNode.getAttributeNode( "name" ).value;
    if( formName != null && formName.length > 0 && componentGroup != null ) {
        formNode.onsubmit = function() {
            componentGroup.Accept( new ComponentGroupExtender() );
        }
    }
}

function invokeFormValidation( formNode, formObjectHandler, errorHandler ) {
    return validateForm( formNode, formObjectHandler, errorHandler, false );
};

function invokeFormValidation( formNode, formObjectFactoryHandler, errorHandler, validateAll ) {
    var valid = false;
    if( formNode != null ) {

        valid = true;
        if( formObjectFactoryHandler != null ) {

            var formObjectsArray = formObjectFactoryHandler.call( this, formNode );
            var validationComposite = new ValidatorComposite( formObjectsArray, validateAll );

            valid = validationComposite.validate();
            if( valid == false ) {

                var invalidFormObjects = validationComposite.getInvalidFormObjects();
                if( invalidFormObjects != null && invalidFormObjects.length > 0 ) {

                    if( errorHandler != null ) {
                        if( validateAll == true ) {
                            // invoke errorHandler for all invalid elements
                            for( var n=0; n < invalidFormObjects.length; n++ ) {
                                errorHandler.call( this, invalidFormObjects[n] );
                            }

                        } else {
                            // invoke errorHandler for first invalid element
                            errorHandler.call( this, invalidFormObjects[0] );
                        }
                    }
                }
            }
        }

    }
    return valid;
};


function lookUpOnChangeCandidates( formName ) {
    return lookupFunctionByName( formName, "getOnChangeNodes_" );
};
function lookUpDateWatchers( formName ) {
    return lookupFunctionByName( formName, "getComponentDateWatchers_" );
};
function lookUpDateRangeWatchers( formName ) {
    return lookupFunctionByName( formName, "getComponentDateRangeWatchers_" );
};
function lookUpDateAndDurationWatchers( formName ) {
    return lookupFunctionByName( formName, "getComponentDateAndDurationWatchers_" );
};
function lookUpHierachicalGroupNames( formName ) {
    return lookupFunctionByName( formName, "getHierachicalGroupNames_" );
};
function lookUpComponentGroupNames( formName ) {
    return lookupFunctionByName( formName, "getComponentGroups_" );
};

function lookupFunctionByName( formName, functionPrefix ) {
    var handler = null;

    if( formName != null && formName.length > 0 && functionPrefix != null && functionPrefix.length > 0 ) {

        var handlerFunctionName = functionPrefix + formName;
        handler = this[ handlerFunctionName ];
        if( !isFunction( handler ) ) {
            handler = null;
        }
    }
    return handler;
};

function isFunction( someObject ) {
    return someObject != null && typeof( someObject ) == "function";
};

