// ---------------------------------------------------------------------------
//  cbForm.js
//
//      requires: cb.js, , cbEvent.js, cbClass.js
//
//      Schnittstelle FormHandler
//
//      cbForm(formId)
//
//  new cbForm(formId[, is_error]);
//  addInput( config_obj );

//  setInputRequired(inputId, required );
//  setInputPattern(inputId, pattern);
//
//  addSubmit( submitId );
//  removeSubmit( submitId );
//
//  setMessageContainerId( containerId );
//
//  addTableRowLimiter( controlId, tableId, hideIds, showIds );
//
//  addClipper( controllerId, prefix, suffix, inputIds );
//
//  addExclusiveSet( obj )
//
//  addParty( obj )
//
// ---------------------------------------------------------------------------

function cbForm( form_id, is_error, prompt_errors ) {

    var cl_fed  = 'al_fed_in',              //  style class - data fed in
        cl_lab  = 'al_label',               //  style class - normal label
        cl_err  = 'al_error',               //  style class - label on error
        myForm  = this;

    this.form           = xGetElementById( form_id );
    if ( !this.form ) {
        alert( "cbForm: Could not get form element ... giving up" );
        return null;
    }

    this.form.cbf       = { 'cbForm' : myForm };
    this.form_id        = form_id;

    this.is_error       = isBool( is_error ) ? is_error  :  false;
    this.prompt_errors	= prompt_errors || false;
    this.jump_to_errors = false;

    this.input_ids      = [];
    this.input_objs     = {};

    this.submit_ids     = [];
    this.submit_objs    = {};

    this.limiter_ids    = [];
    this.limiter_objs   = {};
    this.table_limiters = {};

    this.clipper_ids    = [];
    this.clipper_objs   = {};

    this.bd_updaters    = [];

    this.msg_div_id     = null;
    this.msg_div        = null;

    // ------------------------------------------------------------------------
    //  ... methods --- interface functions
    // ------------------------------------------------------------------------

    //
    // jump_to_errors
    //
    this.setJumpToErrors = function ( boolval ) {
        this.jump_to_errors = boolval;
    };

    this.getJumpToErrors = function ( ) {
        return this.jump_to_errors;
    };

    //
    //  Inputs
    //
    this.addInput
        = function ( obj_ref ) {
            var new_input = new cbfInput( obj_ref );
            if ( new_input ) {
                push( this.input_ids, new_input.id );
                this.input_objs[ new_input.id ] = new_input;
            }
            else {
                this.showError( 'Could not add new Input for ' + obj_ref.id );
            }
        };

    this.setInputRequired
        = function( id, required ) {
            if ( this.input_objs[ id ] ) {
                this.input_objs[ id ].set_required( required );
            }
        };

    this.setInputPattern
        = function( id, pattern ) {
            if ( this.input_objs[ id ] ) {
                this.input_objs[ id ].add_pattern( pattern );
            }
        };
    this.addInputPattern = this.setInputPattern;

    this.addInputPatterns
        = function( id  ) {
            if ( this.input_objs[ id ] ) {
                this.input_objs[ id ].add_patterns( arguments.slice( 1 ) );
            }
        };

    this.removeInput
        = function( id ) {
            if ( this.input_objs[ id ] ) {
                this.input_objs[ id ].remove( );
                this.input_ids = take_out( this.input_ids, id );
                this.input_objs[ id ] = null;
            }
        };

    //
    //	Submits
    //
    this.addSubmit
        = function( id ) {
            var new_submit = new cbfSubmit( id );
            if ( new_submit ) {
                push( this.submit_ids, id );
                this.submit_objs[ id ] = new_submit;
            }
            else {
                this.showError( 'Could not add Submit [id: '+new_submit.id+' ]' );
            }
        };

    this.addSubmits
        = function( ids ) {
            for ( var i = 0; i < this.addSubmits.arguments.length; i++ ) {
                this.addSubmit( this.addSubmits.arguments[ i ] );
            }
        };

    this.removeSubmit
        = function( id ) {
            if ( this.submit_objs[ id ] ) {
                this.submit_objs[ id ].remove( );
                this.submit_ids = take_out( this.submit_ids, id );
                this.submit_objs[ id ] = null;
            }
        };

    this.removeSubmits
        = function( ids ) {
            for ( var i = 0; i < this.removeSubmits.arguments.length; i++ ) {
                this.removeSubmit( this.removeSubmits.arguments[ i ] );
            }
        };

    //
    //  TableRowLimiter
    //
    this.addTableRowLimiter
        = function( control_id, table_id, hideIds, showIds, blockingFields, multiplicity, styleClasses ) {
            var e_ctl = xGetElementById( control_id );
            if ( !e_ctl )
                this.showError( 'Limiter: no such control '+control_id );
            push( this.limiter_ids, control_id );
            var limiter = new cbfLimiter( e_ctl, table_id, hideIds, showIds, blockingFields, multiplicity, styleClasses );
            this.limiter_objs[ control_id ] = limiter;
            this.table_limiters[ table_id ] = limiter;
        };

    this.removeTableRowLimiter
        = function( id ) {
            if ( this.limiter_objs[ id ] ) {
                this.limiter_objs[ id ].remove( );
                this.limiter_ids = take_out( this.limiter_ids, id );
                this.limiter_objs[ id ] = null;
                this.table_limiters[ table_id ] = null;
            }
        };


    //
    //  Clipper
    //
    this.addClipper = function( controllerId, prefix, suffix, inputIds ) {
        var clipper = new cbfClipper( controllerId, prefix, suffix, inputIds );
        push( this.clipper_ids, controllerId );
        this.clipper_objs[ controllerId ] = clipper;
    };


    //
    //  Exclusive Set
    //
    this.addExclusiveSets
        = function( objs ) {
            var new_xset = new ExclusiveSets( objs );
        };


    //
    //  Message Containers
    //
    this.setMessageContainerId
        = function( id ) {
            var m_ele = xGetElementById( id );
            if ( m_ele ) {
                this.msg_div_id = id;
                this.msg_div    = m_ele;
            }
        };

    this.hasMessageContainer
        = function( ) { return this.msg_div_id != null; };


    //
    //  booking data updater
    //
    this.addBdPartyUpdater
        = function( cfg_obj ) {
            var upd = new bdPartyUpdater( cfg_obj );
            if ( upd ) push( this.bd_updaters, upd );
        };

    //
    //	conditional hiders
    //
    this.addConditionalHider
        = function( obj ) {
            var ch = new cbConditionalHider( obj );
        };

        this.addInputFieldModeSwitcher
                = function( obj ) {
            var ims = new cbInputFieldModeSwitcher( obj );
        };

    this.addRadioGroupSimulator
        = function( cfg ) {
                var rsim = new cbRadioGroupSimulator( cfg );
        };

    // ------------------------------------------------------------------------
    //  end methods --- interface functions
    // ------------------------------------------------------------------------

    // ------------------------------------------------------------------------
    //  ... error handling
    // ------------------------------------------------------------------------

    this.errtxt_id  = 'cbf_err_txt';
    this.errhdr_id  = 'cbf_err_hdr';
    this.errhdrText = 'Input required!';
    this.errNoInput = 'Eingabe erforderlich!';
    this.errBadInput = 'Eingabe unbrauchbar!';
    this.errtxtText = 'Please enter your data';

    function create_elem( tag, id, cl, ct ) {
        var e = document.createElement( tag );
        if ( isStr( id ) && id.length > 0 ) e.id        = id;
        if ( isStr( cl ) && cl.length > 0 ) e.className = cl;
        if ( isStr( ct ) && ct.length > 0 ) xInnerHtml( e, ct );
        return e;
    }

    function create_errDiv( id_hdr, id_str ) {
        var d = create_elem( 'div', null, 'cbf_error' );
        xHide( d );
        d.appendChild( create_elem( 'p', id_hdr, 'cbf_errHeader', myForm.errhdrText ) );
        d.appendChild( create_elem( 'p', id_str, 'cbf_errText', myForm.errtxtText ) );
        document.body.appendChild( d );
        return d;
    }

    this.errDiv     = create_errDiv( this.errhdr_id, this.errtxt_id );

    this.showError
        = function( txt ) {
            xInnerHtml( myForm.errhdr_id, 'Programming Error ???' );
            xInnerHtml( myForm.errtxt_id, txt );
            var l = Math.round( ( xClientWidth( ) - xWidth( this.errDiv ) ) / 2 );
            xMoveTo( this.errDiv, l, 200 );
            xShow( this.errDiv );
            this.errDiv.focus( );
        };

    this.errClean
        = function( e ) {
            xHide( myForm.errDiv );
        };

    //
    //  messages
    //
    this.getInputPatternErrors
        = function( pat_ids ) {
            var i, err_msgs = [];
            for ( i = 0; i < pat_ids.length; i++ ) {
                push( err_msgs, this.input_objs[ pat_ids[ i ] ].get_pattern_error( ) );
            }
            return err_msgs;
        };

    this.getInputErrorMessages
        = function( err_ids ) {
            var i, err_msgs = [];
            for ( i = 0; i < err_ids.length; i++ ) {
                push( err_msgs, this.input_objs[ err_ids[ i ] ].get_error_msg( ) );
            }
            return err_msgs;
        };

    this.msgOut
        = function( pat_ids, err_ids ) {
            var i, m,
                html    = '',
                msg_map = {},
                msgs    = [];

            if ( this.hasMessageContainer( )  ) {
                msgs = msgs.concat( this.getInputPatternErrors( pat_ids ) );
                msgs = msgs.concat( this.getInputErrorMessages( err_ids ) );
                for ( i = 0; i < msgs.length; i++ ) {
                        msg_map[ msgs[ i ] ] = true;
                }
                for ( m in msg_map ) {
                    if ( msg_map[ m ] )
                        html += '<li>' + m + '</li>';
                }
                if ( html ) {
                    html = '<ul>' + html + '</ul>';
                    xInnerHtml( this.msg_div, html );
                }
                if ( this.jump_to_errors ) {
                    window.scrollTo( 0, xPageY( this.msg_div ) - 10 );
                }
            }
        };

    // ------------------------------------------------------------------------
    //  end error handling
    // ------------------------------------------------------------------------

// ----------------------------------------------------------------------------
// ... cbfInput  - private object
//
//  interface functions    -   methods
//      set_required( required )
//      add_pattern( pattern )
//      add_patterns( patterns ) {
//      set_patterns( patterns ) {
//      check_patterns( )
//      remove( )
//
//  private functions, event handlers
//      cbf_input_focus( e )
//      cbf_input_blur( e )
// ----------------------------------------------------------------------------

    function cbfInput( obj_ref ) {
        var ele         = xGetElementById( obj_ref.id );
        if ( !ele ) {
            alert( 'cbfInput: Cannot find id ' + obj_ref.id + ' !!!');
            return null;
        }

        var myInput     = this;

        this.id         = obj_ref.id;
        this.ele        = ele;
        this.required   = obj_ref.defaultRequired || obj_ref.required;

        this.patterns   = obj_ref.pattern ?
                [ obj_ref.pattern ]
            :   [];

        this.messages   = obj_ref.validatorMessage ?
                [ obj_ref.validatorMessage ]
            :   [];

        this.valid_ids  = obj_ref.enableOnCommandIds ?
                split_into_hash( obj_ref.enableOnCommandIds, "," )
            :   null;

        this.inval_ids  = obj_ref.disableOnCommandIds ?
                split_into_hash( obj_ref.disableOnCommandIds, "," )
            :   null;


        // --------------------------------------------------------------------
        //  ... cbfInput Event handlers
        // --------------------------------------------------------------------

        // focus event handler for input fields
        function cbf_input_focus( e ) {
            var evt = new xEvent( e );
            var ele = evt.target;

            if ( ele.title === ele.value ||
                 ele.title === ele.value + '*' ||
                 ele.title + '*' === ele.value) {
                ele.value = '';
            }
            if ( ele.value == '' ) {
                xSwitchClasses( ele, ele.cbf.cl_bad, ele.cbf.cl_ok );
                if ( ele.cbf.cl_bad == myForm.cl_err )
                    ele.show_error( myForm.errNoInput );
            }
            else {
                if ( myInput.get_pattern_errors( ) ) {
                    xSwitchClasses( ele, ele.cbf.cl_ok, ele.cbf.cl_bad );
                }
                else {
                    xSwitchClasses( ele, ele.cbf.cl_bad, ele.cbf.cl_ok );
                }
            }
        }

        // blur event handler for input fields
        function cbf_input_blur( e ) {
            var evt = new xEvent( e );
            var ele = evt.target;

            // if present, cut out  --- title + '*' ---
            var ttt = ele.title;
            if ( ttt ) {
                if ( ttt.indexOf( '*' ) === -1 ) {
                    ttt += '*';
                }
                ele.value = ele.value.replace( ttt, '' );
            }

            if ( ele.value === '' || ele.value === ele.title ||
                 ele.value === ele.title + '*' ||
                 ele.value + '*' === ele.title ) {
                ele.value = ele.title;
                xSwitchClasses( ele, ele.cbf.cl_ok, ele.cbf.cl_bad );
            }
            else {
                if ( !ele.cbf.limit || ele.cbf.limit.enabled ) {
                    if ( myInput.get_pattern_errors( ) ) {
                        xSwitchClasses( ele, ele.cbf.cl_ok, ele.cbf.cl_bad );
                    }
                    else {
                        xSwitchClasses( ele, ele.cbf.cl_bad, ele.cbf.cl_ok );
                    }
                }
                else {
                    xSwitchClasses( ele, ele.cbf.cl_bad, ele.cbf.cl_ok );
                }
            }

            myForm.errClean( ele );
        }

        xAddEventListener( ele, 'focus', cbf_input_focus,  false );
        xAddEventListener( ele, 'blur',  cbf_input_blur,   false );

        // --------------------------------------------------------------------
        //  end cbfInput Event handlers
        // --------------------------------------------------------------------

        // --------------------------------------------------------------------
        // ... cbfInput interface methods
        // --------------------------------------------------------------------

        this.set_errorlook
            = function( b ) {
                xRemoveClass( this.ele, this.ele.cbf.cl_bad );
                this.ele.cbf.cl_bad = b ? cl_err : cl_lab;
                xAddClass( this.ele, this.ele.cbf.cl_bad );
            };

        this.set_required
            = function( required ) {
                this.ele.cbf.required = required;

                var old_title = this.ele.title;
                var no_star = this.ele.title.search(/\*$/) == -1;

                if ( required && no_star ) {
                    this.ele.title += '*';
                }
                if ( !required && !no_star ) {
                    this.ele.title  = this.ele.title.replace(/\*$/, '' );
                }
                if ( this.ele.value == old_title ) {
                    this.ele.value = this.ele.title;
                }
            };

        this.is_required
            = function( ) { return this.ele.cbf.required; };


        this.is_empty
            = function( ) {
                return this.ele.value == '' || this.ele.value == this.ele.title;
            };

        this.set_empty
            = function( ) {
                if ( this.ele.value == this.ele.title ) this.ele.value = '' ;
            };

        this.inLimit
            = function( ) {
                return !this.ele.cbf.limit || this.ele.cbf.limit.enabled;
            };

        this.outOfLimit
            = function( ) { return !this.inLimit( ); };

        this.set_value
            = function( ) { ele.value = ele.title; };

        this.clear_value
            = function( ) { ele.value = ''; };

        this.add_pattern
            = function( pattern, message ) {
                if ( this.ele.cbf && this.ele.cbf.patterns ) {
                    if ( pattern && pattern.length > 0 ) {
                        push( this.ele.cbf.patterns,
                             { 're' : pattern, 'msg' : message, 'ok': true } );
                    }
                }
            };

        this.add_patterns
            = function( patterns, messages ) {
                for ( var i = 0; i < patterns.length; i++ ) {
                    var last_msg = messages[ i ] || last_msg;
                    this.add_pattern( patterns[ i ], last_msg );
                }
            };

        this.check_patterns
            = function( ) {
                var ele = this.ele;
                var msg = [ ];
                if ( this.inLimit( ) ) {
                    for ( var i = 0; i < ele.cbf.patterns.length; i++ ) {
                        var re = ele.cbf.patterns[ i ].re;
                        var rs = ele.value.match( re );
                        if ( !ele.value.match( re ) ) {
                            push( msg, ele.cbf.patterns[ i ].msg );
                        }
                    }
                }
                return msg.length > 0 ? msg : null;
            };
        this.get_pattern_errors = this.check_patterns;

        this.match_patterns
            = function( ) {
                var ele = this.ele;
                if ( this.inLimit( ) ) {
                    for ( var i = 0; i < ele.cbf.patterns.length; i++ ) {
                        var re = ele.cbf.patterns[ i ].re;
                        var rs = ele.value.match( re );
                        if ( !ele.value.match( re ) ) {
                            ele.cbf.patterns[ i ].ok = false;
                            return false;
                        }
                        else {
                            ele.cbf.patterns[ i ].ok = true;
                        }
                    }
                }
                return true;
            };

        this.check_for
            = function( sid ) {
                return !this.inLimit( )           ? 'hidden'
                     : !this.has_validator( sid ) ? 'opt_empty'
                     :  this.is_empty( )          ?
                             ( this.is_required() ? 'req_empty' : 'opt_empty' )
                     :   ( this.match_patterns( ) ? 'ok' : 'pattern' )
                     ;
            };

        this.get_pattern_error
            = function( ) {
                var i, err_msgs = [];
                if ( this.ele.cbf.patterns ) {
                    for ( i = 0; i < this.ele.cbf.patterns.length; i++ ) {
                        if ( !this.ele.cbf.patterns[i].ok ) {
                            push( err_msgs, this.ele.cbf.patterns[i].msg );
                        }
                    }
                }
                return err_msgs;
            };

        this.get_error_msg
            = function( ) {
            	return this.ele.cbf.patterns[0] ?
            		   this.ele.cbf.patterns[0].msg : '';
            };

        this.has_validator
            = function( submit_id ) {
                var va  = this.ele.cbf.validator.valid_ids,
                    iv  = this.ele.cbf.validator.inval_ids;

                return va ?  ( submit_id in va )
                    :  iv ? !( submit_id in iv )
                    :        true;
            };

        this.remove
            = function( ) {
                var ele = this.ele;

                if ( ele.value == ele.title ) ele.value = '';
                if ( ele.cbf ) {
                    xRemoveClass( ele, ele.cbf.cl_ok );
                    xRemoveClass( ele, ele.cbf.cl_bad );
                    // delete( ele.cbf );
                }

                xRemoveEventListener( ele, 'focus', cbf_input_focus,  false );
                xRemoveEventListener( ele, 'blur',  cbf_input_blur,   false );

            };

        this.show_error
            = function( htxt, ttxt ) {
                if ( !myForm.prompt_errors ) return;
                var err_def = this.is_empty() ? myForm.errNoInput : myForm.errBadInput;
                var h = isStr( htxt ) && htxt.length > 0 ? htxt : err_def;
                xInnerHtml( myForm.errhdr_id, h );
                var t = isStr( ttxt ) && ttxt.length > 0 ? ttxt : ele.title;
                xInnerHtml( myForm.errtxt_id, t );
                xMoveTo( myForm.errDiv, xPageX( ele ) + 30, xPageY( ele ) + xHeight( ele ) + 3 );
                xShow( myForm.errDiv );
                ele.focus( );
            };

        // --------------------------------------------------------------------
        // end cbfInput interface methods
        // --------------------------------------------------------------------


        var al      = {
            'type'     : 'Input',
            'cl_ok'    : cl_fed,
            'cl_bad'   : is_error && this.required ? cl_err : cl_lab,
            'required' : this.required,
            'patterns' : [ ],
            'validator': {
                            'valid_ids' : this.valid_ids,
                            'inval_ids' : this.inval_ids
                         }
        };

        for ( var i = 0; i < this.patterns.length; i++ ) {
            var last_msg = this.messages[ i ] || last_msg;
            push( al.patterns, { 're' : this.patterns[ i ], 'msg' : last_msg } );
        }

        this.ele.cbf = al;

        this.set_required( this.required );

        if ( isStr( ele.title ) && ( !isStr( ele.value ) || !ele.value ) ) {
            ele.value = ele.title;
        }

        xAddClass( ele, this.is_empty() ? ele.cbf.cl_bad : ele.cbf.cl_ok );

        this.is_error   = isBool( is_error ) ? is_error  :  false;

        return this;

    }

// ----------------------------------------------------------------------------
// end cbfInput  - private object
// ----------------------------------------------------------------------------


// ----------------------------------------------------------------------------
// ... cbfSubmit  - private object
// ----------------------------------------------------------------------------

    function cbfSubmit( id ) {

        var ele = xGetElementById( id );

        if ( !ele ) {
            alert( 'cbfSubmit: No Form Element ' + id + ' found!!! ');
            return null;
        }

        var cbf      = {};
        cbf.form_obj = myForm;
        cbf.form_ele = myForm.form;
        cbf.id       = id;
        ele.cbf      = cbf;

        xAddEventListenerPrepended( ele, 'click', cbf_submit, false );

        // --------------------------------------------------------------------
        //  ... cbfsubmit  interface methods
        // --------------------------------------------------------------------

        this.remove
            = function( id ) {
                var ele = this.ele;
                if ( ele.cbf ) { delete ele.cbf; };
                xRemoveEventListener( ele, 'click', cbf_submit, false );
            };

        // --------------------------------------------------------------------
        //  end cbfsubmit  interface methods
        // --------------------------------------------------------------------


        // --------------------------------------------------------------------
        //  ... cbfsubmit Event handlers
        // --------------------------------------------------------------------

        function cbf_submit( e ) {
            var evt = new xEvent( e );
            // var cmd = evt.target;
            var cmd = evt.getTargetWithProperty( 'cbf' );

            var field_status    = {};
            var first_err_obj   = null;

            var chk = {
                'ok'        : [],
                'hidden'    : [],
                'opt_empty' : [],
                'req_empty' : [],
                'pattern'   : []
            };

            for ( var i = 0; i < myForm.input_ids.length; i++ ) {
                // check input fields
                var id = myForm.input_ids[ i ];
                var oo = myForm.input_objs[ id ];
                var ee = oo.ele;
                if ( !ee || !oo ) continue;

                var rs = oo.check_for( cmd.cbf.id );
                field_status[ id ] = rs;
                push( chk[  rs ], id );

                if ( !first_err_obj && ( rs == 'req_empty' || rs == 'pattern' ) )
                    first_err_obj = oo;
            }

            if ( chk['req_empty'].length > 0 || chk['pattern'].length > 0 ) {
                // some error in page --> stay and show errors

                for ( var i = 0; i < chk['req_empty'].length; i++  ) {
                    myForm.input_objs[ chk['req_empty'][ i ] ].set_errorlook( true );
                }
                for ( var i = 0; i < chk['pattern'].length; i++   ) {
                    myForm.input_objs[ chk['pattern'][ i ] ].set_errorlook( true );
                }

                myForm.msgOut( chk['pattern'], chk['req_empty'] );

                first_err_obj.show_error( );
                return false;
            }
            else {
                // no errors --> empty out labels and return true

                for ( var oo in myForm.input_objs ) {
                    if ( myForm.input_objs[ oo ].is_empty( ) )
                        myForm.input_objs[ oo ].set_empty( );
                }
                return true;
            }
        }

        return this;

    }

// ----------------------------------------------------------------------------
// end cbfSubmit  - private object
// ----------------------------------------------------------------------------

// ----------------------------------------------------------------------------
// ... cbfClipper  - private object
//
//    new cbfClipper( {
//        controllerId: 'formname:ctrlId',
//        prefix: 'myForm:myTable',
//        suffix: 'divId',
//        input_ids: [ 'firstName', 'lastName', ... ]
//    } );
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------

    function cbfClipper( ctlId, id_prefix, id_suffix, input_names ) {
        var controller,
            DOM_blocks = [],
            DOM_inputs = [],    	    line_inputs,
            i, j, el,
            name, id,
            get_id = function( i, sfx ) {
                return [id_prefix, i, sfx].join(':');
            },
            max_val;


        controller = xGetElementById( ctlId );

        for ( i = 0; el = xGetElementById( get_id( i, id_suffix ) ); i += 1 ) {
            DOM_blocks.push( el );
        }

        if ( !controller || DOM_blocks.length === 0 ) {
            alert( "cbForm - cbfClipper: " +
                   "No DOM Element with id " + id_prefix + '0' + id_suffix +
                   " or no Control with id " + ctlId + " found!!!");
            return;
        }
        this.controller = controller;
        this.DOM_blocks = DOM_blocks;
        max_val         = DOM_blocks.length;
        this.maxval     = max_val;

        for ( i = 0; i < this.maxval; i += 1 ) {
            line_inputs = {};
            for ( j = 0; j < input_names.length; j += 1 ) {
                name = input_names[ j ];
                id = get_id( i, name );
                el = xGetElementById( id );
                el.cbf = el.cbf || {};
                el.cbf.limit = {
                    row_ind: i,
                    enabled: i < this.controller.value,
                    maxrows: this.maxval
                };
                line_inputs[ name ] = el;
            }
            DOM_inputs.push( line_inputs );
        }


        function change_limit( ) {
            var act = parseInt( controller.value ),
                i, j;

            for ( i = 0; i < act; i++ ) {
                for ( name in DOM_inputs[ i ] ) {
                    DOM_inputs[ i ][ name ].cbf.limit.enabled = true;
                }
                xRemoveClass( DOM_blocks[ i ], 'hidden' );
            }

            for ( i = act; i < max_val; i++ ) {
                for ( name in DOM_inputs[ i ] ) {
                    DOM_inputs[ i ][ name ].cbf.limit.enabled = false;
                }
                xAddClass( DOM_blocks[ i ], 'hidden' );
            }
        }

        change_limit();

        xAddEventListener( controller, 'change', change_limit, false );
    }



// ----------------------------------------------------------------------------
// ... cbfLimiter  - private object
// ----------------------------------------------------------------------------

    function cbfLimiter( ctl_ele, table_id, hideIds, showIds, blockingFields, multiplicity, styleClasses ) {

        this.table_id   = table_id;
        this.ctl_ele    = ctl_ele;

        var e_tbl       = xGetElementsByTagName( 'tbody', table_id )[ 0 ];

        var limit_max   = ( e_tbl && e_tbl.rows ) ? e_tbl.rows.length : 0;
        this.limit_max  = limit_max;

        var ctl_value   = ctl_ele.value ? parseInt( ctl_ele.value ) : limit_max;

        var limited_els = [];
        for ( var i = 0; i < limit_max; i++ ){
            limited_els[ i ] = [];
        }

        for ( var input_id in myForm.input_objs ) {
            var id_str = input_id;
            if ( id_str.match( table_id ) ) {
                var e_input = myForm.input_objs[ input_id ].ele;

                var row = id_str.match( /:(\d+):/ )[ 1 ];
                if ( e_input.cbf && row )
                    e_input.cbf.limit = {
                        'row_ind' : parseInt( row ),
                        'enabled' : row < ctl_value,
                        'maxrows' : limit_max
                    };
                push( limited_els[ row ], e_input );
            }
        }

        function show_and_hide( ) {
            for ( var i = 0; i < showIds.length; i++ ) {
                xRemoveClass( showIds[ i ], 'hidden' );
            }
            for ( var i = 0; i < hideIds.length; i++ ) {
                xAddClass( hideIds[ i ], 'hidden' );
            }
        }

        function restore_show_and_hide( ) {
            for ( var i = 0; i < hideIds.length; i++ ) {
                xRemoveClass( hideIds[ i ], 'hidden' );
            }
            for ( var i = 0; i <showIds.length; i++ ) {
                xAddClass( showIds[ i ], 'hidden' );
            }
        }

        function change_limit( ele ) {
            var act = parseInt( ele.value );

            for ( var i = 0; i < act; i++ ) {
                for ( var j = 0; j < limited_els[ i ].length; j++ ) {
                    limited_els[ i ][ j ].cbf.limit.enabled = true;
                }
            }
            for ( var i = act; i < limit_max; i++ ) {
                for ( var j = 0; j < limited_els[ i ].length; j++ ) {
                    limited_els[ i ][ j ].cbf.limit.enabled = false;
                }
            }
        }

        function cbf_limit_change( e ) {
            var evt = new xEvent( e );
            var ele = evt.target;

            change_limit( ele );
            show_and_hide( );
        }

        xAddEventListener( ctl_ele, 'change', cbf_limit_change,  false );

        function get_paxtype( s ) {
            var pt = {
                '0'  : 'infant', '1' : 'infant','INF': 'infant',
                '2'  : 'child',  '3' : 'child',  '4' : 'child', '5'  : 'child',
                '6'  : 'child',  '7' : 'child',  '8' : 'child', '9'  : 'child',
                '10' : 'child', '11' : 'child', 'CHD': 'child',
                '12' : 'adult', '13' : 'adult', '14' : 'adult', '15' : 'adult',
                '16' : 'adult', '17' : 'adult', '18' : 'adult', '99' : 'adult',
                'MR' : 'adult', 'MRS': 'adult'
            };
            return pt[ s ] || 'none';
        }

        var all_blocker_els = [ ];

        function hide_if_different( ) {
            if ( ctl_value == ctl_ele.value ) {

                for ( var i = 0; i < all_blocker_els.length; i++ ) {
                    var e = all_blocker_els[ i ];
                    if ( get_paxtype( e.value ) != get_paxtype( e.start_value ) ) {
                        show_and_hide( );
                        return;
                    }
                }
                restore_show_and_hide( );
            }
        }


        if ( blockingFields ) {
            for ( var i = 0; i < ctl_value; i++ ) {
                for ( var j = 0; j < blockingFields.length; j++ ) {
                    var id = table_id + ':' + i + ':' + blockingFields[ j ];
                    var b_ele = xGetElementById( id );
                    push( all_blocker_els, b_ele );
                    if ( b_ele ) {
                        b_ele.start_value = b_ele.value;
                        xAddEventListener( b_ele, 'change', hide_if_different, false );
                    }
                }
            }
        }

        function sizeTable() {
            var factor = multiplicity ? parseInt(multiplicity, 10) : 1,
                value  = parseInt(ctl_ele.value, 10),
                size   = value * factor,
                rows   = e_tbl.rows,
                len    = rows.length,
                styles = styleClasses || [],
                slen   = styles.length,
                i, row;

            for (i = 0; i < len; i+= 1) {
                row = rows[i];
                if (i < size) {
                    if (slen > 0) {
                        xRemoveClass(row, styles[0]);
                        if (slen > 1) {
                            xAddClass(row, styles[1]);
                        }
                    }
                    else {
                        xExpandTableRowById(row);
                    }
                }
                else {
                    if (slen > 0) {
                        if (slen > 1) {
                            xRemoveClass(row, styles[1]);
                        }
                        xAddClass(row, styles[0]);
                    }
                    else {
                        xCollapseTableRowById(row);
                    }
                }
            }
        }

        xAddEventListener( ctl_ele, "change", sizeTable, false );
        sizeTable( );

        this.remove
            = function( ) {
                var ele = ctl_ele;
            };

        return this;
    }

// ----------------------------------------------------------------------------
// end cbfLimiter  - private object
// ----------------------------------------------------------------------------

// ----------------------------------------------------------------------------
//  ... ExclusiveSet
//      switcher_objs   Array of Objects
//          id:                 switcher id
//          check_for:          'value', 'checked'  ...
//          value_for_first:    'checked'
//          event_type:         'change', 'click', ...
//      first_set_obj   Object
//          container_id:       to hide and show
//          field_ids:          array to handle required fields
//ibe.load = function() {
//      var form = ibe.forms["paymentform"];
//      form.isError = false;
//      form.tableRowLimiter = {};
//      form.tableRowLimiter["paymentform:coupons"] = {controllerId: "paymentform:couponCount"};
//
//      form.creditCardOption = {
//          container: "creditCardOption",
//          inputs: [
//              "paymentform:creditCardNumber",
//              "paymentform:creditCardSecurityCode"
//          ]
//      };
//      form.bankOption = {
//          container: "bankOption",
//          inputs: [
//              "paymentform:bankAccountHolder",
//              "paymentform:bankAccountNumber",
//              "paymentform:bankName", "paymentform:bankCode"
//          ]
//      };
//      form.exclusiveSets["bank_creditCard"]
//          = [ { enable: { id: 'paymentform:paymentType:0' },
//                          set: form.creditCardOption,
//                          isBlock: true },
//              { enable: { id: 'paymentform:paymentType:1' }, set: form.bankOption  } ];
//
//      initCbForms(ibe.forms);
//};
// ----------------------------------------------------------------------------

    function ExclusiveSets( objs ) {
        if ( objs.length != 2 )  return null;

        var useBlockHide = false;

        for ( var i = 0; i < objs.length; i++ ) {
            var el = {};
            el.container    = xGetElementById( objs[ i ].set.container );
            if ( !el.container ) return null;
            el.controller   = xGetElementById( objs[ i ].enable.id );
            if (objs[i].isBlock) {
            	useBlockHide = true;
            }
            // if ( !el.controller ) return null;
            el.inputs = [];
            for ( var j = 0; j < objs[ i ].set.inputs.length; j++ ) {
                push( el.inputs, xGetElementById( objs[ i ].set.inputs[ j ] ) );
            }
            objs[ i ].el = el;
        }

        this.sw1 = new Switcher( objs[ 0 ], objs[ 1 ], useBlockHide );
        this.sw2 = new Switcher( objs[ 1 ], objs[ 0 ], useBlockHide );

        function Switcher( me, other, isBlock ) {
            var sw              = me.enable;
            var id              = sw.id;
            var check_for       = sw.check_for || 'checked';
            var value_for_first = sw.value_for_first || true;
            var event_type      = sw.event_type || 'click';
            var useBlockHide    = typeof(isBlock) != 'undefined' ? isBlock : false;
            function do_switch( ) {

                for ( var i = 0; i < other.set.inputs.length; i++ ) {
                    myForm.setInputRequired( other.set.inputs[ i ], false );
                }
                for ( var i = 0; i < me.set.inputs.length; i++ ) {
                    myForm.setInputRequired( me.set.inputs[ i ], true );
                }
                if (useBlockHide) {
                	xDisplay(other.el.container, "none");
                	xDisplay(me.el.container, "block");
                } else {
                	xHide( other.el.container );
                	xShow( me.el.container );
                }
            }

            if ( me.el.controller ) {
                xAddEventListener( id, event_type, do_switch, false );

                if ( me.el.controller[ check_for ] == value_for_first ) {
                    do_switch( );
                }
            }
        }

        return this;
    }
// ----------------------------------------------------------------------------
//  ... end ExclusiveSet
// ----------------------------------------------------------------------------

// ----------------------------------------------------------------------------
//  bdSyncher   synch party related summaries in booking data block
// ----------------------------------------------------------------------------

    function bdSyncher( tgt_id ) {
        var me = this;

        me.tgt    = xGetElementById( tgt_id );
        if ( !tgt_ID || !me.tgt ) {
            alert( 'bdSyncher: invalid update target! ... exiting' );
            return null;
        }

        me.getTotalVal
            = function( ) {
                return ibeUtil.read_tt_value( me.tgt );
            };

        me.itemValueFields = [];
        me.addItemField
            = function( f ) { push( me.itemValueFields, f ); };

        me.net_price = ibeUtil.read_tt_value( me.tgt ) || 0;

        me.changers = [ ];

        me.updaters = [ ];
        me.payments = [ ];


        me.addUpdater
            = function( cfg ) {
                if ( cfg.name == 'insurance' ) {
                    var upd = new bdInsurance( cfg );
                    if ( upd ) push( me.updaters, upd );
                }
            };

        me.addPartyUpdater
            = function( cfg ) {

            };


// ----------------------------------------------------------------------------
//  bdInsurance
// ----------------------------------------------------------------------------
//    ibe.upd_bd = { };
//    ibe.upd_bd[ "insurance" ] = {
//            name: 'insurance',
//            tgt: {
//                    container: bdInsuranceItem',
//                    val: 'bdInsuranceItemValue',
//                    qty: 'bdInsuranceItemQuantity'
//            },
//            src: {
//                    form: 'paymentform',
//                    field: 'insurance'
//            },
//            price: {
//                    adult: 30,
//                    child: 15,
//                    infant: 5
//            },
//            hide: [
//                    { id: 'paymentform:insuranceTerms', node: 'parentNode' }
//            ]
//    };
// ----------------------------------------------------------------------------

        function bdInsurance( cfg ) {
            var tgt         = cfg.tgt;
            var bdDiv_el    = xGetElementById( tgt.container );
            var bdVal_el    = xGetElementById( tgt.val );
            var bdQty_el    = xGetElementById( tgt.qty );

            me.addItemField( bdVal_el );

            this.getValue
                = function( ) {
                    return ibeUtil.read_tt_value( bdVal_el );
                };

            var bd_val  = ibeUtil.read_tt_value( bdVal_el );

            // var bd_total_val = parseInt( xInnerHtml( me.tgt ).replace('.', '') );

            // me.net_price   = me.net_price - bd_val;

            var controls = [];
            var i   = 0;
            var src = cfg.src;

            var el = xGetElementById( src.form + ':' + src.field + ':' + i++ );
            while ( el ) {
                controls[ controls.length ] = el;
                el = xGetElementById( src.form + ':' + src.field + ':' + i++ );
            }

            var toHide_el = null;
            if ( toHideChild ) {
                toHide_el = xGetElementById( toHideChild ).parentNode;
            }

            for ( i = 0; i < controls.length; i++ ) {
                var ctl_el  = controls[ i ];

                function mk_handler( ctl_el ) {
                    var ikey	= ctl_el.value;
                    var ctl_val = idata[ ikey ] ? parseInt( idata[ ikey ].price ) : 0;
                    return function ( ) {
                        if ( ctl_el.checked ) {
                            ibeUtil.write_tt_value( bdItem_el,  ctl_val );
                            ibeUtil.write_tt_value( bdTotal_el, net_total + ctl_val );
                        }
                        if ( ctl_val ) {
                            xRemoveClass( bdTable_el, 'hidden' );
                            if ( toHide_el ) xRemoveClass( toHide_el, 'hidden' );
                        }
                        else {
                            xAddClass( bdTable_el, 'hidden' );
                            if ( toHide_el ) xAddClass( toHide_el, 'hidden' );
                        }
                        disp_extra_payments( );
                    };
                }
                xAddEventListener( ctl_el, 'click', mk_handler( ctl_el ), false );
            }

            return this;
        }


        function bdAdder( ) {
        }

        function bdPayment( ) {
        }

        return this;
    }

// ----------------------------------------------------------------------------
//  ... bdSyncher   synch party related summaries in booking data block
// ----------------------------------------------------------------------------

// ----------------------------------------------------------------------------
//  bdUpdater   update party related summaries in booking data block
//
//    new bdPartyUpdater( {
//        src: {
//            table: 'paxform:paxes'
//            field: 'flexPackage'
//        }
//        tgt_ids: {
//            container: 'bdFlexItem',
//            qty: 'bdFlexItemQuantity',
//            val: 'bdFlexItemValue',
//            total: 'bdTotalPriceValue'
//        },
//        price: {
//            adult: 58,
//            child: 44
//        },
//        extra_payments: [
//          {
//              name: 'coupon',
//              qty_id: '',
//              val_id: '',
//              total_amount: 100,
//              total_id: '',
//              limited_by_price: true
//          }
//        ]
//    } );
// ----------------------------------------------------------------------------

    function bdPartyUpdater( cfg ) {
        var bd_cont_el  = xGetElementById( cfg.tgt.container );
        var bd_qty_el   = xGetElementById( cfg.tgt.qty );
        var bd_val_el   = xGetElementById( cfg.tgt.val );
        var bd_total_el = xGetElementById( cfg.tgt.total );

        var init_bd_total = ibeUtil.read_tt_value( bd_total_el );
        var init_bd_val   = ibeUtil.read_tt_value( bd_val_el );
        var net_total     = init_bd_total - init_bd_val;

        var table_id    = cfg.src.table;
        var table_el    = xGetElementById( cfg.src.table );

        var fieldname   = cfg.src.fieldname;

        var extras      = null;
        var anz_extras  = 0;

        if ( cfg.extra_payments ) {
            extras = [];
            anz_extras = cfg.extra_payments.length;
            for ( var i = 0; i < cfg.extra_payments.length; i++ ) {
                var payment = cfg.extra_payments[ i ];
                var ex = {};
                ex.name   = payment.name || '';
                ex.qty_el = xGetElementById( payment.qty_id ) || null;
                ex.val_el = xGetElementById( payment.val_id ) || null;
                ex.total_el = xGetElementById( payment.total_id ) || null;
                ex.amount   = payment.total_amount;
                ex.limited_by_price
                    = isDef( payment.limited_by_price ) ? payment.limited_by_price
                    :                                     true;

                push( extras, ex );
            }
        }

        function disp_extra_payments( ) {
            if ( anz_extras > 0 ) {
                var rest_amount = ibeUtil.read_tt_value( bd_total_el );
                for ( var i = 0; i < extras.length; i++ ) {
                    var extra  = extras[ i ];
                    rest_amount -= extra.amount;
                    if ( rest_amount < 0 ) rest_amount = 0;

                    if ( extra.val_el ) {
                        ibeUtil.write_tt_value( extra.val_el, extra.amount );
                    }
                    if ( extra.total_el ) {
                        ibeUtil.write_tt_value( extra.total_el, rest_amount );
                    }
                }
            }
        }

        function price_by_salutation( sal ) {
            return  sal == 'MR'  ? cfg.price.adult  || 0
                :   sal == 'MRS' ? cfg.price.adult  || 0
                :   sal == 'CHD' ? cfg.price.child  || 0
                :   sal == 'INF' ? cfg.price.infant || 0
                :                  0;
        }

        function price_by_age( age ) {
            var a = parseInt( age );
            return  a > 11 ? cfg.price.adult  || 0
                :   a >  1 ? cfg.price.child  || 0
                :   a >= 0 ? cfg.price.infant || 0
                :            0;
        }

        var myLimiter = myForm.table_limiters[ table_id ];
        var max_pax   = myForm.table_limiters[ table_id ].limit_max;

        //
        //      fields to check
        //
        var val_fields = [];
        var age_fields = [];
        var sal_fields = [];
        for ( var i = 0; i < max_pax; i++ ) {
            push( val_fields, xGetElementById( table_id + ':' + i + ':' + fieldname ) );
            push( age_fields, xGetElementById( table_id + ':' + i + ':' + 'age' ) );
            push( sal_fields, xGetElementById( table_id + ':' + i + ':' + 'salutation' ) );
        }

        function calc_field_val_by_age( ) {
            var total  = 0;
            var anzahl = 0;
            // if controlled by a limiter, respect actual limit
            var max_index = myLimiter ? myLimiter.ctl_ele.value : cal_fields.length;
            for ( var i = 0; i < max_index; i++ ) {
                if ( age_fields[ i ].value < 2 ) val_fields[ i ].checked = false;
                if ( val_fields[ i ].checked ) {
                    anzahl++;
                    total += price_by_age( age_fields[ i ].value );
                }
            }
            return( { 'value': total, 'count': anzahl } );
        }

        function calc_field_val_by_salutation( ) {
            var total  = 0;
            var anzahl = 0;

            // cf. calc_field_val_by_age
            var max_index = myLimiter ? myLimiter.ctl_ele.value : cal_fields.length;
            for ( var i = 0; i < max_index; i++ ) {
                if ( sal_fields[ i ].value == 'INF' ) {
                    val_fields[ i ].checked = false;
                }
                if ( val_fields[ i ].checked ) {
                    anzahl++;
                    total += price_by_salutation( sal_fields[ i ].value );
                }
            }
            return( { 'value': total, 'count': anzahl } );
        }

        function update_targets( obj ) {
            ibeUtil.write_tt_value( bd_qty_el, obj.count );
            ibeUtil.write_tt_value( bd_val_el, obj.value );
            ibeUtil.write_tt_value( bd_total_el, net_total + obj.value );
            if ( obj.count )
                xRemoveClass( bd_cont_el, 'hidden' );
            else
                xAddClass( bd_cont_el, 'hidden' );
            disp_extra_payments( );
        }

        function update_targets_sal( ) {
            update_targets( calc_field_val_by_salutation( ) );
        }

        function update_targets_age( ) {
            update_targets( calc_field_val_by_age( ) );
        }

        for ( var i = 0; i < val_fields.length; i++ ) {
            xAddEventListener( val_fields[ i ], 'click',  update_targets_sal, false );
            xAddEventListener( sal_fields[ i ], 'change', update_targets_sal, false );
            xAddEventListener( age_fields[ i ], 'change', update_targets_age, false );
        }
        xAddEventListener( myLimiter.ctl_ele, 'change', update_targets_sal, false );

        update_targets_age( );

    }

// ----------------------------------------------------------------------------
//      end bdUpdater   update party related summaries in booking data block
// ----------------------------------------------------------------------------

// ----------------------------------------------------------------------------
//  cbConditionalHider   hide block elements according to specified conditions
//
//  new cbConditionalHider(
//      {
//          src: 'paymentform:couponCount',     // control id
//          tgt: 'checkCoupons',                // target id
//          chk_prop: 'value',                  // property to check against
//          chk: 'eq',                          // check operator
//          hide: '0'                           // condition for hiding
//      }
//  );
// ----------------------------------------------------------------------------

    function cbConditionalHider( cfg ) {
        var control_el = xGetElementById( cfg.src );
        var target_el  = xGetElementById( cfg.tgt );

        if ( !target_el ) {
                return;
        }

        function hide_conditionally( ) {
            if ( ( cfg.chk == "eq" && control_el.value   == cfg.hide ) ||
                 ( cfg.chk == "le" && control_el.value   <= cfg.hide ) ||
                 ( cfg.chk == "ne" && control_el.value   != cfg.hide ) ||
                 ( cfg.chk == "ge" && control_el.value   >= cfg.hide ) ||
                 ( cfg.chk == "ch" && control_el.checked == cfg.hide )    ) {
                xAddClass( target_el, 'hidden' );
            }
            else {
                xRemoveClass( target_el, 'hidden' );
            }
        }
        xAddEventListener( control_el, 'change', hide_conditionally, false );
        hide_conditionally( );
    }

// ----------------------------------------------------------------------------
//      end conditionalHider   hide block elements ...
// ----------------------------------------------------------------------------

// ----------------------------------------------------------------------------
//  cbInputFieldModeSwitcher   	switch input field mode required / not required
//
//  Synopsis:
//      new cbInputFieldModeSwitcher(
//      {
//          src:    {
//              id: 'sel_id',
//              values_to_show: [ 'aaa', 'bbb', ... ]
//          },
//          tgt: {
//              id: 'target_id'
//          },
//          hide_if_not_required: true
//
//      }
// );
// ----------------------------------------------------------------------------

    function cbInputFieldModeSwitcher( cfg ) {
        this.src = xGetElementById( cfg.src.id );
        var show_on = { };

        for ( var i = 0; i < cfg.src.values_to_show.length; i++ ) {
            show_on[ cfg.src.values_to_show[ i ] ] = true;
        }

        this.src.cbIMS = {
            show_on: show_on,
            tgt_id:  cfg.tgt.id,
            hide:    cfg.hide_if_not_required
        };

        function hd_change( evt ) {
            var e = new xEvent( evt );
            var el = e.target;

            if ( el.cbIMS.show_on[ el.value ] ) {
                myForm.setInputRequired( el.cbIMS.tgt_id, true );
                if ( el.cbIMS.hide ) {
                    xRemoveClass( el.cbIMS.tgt_id, 'hidden');
                }
            }
            else {
                myForm.setInputRequired( el.cbIMS.tgt_id, false );
                if ( el.cbIMS.hide ) {
                    xAddClass( el.cbIMS.tgt_id, 'hidden');
                }
            }
        }
        xAddEventListener( this.src, 'change', hd_change, false );

        if ( show_on[ this.src.value ] ) {
            myForm.setInputRequired( cfg.tgt.id, true );
            if ( this.src.cbIMS.hide ) {
                xRemoveClass( this.src.cbIMS.tgt_id, 'hidden');
            }
        }
        else {
            myForm.setInputRequired( cfg.tgt.id, false );
            if ( this.src.cbIMS.hide ) {
                xAddClass( this.src.cbIMS.tgt_id, 'hidden');
            }
        }
    }

// ---------------------------------------------------------------------------
//      end cbInputFieldModeSwitcher   switch input field mode ...
// ----------------------------------------------------------------------------

// ----------------------------------------------------------------------------
// cbRadioGroupSimulator    hide all other checkboxes, if one is clicked
//
//  Synopsis:
//  new cbRadioGroupSimulator(
//          {
//              pre_index_id:   'form:table',
//              post_index_id:  'fieldname'
//          }
//  );
// ----------------------------------------------------------------------------

    function cbRadioGroupSimulator( cfg ) {
        this.flds = [ ];
        var ids  = [ ],
            el,
            i = 0,
            pre  = cfg.pre_index_id,
            post = cfg.post_index_id;

        if ( pre )  pre  = pre + ':';
        if ( post ) post = ':' + post;

        while ( el = xGetElementById( pre + i + post ) ) {
            this.flds.push( el );
            ids.push( pre + i + post );
            i += 1;
        }

        function hd_click( evt ) {
            var e = new xEvent( evt );
            var el = e.target;

            for ( var i = 0; i < el.rsim.length; i++ ) {
                if ( el.rsim[ i ] != el.id ) {
                    if ( el.checked ) {
                        xGetElementById( el.rsim[ i ] ).checked = false;
                    }
                }
            }
        }

        for ( i = 0; i < this.flds.length; i++ ) {
            this.flds[ i ].rsim = ids;
            xAddEventListener( this.flds[ i ], 'click', hd_click, false );
        }

    }

// ---------------------------------------------------------------------------
//      end cbRadioGroupSimulator   hide all other checkboxes, if one is clicked ...
// ----------------------------------------------------------------------------

    this.unload
        = function( ) {
        };


    // ------------------------------------------------------------------------
    //  ... private functions
    // ------------------------------------------------------------------------

    function push( a, e ) { a[a.length] = e; }
    function take_out( a, e ) {
        for ( var i = 0; i < a.length; i++ ) {
            if ( a[ i ] == id ) {
                a.splice( i, 1 );
                break;
            }
        }
        return a;
    }

    function set_all_values( a, v ) {
        for ( var i = 0; i < a.length; i++ ) {
            a[ i ].value = v;
        }
    }

    function trim( s ) { return s.replace (/^\s+/, '').replace (/\s+$/, ''); }

    function split_into_hash( s, re ) {
        var map = {}, arr = s.split( re );
        for ( var i = 0; i < arr.length; i++ ) {
            map[ trim( arr[i] ) ] = true;
        }
        return map;
    }

    // ------------------------------------------------------------------------
    //  end private functions
    // ------------------------------------------------------------------------

    this.done = 'jawoll';
    return this;

}

