    /*

    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.ResultPanel', {
        extend : 'Ext.Panel',
        alias  : 'widget.resultpanel',

        requires : [
            'Siesta.Project.Browser.UI.AssertionGrid',
            'Siesta.Project.Browser.UI.DomContainer',
            'Siesta.Project.Browser.UI.SourcePanel',

            'Siesta.Recorder.UI.RecorderPanel'
        ],

        slots               : true,

        test                : null,
        testListeners       : null,

        maintainViewportSize : true,

        scaleToFit          : true,
        scaleToFitMode      : 'full',
        viewDOM             : false,
        border              : false,
        canManageDOM        : true,

        project             : null,

        isStandalone        : false,
        showToolbar         : true,
        title               : 'Result panel',
        header              : false,
        minWidth            : 100,
        layout              : 'border',

        sourceButton        : null,
        filterButton        : null,
        inspectionButton    : null,
        recorderPanel       : null,
        recorderConfig      : null,
        recorderPanelClass  : 'Siesta.Recorder.UI.RecorderPanel',

        domContainerRegion  : 'east',

        isReadOnlyReport    : false,

        initComponent : function () {
            var me = this;
            var R  = Siesta.Resource('Siesta.Project.Browser.UI.ResultPanel');

            var domContainerRegion = this.domContainerRegion || 'east'

            Ext.apply(this, {
                cls   : 'tr-container',
                tbar  : {
                    cls      : 'resultpanel-toolbar',
                    defaults : {
                        tooltipType : 'title',
                        scope       : this
                    },

                    items       : this.getTopToolbarItems(R)
                },
                items : [
                    // a card container
                    {
                        region     : 'center',
                        slot       : 'cardContainer',
                        xtype      : 'container',
                        layout     : {
                            type           : 'card',
                            deferredRender : true
                        },
                        activeItem : 0,
                        minWidth   : 100,

                        items : [
                            // grid with assertion
                            {
                                xtype : 'assertiongrid',
                                slot  : 'grid',

                                isStandalone : this.isStandalone,
                                listeners    : {
                                    itemdblclick : this.onAssertionDoubleClick,
                                    scope        : this
                                }

                            },
                            // eof grid with assertion
                            {
                                xtype : 'sourcepanel',
                                slot  : 'source',
                                listeners : {
                                    render : function(panel) {
                                        var el = panel.getEl().appendChild({
                                            cls : 'si-sourcepanel-close fa-close',
                                            style : 'right:' + (Ext.getScrollbarSize().width + 5) + 'px'
                                        });

                                        el.on('click', this.hideSource, this);
                                    },
                                    scope : this
                                }
                            }
                        ].concat(
                            Ext.ClassManager.getByAlias('widget.coveragereport') ?
                            {
                                // to avoid coverage report to be picked up as a dependency by sencha cmd compiler
                                xtype   : 'coverage' + 'report',
                                slot    : 'coverageReport',
                                project : this.project
                            } : []
                        )
                    },
                    {
                        xtype       : 'domcontainer',
                        region      : domContainerRegion,
                        collapsible : true,

                        hidden      : this.isReadOnlyReport,

                        split : { size : 7 },

                        bodyStyle : 'text-align : center',

                        slot     : 'domContainer',
                        stateful : true,             // Turn off for recursive siesta demo

                        id     : this.id + '-domContainer',
                        width  : (domContainerRegion == 'east' || domContainerRegion == 'west') ? '50%' : null,
                        height : (domContainerRegion == 'south' || domContainerRegion == 'north') ? '50%' : null,
                        cls    : 'siesta-domcontainer',

                        collapsed   : !this.viewDOM,
                        scaleToFit          : this.scaleToFit,
                        scaleToFitMode      : this.scaleToFitMode
                    }
                ]
            })

            this.callParent()

            this.slots.domContainer && this.slots.domContainer.on({
                expand   : this.onDomContainerExpand,
                collapse : this.onDomContainerCollapse,

                inspectionstart : function () {
                    this.inspectionButton.toggle(true);
                },
                inspectionstop  : function () {
                    this.inspectionButton.toggle(false);
                },

                scope : this
            });
        },

        onLoadReportFileChange : function (field) {
            var me      = this
            var file    = field.fileInputEl.dom.files[ 0 ]

            var reader  = new FileReader()

            reader.onload = function () {
                try {
                    var json    = JSON.parse(reader.result)
                } catch (e) {
                    Ext.Msg.alert("Error", "Error parsing JSON")
                }

                if (json) me.fireEvent('newjsonreport', me, json)
            }

            reader.onerror = function () {
                Ext.Msg.alert("Error", "Error loading file")
            }

            reader.readAsText(file)
        },

        getTopToolbarItems : function (R) {
            if (!this.showToolbar) return null

            var isReadOnlyReport    = this.isReadOnlyReport
            var items               = []

            if (!isReadOnlyReport) items.push(
                {
                    text    : R.get('rerunText'),
                    cls     : 'rerun-button',
                    glyph   : 0xf04b,
                    scale   : 'medium',
                    handler : this.onRunTestClick
                }
            )

            items.push(
                {
                    xtype  : 'label',
                    cls    : 'resultpanel-testtitle',
                    itemId : 'resultpanel-testtitle',
                    margin : '0 0 0 10',
                    height : 48,
                    text   : ' ',
                    flex   : 1
                }
            )

            if (isReadOnlyReport && window.FileReader) items.push(
                {
                    xtype       : 'fileuploadfield',
                    buttonOnly  : true,
                    buttonText  : 'Load data file',

                    listeners   : {
                        change  : this.onLoadReportFileChange,
                        scope   : this
                    }
                }
            )

            if (!isReadOnlyReport) items.push(

                this.viewDomButton = new Ext.Button({
                    tooltip      : "Force native events simulation",
                    cls          : 'testaction-button',
                    action       : 'force-native',
                    scale        : 'medium',
                    glyph        : 0xf25a,
                    enableToggle : true,
                    scope        : this,
                    pressed      : this.project.simulation == 'native',
                    handler      : function (btn) {
                        this.project.simulation     = btn.pressed ? 'native' : 'synthetic'
                    }
                }),

                this.viewDomButton = new Ext.Button({
                    tooltip      : R.get('toggleDomVisibleText'),
                    cls          : 'testaction-button',
                    action       : 'view-dom',
                    scale        : 'medium',
                    glyph        : 0xf26c,
                    enableToggle : true,
                    scope        : this,
                    pressed      : this.viewDOM,
                    handler      : function (btn) {
                        this.setViewDOM(btn.pressed);
                    }
                }),
                this.scaleToFitButton = new Ext.SplitButton({
                    tooltip      : 'Scale to fit',
                    cls          : 'testaction-button',
                    action       : 'scale-to-fit',
                    scale        : 'medium',
                    glyph        : 0xf065,
                    enableToggle : true,
                    pressed      : Boolean(this.scaleToFit),
                    menu         : {
                        items   : [
                            { glyph : 0xf0b2, text : 'Fit full', itemId : 'full' },
                            { glyph : 0xf07e, text : 'Fit width', itemId : 'width' },
                            { glyph : 0xf07d, text : 'Fit height', itemId : 'height' }
                        ],
                        listeners: {
                            click : function(menu, item) {
                                this.slots.domContainer.setScaleToFit(true, item.itemId)
                                this.scaleToFitButton.setPressed(true);
                            },
                            scope : this
                        }
                    },
                    scope        : this,
                    handler      : function(btn) {
                        this.slots.domContainer.setScaleToFit(btn.pressed)
                    }
                }),
                this.sourceButton = new Ext.Button({
                    tooltip      : R.get('viewSourceText'),
                    action       : 'view-source',
                    cls          : 'testaction-button',
                    glyph        : 0xf0f6,
                    scale        : 'medium',
                    tooltipType  : 'title',
                    disabled     : true,
                    enableToggle : true,
                    scope        : this,

                    handler : function (btn) {
                        if (btn.pressed) {
                            this.showSource();
                        } else {
                            this.hideSource()
                        }
                    }
                }),
                this.filterButton = new Ext.Button({
                    tooltip      : R.get('showFailedOnlyText'),
                    action       : 'show-failed-only',
                    cls          : 'testaction-button',
                    scale        : 'medium',
                    glyph        : 0xf188,
                    tooltipType  : 'title',
                    scope        : this,
                    enableToggle : true,
                    handler      : this.onAssertionFilterClick
                }),
                this.inspectionButton = new Ext.Button({
                    glyph        : 0xf002,
                    cls          : 'testaction-button cmp-inspector',
                    action       : 'toggle-cmp-inspector',
                    scale        : 'medium',
                    tooltip      : 'Target highlighter',
                    tooltipType  : 'title',
                    handler      : this.toggleComponentInspectionMode,
                    scope        : this,
                    enableToggle : true
                }),

                this.recorderButton = new Ext.Button({
                    glyph        : 0xf03d,
                    action       : 'toggle-recorder',
                    cls          : 'testaction-button',
                    scale        : 'medium',
                    disabled     : !Siesta.Recorder || Ext.isIE9m,
                    tooltip      : R.get('eventRecorderText'),
                    handler      : this.onRecorderClick,
                    margin       : '0 30 0 0',
                    scope        : this,
                    enableToggle : true
                }),
                {
                    xtype : 'versionupdatebutton'
                },
                {
                    xtype : 'component',
                    id    : 'siesta-logo'
                }
            )

            return items
        },

        // This method makes sure that the min width of the card panel is respected when
        // the width of this class changes (after resizing Test TreePanel).
        ensureLayout : function () {
            var availableWidth    = this.getWidth();
            var cardPanel         = this.slots.cardContainer;
            var domContainer      = this.slots.domContainer;
            var domContainerWidth = domContainer.getWidth();
            var minimumForCard    = cardPanel.minWidth + 20; // Some splitter space

            if (availableWidth - domContainerWidth < minimumForCard) {
                domContainer.setWidth(Math.max(0, availableWidth - minimumForCard));
            }
        },

        showSource : function (lineNbr) {
            var test = this.test

            if (!this.test) return;

            var sourceLines   = [];
            var slots         = this.slots
            var cardContainer = slots.cardContainer
            var sourceCt      = slots.source;

            // Do this first since rendering is deferred
            cardContainer.layout.setActiveItem(sourceCt);

            if (arguments.length === 0) {
                // Highlight all failed rows
                Ext.each(test.getFailedAssertions(), function (assertion) {
                    if (assertion.sourceLine != null) {
                        sourceLines.push(assertion.sourceLine)
                    }
                });
            }
            else {
                // Highlight just a single row (user double clicked a failed row)
                sourceLines = [lineNbr];
            }

            sourceCt.setSource(test.getSource(), sourceLines);
        },

        hideSource : function () {
            var slots         = this.slots
            var cardContainer = slots.cardContainer

            if (cardContainer.layout.getActiveItem() === slots.source) {
                this.sourceButton.setPressed(false);
                cardContainer.layout.setActiveItem(slots.grid);
            }
        },

        setViewDOM : function (value) {
            var domContainer = this.slots.domContainer

            if (value)
                domContainer.expand(false)
            else
                domContainer.collapse(null, false)
        },

        onDomContainerCollapse : function () {
            this.viewDOM = false;
            this.viewDomButton.toggle(false);
            this.fireEvent('viewdomchange', this, false);
        },

        onDomContainerExpand : function () {
            this.viewDOM = true;
            this.viewDomButton.toggle(true);
            this.fireEvent('viewdomchange', this, true);
        },

        onRunTestClick : function () {
            this.fireEvent('runbuttonclick', this);
        },

        showTest : function (test, assertionsStore) {
            var recorder = this.slots.recorderPanel;

            this.slots.source.clear();

            this.filterButton && this.filterButton.toggle(false)
            this.hideSource();

            this.sourceButton && this.sourceButton.enable()

            var url     = test.url;

            Ext.suspendLayouts();

            this.slots.grid.showTest(test, assertionsStore)
            this.slots.domContainer.showTest(test, assertionsStore)

            if (recorder) {
                if (!recorder.test || test.url !== recorder.test.url) {
                    recorder.stop();
                    recorder.attachTo(test);
                }
            }

            this.setTestTitle(url === '/' ? recorder.getRecordingName() : url);

            Ext.resumeLayouts();

            this.test = test;
        },

        setTestTitle : function (url) {
            this.testTitle.setText(url);
        },

        onAssertionFilterClick : function (btn) {
            var grid            = this.slots.grid;
            var assertionsStore = grid.store;

            // need this check for cases when users clicks on the button
            // before running any test - in this case assertion grid will have an empty Ext.data.TreeStore instance
            if (!assertionsStore.filterTreeBy) return

            if (btn.pressed) {
                grid.addCls('assertiongrid-filtered');
                assertionsStore.filterTreeBy(function (resultRecord) {
                    var result = resultRecord.getResult()

                    // this covers the cases when "result" is a summary record, diagnostic record, etc
                    return result.passed === false && !result.isTodo
                })
            } else {
                grid.removeCls('assertiongrid-filtered');
                assertionsStore.clearTreeFilter()
            }
        },

        alignIFrame : function () {
            this.slots.domContainer.alignIFrame()
        },

        hideIFrame : function () {
            this.slots.domContainer.hideIFrame()
        },

        setInitializing : function (initializing) {
            this.slots.grid.setInitializing(initializing)
        },

        onAssertionDoubleClick : function (view, record) {
            var result = record.getResult()

            if ((result instanceof Siesta.Result.Assertion) && !result.isPassed(true)) {
                this.showSource(result.sourceLine);
            }
        },

        toggleComponentInspectionMode : function (btn) {
            this.slots.domContainer.toggleInspectionMode(btn.pressed);
        },

        onRecorderClick : function () {
            var cardContainer = this.slots.cardContainer

            if (!this.recorderPanel) {
                this.recorderPanel = Ext.create(this.recorderPanelClass, {
                    slot           : 'recorderPanel',
                    project        : this.project,
                    domContainer   : this.slots.domContainer,
                    recorderConfig : this.recorderConfig,
                    closeButton    : {
                        text    : Siesta.Resource('Siesta.Project.Browser.UI.ResultPanel', 'closeText'),
                        cls     : 'recorder-tool',
                        handler : function () {
                            cardContainer.layout.setActiveItem(0);
                        }
                    },
                    listeners      : {
                        startrecord : function (pnl, test) {
                            this.fireEvent('startrecord', pnl, test);

                            this.showTest(test);
                        },
                        show        : function () {
                            this.recorderButton.toggle(true);
                        },
                        play        : function (pnl, test) {
                            this.showTest(test);
                        },
                        hide        : function () {
                            this.recorderButton.toggle(false);
                        },
                        scope       : this
                    }
                });
                this.slots.cardContainer.add(this.recorderPanel);

                this.relayEvents(this.recorderPanel, [ 'startrecord', 'play' ], 'recorder');

                if (this.test) {
                    this.slots.recorderPanel.attachTo(this.test);
                }
            }

            if (cardContainer.layout.getActiveItem() === this.recorderPanel) {
                cardContainer.layout.setActiveItem(this.slots.grid);
            } else {
                cardContainer.layout.setActiveItem(this.recorderPanel);
            }
        },

        afterRender : function () {
            this.callParent(arguments);

            var splitter = this.child('bordersplitter');

            this.testTitle = this.down('#resultpanel-testtitle');

            // To avoid the DOM container splitter getting stuck
            splitter && (splitter.tracker.tolerance = 0);
        }
    });