/**
 * This plugin allows grid data export using various exporters. Each exporter should extend
 * the {@link Ext.exporter.Base} class.
 *
 * Two new methods are created on the grid panel by this plugin:
 *
 *  - saveDocumentAs(config): saves the document
 *  - getDocumentData(config): returns the document content
 *
 * The grid data is exported for all grid columns that have the flag
 * {@link Ext.grid.column.Column#ignoreExport ignoreExport} as false.
 *
 * A grid column may have an {@link Ext.grid.column.Column#exportStyle exportStyle} defined which is used during
 * data export. If no `exportStyle` is defined for a column then column formatter is used if
 * defined.
 *
 * Example usage:
 *
 *      {
 *          xtype: 'grid',
 *          plugins: [{
 *              type: 'gridexporter'
 *          }],
 *          columns: [{
 *              dataIndex: 'value',
 *              text: 'Total',
 *              exportStyle: {
 *                  format: 'Currency',
 *                  alignment: {
 *                      horizontal: 'Right'
 *                  }
 *              }
 *          }]
 *      }
 *
 *      grid.saveDocumentAs({
 *          type: 'xlsx',
 *          title: 'My export',
 *          fileName: 'myExport.xlsx'
 *      });
 *
 */
Ext.define('Ext.grid.plugin.Exporter', {
    alias: [
        'plugin.gridexporter'
    ],
 
    extend: 'Ext.exporter.Plugin',
 
    /**
     * @event beforedocumentsave
     * Fires on the grid panel before a document is exported and saved.
     * @param {Ext.grid.Panel} grid Reference to the grid panel
     */
    /**
     * @event documentsave
     * Fires on the grid panel whenever a document is exported and saved.
     * @param {Ext.grid.Panel} grid Reference to the grid panel
     */
    /**
     * @event dataready
     * Fires on the grid panel when the {Ext.exporter.data.Table data object} is ready.
     * You could adjust styles or data before the document is generated and saved.
     * @param {Ext.grid.Panel} grid Reference to the grid panel
     */
 
    /**
     * Save the export file. This method is added to the grid panel as "saveDocumentAs".
     *
     * Pass in exporter specific configs to the config parameter.
     *
     * @method saveDocumentAs
     * @param {Ext.exporter.Base} config Config object used to initialize the proper exporter
     * @param {String} config.type Type of the exporter as defined in the exporter alias. Default is `excel`.
     * @param {String} [config.title] Title added to the export document
     * @param {String} [config.author] Who exported the document?
     * @param {String} [config.fileName] Name of the exported file, including the extension
     * @param {String} [config.charset] Exported file's charset
     *
     */
 
    /**
     * Fetch the export data. This method is added to the grid panel as "getDocumentData".
     *
     * Pass in exporter specific configs to the config parameter.
     *
     * @method getDocumentData
     * @param {Ext.exporter.Base} config Config object used to initialize the proper exporter
     * @param {String} [config.type] Type of the exporter as defined in the exporter alias. Default is `excel`.
     * @param {String} [config.title] Title added to the export document
     * @param {String} [config.author] Who exported the document?
     * @return {String}
     *
     */
 
    /**
     * @inheritdoc
     */
    prepareData: function(config){
        var me = this,
            grid = me.cmp,
            table = new Ext.exporter.data.Table(),
            store = grid.getStore(),
            headers, group;
 
        headers = me.getColumnHeaders(grid.getHeaderContainer().innerItems, config);
 
        table.setColumns(headers);
 
        if (!store || (store && store.isDestroyed)) {
            return table;
        }
 
        // <debug> 
        if (store && store.isBufferedStore) {
            Ext.raise('BufferedStore can\'t be exported because it doesn\'t have all data available');
        }
        // </debug> 
 
        group = {
            text: ''
        };
 
        me.extractGroups(group, grid.getColumns());
        table.addGroup(group);
 
        return table;
    },
 
    /**
     * Fetch all columns that will be exported
     * @param {Array} columns 
     * @param {Object} config 
     * @return {Array}
     *
     * @private
     */
    getColumnHeaders: function(columns, config){
        var cols = [],
            i, obj, col;
 
        for(= 0; i < columns.length; i++){
            col = columns[i];
 
            obj = {
                text: col.getText(),
                width: col.getWidth()
            };
 
            if(col.isHeaderGroup){
                obj.columns = this.getColumnHeaders(col.innerItems, config);
                if(obj.columns.length === 0){
                    // all children columns are ignored for export so there's no need to export this grouped header 
                    obj = null;
                }
            }else if(!col.getHidden() && !col.getIgnoreExport()){
                obj.style = this.getExportStyle(col.getExportStyle(), config);
                obj.width = obj.width || col.getComputedWidth();
            }else{
                obj = null;
            }
 
            if(obj) {
                cols.push(obj);
            }
        }
 
        return cols;
    },
 
    /**
     * Generate the data that the exporter can consume
     *
     * @param group
     * @param columns
     * @return {Ext.exporter.data.Group}
     *
     * @private
     */
    extractGroups: function(group, columns){
        var store = this.cmp.getStore(),
            len = store.getCount(),
            lenCols = columns.length,
            i, j, record, row, col, value, formatter, exportStyle;
 
        // we could also export grouped stores 
        group.rows = [];
        for(= 0; i < len; i++){
            record = store.getAt(i);
            row = {
                cells: []
            };
 
            for(= 0; j < lenCols; j++){
                col = columns[j];
                // each column has a config 'ignoreExport' that can tell us to ignore the column on export 
                if(!col.getHidden() && !col.getIgnoreExport()) {
                    value = record.get(col.getDataIndex());
                    formatter = col.getFormatter();
                    exportStyle = col.getExportStyle();
                    if((!exportStyle || !(exportStyle && exportStyle.format)) && formatter) {
                        value = formatter(value);
                    }
                    row.cells.push({
                        value: value
                    });
                }
            }
            group.rows.push(row);
        }
 
        return group;
    }
 
});