var AutoLabeler = cbForm;

function initCbForms( f ) {
    for ( var formId in f ) {
        var ff = f[ formId ];
        ff.cbForm = new cbForm( formId, ff[ "isError" ] );
        if ( ff.cbForm ) {
            ff.cbForm.setMessageContainerId( ff[ "messagesContainerId" ] );
            for ( var id in ff.inputs ) {
                ff.inputs[ id ].id = id;
                ff.cbForm.addInput( ff.inputs[ id ] );
            }
            for ( var id in ff.submits ) {
                ff.cbForm.addSubmit( id );
            }
            if ( ff.tableRowLimiter ) {
                for ( var id in ff.tableRowLimiter ) {
                    ff.cbForm.addTableRowLimiter( ff.tableRowLimiter[ id ].controllerId,
                                                  id,
                                                  ff.tableRowLimiter[ id ].hideIds || [],
                                                  ff.tableRowLimiter[ id ].showIds || [],
                                                  ff.tableRowLimiter[ id ].blockingFields,
                                                  ff.tableRowLimiter[ id ].multiplicity,
                                                  ff.tableRowLimiter[ id ].styleClasses || []);
                }
            }
            if ( ff.repeatLimiter ) {
                for ( var id in ff.repeatLimiter ) {
                    ff.cbForm.addClipper( ff.repeatLimiter[ id ].controllerId,
                                          ff.repeatLimiter[ id ].prefix,
                                          ff.repeatLimiter[ id ].suffix,
                                          ff.repeatLimiter[ id ].inputIds );
                }
            }
            if ( ff.exclusiveSets ) {
                for ( var obj in ff.exclusiveSets ) {
                    ff.cbForm.addExclusiveSets( ff.exclusiveSets[ obj ] );
                }
            }
            if ( ff.bdPartyUpdater ) {
                for ( var obj in ff.bdPartyUpdater ) {
                    ff.cbForm.addBdPartyUpdater( ff.bdPartyUpdater[ obj ] );
                }
            }
            if ( ff.conditionalHiders ) {
                for ( var obj in ff.conditionalHiders ) {
                    ff.cbForm.addConditionalHider( ff.conditionalHiders[ obj ] );
                }
            }
            if ( ff.inputFieldModeSwitchers ) {
                for ( var obj in ff.inputFieldModeSwitchers ) {
                    ff.cbForm.addInputFieldModeSwitcher( ff.inputFieldModeSwitchers[ obj ] );
                }
            }
            if ( ff.radioGroupSimulator ) {
                for ( var obj in ff.radioGroupSimulator ) {
                    ff.cbForm.addRadioGroupSimulator( ff.radioGroupSimulator[ obj ] );
                }
            }
        }
    }
}

