/*
 *  Copyright 2010 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.
 */

/**
 * Model for repository node as a search result. 
 * @private
 */
Ext.define('Ametys.repository.data.RepositorySearchNode', {
    extend: 'Ext.data.TreeModel',
    fields: [
        {name: 'text', mapping: '@path', persist: false},
        {name: 'path', mapping: '@path'},
        {name: 'pathWithGroups', mapping: '@pathWithGroups'},
        {name: 'name', mapping: '@name'},
        {name: 'iconCls', defaultValue: 'a-tree-glyph ametysicon-document112'},
        {name: 'leaf', defaultValue: true}
    ]
});

/**
 * Tree panel used to display search results.
 * @private
 */
Ext.define('Ametys.repository.tree.SearchTreePanel',
{
    extend: 'Ext.tree.Panel',
    
    config: {
        /**
         * @cfg {String} [defaultWorkspaceName='default'] The default workspace. Defaults to 'default'
         */
        defaultWorkspaceName : 'default',
        
        /**
         * @cfg {String} searchUrl The search URL.
         */
        searchUrl: Ametys.getPluginDirectPrefix('repositoryapp') + '/repository/query',
        
        /**
         * @cfg {String} modelName The model name.
         */
        modelName: 'Ametys.repository.data.RepositorySearchNode'
    },
    
    statics: {
        /**
         * @property {String} JCR_ICON_SEARCH
         * The icon used for the search root.
         */
        JCR_ICON_SEARCH: Ametys.getPluginResourcesPrefix('repositoryapp') + '/img/jcr/search_16.png'
    },
    
    /**
     * @property {String} _workspaceName The workspace name.
     * @private
     */
    _workspaceName: null,
    
    // Tree properties.
    scrollable: true,
    animate: true,
    hidden: true,
    
    initComponent: function() {
        var store = Ext.create('Ext.data.TreeStore', {
            model: this.modelName,
            proxy: {
                type: 'ajax',
                url: this.searchUrl,
                reader: {
                    type: 'xml',
                    rootProperty: 'resultList',
                    record: 'result',
                    successProperty: function(data) {
                        return data.firstChild == null || data.firstChild.tagName != 'error';
                    }
                }
            },
            root: {
                text: "{{i18n PLUGINS_REPOSITORYAPP_SEARCH_ROOT_NODE_LABEL}}",
                iconCls: 'a-tree-glyph ametysicon-magnifier12',
                path: '',
                expanded: true,
				'config-doNotEscapeHtml': true,
                leaf: false
            },
            folderSort: true,
            sorters: [{
                property: 'text',
                direction: 'ASC'
            }],
            listeners: {
                beforeload: {fn: this.onBeforeLoad, scope: this},
                load: {fn: this.onLoad, scope: this}
            }
        });
        
        Ext.apply(this, {
            store: store,
            viewConfig: {
                toggleOnDblClick: false
            }
        });
        
        this.callParent(arguments);
        
        this.getSelectionModel().on('beforeselect', this.beforeSelectNode, this);
        
        this.getRootNode().on('expand', this.onExpandRoot, this);
        this.getRootNode().on('collapse', this.onCollapseRoot, this);
    },
    
    /**
     * Adds additional parameters to the Operation before loading the store.
     * @param {Ext.data.TreeStore} store The tree store.
     * @param {Ext.data.Operation} operation The operation object that will be passed to the Proxy to load the Store.
     * @param {Object} eOpts Options added to the addListener
     * @private
     */
    onBeforeLoad: function(store, operation, eOpts)
    {
        if (this._waitMsg != null)
        {
            this._waitMsg.hide();
        }
        
        // Do not load the store if there is no query.
        if (this._query == null || this._query == '')
        {
            return false;
        }
        
        Ext.getBody().mask("{{i18n PLUGINS_REPOSITORYAPP_QUERY_EXECUTE_WAITING_MSG}}", "ametys-mask-unloading");
        
        // Set the current workspace name
        operation.setParams({
        	workspaceName: this._workspaceName || this.defaultWorkspaceName,
        	query: this._query,
        	language: this._language
        });
    },
    
    /**
     * Fired when the store is loaded.
     * @param {Ext.data.TreeStore} store The tree store.
     * @param {Ext.data.TreeModel[]} records The loaded records.
     * @param {Boolean} successful true if the operation was successful, false otherwise.
     * @param {Ext.data.Operation} operation The operation that triggered this load.
     * @param {Ext.data.NodeInterface} node The loaded node.
     * @private
     */
    onLoad: function(store, records, successful, operation, node)
    {
    	Ext.getBody().unmask();
    	
    	var root = store.getRoot();
        
        if (!successful)
        {
            Ametys.Msg.show({
                title: "{{i18n PLUGINS_REPOSITORYAPP_QUERY_PROMPT_TITLE}}",
                msg: "{{i18n PLUGINS_REPOSITORYAPP_QUERY_EXECUTE_UNEXPECTED_ERROR_MSG}}",
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.ERROR
            });
            
            root.set('text', "<b>{{i18n PLUGINS_REPOSITORYAPP_SEARCH_ROOT_NODE_LABEL}} : 0 {{i18n PLUGINS_REPOSITORYAPP_SEARCH_NB_RESULTS}} - <span style='color:red'>{{i18n PLUGINS_REPOSITORYAPP_QUERY_EXECUTE_ERROR_NODE}}</span></b>");
            root.commit();
            root.removeAll();
            
            this.setHeight(20);
            this.setVisible(true);
            
            return;
        }
        
        var nbResults = root.childNodes.length;
        
        if (nbResults == 1 && root.childNodes[0].get('type') == 'error')
        {
            Ametys.Msg.show({
                title: "{{i18n PLUGINS_REPOSITORYAPP_QUERY_PROMPT_TITLE}}",
                msg: "{{i18n PLUGINS_REPOSITORYAPP_QUERY_EXECUTE_ERROR_MSG}}",
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.ERROR
            });
            
            root.set('text', "<b>{{i18n PLUGINS_REPOSITORYAPP_SEARCH_ROOT_NODE_LABEL}} : 0 {{i18n PLUGINS_REPOSITORYAPP_SEARCH_NB_RESULTS}} - <span style='color:red'>{{i18n PLUGINS_REPOSITORYAPP_QUERY_EXECUTE_ERROR_NODE}}</span></b>");
            root.commit();
            root.removeAll();
            
            this.setHeight(20);
        }
        else
        {
            root.set('text', "<b>{{i18n PLUGINS_REPOSITORYAPP_SEARCH_ROOT_NODE_LABEL}} : " + nbResults + " {{i18n PLUGINS_REPOSITORYAPP_SEARCH_NB_RESULTS}}</b>");
            root.commit();
            this.setHeight(nbResults > 0 ? 200 : 20);
        }
        
        this.setVisible(true);
        this.expand();
    },
    
    /**
     * Set the query to execute.
     * @param {String} query The query to execute.
     * @param {String} language The query language.
     * @param {String} workspaceName The workspace to execute the query in.
     */
    setQuery: function(query, language, workspaceName)
    {
        this._query = query;
        this._workspaceName = workspaceName || this.defaultWorkspaceName;
        this._language = language != null ? language : 'xpath';
    },
    
    /**
     * Tracks root expansion to expand/collapse the panel.
     * @param {Ext.data.TreeModel} node The expanded node.
     * @param {Object} eOpts Options added to the addListener
     * @private
     */
    onExpandRoot: function(node, eOpts)
    {
        this.setHeight(200);
    },
    
    /**
     * Tracks root collapse to expand/collapse the panel.
     * @param {Ext.data.TreeModel} node The collapsed node.
     * @param {Object} eOpts Options added to the addListener
     * @private
     */
    onCollapseRoot: function(node, eOpts)
    {
        this.setHeight(20);
    },
    
    /**
     * Listens before a node selection to prevent selecting the root node.
     * @param {Ext.selection.TreeModel} sm The tree selection model.
     * @param {Ext.data.NodeInterface} record The selected node.
     * @param {Number} index The row index of the record
     * @param {Object} eOpts Options added to the addListener
     * @private
     */
    beforeSelectNode: function(sm, record, index, eOpts)
    {
        // Prevent selecting the root node.
        if (record == null || record.isRoot())
        {
            return false;
        }
    }
    
});