/**
 * An explorer component for navigating hierarchical content.  Consists of a breadcrumb bar
 * at the top, tree navigation on the left, and a center panel which displays the contents
 * of a given node.
 */
Ext.define('Ext.ux.Explorer', {
    extend: 'Ext.panel.Panel',
    xtype: 'explorer',
    requires: [
        'Ext.layout.container.Border',
        'Ext.toolbar.Breadcrumb',
        'Ext.tree.Panel'
    ],

    config: {
        /**
         * @cfg {Object} breadcrumb
         * Configuration object for the breadcrumb toolbar
         */
        breadcrumb: {
            dock: 'top',
            xtype: 'breadcrumb',
            reference: 'breadcrumb'
        },

        /* eslint-disable max-len, indent */
        /**
         * @cfg {Object} contentView
         * Configuration object for the "content" data view
         */
        contentView: {
            xtype: 'dataview',
            reference: 'contentView',
            region: 'center',
            cls: Ext.baseCSSPrefix + 'explorer-view',
            itemSelector: '.' + Ext.baseCSSPrefix + 'explorer-item',
            tpl:
                '<tpl for=".">' +
                    '<div class="' + Ext.baseCSSPrefix + 'explorer-item">' +
                        '<div class="{iconCls}">' +
                            '<div class="' + Ext.baseCSSPrefix + 'explorer-node-icon' +
                                '{[values.leaf ? " ' + Ext.baseCSSPrefix + 'explorer-leaf-icon' + '" : ""]}' + '">' +
                            '</div>' +
                            '<div class="' + Ext.baseCSSPrefix + 'explorer-item-text">{text}</div>' +
                        '</div>' +
                    '</div>' +
                '</tpl>'
        },
        /* eslint-enable max-len, indent */

        /**
         * @cfg {Ext.data.TreeStore} store
         * The TreeStore to use as the data source
         */
        store: null,

        /**
         * @cfg {Object} tree
         * Configuration object for the tree
         */
        tree: {
            xtype: 'treepanel',
            reference: 'tree',
            region: 'west',
            width: 200
        }
    },

    renderConfig: {
        /**
         * @cfg {Ext.data.TreeModel} selection
         * The selected node
         * @accessor
         */
        selection: null
    },

    layout: 'border',
    referenceHolder: true,
    defaultListenerScope: true,
    cls: Ext.baseCSSPrefix + 'explorer',

    initComponent: function() {
        var me = this,
            store = me.getStore();

        //<debug>
        if (!store) {
            Ext.raise('Ext.ux.Explorer requires a store.');
        }
        //</debug>

        me.dockedItems = [ me.getBreadcrumb() ];

        me.items = [ me.getTree(), me.getContentView() ];

        me.callParent();
    },

    applyBreadcrumb: function(breadcrumb) {
        var store = this.getStore();

        breadcrumb = Ext.create(Ext.apply({
            store: store,
            selection: store.getRoot()
        }, breadcrumb));

        breadcrumb.on('selectionchange', '_onBreadcrumbSelectionChange', this);

        return breadcrumb;
    },

    applyContentView: function(contentView) {
        /**
         * @property {Ext.data.Store} contentStore
         * @private
         * The backing store for the content view
         */
        var contentStore = this.contentStore = new Ext.data.Store({
            model: this.getStore().model
        });

        contentView = Ext.create(Ext.apply({
            store: contentStore
        }, contentView));

        return contentView;
    },

    applyTree: function(tree) {
        tree = Ext.create(Ext.apply({
            store: this.getStore()
        }, tree));

        tree.on('selectionchange', '_onTreeSelectionChange', this);

        return tree;
    },

    updateSelection: function(node) {
        var me = this,
            refs = me.getReferences(),
            breadcrumb = refs.breadcrumb,
            tree = refs.tree,
            treeSelectionModel = tree.getSelectionModel(),
            contentStore = me.contentStore,
            parentNode, treeView;

        if (breadcrumb.getSelection() !== node) {
            breadcrumb.setSelection(node);
        }

        if (treeSelectionModel.getSelection()[0] !== node) {
            treeSelectionModel.select([node]);
            parentNode = node.parentNode;

            if (parentNode) {
                parentNode.expand();
            }

            treeView = tree.getView();
            treeView.scrollRowIntoView(treeView.getRow(node));
        }

        contentStore.removeAll();
        contentStore.add(node.hasChildNodes() ? node.childNodes : [node]);
    },

    updateStore: function(store) {
        this.getBreadcrumb().setStore(store);
    },

    privates: {
        /**
         * Handles the tree's selectionchange event
         * @private
         * @param {Ext.tree.Panel} tree
         * @param {Ext.data.TreeModel[]} selection
         */
        _onTreeSelectionChange: function(tree, selection) {
            this.setSelection(selection[0]);
        },

        /**
         * Handles the breadcrumb bar's selectionchange event
         */
        _onBreadcrumbSelectionChange: function(breadcrumb, selection) {
            this.setSelection(selection);
        }
    }
});
