/*
 *  Copyright 2016 Anyware Services
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
 
/**
 * @private
 * This tool displays a sql table
 * Must be parametrized with 'id', an id of a datasource ; and 'table' the sql table name
 */ 
Ext.define('Ametys.plugins.datasourcesexplorer.tool.DatasourcesExplorerSQLTableViewTool', {
    extend: 'Ametys.tool.Tool',
    
    /**
     * @private
     * @property {String} _datasourceId The displayed datasource id
     */
    /**
     * @private
     * @property {String} _sqlTableName The displayed table name
     */
    /**
     * @private
     * @property {String} _modelName The name of the store model to use
     */
    /**
     * @private
     * @property {Ext.grid.Panel} _grid The main grid panel
     */
    /**
     * @private
     * @property {Number} _columnsHashCode Th server columns hashcode of the last reconfiguration
     */
    
    statics: {
        /** 
         * @readonly
         * @private
         * @property {Number} __PAGE_SIZE the default value for pagination size
         */
        __PAGE_SIZE: 10
    },
    
    constructor: function(config)
    {
        this.callParent(arguments);
        
        // Bus messages listeners
        Ametys.message.MessageBus.on(Ametys.message.Message.MODIFIED, this._onModified, this);
        Ametys.message.MessageBus.on(Ametys.message.Message.DELETED, this._onDeleted, this);
    },

    createPanel: function()
    {
        var store = this.createStore();
        
        this._grid = Ext.create('Ext.grid.Panel', {
            store: store,
            columns: [],
            dockedItems: [{
                xtype: 'pagingtoolbar',
                store: store,
                dock: 'bottom',
                itemId: 'paging',
                items: [
                    { 
                        xtype: 'component', 
                        flex: 1 
                    }, 
                    { 
                        xtype: 'textfield', 
                        fieldLabel: 'WHERE', 
                        labelSeparator: '', 
                        labelWidth: 50, 
                        flex: 20, 
                        itemId: 'where',
                        listeners: {
                            'blur': function() {
                                this._grid.getStore().load();
                            },
                            'specialkey': function(field, e) {
                                if (e.getKey() == e.ENTER) {
                                    this._grid.getStore().load();
                                }
                            },
                            scope: this
                        }
                    },
                    { 
                        xtype: 'textfield', 
                        fieldLabel: 'BY', 
                        labelSeparator: '', 
                        labelWidth: 20, 
                        width: 60, 
                        itemId: 'by',
                        value: Ametys.plugins.datasourcesexplorer.tool.DatasourcesExplorerSQLTableViewTool.__PAGE_SIZE,
                        listeners: {
                            'blur': function() {
                                this._grid.getStore().load();
                            },
                            'specialkey': function(field, e) {
                                if (e.getKey() == e.ENTER) {
                                    this._grid.getStore().load();
                                }
                            },
                            scope: this
                        }
                    }
                ],
                displayInfo: true
            }]
        });
        
        return this._grid;
    },
    
    /**
     * @protected
     * Get the store the grid should use as its data source.
     * @return {Ext.data.Store} The store
     */
    createStore: function()
    {
        this._createModel();
        return Ext.create('Ext.data.Store', {
            model: this._modelName,
            autoDestroy: true,
            
            remoteSort: true,
            proxy: {
                type: 'ametys',
                plugin: 'datasources-explorer',
                url: 'sql-data.json',
                reader: {
                    type: 'json',
                    rootProperty: 'data',
                    metaProperty: 'meta'
                }
            },
             
            pageSize: Ametys.plugins.datasourcesexplorer.tool.DatasourcesExplorerSQLTableViewTool.__PAGE_SIZE,
            sortOnLoad: true,
             
            listeners: {
                'beforeload': {fn: this._onBeforeLoad, scope: this},
                'metachange': {fn: this._onMetaChange, scope: this}  
            }
        });
    },
    
    /**
     * Function called before loading the store
     * @param {Ext.data.Store} store The store
     * @param {Ext.data.operation.Operation} operation The object that will be passed to the Proxy to load the store
     * @private
     */
    _onBeforeLoad: function(store, operation)
    {
        if (this._sqlTableName)
        {
            this._grid.getView().unmask();

            var pageSize = this._grid.getDockedComponent('paging').getComponent('by').getValue(); 
            operation.setParams( Ext.apply(operation.getParams() || {}, {
                datasourceId: this._datasourceId,
                sqlTableName: this._sqlTableName,
                where: this._grid.getDockedComponent('paging').getComponent('where').getValue(),
                limit: pageSize
            }));
            this._grid.getStore().setPageSize(pageSize);
        }
        else
        {
            // not parametrized yet
            return false;
        }
    },
    
    /**
     * @private
     * Fired when the strucure is send
     * @param {Ext.data.Store} store The data store
     * @param {Object} response The server side response for the metadata part
     */
    _onMetaChange: function(store, response)
    {
        if (response.columnsHashcode != this._columnsHashCode)
        {
            response.columnsHashcode = this._columnsHashCode;
            
            this.setTitle(this._sqlTableName + " (" + response.datasource + ")");
            
            // Update model and columns
            var fields = [{name: '_internal_id'}];
            var columns = [];
            for (var i = 0; i < response.columns.length; i++)
            {
                fields.push({ name: response.columns[i].name });
                columns.push({ dataIndex: response.columns[i].name, text: response.columns[i].label, width: Math.max(100, Math.min(250, response.columns[i].displaySize*3)), renderer: Ext.bind(this._renderColumn, this) });
            }
            
            this._createModel(fields);
            this._grid.reconfigure (this._grid.getStore(), columns);
        }        
    },
    
    /**
     * @private
     * Render the column to escape special characters
     * @param {String} value The value
     */
    _renderColumn: function(value)
    {
        return value ? value.replace(/</g, '&lt;') : "<em>&lt;null&gt;</em>";
    },
    
    /**
     * Creates the model for the store
     * @param {Object[]} [fields] The fields for this model
     * @private
     */
    _createModel: function (fields)
    {
        fields = fields || [{name: '_internal_id'}];
                
        this._modelName = this.getId() + "-Entry";
        
        if (Ext.data.schema.Schema.get('default').hasEntity(this._modelName)) 
        {
            Ext.data.schema.Schema.get('default').getEntity(this._modelName).replaceFields(fields, true);
        }
        else
        {
            Ext.define(this._modelName, {
                extend: 'Ext.data.Model',
                schema: 'default',
                idProperty: '_internal_id',
                fields: fields
            });
        }
    },

    setParams: function(params)
    {
        this.callParent(arguments);
        this._datasourceId = params['datasource-id'];
        this._sqlTableName = params['table'];
        this._columnsHashCode = 0;
        this.setTitle("...");
        this.refresh();
    },
    
    getMBSelectionInteraction: function() 
    {
        return Ametys.tool.Tool.MB_TYPE_ACTIVE;
    },
    
    sendCurrentSelection : function()
    {
        var targets = [];
        targets.push({
            id: Ametys.message.MessageTarget.DATASOURCE_SQLTABLE,
            parameters: {
                id: this._datasourceId,
                name: this._sqlTableName
            }
        });
        
        Ext.create("Ametys.message.Message", {
            type: Ametys.message.Message.SELECTION_CHANGED,
            targets: targets
        });
    },
    
    refresh: function ()
    {
        this.showRefreshing();
        this._grid.getStore().load({callback: this.showRefreshed, scope: this});
    },
    
    /**
     * @private
     * Handler function invoked whenever a {@link Ametys.message.Message#MODIFIED} message is sent out on the 
     * message bus. Update the corresponding record of the grid panel's store.
     * @param {Ametys.message.Message} message the message
     */
    _onModified: function (message)
    {
        var targets = message.getTargets(Ametys.message.MessageTarget.DATASOURCE);
        for (var i=0; i < targets.length; i++)
        {
            if (target.getParameters().id == this._datasourceId)
            {
                this.showOutOfDate();
                break;
            }
        }
    },
    
    /**
     * @private
     * Handler function invoked whenever a {@link Ametys.message.Message#DELETED} message 
     * is sent out on the message bus. Delete the corresponding record from the grid panel's store.
     * @param {Ametys.message.Message} message the message
     */
    _onDeleted: function (message)
    {
        var targets = message.getTargets(Ametys.message.MessageTarget.DATASOURCE);
        for (var i=0; i < targets.length; i++)
        {
            if (target.getParameters().id == this._datasourceId)
            {
                this.close();
                break;
            }
        }
    }
});