/**
 * This plugin allows the user to view all records that were aggregated for a specified cell.
 *
 * The user has to double click that cell to open the records viewer.
 *
 * **Note:** If a {@link Ext.pivot.matrix.Remote} matrix is used then the plugin requires
 * a {@link #remoteStore} to be provided to fetch the records for a left/top keys pair.
 */
Ext.define('Ext.pivot.plugin.DrillDown', {
    alias: [
        'plugin.pivotdrilldown'
    ],
 
    extend: 'Ext.plugin.Abstract',
 
    requires: [
        'Ext.pivot.Grid',
        'Ext.Panel',
        'Ext.layout.Fit',
        'Ext.TitleBar',
        'Ext.Button',
        'Ext.data.proxy.Memory',
        'Ext.data.Store',
        'Ext.grid.plugin.PagingToolbar'
    ],
 
    /**
     * Fired on the pivot component when the drill down panel is visible
     *
     * @event showdrilldownpanel
     * @param {Ext.Panel} panel Drill down panel
     */
 
    /**
     * Fired on the pivot component when the drill down panel is hidden
     *
     * @event hidedrilldownpanel
     * @param {Ext.Panel} panel Drill down panel
     */
 
    config: {
        /**
         * @cfg {Ext.grid.column.Column[]} [columns] Specify which columns should be visible in the grid.
         *
         * Use the same definition as for a grid column.
         */
        columns: null,
        /**
         * @cfg {Number} width 
         *
         * Width of the viewer's window.
         */
        width: 500,
        /**
         * @cfg {Ext.data.Store} remoteStore
         * Provide either a store config or a store instance when using a {@link Ext.pivot.matrix.Remote Remote} matrix on the pivot grid.
         *
         * The store will be remotely filtered to fetch records from the server.
         */
        remoteStore: null,
 
        /**
         * @cfg {Object} panel 
         *
         * Configuration object used to instantiate the drill down panel.
         */
        panel: {
            lazy: true,
            $value: {
                xtype: 'panel',
                hidden: true,
                floated: true,
                modal: true,
                hideOnMaskTap: true,
                right: 0,
                height: '100%',
                showAnimation: {
                    type: 'slideIn',
                    duration: 250,
                    easing: 'ease-out',
                    direction: 'left'
                },
                hideAnimation: {
                    type: 'slideOut',
                    duration: 250,
                    easing: 'ease-in',
                    direction: 'right'
                },
 
                layout: 'fit',
                items: [{
                    docked: 'top',
                    xtype: 'titlebar',
                    itemId: 'title',
                    items: {
                        xtype: 'button',
                        text: 'Done',
                        ui: 'action',
                        align: 'right',
                        itemId: 'done'
                    }
                }, {
                    xtype: 'grid',
                    itemId: 'grid',
                    plugins: [{
                        type: 'gridpagingtoolbar'
                    }]
                }]
            }
        },
        /**
         * @private
         */
        pivot: null
    },
 
    titleText: 'Drill down',
    doneText: 'Done',
 
    init: function (pivot) {
        //<debug> 
        // this plugin is available only for the pivot grid 
        if (!pivot.isPivotGrid) {
            Ext.raise('This plugin is only compatible with Ext.pivot.Grid');
        }
        //</debug> 
 
        this.setPivot(pivot);
        return this.callParent([pivot]);
    },
 
    destroy: function () {
        this.setConfig({
            pivot: null,
            panel: null
        });
        this.callParent();
    },
 
    updatePivot: function (grid) {
        Ext.destroy(this.gridListeners);
 
        if (grid) {
            this.gridListeners = grid.on({
                pivotitemcelldoubletap: 'showPanel',
                pivotgroupcelldoubletap: 'showPanel',
                pivottotalcelldoubletap: 'showPanel',
                scope: this,
                destroyable: true
            });
        }
    },
 
    applyPanel: function (panel, oldPanel) {
        if (panel) {
            panel = panel.isInstance ? panel : Ext.create(panel);
        }
 
        return panel;
    },
 
    updatePanel: function (panel, oldPanel) {
        var me = this,
            pivot = this.getPivot();
 
        Ext.destroy(oldPanel, me.panelListeners, me.buttonListeners);
 
        if (panel) {
            me.panelListeners = panel.on({
                hiddenchange: 'onPanelHiddenChange',
                scope: me,
                destroyable: true
            });
 
            panel.down('#title').setTitle(me.titleText);
            me.buttonListeners = panel.down('#done').on({
                tap: 'hidePanel',
                scope: me,
                destroyable: true
            });
 
            me.initializeStoreAndColumns();
 
            pivot.add(panel);
        }
    },
 
    initializeStoreAndColumns: function () {
        var me = this,
            panel = me.getPanel(),
            matrix = me.getPivot().getMatrix(),
            columns = Ext.Array.from(me.getColumns() || []),
            result, fields, store, filters, view,
            i, len, value, grid;
 
        if (!matrix || !panel || !(grid = panel.down('#grid'))) {
            return;
        }
 
        if (matrix.isLocalMatrix) {
            fields = matrix.store.model.getFields();
            store = new Ext.data.Store({
                pageSize: 0,
                fields: Ext.clone(fields),
                proxy: {
                    type: 'memory',
                    reader: {
                        type: 'array'
                    }
                }
            });
            // if no columns are defined then use those defined in the pivot grid store 
            if (columns.length === 0) {
                len = fields.length;
                for (= 0; i < len; i++) {
                    value = fields[i];
                    columns.push({
                        text: Ext.String.capitalize(value.name),
                        dataIndex: value.name,
                        xtype: 'column'
                    });
                }
            }
        } else {
            store = Ext.getStore(me.getRemoteStore());
 
            if (store) {
                store.setRemoteFilter(true);
            }
        }
 
        //<debug> 
        if (columns.length === 0) {
            Ext.raise('No columns defined for the drill down grid!');
        }
        //</debug> 
 
        grid.setConfig({
            store: store,
            columns: columns
        });
    },
 
    onPanelHiddenChange: function (panel, hidden) {
        this.getPivot().fireEvent(hidden ? 'hidedrilldownpanel' : 'showdrilldownpanel', panel);
    },
 
    getWidth: function () {
        var pivot = this.getPivot(),
            viewport = Ext.Viewport,
            maxWidth = 100;
 
        if (pivot && pivot.element) {
            maxWidth = pivot.element.getWidth();
        }
        if (viewport) {
            maxWidth = Math.min(maxWidth, viewport.element.getHeight(), viewport.element.getWidth());
        }
 
        return Ext.Number.constrain(this._width, 100, maxWidth);
    },
 
    showPanel: function (params) {
        var me = this,
            panel = me.getPanel(),
            matrix = me.getPivot().getMatrix(),
            result, grid, store, filters;
 
        // do nothing if the plugin is disabled 
        if (me.disabled) {
            return;
        }
 
        result = matrix.results.get(params.leftKey, params.topKey);
 
        if (!result || !panel || !(grid = panel.down('#grid'))) {
            return;
        }
 
        store = grid.getStore();
 
        if (matrix.isLocalMatrix) {
            store.loadData(result.records);
        } else {
            filters = Ext.Array.merge(me.getFiltersFromParams(result.getLeftAxisItem() ? result.getLeftAxisItem().data : {}), me.getFiltersFromParams(result.getTopAxisItem() ? result.getTopAxisItem().data : {}));
            store.clearFilter(true);
            if (filters.length > 0) {
                store.addFilter(filters);
            } else {
                store.load();
            }
        }
 
        panel.setWidth(me.getWidth());
        panel.show();
    },
 
    hidePanel: function () {
        var panel = this.getPanel();
 
        if (panel) {
            panel.hide();
        }
    },
 
    getFiltersFromParams: function (obj) {
        var filters = [],
            i, len, keys;
 
        if (Ext.isObject(obj)) {
            keys = Ext.Object.getKeys(obj);
            len = keys.length;
 
            for (= 0; i < len; i++) {
                filters.push({
                    property: keys[i],
                    exactMatch: true,
                    value: obj[keys[i]]
                });
            }
        }
 
        return filters;
    }
 
});