    /*

    Siesta 5.3.0
    Copyright(c) 2009-2019 Bryntum AB
    https://bryntum.com/contact
    https://bryntum.com/products/siesta/license

    */
    Ext.define('Siesta.Project.Browser.UI.AssertionGrid', {
        alias : 'widget.assertiongrid',
        extend : 'Ext.tree.Panel',

        mixins : [
            'Siesta.Project.Browser.UI.CanFillAssertionsStore'
        ],

        requires            : [
            'Siesta.Project.Browser.Model.AssertionTreeStore',
            'Siesta.Project.Browser.UI.FilterableTreeView',
            'Siesta.Project.Browser.UI.AssertionTreeColumn'
        ],

        cls : 'siesta-assertion-grid',

        enableColumnHide   : false,
        enableColumnMove   : false,
        enableColumnResize : false,

        sortableColumns    : false,
        useArrows          : true,
        border             : false,
        minWidth           : 100,
        trackMouseOver     : false,
        autoScrollToBottom : true,
        hideHeaders        : true,
        rowLines           : false,
        rootVisible        : false,
        collapseDirection  : 'left',
        viewType           : 'filterabletreeview',
        lines              : false,
        disableSelection   : true,
        bufferedRenderer   : false,

        isStandalone       : false,
        test               : null,
        testListeners      : null,

        initComponent : function () {
            var me = this;

            this.testListeners = []

            if (!this.store) this.store = new Siesta.Project.Browser.Model.AssertionTreeStore({

                proxy : 'memory',

                root : {
                    id       : '__ROOT__',
                    expanded : true,
                    loaded   : true
                }
            })

            Ext.apply(this, {

                columns : [
                    this.assertionColumn = new Siesta.Project.Browser.UI.AssertionTreeColumn()
                ],

                viewConfig : {
                    enableTextSelection : true,
                    stripeRows          : false,
                    markDirty           : false,
                    // Animation is disabled until: http://www.sencha.com/forum/showthread.php?265901-4.2.0-Animation-breaks-the-order-of-nodes-in-the-tree-view&p=974172
                    // is resolved
                    animate             : false,
                    trackOver           : false,

                    // dummy store to be re-defined before showing each test
                    store               : new Ext.data.Store({ fields : [], data : [] }),

                    // this should be kept `false` - otherwise assertion grid goes crazy, see #477
                    deferInitialRefresh : false,

                    getRowClass : this.getRowClass
                },

                listeners : {
                    itemexpand      : this.adaptColumnSize,
                    scope           : this
                }
            });

            this.callParent(arguments);

            this.getView().on('itemadd', this.onMyItemAdd, this);
        },

        onMyItemAdd : function (records) {
            // Scroll to bottom when test is running
            if (!this.test.isFinished() && this.autoScrollToBottom) {
                this.ensureVisible(records[0]);
            }
        },

        getRowClass : function (record, rowIndex, rowParams, store) {
            var result = record.getResult()

            var cls = ''

            // TODO switch to "instanceof"
            switch (result.meta.name) {
                case 'Siesta.Result.Diagnostic':
                    return 'tr-diagnostic-row ' + (result.isWarning ? 'tr-warning-row' : '');

                case 'Siesta.Result.Summary':
                    return 'tr-summary-row ' + (result.isFailed ? ' tr-summary-failure' : '');

                case 'Siesta.Result.SubTest':
                    cls = 'tr-subtest-row tr-subtest-row-' + record.get('folderStatus')

                    if (result.test.specType == 'describe') cls += ' tr-subtest-row-describe'
                    if (result.test.specType == 'it') cls += ' tr-subtest-row-it'

                    return cls;

                case 'Siesta.Result.Assertion':
                    cls += 'tr-assertion-row '

                    if (result.isWaitFor)
                        cls += 'tr-waiting-row ' + (result.completed ? (result.passed ? 'tr-waiting-row-passed' : 'tr-assertion-row-failed tr-waiting-row-failed') : '')
                    else if (result.isException)
                        cls += result.isTodo ? 'tr-exception-todo-row' : 'tr-exception-row'
                    else if (result.isTodo)
                        cls += result.passed ? 'tr-todo-row-passed' : 'tr-todo-row-failed'
                    else
                        cls += result.passed ? 'tr-assertion-row-passed' : 'tr-assertion-row-failed'

                    return cls
                default:
                    throw "Unknown result class"
            }
        },

        showTest : function (test, assertionsStore) {
            if (this.test) {
                Joose.A.each(this.testListeners, function (listener) {
                    listener.remove()
                })

                this.testListeners = []
            }

            this.test = test

            this.testListeners = [].concat(
                this.isStandalone ? [
                    test.on('testupdate', this.onTestUpdate, this),
                    test.on('testendbubbling', this.onEveryTestEnd, this),
                    test.on('assertiondiscard', this.onAssertionDiscarded, this)
                ] : [
                    test.on('testfinalize', this.adaptColumnSize, this)
                ]
            )

            Ext.suspendLayouts()

            if (assertionsStore) {
                if (this.store !== assertionsStore) this.reconfigure(assertionsStore)
            } else
                if (this.getStore().getRoot().childNodes.length > 0) this.store.removeAll()

            Ext.resumeLayouts()
        },

        onTestUpdate   : function (event, test, result, parentResult) {
            this.processNewResult(this.store, test, result, parentResult)
        },

        adaptColumnSize : function () {
            var headerCt = this.getHeaderContainer();
            var maxWidth = this.getView().getMaxContentWidth(this.assertionColumn); // HACK private method

            this.assertionColumn.setWidth(Math.max(maxWidth, this.getWidth()));
        },

        onResize : function() {
            this.callParent(arguments);
            this.adaptColumnSize();
        },

        // is bubbling and thus triggered for all tests (including sub-tests)
        onEveryTestEnd : function (event, test) {
            this.processEveryTestEnd(this.store, test)
        },

        onAssertionDiscarded : function(event, test, result) {
            this.store.getNodeById(result.id).remove();
        },

        bindStore : function (treeStore, isInitial, prop) {
            this.callParent(arguments)

            this.store = treeStore;

            if (treeStore && treeStore.nodeStore) {
                this.getView().dataSource = treeStore.nodeStore
                // passing the tree store instance to the underlying `filterabletreeview`
                // the view will re-bind the tree store listeners
                this.getView().bindStore(treeStore, isInitial, prop)
            }
        },

        destroy : function () {
            Joose.A.each(this.testListeners, function (listener) {
                listener.remove()
            })

            this.testListeners = []

            this.test = null

            this.callParent(arguments)
        },

        setInitializing : function (initializing) {
            if (initializing) {
                this.getView().addCls('siesta-test-initializing');
            } else {
                this.getView().removeCls('siesta-test-initializing');
            }
        }

    })