text:
describe( 'Custom labels: Adding models to a collection', function () {

    var Model = Backbone.Model.extend( {
        initialize: function () {
            Backbone.Select.Me.applyTo( this );
        }
    } );

    var SelectOneCollection = Backbone.Collection.extend( {
        initialize: function ( models ) {
            Backbone.Select.One.applyTo( this, models );
        }
    } );

    var SelectManyCollection = Backbone.Collection.extend( {
        initialize: function ( models ) {
            Backbone.Select.Many.applyTo( this, models );
        }
    } );

    beforeAll( function () {
        limitJasmineRecursiveScreenOutput();
    } );

    afterAll( function () {
        restoreJasmineRecursiveScreenOutput();
    } );

    describe( 'Using a custom "starred" label along with conventional selections (label "selected")', function () {
        var m1, m2, m3, events;

        beforeEach( function () {
            m1 = new Model();
            m2 = new Model();
            m3 = new Model();

            m1.select();

            m2.select();
            m2.select( { label: "starred" } );

            m3.select( { label: "starred" } );
        } );

        describe( 'Passing in models when creating a collection', function () {

            describe( 'Select.One collection', function () {
                var selectOneCollection;

                describe( 'with each model changing only one selection ("selected" or "starred") at a time', function () {

                    beforeEach( function () {
                        events = getEventSpies( [m1, m2, m3 ], ["selected", "starred"] );

                        selectOneCollection = new SelectOneCollection( [m1, m2, m3] );
                    } );

                    afterEach( function () {
                        selectOneCollection.close();
                    } );

                    describe( 'Status', function () {

                        it( 'the last model for the "selected" label retains its status, the other is deselected', function () {
                            expect( m1.selected ).toBe( false );
                            expect( m2.selected ).toBe( true );
                            expect( m3.selected ).toBeFalsy();
                        } );

                        it( 'the "selected" property of the collection is set to the last "selected" model', function () {
                            expect( selectOneCollection.selected ).toBe( m2 );
                        } );

                        it( 'the last model for the "starred" label retains its status, the other is deselected', function () {
                            expect( m1.starred ).toBeFalsy();
                            expect( m2.starred ).toBe( false );
                            expect( m3.starred ).toBe( true );
                        } );

                        it( 'the "starred" property of the collection is set to the last "starred" model', function () {
                            expect( selectOneCollection.starred ).toBe( m3 );
                        } );

                    } );

                    describe( 'Events', function () {

                        // NB We can't attach handlers to the collection while it is instantiated, so we only test
                        // model events here. (For a more involved test of collection events during instantiation,
                        // see the corresponding basic tests without label. Collection events shouldn't fire anyway.)

                        it( 'should not trigger a selected event, including for any of the namespaces, for any model', function () {
                            expect( events.get( m1, "selected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m2, "selected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m3, "selected:*" ) ).not.toHaveBeenCalled();
                        } );

                        it( 'should trigger a deselected event, with label "selected" in the event options, for the first of the two models which had been selected', function () {
                            expect( events.get( m1, "deselected" ) ).toHaveBeenCalledWith( m1, { label: "selected" } );
                        } );

                        it( 'should trigger a deselected:starred event for the first of the two models which had been selected', function () {
                            expect( events.get( m1, "deselected:selected" ) ).toHaveBeenCalledWith( m1, { label: "selected" } );
                        } );

                        it( 'should trigger a deselected event, with label "starred" in the event options, for the first of the two models which had been starred', function () {
                            expect( events.get( m2, "deselected" ) ).toHaveBeenCalledWith( m2, { label: "starred" } );
                        } );

                        it( 'should trigger a deselected:starred event for the first of the two models which had been starred', function () {
                            expect( events.get( m2, "deselected:starred" ) ).toHaveBeenCalledWith( m2, { label: "starred" } );
                        } );

                        it( 'should not trigger more than those four deselected events (including namespaced ones)', function () {
                            expect( events.get( m1, "deselected:*" ) ).toHaveCallCount( 2 );
                            expect( events.get( m2, "deselected:*" ) ).toHaveCallCount( 2 );
                            expect( events.get( m3, "deselected:*" ) ).not.toHaveBeenCalled();
                        } );

                        it( 'should not trigger a reselected event, including for any of the namespaces, for any model', function () {
                            expect( events.get( m1, "reselected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m2, "reselected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m3, "reselected:*" ) ).not.toHaveBeenCalled();
                        } );

                    } );

                } );

                describe( 'with the last model changing both selections ("selected" and "starred") at the same time', function () {
                    var m4;

                    beforeEach( function () {
                        m4 = new Model();
                        m4.select();
                        m4.select( { label: "starred" } );

                        events = getEventSpies( [m1, m2, m3, m4 ], ["selected", "starred"] );

                        selectOneCollection = new SelectOneCollection( [m1, m2, m3, m4] );
                    } );

                    afterEach( function () {
                        selectOneCollection.close();
                    } );

                    describe( 'Status', function () {

                        it( 'the last model for the "selected" label retains its status, the other is deselected', function () {
                            expect( m1.selected ).toBe( false );
                            expect( m2.selected ).toBe( false );
                            expect( m3.selected ).toBeFalsy();
                            expect( m4.selected ).toBe( true );

                        } );

                        it( 'the "selected" property of the collection is set to the last "selected" model', function () {
                            expect( selectOneCollection.selected ).toBe( m4 );
                        } );

                        it( 'the last model for the "starred" label retains its status, the other is deselected', function () {
                            expect( m1.starred ).toBeFalsy();
                            expect( m2.starred ).toBe( false );
                            expect( m3.starred ).toBe( false );
                            expect( m4.starred ).toBe( true );
                        } );

                        it( 'the "starred" property of the collection is set to the last "starred" model', function () {
                            expect( selectOneCollection.starred ).toBe( m4 );
                        } );

                    } );

                    describe( 'Events', function () {

                        // NB We can't attach handlers to the collection while it is instantiated, so we only test
                        // model events here. (For a more involved test of collection events during instantiation,
                        // see the corresponding basic tests without label. Collection events shouldn't fire anyway.)

                        it( 'should not trigger a selected event, including for any of the namespaces, for any model', function () {
                            expect( events.get( m1, "selected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m2, "selected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m3, "selected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m4, "selected:*" ) ).not.toHaveBeenCalled();
                        } );

                        it( 'should trigger a deselected event, with label "starred" in the event options, for the first two of the three models which had been starred', function () {
                            expect( events.get( m2, "deselected" ) ).toHaveBeenCalledWith( m2, { label: "starred" } );
                            expect( events.get( m3, "deselected" ) ).toHaveBeenCalledWith( m3, { label: "starred" } );
                        } );

                        it( 'should trigger a deselected:starred event for the first two of the three models which had been starred', function () {
                            expect( events.get( m2, "deselected:starred" ) ).toHaveBeenCalledWith( m2, { label: "starred" } );
                            expect( events.get( m3, "deselected:starred" ) ).toHaveBeenCalledWith( m3, { label: "starred" } );
                        } );

                        it( 'should trigger a deselected event, with label "selected" in the event options, for the first two of the three models which had been selected', function () {
                            expect( events.get( m1, "deselected" ) ).toHaveBeenCalledWith( m1, { label: "selected" } );
                            expect( events.get( m2, "deselected" ) ).toHaveBeenCalledWith( m2, { label: "selected" } );
                        } );

                        it( 'should trigger a deselected:selected event for the first two of the three models which had been selected', function () {
                            expect( events.get( m1, "deselected:selected" ) ).toHaveBeenCalledWith( m1, { label: "selected" } );
                            expect( events.get( m2, "deselected:selected" ) ).toHaveBeenCalledWith( m2, { label: "selected" } );
                        } );

                        it( 'should not trigger more than those eight deselected events (including namespaced ones)', function () {
                            expect( events.get( m1, "deselected:*" ) ).toHaveCallCount( 2 );
                            expect( events.get( m2, "deselected:*" ) ).toHaveCallCount( 4 );
                            expect( events.get( m3, "deselected:*" ) ).toHaveCallCount( 2 );
                            expect( events.get( m4, "deselected:*" ) ).not.toHaveBeenCalled();
                        } );

                        it( 'should not trigger a reselected event, including for any of the namespaces, for any model', function () {
                            expect( events.get( m1, "reselected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m2, "reselected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m3, "reselected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m4, "reselected:*" ) ).not.toHaveBeenCalled();
                        } );

                    } );

                } );

            } );

            describe( 'Select.Many collection', function () {
                var selectManyCollection, expected;

                beforeEach( function () {
                    expected = {};
                } );

                describe( 'with each model changing only one selection ("selected" or "starred") at a time', function () {

                    beforeEach( function () {
                        events = getEventSpies( [m1, m2, m3 ], ["selected", "starred"] );

                        selectManyCollection = new SelectManyCollection( [m1, m2, m3] );
                    } );

                    afterEach( function () {
                        selectManyCollection.close();
                    } );

                    describe( 'Status', function () {

                        it( 'all models retain their status for the "selected" label', function () {
                            expect( m1.selected ).toBe( true );
                            expect( m2.selected ).toBe( true );
                            expect( m3.selected ).toBeFalsy();
                        } );

                        it( 'the "selected" property of the collection contains the "selected" models', function () {
                            expected[m1.cid] = m1;
                            expected[m2.cid] = m2;
                            expect( selectManyCollection.selected ).toEqual( expected );
                        } );

                        it( 'all models retain their status for the "starred" label', function () {
                            expect( m1.starred ).toBeFalsy();
                            expect( m2.starred ).toBe( true );
                            expect( m3.starred ).toBe( true );
                        } );

                        it( 'the "starred" property of the collection contains the "starred" models', function () {
                            expected[m2.cid] = m2;
                            expected[m3.cid] = m3;
                            expect( selectManyCollection.starred ).toEqual( expected );
                        } );

                    } );

                    describe( 'Events', function () {

                        // NB We can't attach handlers to the collection while it is instantiated, so we only test
                        // model events here. (For a more involved test of collection events during instantiation,
                        // see the corresponding basic tests without label. Collection events shouldn't fire anyway.)

                        it( 'should not trigger a selected event, including for any of the namespaces, for any model', function () {
                            expect( events.get( m1, "selected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m2, "selected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m3, "selected:*" ) ).not.toHaveBeenCalled();
                        } );

                        it( 'should not trigger a deselected event, including for any of the namespaces, for any model', function () {
                            expect( events.get( m1, "deselected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m2, "deselected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m3, "deselected:*" ) ).not.toHaveBeenCalled();
                        } );

                        it( 'should not trigger a reselected event, including for any of the namespaces, for any model', function () {
                            expect( events.get( m1, "reselected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m2, "reselected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m3, "reselected:*" ) ).not.toHaveBeenCalled();
                        } );

                    } );

                } );

                describe( 'with the last model changing both selections ("selected" and "starred") at the same time', function () {
                    var m4;

                    beforeEach( function () {
                        m4 = new Model();
                        m4.select();
                        m4.select( { label: "starred" } );

                        events = getEventSpies( [m1, m2, m3, m4 ], ["selected", "starred"] );

                        selectManyCollection = new SelectManyCollection( [m1, m2, m3, m4] );
                    } );

                    afterEach( function () {
                        selectManyCollection.close();
                    } );

                    describe( 'Status', function () {

                        it( 'all models retain their status for the "selected" label', function () {
                            expect( m1.selected ).toBe( true );
                            expect( m2.selected ).toBe( true );
                            expect( m3.selected ).toBeFalsy();
                            expect( m4.selected ).toBe( true );
                        } );

                        it( 'the "selected" property of the collection contains the "selected" models', function () {
                            expected[m1.cid] = m1;
                            expected[m2.cid] = m2;
                            expected[m4.cid] = m4;
                            expect( selectManyCollection.selected ).toEqual( expected );
                        } );

                        it( 'all models retain their status for the "starred" label', function () {
                            expect( m1.starred ).toBeFalsy();
                            expect( m2.starred ).toBe( true );
                            expect( m3.starred ).toBe( true );
                            expect( m4.starred ).toBe( true );
                        } );

                        it( 'the "starred" property of the collection contains the "starred" models', function () {
                            expected[m2.cid] = m2;
                            expected[m3.cid] = m3;
                            expected[m4.cid] = m4;
                            expect( selectManyCollection.starred ).toEqual( expected );
                        } );

                    } );

                    describe( 'Events', function () {

                        // NB We can't attach handlers to the collection while it is instantiated, so we only test
                        // model events here. (For a more involved test of collection events during instantiation,
                        // see the corresponding basic tests without label. Collection events shouldn't fire anyway.)

                        it( 'should not trigger a selected event, including for any of the namespaces, for any model', function () {
                            expect( events.get( m1, "selected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m2, "selected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m3, "selected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m4, "selected:*" ) ).not.toHaveBeenCalled();
                        } );

                        it( 'should not trigger a deselected event, including for any of the namespaces, for any model', function () {
                            expect( events.get( m1, "deselected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m2, "deselected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m3, "deselected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m4, "deselected:*" ) ).not.toHaveBeenCalled();
                        } );

                        it( 'should not trigger a reselected event, including for any of the namespaces, for any model', function () {
                            expect( events.get( m1, "reselected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m2, "reselected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m3, "reselected:*" ) ).not.toHaveBeenCalled();
                            expect( events.get( m4, "reselected:*" ) ).not.toHaveBeenCalled();
                        } );

                    } );

                } );

            } );

        } );

        describe( 'add()', function () {

            describe( 'Select.One collection', function () {
                var selectOneCollection;

                describe( 'Status: When adding the models to the collection', function () {

                    beforeEach( function () {
                        selectOneCollection = new SelectOneCollection();
                        selectOneCollection.add( m1 );
                        selectOneCollection.add( m2 );
                        selectOneCollection.add( m3 );
                    } );

                    afterEach( function () {
                        selectOneCollection.close();
                    } );

                    describe( 'with each model changing only one selection ("selected" or "starred") at a time', function () {

                        it( 'the last model for the "selected" label retains its status, the other is deselected', function () {
                            expect( m1.selected ).toBe( false );
                            expect( m2.selected ).toBe( true );
                            expect( m3.selected ).toBeFalsy();
                        } );

                        it( 'the "selected" property of the collection is set to the last "selected" model', function () {
                            expect( selectOneCollection.selected ).toBe( m2 );
                        } );

                        it( 'the last model for the "starred" label retains its status, the other is deselected', function () {
                            expect( m1.starred ).toBeFalsy();
                            expect( m2.starred ).toBe( false );
                            expect( m3.starred ).toBe( true );
                        } );

                        it( 'the "starred" property of the collection is set to the last "starred" model', function () {
                            expect( selectOneCollection.starred ).toBe( m3 );
                        } );

                    } );

                    describe( 'with the last model changing both selections ("selected" and "starred") at the same time', function () {
                        var m4;

                        beforeEach( function () {
                            m4 = new Model();
                            m4.select();
                            m4.select( { label: "starred" } );

                            selectOneCollection.add( m4 );
                        } );

                        it( 'the last model for the "selected" label retains its status, the other is deselected', function () {
                            expect( m1.selected ).toBe( false );
                            expect( m2.selected ).toBe( false );
                            expect( m3.selected ).toBeFalsy();
                            expect( m4.selected ).toBe( true );
                        } );

                        it( 'the "selected" property of the collection is set to the last "selected" model', function () {
                            expect( selectOneCollection.selected ).toBe( m4 );
                        } );

                        it( 'the last model for the "starred" label retains its status, the other is deselected', function () {
                            expect( m1.starred ).toBeFalsy();
                            expect( m2.starred ).toBe( false );
                            expect( m3.starred ).toBe( false );
                            expect( m4.starred ).toBe( true );
                        } );

                        it( 'the "starred" property of the collection is set to the last "starred" model', function () {
                            expect( selectOneCollection.starred ).toBe( m4 );
                        } );

                    } );

                } );

                describe( 'Status: When adding the models to the collection, with options.silent enabled', function () {

                    beforeEach( function () {
                        selectOneCollection = new SelectOneCollection();
                        selectOneCollection.add( m1, { silent: true } );
                        selectOneCollection.add( m2, { silent: true } );
                        selectOneCollection.add( m3, { silent: true } );
                    } );

                    afterEach( function () {
                        selectOneCollection.close();
                    } );

                    describe( 'with each model changing only one selection ("selected" or "starred") at a time', function () {

                        it( 'the last model for the "selected" label retains its status, the other is deselected', function () {
                            expect( m1.selected ).toBe( false );
                            expect( m2.selected ).toBe( true );
                            expect( m3.selected ).toBeFalsy();
                        } );

                        it( 'the "selected" property of the collection is set to the last "selected" model', function () {
                            expect( selectOneCollection.selected ).toBe( m2 );
                        } );

                        it( 'the last model for the "starred" label retains its status, the other is deselected', function () {
                            expect( m1.starred ).toBeFalsy();
                            expect( m2.starred ).toBe( false );
                            expect( m3.starred ).toBe( true );
                        } );

                        it( 'the "starred" property of the collection is set to the last "starred" model', function () {
                            expect( selectOneCollection.starred ).toBe( m3 );
                        } );

                    } );

                    describe( 'with the last model changing both selections ("selected" and "starred") at the same time', function () {
                        var m4;

                        beforeEach( function () {
                            m4 = new Model();
                            m4.select();
                            m4.select( { label: "starred" } );

                            selectOneCollection.add( m4, { silent: true } );
                        } );

                        it( 'the last model for the "selected" label retains its status, the other is deselected', function () {
                            expect( m1.selected ).toBe( false );
                            expect( m2.selected ).toBe( false );
                            expect( m3.selected ).toBeFalsy();
                            expect( m4.selected ).toBe( true );
                        } );

                        it( 'the "selected" property of the collection is set to the last "selected" model', function () {
                            expect( selectOneCollection.selected ).toBe( m4 );
                        } );

                        it( 'the last model for the "starred" label retains its status, the other is deselected', function () {
                            expect( m1.starred ).toBeFalsy();
                            expect( m2.starred ).toBe( false );
                            expect( m3.starred ).toBe( false );
                            expect( m4.starred ).toBe( true );
                        } );

                        it( 'the "starred" property of the collection is set to the last "starred" model', function () {
                            expect( selectOneCollection.starred ).toBe( m4 );
                        } );

                    } );

                } );

                describe( 'Events', function () {

                    describe( 'When adding a model which is "starred"', function () {
                        var events;

                        beforeEach( function () {
                            selectOneCollection = new SelectOneCollection( [m1, m2] );

                            events = getEventSpies( [m1, m2, m3, selectOneCollection ], ["selected", "starred"] );

                            selectOneCollection.add( m3 );
                        } );

                        afterEach( function () {
                            selectOneCollection.close();
                        } );

                        describe( 'model events', function () {

                            it( 'should not trigger a selected event, including for any of the namespaces, for any model', function () {
                                expect( events.get( m1, "selected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m2, "selected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m3, "selected:*" ) ).not.toHaveBeenCalled();
                            } );

                            it( 'should trigger a deselected event, with label "starred" in the event options, for an existing model which had been starred', function () {
                                expect( events.get( m2, "deselected" ) ).toHaveBeenCalledWith( m2, { label: "starred" } );
                            } );

                            it( 'should trigger a deselected:starred event for an existing model which had been starred', function () {
                                expect( events.get( m2, "deselected:starred" ) ).toHaveBeenCalledWith( m2, { label: "starred" } );
                            } );

                            it( 'should not trigger more than those two deselected events (including namespaced ones)', function () {
                                expect( events.get( m1, "deselected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m2, "deselected:*" ) ).toHaveCallCount( 2 );
                                expect( events.get( m3, "deselected:*" ) ).not.toHaveBeenCalled();
                            } );

                            it( 'should not trigger a reselected event, including for any of the namespaces, for any model', function () {
                                expect( events.get( m1, "reselected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m2, "reselected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m3, "reselected:*" ) ).not.toHaveBeenCalled();
                            } );

                        } );

                        describe( 'collection events', function () {

                            it( 'should trigger a select:one event, with label "starred" in the event options, for the added model', function () {
                                expect( events.get( selectOneCollection, "select:one" ) ).toHaveBeenCalledWith( m3, selectOneCollection, { label: "starred", _externalEvent: "add" } );
                            } );

                            it( 'should trigger a select:one:starred event for the added model', function () {
                                expect( events.get( selectOneCollection, "select:one:starred" ) ).toHaveBeenCalledWith( m3, selectOneCollection, { label: "starred", _externalEvent: "add" } );
                            } );

                            it( 'should not trigger more than those two select:one events (including namespaced ones)', function () {
                                expect( events.get( selectOneCollection, "select:one:*" ) ).toHaveCallCount( 2 );
                            } );

                            it( 'should trigger a deselect:one event, with label "starred" in the event options, for an existing model which had been starred', function () {
                                expect( events.get( selectOneCollection, "deselect:one" ) ).toHaveBeenCalledWith( m2, selectOneCollection, { label: "starred", _externalEvent: "add" } );
                            } );

                            it( 'should trigger a deselect:one:starred event for an existing model which had been starred', function () {
                                expect( events.get( selectOneCollection, "deselect:one:starred" ) ).toHaveBeenCalledWith( m2, selectOneCollection, { label: "starred", _externalEvent: "add" } );
                            } );

                            it( 'should not trigger more than those two deselect:one events (including namespaced ones)', function () {
                                expect( events.get( selectOneCollection, "deselect:one:*" ) ).toHaveCallCount( 2 );
                            } );

                            it( "should not trigger a reselect:one event, including any of the namespaces", function () {
                                expect( events.get( selectOneCollection, "reselect:one:*" ) ).not.toHaveBeenCalled();
                            } );

                        } );

                    } );

                    describe( 'When adding a model which is "starred", with options.silent enabled', function () {
                        var events;

                        beforeEach( function () {
                            selectOneCollection = new SelectOneCollection( [m1, m2] );

                            events = getEventSpies( [m1, m2, m3, selectOneCollection ], ["selected", "starred"] );

                            selectOneCollection.add( m3, { silent: true } );
                        } );

                        afterEach( function () {
                            selectOneCollection.close();
                        } );

                        describe( 'model events', function () {

                            it( 'should not trigger a selection-related event, including for any of the namespaces, for any model', function () {
                                expect( events.get( m1, "*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m2, "*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m3, "*" ) ).not.toHaveBeenCalled();
                            } );

                        } );

                        describe( 'collection events', function () {

                            it( "should not trigger a selection-related event, including for any of the namespaces", function () {
                                expect( events.get( selectOneCollection, "*" ) ).not.toHaveBeenCalled();
                            } );

                        } );

                    } );

                    describe( 'When adding a model which is both "selected" and "starred"', function () {
                        var m4, events;

                        beforeEach( function () {
                            m4 = new Model();
                            m4.select();
                            m4.select( { label: "starred" } );

                            selectOneCollection = new SelectOneCollection( [m1, m2, m3] );
                            events = getEventSpies( [m1, m2, m3, m4, selectOneCollection ], ["selected", "starred"] );

                            selectOneCollection.add( m4 );
                        } );

                        afterEach( function () {
                            selectOneCollection.close();
                        } );

                        describe( 'model events', function () {

                            it( 'should not trigger a selected event, including for any of the namespaces, for any model', function () {
                                expect( events.get( m1, "selected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m2, "selected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m3, "selected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m4, "selected:*" ) ).not.toHaveBeenCalled();
                            } );

                            it( 'should trigger a deselected event, with label "starred" in the event options, for an existing model which had been starred', function () {
                                expect( events.get( m3, "deselected" ) ).toHaveBeenCalledWith( m3, { label: "starred" } );
                            } );

                            it( 'should trigger a deselected:starred event for an existing model which had been starred', function () {
                                expect( events.get( m3, "deselected:starred" ) ).toHaveBeenCalledWith( m3, { label: "starred" } );
                            } );

                            it( 'should trigger a deselected event, with label "selected" in the event options, for an existing model which had been selected', function () {
                                expect( events.get( m2, "deselected" ) ).toHaveBeenCalledWith( m2, { label: "selected" } );
                            } );

                            it( 'should trigger a deselected:selected event for an existing model which had been selected', function () {
                                expect( events.get( m2, "deselected:selected" ) ).toHaveBeenCalledWith( m2, { label: "selected" } );
                            } );

                            it( 'should not trigger more than those four deselected events (including namespaced ones)', function () {
                                expect( events.get( m1, "deselected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m2, "deselected:*" ) ).toHaveCallCount( 2 );
                                expect( events.get( m3, "deselected:*" ) ).toHaveCallCount( 2 );
                                expect( events.get( m4, "deselected:*" ) ).not.toHaveBeenCalled();
                            } );

                            it( 'should not trigger a reselected event, including for any of the namespaces, for any model', function () {
                                expect( events.get( m1, "reselected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m2, "reselected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m3, "reselected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m4, "reselected:*" ) ).not.toHaveBeenCalled();
                            } );

                        } );

                        describe( 'collection events', function () {

                            it( 'should trigger a select:one event, with label "starred" in the event options, for the added model', function () {
                                expect( events.get( selectOneCollection, "select:one" ) ).toHaveBeenCalledWith( m4, selectOneCollection, { label: "starred", _externalEvent: "add" } );
                            } );

                            it( 'should trigger a select:one:starred event for the added model', function () {
                                expect( events.get( selectOneCollection, "select:one:starred" ) ).toHaveBeenCalledWith( m4, selectOneCollection, { label: "starred", _externalEvent: "add" } );
                            } );

                            it( 'should trigger a select:one event, with label "selected" in the event options, for the added model', function () {
                                expect( events.get( selectOneCollection, "select:one" ) ).toHaveBeenCalledWith( m4, selectOneCollection, { label: "selected", _externalEvent: "add" } );
                            } );

                            it( 'should trigger a select:one:selected event for the added model', function () {
                                expect( events.get( selectOneCollection, "select:one:selected" ) ).toHaveBeenCalledWith( m4, selectOneCollection, { label: "selected", _externalEvent: "add" } );
                            } );

                            it( 'should not trigger more than those four select:one events (including namespaced ones)', function () {
                                expect( events.get( selectOneCollection, "select:one:*" ) ).toHaveCallCount( 4 );
                            } );

                            it( 'should trigger a deselect:one event, with label "starred" in the event options, for an existing model which had been starred', function () {
                                expect( events.get( selectOneCollection, "deselect:one" ) ).toHaveBeenCalledWith( m3, selectOneCollection, { label: "starred", _externalEvent: "add" } );
                            } );

                            it( 'should trigger a deselect:one:starred event for an existing model which had been starred', function () {
                                expect( events.get( selectOneCollection, "deselect:one:starred" ) ).toHaveBeenCalledWith( m3, selectOneCollection, { label: "starred", _externalEvent: "add" } );
                            } );

                            it( 'should trigger a deselect:one event, with label "selected" in the event options, for an existing model which had been selected', function () {
                                expect( events.get( selectOneCollection, "deselect:one" ) ).toHaveBeenCalledWith( m2, selectOneCollection, { label: "selected", _externalEvent: "add" } );
                            } );

                            it( 'should trigger a deselect:one:selected event for an existing model which had been selected', function () {
                                expect( events.get( selectOneCollection, "deselect:one:selected" ) ).toHaveBeenCalledWith( m2, selectOneCollection, { label: "selected", _externalEvent: "add" } );
                            } );

                            it( 'should not trigger more than those four deselect:one events (including namespaced ones)', function () {
                                expect( events.get( selectOneCollection, "deselect:one:*" ) ).toHaveCallCount( 4 );
                            } );

                            it( "should not trigger a reselect:one event, including any of the namespaces", function () {
                                expect( events.get( selectOneCollection, "reselect:one:*" ) ).not.toHaveBeenCalled();
                            } );

                        } );

                    } );

                    describe( 'When adding a model which is both "selected" and "starred", with options.silent enabled', function () {
                        var m4, events;

                        beforeEach( function () {
                            m4 = new Model();
                            m4.select();
                            m4.select( { label: "starred" } );

                            selectOneCollection = new SelectOneCollection( [m1, m2, m3] );
                            events = getEventSpies( [m1, m2, m3, m4, selectOneCollection ], ["selected", "starred"] );

                            selectOneCollection.add( m4, { silent: true } );
                        } );

                        afterEach( function () {
                            selectOneCollection.close();
                        } );

                        describe( 'model events', function () {

                            it( 'should not trigger a selection-related event, including for any of the namespaces, for any model', function () {
                                expect( events.get( m1, "*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m2, "*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m3, "*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m4, "*" ) ).not.toHaveBeenCalled();
                            } );

                        } );

                        describe( 'collection events', function () {

                            it( "should not trigger a selection-related event, including for any of the namespaces", function () {
                                expect( events.get( selectOneCollection, "*" ) ).not.toHaveBeenCalled();
                            } );

                        } );

                    } );

                } );

            } );

            describe( 'Select.Many collection', function () {
                var selectManyCollection, expected;

                beforeEach( function () {
                    expected = {};
                } );

                describe( 'Status: When adding the models to the collection', function () {

                    beforeEach( function () {
                        selectManyCollection = new SelectManyCollection();
                        selectManyCollection.add( m1 );
                        selectManyCollection.add( m2 );
                        selectManyCollection.add( m3 );
                    } );

                    afterEach( function () {
                        selectManyCollection.close();
                    } );

                    it( 'all models retain their status for the "selected" label', function () {
                        expect( m1.selected ).toBe( true );
                        expect( m2.selected ).toBe( true );
                        expect( m3.selected ).toBeFalsy();
                    } );

                    it( 'the "selected" property of the collection contains the "selected" models', function () {
                        expected[m1.cid] = m1;
                        expected[m2.cid] = m2;
                        expect( selectManyCollection.selected ).toEqual( expected );
                    } );

                    it( 'all models retain their status for the "starred" label', function () {
                        expect( m1.starred ).toBeFalsy();
                        expect( m2.starred ).toBe( true );
                        expect( m3.starred ).toBe( true );
                    } );

                    it( 'the "starred" property of the collection contains the "starred" models', function () {
                        expected[m2.cid] = m2;
                        expected[m3.cid] = m3;
                        expect( selectManyCollection.starred ).toEqual( expected );
                    } );

                } );

                describe( 'Status: When adding the models to the collection, with options.silent enabled', function () {

                    beforeEach( function () {
                        selectManyCollection = new SelectManyCollection();
                        selectManyCollection.add( m1, { silent: true } );
                        selectManyCollection.add( m2, { silent: true } );
                        selectManyCollection.add( m3, { silent: true } );
                    } );

                    afterEach( function () {
                        selectManyCollection.close();
                    } );

                    it( 'all models retain their status for the "selected" label', function () {
                        expect( m1.selected ).toBe( true );
                        expect( m2.selected ).toBe( true );
                        expect( m3.selected ).toBeFalsy();
                    } );

                    it( 'the "selected" property of the collection contains the "selected" models', function () {
                        expected[m1.cid] = m1;
                        expected[m2.cid] = m2;
                        expect( selectManyCollection.selected ).toEqual( expected );
                    } );

                    it( 'all models retain their status for the "starred" label', function () {
                        expect( m1.starred ).toBeFalsy();
                        expect( m2.starred ).toBe( true );
                        expect( m3.starred ).toBe( true );
                    } );

                    it( 'the "starred" property of the collection contains the "starred" models', function () {
                        expected[m2.cid] = m2;
                        expected[m3.cid] = m3;
                        expect( selectManyCollection.starred ).toEqual( expected );
                    } );

                } );

                describe( 'Events', function () {

                    describe( 'When adding a model which is "starred"', function () {
                        var events;

                        beforeEach( function () {
                            selectManyCollection = new SelectManyCollection( [m1, m2] );

                            events = getEventSpies( [m1, m2, m3, selectManyCollection ], ["selected", "starred"] );

                            selectManyCollection.add( m3 );
                        } );

                        afterEach( function () {
                            selectManyCollection.close();
                        } );

                        describe( 'model events', function () {

                            it( 'should not trigger a selected event, including for any of the namespaces, for any model', function () {
                                expect( events.get( m1, "selected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m2, "selected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m3, "selected:*" ) ).not.toHaveBeenCalled();
                            } );

                            it( 'should not trigger a deselected event, including for any of the namespaces, for any model', function () {
                                expect( events.get( m1, "deselected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m2, "deselected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m3, "deselected:*" ) ).not.toHaveBeenCalled();
                            } );

                            it( 'should not trigger a reselected event, including for any of the namespaces, for any model', function () {
                                expect( events.get( m1, "reselected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m2, "reselected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m3, "reselected:*" ) ).not.toHaveBeenCalled();
                            } );

                        } );

                        describe( 'collection events', function () {

                            it( 'should trigger a select:some event, with label "starred" in the event options, for the added model', function () {
                                expect( events.get( selectManyCollection, "select:some" ) ).toHaveBeenCalledWith( {
                                    selected: [m3],
                                    deselected: []
                                }, selectManyCollection, { label: "starred", _externalEvent: "add" } );
                            } );

                            it( 'should trigger a select:some:starred event for the added model', function () {
                                expect( events.get( selectManyCollection, "select:some:starred" ) ).toHaveBeenCalledWith( {
                                    selected: [m3],
                                    deselected: []
                                }, selectManyCollection, { label: "starred", _externalEvent: "add" } );
                            } );

                            it( 'should not trigger more than those two select:some events (including namespaced ones)', function () {
                                expect( events.get( selectManyCollection, "select:some:*" ) ).toHaveCallCount( 2 );
                            } );

                            it( "should not trigger a select:all event, including any of the namespaces", function () {
                                expect( events.get( selectManyCollection, "select:all:*" ) ).not.toHaveBeenCalled();
                            } );

                            it( "should not trigger a select:none event, including any of the namespaces", function () {
                                expect( events.get( selectManyCollection, "select:none:*" ) ).not.toHaveBeenCalled();
                            } );

                            it( "should not trigger a reselect:any event, including any of the namespaces", function () {
                                expect( events.get( selectManyCollection, "reselect:any:*" ) ).not.toHaveBeenCalled();
                            } );

                        } );

                    } );

                    describe( 'When adding a model which is "starred", with options.silent enabled', function () {
                        var events;

                        beforeEach( function () {
                            selectManyCollection = new SelectManyCollection( [m1, m2] );

                            events = getEventSpies( [m1, m2, m3, selectManyCollection ], ["selected", "starred"] );

                            selectManyCollection.add( m3, { silent: true } );
                        } );

                        afterEach( function () {
                            selectManyCollection.close();
                        } );

                        describe( 'model events', function () {

                            it( 'should not trigger a selection-related event, including for any of the namespaces, for any model', function () {
                                expect( events.get( m1, "*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m2, "*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m3, "*" ) ).not.toHaveBeenCalled();
                            } );

                        } );

                        describe( 'collection events', function () {

                            it( 'should not trigger a selection-related event, including for any of the namespaces', function () {
                                expect( events.get( selectManyCollection, "*" ) ).not.toHaveBeenCalled();
                            } );

                        } );

                    } );

                    describe( 'When adding a model which is both "selected" and "starred"', function () {
                        var m4, events;

                        beforeEach( function () {
                            m4 = new Model();
                            m4.select();
                            m4.select( { label: "starred" } );

                            selectManyCollection = new SelectManyCollection( [m1, m2, m3] );
                            events = getEventSpies( [m1, m2, m3, m4, selectManyCollection ], ["selected", "starred"] );

                            selectManyCollection.add( m4 );
                        } );

                        afterEach( function () {
                            selectManyCollection.close();
                        } );

                        describe( 'model events', function () {

                            it( 'should not trigger a selected event, including for any of the namespaces, for any model', function () {
                                expect( events.get( m1, "selected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m2, "selected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m3, "selected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m4, "selected:*" ) ).not.toHaveBeenCalled();
                            } );

                            it( 'should not trigger a deselected event, including for any of the namespaces, for any model', function () {
                                expect( events.get( m1, "deselected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m2, "deselected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m3, "deselected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m4, "deselected:*" ) ).not.toHaveBeenCalled();
                            } );

                            it( 'should not trigger a reselected event, including for any of the namespaces, for any model', function () {
                                expect( events.get( m1, "reselected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m2, "reselected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m3, "reselected:*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m4, "reselected:*" ) ).not.toHaveBeenCalled();
                            } );

                        } );

                        describe( 'collection events', function () {

                            it( 'should trigger a select:some event, with label "starred" in the event options, for the added model', function () {
                                expect( events.get( selectManyCollection, "select:some" ) ).toHaveBeenCalledWith( {
                                    selected: [m4],
                                    deselected: []
                                }, selectManyCollection, { label: "starred", _externalEvent: "add" } );
                            } );

                            it( 'should trigger a select:some:starred event for the added model', function () {
                                expect( events.get( selectManyCollection, "select:some:starred" ) ).toHaveBeenCalledWith( {
                                    selected: [m4],
                                    deselected: []
                                }, selectManyCollection, { label: "starred", _externalEvent: "add" } );
                            } );

                            it( 'should trigger a select:some event, with label "selected" in the event options, for the added model', function () {
                                expect( events.get( selectManyCollection, "select:some" ) ).toHaveBeenCalledWith( {
                                    selected: [m4],
                                    deselected: []
                                }, selectManyCollection, { label: "selected", _externalEvent: "add" } );
                            } );

                            it( 'should trigger a select:some:selected event for the added model', function () {
                                expect( events.get( selectManyCollection, "select:some:selected" ) ).toHaveBeenCalledWith( {
                                    selected: [m4],
                                    deselected: []
                                }, selectManyCollection, { label: "selected", _externalEvent: "add" } );
                            } );

                            it( 'should not trigger more than those four select:some events (including namespaced ones)', function () {
                                expect( events.get( selectManyCollection, "select:some:*" ) ).toHaveCallCount( 4 );
                            } );

                            it( "should not trigger a select:all event, including any of the namespaces", function () {
                                expect( events.get( selectManyCollection, "select:all:*" ) ).not.toHaveBeenCalled();
                            } );

                            it( "should not trigger a select:none event, including any of the namespaces", function () {
                                expect( events.get( selectManyCollection, "select:none:*" ) ).not.toHaveBeenCalled();
                            } );

                            it( "should not trigger a reselect:any event, including any of the namespaces", function () {
                                expect( events.get( selectManyCollection, "reselect:any:*" ) ).not.toHaveBeenCalled();
                            } );

                        } );

                    } );

                    describe( 'When adding a model which is both "selected" and "starred", with options.silent enabled', function () {
                        var m4, events;

                        beforeEach( function () {
                            m4 = new Model();
                            m4.select();
                            m4.select( { label: "starred" } );

                            selectManyCollection = new SelectManyCollection( [m1, m2, m3] );
                            events = getEventSpies( [m1, m2, m3, m4, selectManyCollection ], ["selected", "starred"] );

                            selectManyCollection.add( m4, { silent: true } );
                        } );

                        afterEach( function () {
                            selectManyCollection.close();
                        } );

                        describe( 'model events', function () {

                            it( 'should not trigger a selection-related event, including for any of the namespaces, for any model', function () {
                                expect( events.get( m1, "*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m2, "*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m3, "*" ) ).not.toHaveBeenCalled();
                                expect( events.get( m4, "*" ) ).not.toHaveBeenCalled();
                            } );

                        } );

                        describe( 'collection events', function () {

                            it( "should not trigger a selection-related event, including for any of the namespaces", function () {
                                expect( events.get( selectManyCollection, "*" ) ).not.toHaveBeenCalled();
                            } );

                        } );

                    } );

                } );

            } );

        } );

    } );

} );


text:
package org.broadleafcommerce.common.extensibility.context.merge;

import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

/**
 * This {@link MergeBeanStatusProvider} can be utilized by modules that are trying to provide functionality that
 * is only required when MultiTenant is loaded.
 *
 * @author Andre Azzolini (apazzolini)
 */
@Component("blMultiTenantMergeBeanStatusProvider")
public class MultiTenantMergeBeanStatusProvider implements MergeBeanStatusProvider {

    @Override
    public boolean isProcessingEnabled(Object bean, String beanName, ApplicationContext appCtx) {
        return appCtx.containsBean("blMultiTenantFilterClassTransformer");
    }

}

redpajama_set_name: RedPajamaGithub


text:
package errors

import (
	"net/http"

	"github.com/docker/distribution/registry/api/errcode"
)

var (
	// ErrorCodeNewerClientVersion is generated when a request from a client
	// specifies a higher version than the server supports.
	ErrorCodeNewerClientVersion = errcode.Register(errGroup, errcode.ErrorDescriptor{
		Value:          "NEWERCLIENTVERSION",
		Message:        "client is newer than server (client API version: %s, server API version: %s)",
		Description:    "The client version is higher than the server version",
		HTTPStatusCode: http.StatusBadRequest,
	})

	// ErrorCodeOldClientVersion is generated when a request from a client
	// specifies a version lower than the minimum version supported by the server.
	ErrorCodeOldClientVersion = errcode.Register(errGroup, errcode.ErrorDescriptor{
		Value:          "OLDCLIENTVERSION",
		Message:        "client version %s is too old. Minimum supported API version is %s, please upgrade your client to a newer version",
		Description:    "The client version is too old for the server",
		HTTPStatusCode: http.StatusBadRequest,
	})

	// ErrorNetworkControllerNotEnabled is generated when the networking stack in not enabled
	// for certain platforms, like windows.
	ErrorNetworkControllerNotEnabled = errcode.Register(errGroup, errcode.ErrorDescriptor{
		Value:          "NETWORK_CONTROLLER_NOT_ENABLED",
		Message:        "the network controller is not enabled for this platform",
		Description:    "Docker's networking stack is disabled for this platform",
		HTTPStatusCode: http.StatusNotFound,
	})

	// ErrorCodeNoHijackConnection is generated when a request tries to attach to a container
	// but the connection to hijack is not provided.
	ErrorCodeNoHijackConnection = errcode.Register(errGroup, errcode.ErrorDescriptor{
		Value:          "HIJACK_CONNECTION_MISSING",
		Message:        "error attaching to container %s, hijack connection missing",
		Description:    "The caller didn't provide a connection to hijack",
		HTTPStatusCode: http.StatusBadRequest,
	})
)


text:
package edu.wustl.cab2b.common.util;

import static edu.wustl.cab2b.common.util.Constants.ATTRIBUTE;
import static edu.wustl.cab2b.common.util.Constants.ATTRIBUTE_WITH_DESCRIPTION;
import static edu.wustl.cab2b.common.util.Constants.CLASS;
import static edu.wustl.cab2b.common.util.Constants.CLASS_WITH_DESCRIPTION;
import static edu.wustl.cab2b.common.util.Constants.CONNECTOR;
import static edu.wustl.cab2b.common.util.Constants.MULTIMODELCATEGORY;
import static edu.wustl.cab2b.common.util.Constants.PV;
import static edu.wustl.cab2b.common.util.Constants.TYPE_CATEGORY;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;

import edu.common.dynamicextensions.domain.BooleanAttributeTypeInformation;
import edu.common.dynamicextensions.domain.DateAttributeTypeInformation;
import edu.common.dynamicextensions.domain.DoubleAttributeTypeInformation;
import edu.common.dynamicextensions.domain.FloatAttributeTypeInformation;
import edu.common.dynamicextensions.domain.IntegerAttributeTypeInformation;
import edu.common.dynamicextensions.domain.LongAttributeTypeInformation;
import edu.common.dynamicextensions.domain.ObjectAttributeTypeInformation;
import edu.common.dynamicextensions.domain.ShortAttributeTypeInformation;
import edu.common.dynamicextensions.domain.StringAttributeTypeInformation;
import edu.common.dynamicextensions.domaininterface.AbstractAttributeInterface;
import edu.common.dynamicextensions.domaininterface.AbstractMetadataInterface;
import edu.common.dynamicextensions.domaininterface.AssociationInterface;
import edu.common.dynamicextensions.domaininterface.AttributeInterface;
import edu.common.dynamicextensions.domaininterface.AttributeTypeInformationInterface;
import edu.common.dynamicextensions.domaininterface.EntityGroupInterface;
import edu.common.dynamicextensions.domaininterface.EntityInterface;
import edu.common.dynamicextensions.domaininterface.PermissibleValueInterface;
import edu.common.dynamicextensions.domaininterface.TaggedValueInterface;
import edu.common.dynamicextensions.domaininterface.UserDefinedDEInterface;
import edu.wustl.cab2b.common.errorcodes.ErrorCodeConstants;
import edu.wustl.cab2b.common.exception.RuntimeException;
import edu.wustl.cab2b.common.queryengine.ICab2bQuery;
import edu.wustl.cab2b.common.queryengine.result.IQueryResult;
import edu.wustl.cab2b.common.queryengine.result.IRecord;
import edu.wustl.cab2b.common.user.ServiceURLInterface;
import edu.wustl.common.querysuite.metadata.associations.IAssociation;
import edu.wustl.common.querysuite.metadata.path.IPath;
import edu.wustl.common.querysuite.queryobject.DataType;
import edu.wustl.common.util.dbManager.DBUtil;

/**
 * Utility Class contain general methods used through out the application.
 *
 * @author Chandrakant Talele
 * @author Gautam Shetty
 */
public class Utility {
    private static final Logger logger = edu.wustl.common.util.logger.Logger.getLogger(Utility.class);

    /**
     * Checks whether passed attribute/association is inherited.
     *
     * @param abstractAttribute
     *            Attribute/Association to check.
     * @return TRUE if it is inherited else returns FALSE
     */
    public static boolean isInherited(AbstractAttributeInterface abstractAttribute) {
        for (TaggedValueInterface tag : abstractAttribute.getTaggedValueCollection()) {
            if (tag.getKey().equals(Constants.TYPE_DERIVED)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Generates unique string identifier for given association. It is generated
     * by concatenating
     *
     * sourceEntityName +{@link Constants#CONNECTOR} + sourceRoleName +{@link Constants#CONNECTOR} +
     * targetRoleName +{@link Constants#CONNECTOR} + TargetEntityName
     *
     * @param association
     *            Association
     * @return Unique string to represent given association
     */
    public static String generateUniqueId(AssociationInterface association) {
        return concatStrings(association.getEntity().getName(), association.getSourceRole().getName(), association
            .getTargetRole().getName(), association.getTargetEntity().getName());
    }

    /**
     * @param s1 String
     * @param s2 String
     * @param s3 String
     * @param s4 String
     * @return Concatenated string made after connecting s1, s2, s3, s4 by {@link Constants#CONNECTOR}
     */
    public static String concatStrings(String s1, String s2, String s3, String s4) {
        StringBuffer buff = new StringBuffer();
        buff.append(s1);
        buff.append(CONNECTOR);
        buff.append(s2);
        buff.append(CONNECTOR);
        buff.append(s3);
        buff.append(CONNECTOR);
        buff.append(s4);
        return buff.toString();
    }

    /**
     * Compares whether given searchPattern is present in passed searchString.
     * If it is present returns the position where match found. Otherwise it
     * returns -1.
     *
     * @param searchPattern
     * @param searchString
     * @return The position where match found, otherwise returns -1.
     */
    public static int indexOfRegEx(String searchPattern, String searchString) {
        Pattern pat = Pattern.compile(searchPattern, Pattern.CASE_INSENSITIVE);
        Matcher mat = pat.matcher(searchString);
        int position = -1;

        if (mat.find()) {
            position = mat.start();
        }
        return position;
    }

    /**
     * Returns the entity group of given entity
     *
     * @param entity
     *            Entity to check
     * @return Returns parent Entity Group
     */
    public static EntityGroupInterface getEntityGroup(EntityInterface entity) {
        for (EntityGroupInterface entityGroup : entity.getEntityGroupCollection()) {
            Collection<TaggedValueInterface> taggedValues = entityGroup.getTaggedValueCollection();
            if (getTaggedValue(taggedValues, Constants.CAB2B_ENTITY_GROUP) != null) {
                return entityGroup;
            }
        }
        throw new RuntimeException("This entity does not have DE entity group", new java.lang.RuntimeException(),
                ErrorCodeConstants.DE_0003);
    }

    /**
     * @param taggedValues
     *            collection of TaggedValueInterface
     * @param key
     *            string
     * @return The tagged value for given key in given tagged value collection.
     */
    public static TaggedValueInterface getTaggedValue(Collection<TaggedValueInterface> taggedValues, String key) {
        for (TaggedValueInterface taggedValue : taggedValues) {
            if (taggedValue.getKey().equals(key)) {
                return taggedValue;
            }
        }
        return null;
    }

    /**
     * @param taggable
     *            taggable object
     * @param key
     *            string
     * @return The tagged value for given key.
     */
    public static TaggedValueInterface getTaggedValue(AbstractMetadataInterface taggable, String key) {
        return getTaggedValue(taggable.getTaggedValueCollection(), key);
    }

    /**
     * Checks whether passed Entity is a category or not.
     *
     * @param entity
     *            Entity to check
     * @return Returns TRUE if given entity is Category, else returns false.
     */
    public static boolean isCategory(EntityInterface entity) {
        TaggedValueInterface tag = getTaggedValue(entity.getTaggedValueCollection(), TYPE_CATEGORY);
        return tag != null;
    }

    /**
     * Checks whether passed Entity is a category or not.
     *
     * @param entity
     *            Entity to check
     * @return Returns TRUE if given entity is Category, else returns false.
     */
    public static boolean isMultiModelCategory(EntityInterface entity) {
        TaggedValueInterface tag = getTaggedValue(entity.getTaggedValueCollection(), MULTIMODELCATEGORY);
        return tag != null;
    }

    /**
     * @param e
     * @return TRUE of given entity in a cateory or multi model category
     */
    public static boolean isCategoryOrMMC(EntityInterface e) {
        return (Utility.isCategory(e) || Utility.isMultiModelCategory(e));
    }

    /**
     * Converts DE data type to queryObject dataType.
     *
     * @param type
     *            the DE attribute type.
     * @return the DataType.
     */
    public static DataType getDataType(AttributeTypeInformationInterface type) {
        if (type instanceof StringAttributeTypeInformation) {
            return DataType.String;
        } else if (type instanceof IntegerAttributeTypeInformation) {
            return DataType.Integer;
        } else if (type instanceof DateAttributeTypeInformation) {
            return DataType.Date;
        } else if (type instanceof FloatAttributeTypeInformation) {
            return DataType.Float;
        } else if (type instanceof BooleanAttributeTypeInformation) {
            return DataType.Boolean;
        } else if (type instanceof LongAttributeTypeInformation) {
            return DataType.Long;
        } else if (type instanceof DoubleAttributeTypeInformation) {
            return DataType.Double;
        } else if (type instanceof ShortAttributeTypeInformation) {
            return DataType.Integer;//TODO define short in data type
        } else if (type instanceof ObjectAttributeTypeInformation) {
            return DataType.String;
        } else {
            throw new RuntimeException("Unknown Attribute type");
        }

    }

    /**
     * @param attribute
     *            Check will be done for this Attribute.
     * @return TRUE if there are any permissible values associated with this
     *         attribute, otherwise returns false.
     */
    public static boolean isEnumerated(AttributeInterface attribute) {
        if (attribute.getAttributeTypeInformation().getDataElement() instanceof UserDefinedDEInterface) {
            UserDefinedDEInterface de =
                    (UserDefinedDEInterface) attribute.getAttributeTypeInformation().getDataElement();
            return de.getPermissibleValueCollection().size() != 0;
        }
        return false;
    }

    /**
     * @param attribute
     *            Attribute to process.
     * @return Returns all the permissible values associated with this
     *         attribute.
     */
    public static Collection<PermissibleValueInterface> getPermissibleValues(AttributeInterface attribute) {
        if (isEnumerated(attribute)) {
            UserDefinedDEInterface de =
                    (UserDefinedDEInterface) attribute.getAttributeTypeInformation().getDataElement();
            return de.getPermissibleValueCollection();
        }
        return new ArrayList<PermissibleValueInterface>(0);
    }

    /**
     * Returns the display name if present as tagged value. Else returns the
     * actual name of the entity
     *
     * @param entity
     *            The entity to process
     * @return The display name.
     */
    public static String getDisplayName(EntityInterface entity) {
        String name = entity.getName();
        if (isCategory(entity)) {
            return name;
        }

        EntityGroupInterface eg = getEntityGroup(entity);

        // As per Bug# 4577 <class name> (app_name v<version name>) e.g. Participant (caTissue Core v1.1)
        String projectName = eg.getLongName();
        if (projectName.equals("caFE Server 1.1")) {
            projectName = "caFE Server";
        }

        StringBuffer buff = new StringBuffer();
        buff.append(name.substring(name.lastIndexOf('.') + 1, name.length()));
        buff.append(" (");
        buff.append(projectName);

        String version = eg.getVersion();
        if (version != null) {
            buff.append(" v");
            buff.append(version);
        }
        buff.append(')');

        return buff.toString();
    }

    /**
     * This method trims out package name form the entity name
     *
     * @param entity
     * @return
     */
    public static String getOnlyEntityName(EntityInterface entity) {
        String name = entity.getName();
        String displayName = name.substring(name.lastIndexOf('.') + 1, name.length());
        return displayName;
    }

    /**
     * @param path
     *            A IPath object
     * @return Display string for given path
     */
    public static String getPathDisplayString(IPath path) {
        String text = getHtmlRepresentation(path);
        StringBuffer sb = new StringBuffer();
        int textLength = text.length();
        int currentStart = 0;
        String currentString = null;
        final int offset = 100;
        int strLen = 0;
        int len = 0;
        while (currentStart < textLength && textLength > offset) {
            int lastIndex = currentStart + offset;
            currentString = text.substring(currentStart, lastIndex);
            strLen = strLen + currentString.length() + len;
            sb.append(currentString);
            int index = text.indexOf("---->", lastIndex);
            if (index == -1) {
                int location = text.indexOf(')', lastIndex);
                if (location != -1) {
                    index = location + 1;
                }
            }
            if (index == -1) {
                index = text.indexOf(',', lastIndex);
            }
            if (index == -1) {
                index = text.indexOf(' ', lastIndex);
            }
            if (index != -1) {
                len = index - strLen;
                currentString = text.substring(lastIndex, (lastIndex + len));
                sb.append(currentString);
                sb.append("
");
            } else {
                if (currentStart == 0) {
                    currentStart = offset;
                }
                sb.append(text.substring(currentStart));
                return sb.toString();
            }

            currentStart = currentStart + offset + len;
            if ((currentStart + offset + len) > textLength) {
                break;
            }
        }
        sb.append(text.substring(currentStart));
        return sb.toString();
    }

    static String getHtmlRepresentation(IPath path) {
        StringBuffer text = new StringBuffer(40);
        text.append("Path:");
        List<IAssociation> pathList = path.getIntermediateAssociations();
        text.append(Utility.getDisplayName(path.getSourceEntity()));
        for (int i = 0; i < pathList.size(); i++) {
            text.append("---->");
            text.append(Utility.getDisplayName(pathList.get(i).getTargetEntity()));
        }
        text.append("");
        return text.toString();
    }

    /**
     * @param entity
     *            Entity to check
     * @return Attribute whose name is "identifier" OR "id"
     */
    public static AttributeInterface getIdAttribute(EntityInterface entity) {
        for (AttributeInterface attribute : entity.getAttributeCollection()) {
            if (isIdentifierAttribute(attribute)) {
                return attribute;
            }
        }
        return null;
    }

    /**
     * @param entity
     *            Entity to check
     * @return Name of the application to which given entity belongs
     */
    public static String getApplicationName(EntityInterface entity) {
        return getEntityGroup(entity).getName();
    }

    /**
     * @param attribute
     *            Attribute to check
     * @return TRUE if attribute name is "identifier" OR "id"
     */
    public static boolean isIdentifierAttribute(AttributeInterface attribute) {
        String attribName = attribute.getName();
        return attribName.equalsIgnoreCase("id") || attribName.equalsIgnoreCase("identifier");
    }

    /**
     * Converts attribute set into a alphabetically sorted list.
     *
     * @param inputAttributeSet
     *            Attribute set to sort
     * @return Sorted list of attributes
     */
    public static List<AttributeInterface> getAttributeList(Set<AttributeInterface> inputAttributeSet) {
        List<AttributeInterface> attributes = new ArrayList<AttributeInterface>(inputAttributeSet);
        Collections.sort(attributes, new AttributeInterfaceComparator());
        return attributes;
    }

    /**
     * @param queryResult
     *            Query result to process.
     * @return List of attributes from query result
     */
    public static List<AttributeInterface> getAttributeList(IQueryResult<IRecord> queryResult) {
        Map<String, List<IRecord>> allRecords = queryResult.getRecords();
        List<AttributeInterface> attributeList = new ArrayList<AttributeInterface>();
        for (List<IRecord> recordList : allRecords.values()) {
            if (!recordList.isEmpty()) {
                IRecord record = recordList.get(0);
                attributeList = getAttributeList(record.getAttributes());
                break;
            }
        }
        return attributeList;
    }

    /**
     * This method converts stack trace to the string representation
     *
     * @param aThrowable
     *            throwable object
     * @return String representation of the stack trace
     */
    public static String getStackTrace(Throwable throwable) {
        final Writer result = new StringWriter();
        final PrintWriter printWriter = new PrintWriter(result);
        throwable.printStackTrace(printWriter);
        return result.toString();
    }

    /**
     * Get the specified resource first look into the cab2b.home otherwise look
     * into the classpath
     *
     * @param resource
     *            the name of the resource
     * @return the URL for the resource
     * @throws MalformedURLException
     */
    public static URL getResource(String resource) {
        String home = System.getProperty("cab2b.home");
        File file = new File(home + "/conf", resource);
        if (file.exists()) {
            try {
                return file.toURI().toURL();
            } catch (MalformedURLException e) {
                logger.error("File not found in cab2b_home, will use default file ", e);
            }
        }
        // is there a better way of getting a non-null class loader ?
        ClassLoader loader = Utility.class.getClassLoader();
        return loader.getResource(resource);
    }

    /**
     * @param queryName
     * @param values
     * @return
     * @throws HibernateException
     */
    public static Collection<?> executeHQL(String queryName, List<Object> values) throws HibernateException {
        Session session = DBUtil.currentSession();
        try {
            Query q = session.getNamedQuery(queryName);

            if (values != null) {
                for (int counter = 0; counter < values.size(); counter++) {

                    Object value = values.get(counter);
                    String objectType = value.getClass().getName();
                    String onlyClassName =
                            objectType.substring(objectType.lastIndexOf('.') + 1, objectType.length());

                    if (onlyClassName.equals("String")) {
                        q.setString(counter, (String) value);
                    } else if (onlyClassName.equals("Integer")) {
                        q.setInteger(counter, Integer.parseInt(value.toString()));
                    } else if (onlyClassName.equals("Long")) {
                        q.setLong(counter, Long.parseLong(value.toString()));
                    }
                }
            }
            return q.list();
        } finally {
            DBUtil.closeSession();
        }
    }

    /**
     * @param queryName
     * @return
     * @throws HibernateException
     */
    public static Collection<?> executeHQL(String queryName) throws HibernateException {
        return executeHQL(queryName, null);
    }

    /**
     * This method replaces the occurrence of find string with replacement in
     * original string.
     *
     * @param original
     * @param find
     * @param replacement
     * @return
     */
    public static String replaceAllWords(String original, String find, String replacement) {
        if (original == null || find == null || replacement == null) {
            return null;
        }

        for (int i = original.indexOf(find); i > -1;) {
            String partBefore = original.substring(0, i);
            String partAfter = original.substring(i + find.length());
            original = partBefore + replacement + partAfter;
            i = original.indexOf(find, i + 1);
        }
        return original;
    }

    /**
     * Loads properties from a file present in classpath to java objects.
     * If any exception occurs, it is callers responsibility to handle it.
     * @param propertyfile Name of property file. It MUST be present in classpath
     * @return Properties loaded from given file.
     */
    public static Properties getPropertiesFromFile(String propertyfile) {
        Properties properties = null;
        try {
            URL url = getResource(propertyfile);
            InputStream is = url.openStream();
            if (is == null) {
                logger.error("Unable fo find property file : " + propertyfile
                        + "\n please put this file in classpath");
            }

            properties = new Properties();
            properties.load(is);
        } catch (IOException e) {
            logger.error("Unable to load properties from : " + propertyfile);
            e.printStackTrace();
        }

        return properties;
    }

    /**
     * Returns a fomatted string.
     *
     * Example : -------------------------------------------
     * -----Input-------|------Output------------- xaQaUtWsdkjsSbAd > Xa Qa Ut
     * Wsdkjs Sb Ad tomDickAndHarry > Tom Dick And Harry id > Identifier
     * pubmedCount > Pubmed Count organism > Organism chromosomeMap > Chromosome
     * Map pubmed5Count > Pubmed5 Count 1234 > 1234
     * ---------------------------------------------
     *
     * Note: first character should be in lower case.
     *
     * @param str
     *            String to format.
     * @return formatted string.
     */
    public static String getFormattedString(String str) {
        String returner = "";

        if (str.equalsIgnoreCase("id")) {
            return "Identifier";
        }
        String[] splitStrings = null;

        int upperCaseCount = countUpperCaseLetters(str);
        if (upperCaseCount > 0) {
            splitStrings = splitCamelCaseString(str, upperCaseCount);
            returner = getFormattedString(splitStrings);
        } else {
            returner = capitalizeFirstCharacter(str);
        }
        return returner;
    }

    /**
     * Utility method to get a formated string
     * @param splitStrings
     * @return
     */
    public static String getFormattedString(String[] splitStrings) {
        String returner = "";
        for (int i = 0; i < splitStrings.length; i++) {
            String str = splitStrings[i];
            if (i == splitStrings.length - 1) {
                returner += str;
            } else {
                returner += str + " ";
            }
        }
        return returner;
    }

    /**
     * Utility method to count upper case characters in the String
     */

    static int countUpperCaseLetters(String str) {
        /*
         * This is the count of Capital letters in a string excluding first
         * character, and continuous upper case letter in the string.
         */
        int countOfCapitalLetters = 0;
        char[] chars = str.toCharArray();

        for (int i = 1; i < chars.length; i++) {
            char character = chars[i];
            char nextCharacter = 'x';
            char prevCharacter = chars[i - 1];

            if ((i + 1) < chars.length) {
                nextCharacter = chars[i + 1];
            }

            if ((Character.isUpperCase(character) && Character.isUpperCase(prevCharacter)
                    && Character.isLowerCase(nextCharacter) && i != chars.length - 1)
                    || (Character.isUpperCase(character) && Character.isLowerCase(prevCharacter) && Character
                        .isUpperCase(nextCharacter))
                    || (Character.isUpperCase(character) && Character.isLowerCase(prevCharacter) && Character
                        .isLowerCase(nextCharacter))) {

                countOfCapitalLetters++;
            }
        }
        return countOfCapitalLetters;
    }

    /**
     * Utility method to capitalize first character in the String
     */
    static String capitalizeFirstCharacter(String str) {
        char[] chars = str.toCharArray();
        char firstChar = chars[0];
        chars[0] = Character.toUpperCase(firstChar);
        return new String(chars);
    }

    /**
     *
     * @param str
     * @param countOfUpperCaseLetter
     * @return
     */
    static String[] splitCamelCaseString(String str, int countOfUpperCaseLetter) {
        String[] splitStrings = new String[countOfUpperCaseLetter + 1];
        char[] chars = str.toCharArray();
        int firstIndex = 0;
        int lastIndex = 0;
        int splitStrCount = 0;

        // change indexing from "chars" 1 to length
        for (int i = 1; i < chars.length; i++) {
            char character = chars[i];
            char nextCharacter;
            char previousCharacter;
            if (splitStrCount != countOfUpperCaseLetter) {
                if (Character.isUpperCase(character)) {
                    if (i == (chars.length - 1)) {
                        splitStrings[splitStrCount++] = str.substring(0, i);

                        char[] lasrCharIsUpperCase = new char[1];
                        lasrCharIsUpperCase[0] = character;
                        splitStrings[splitStrCount++] = new String(lasrCharIsUpperCase);
                    } else {
                        lastIndex = i;

                        previousCharacter = chars[i - 1];
                        nextCharacter = chars[i + 1];
                        if (Character.isUpperCase(previousCharacter)
                                && Character.isLowerCase(nextCharacter)
                                || Character.isLowerCase(previousCharacter)
                                && Character.isUpperCase(nextCharacter)
                                || (Character.isLowerCase(previousCharacter) && Character
                                    .isLowerCase(nextCharacter))) {
                            String split = str.substring(firstIndex, lastIndex);
                            if (splitStrCount == 0) {
                                split = capitalizeFirstCharacter(split);
                            }
                            splitStrings[splitStrCount] = split;
                            splitStrCount++;
                            firstIndex = lastIndex;
                        } else {
                            continue;
                        }
                    }
                }
            } else {
                firstIndex = lastIndex;
                lastIndex = str.length();
                String split = str.substring(firstIndex, lastIndex);
                splitStrings[splitStrCount] = split;
                break;
            }
        }

        return splitStrings;
    }

    /**
     * This method returns the current system date and time in default format
     * @return
     */
    public static String getFormattedSystemDate() {
        return getFormattedDate(new Date(), null);
    }

    /**
     * This method returns the date with default format.
     * @param date
     * @return
     */
    public static String getFormattedDate(Date date) {
        return getFormattedDate(date, null);
    }

    /**
     * This method get the formatted date given the raw date and the string format.
     * If not format is not specified then the default format will be dd/MM/yyyy HH:mm. For example, 01/01/1000 01:01
     *
     * @param date
     * @param dateFormat
     * @return
     */
    public static String getFormattedDate(Date date, String dateFormat) {
        if (null == dateFormat || dateFormat.length() == 0) {
            dateFormat = "dd/MM/yyyy HH:mm";
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
        return simpleDateFormat.format(date);
    }

    /**
     * This method returns short hosting institution name from ServiceURLInterface.
     * If there is no short name available then it returns the institution long name and if
     * that is also not available then the service URL is returned.
     * @param serviceUrlMetadata
     * @return short hosting institution name
     */
    public static String getHostingInstitutionName(ServiceURLInterface serviceUrlMetadata) {
    	if(serviceUrlMetadata==null ) {
    		return "errorNOSUCHNAME";
    	}

        String hostingCenter = serviceUrlMetadata.getHostingCenterShortName();
        //If short name is null
        if (hostingCenter == null || hostingCenter.isEmpty()) {
            // set long name
            hostingCenter = serviceUrlMetadata.getHostingCenter();
            if (hostingCenter == null || hostingCenter.isEmpty() || hostingCenter.equals("No Hosting Center Name Available.")) {
                //if hosting long name is also null set url location
                hostingCenter = serviceUrlMetadata.getUrlLocation();
            }
        }

        return hostingCenter;
    }

    /**
     * This method returns the model name constructed from it long name and the version.
     * @param longName
     * @param version
     * @return
     */
    public static String createModelName(String longName, String version) {
        StringBuffer projectName = new StringBuffer(longName);

        if (version != null && version.length() != 0) {
            projectName.append("_v");
            projectName.append(version);
        }

        return projectName.toString();
    }

    /**
     * @param query caB2B query to check
     * @return TRUE : if given query is being fired on at-least one service containing https
     */
    public static boolean hasAnySecureService(ICab2bQuery query) {

        boolean anySecureSevice = false;
        for (String url : query.getOutputUrls()) {
            if (url.trim().toLowerCase().startsWith("https://")) {
                anySecureSevice = true;
                break;
            }
        }

        return anySecureSevice;
    }

    /**
     * Prepares the array of search targets from the check box values selected by user.
     * @param searchClass TRUE if class search is selected
     * @param searchAttribute TRUE if attribute search is selected
     * @param searchPv TRUE if permissible value search is selected
     * @param includeDesc TRUE if description is to be searched
     * @return Integer array of selections made by user.
     */
    public static int[] prepareSearchTarget(boolean searchClass, boolean searchAttribute, boolean searchPv,
                                            boolean includeDesc) {
        List<Integer> target = new ArrayList<Integer>();
        if (searchClass && includeDesc) {
            target.add(CLASS_WITH_DESCRIPTION);
        } else if (searchClass) {
            target.add(CLASS);
        }

        if (searchAttribute && includeDesc) {
            target.add(ATTRIBUTE_WITH_DESCRIPTION);
        } else if (searchAttribute) {
            target.add(ATTRIBUTE);
        }

        if (searchPv) {
            target.add(PV);
        }
        return toIntArray(target);
    }

    /**
     * @param list List of integers
     * @return array of integers
     */
    public static int[] toIntArray(List<Integer> list) {
        int[] array = new int[list.size()];
        for (int i = 0; i < list.size(); i++) {
            array[i] = list.get(i);
        }
        return array;
    }
}


text:
"""Enumeration of lock resource types.

Locks are acquired on resources. Each resource has a type and an id. The
resource type needs to be a unique string that ensures there is no conflict
between locks of different types. This enumeration lists the resource types
for locks taken by the Viewfinder backend.
"""

__author__ = 'andy@emailscrubbed.com (Andy Kimball)'

class LockResourceType:
  """Set of resource types used for locking. Each lock resource type should
  be two or three characters that are different from all other types. The
  resource type is concatenated with the resource id to form the lock id.
  For example:
    op:123
    vp:v--F
  """
  Job       = 'job'   # Resource id is job name (dbchk, get_logs, etc...).
  Operation = 'op'    # Resource id is user that initiated operation.
  Viewpoint = 'vp'    # Resource id is the viewpoint id.