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

/**
 * This UI helper provides a dialog to select one or more sites
 * See {@link #open} method.
 * 
 * 			Ametys.web.helper.ChooseSite.open({
 * 				multiple: false,
 *              callback:  Ext.bind(this._chooseSiteCb, this)
 * 			});
 */
Ext.define('Ametys.web.helper.ChooseSite', {
    singleton: true,
    
    /**
     * @property {Boolean} [multiple=false] True to allow multiple selections. Defaults to false.
     */
    /**
     * @property {String/String[]} values The name of the selected sites.
     */
    
    /**
     * @property {Function} _cbFn The call back function to call after choosing the sites
     * @private
     */
    /**
     * @property _box {Ametys.window.DialogBox} The dialog box
     * @private
     */
    /**
     * @property _tree {Ext.data.TreeStore} The sites tree panel
     * @private
     */
    /**
     * @property {Boolean} _initialized Internal property reflecting the state of the dialogbox.
     * @private
     */
    
    /**
     * Configure and open the dialog box
     * @param {Object} config The configuration options :
     * @param {String} [config.icon] The full path to icon (16x16 pixels) for the dialog box.
     * @param {String} [config.iconCls] The CSS class for icon of the dialog box
     * @param {String} [config.title] The title of the dialog box.
     * @param {String} [config.helpMessage] The help message to display on top of dialog box.
     * @param {String/String[]} [config.values] the selected site names
     * @param {Boolean} [config.readAccessOnly=false] true to list sites on read access only. Defaults to false.
     * @param {Boolean} [config.sharedSitesOnly=false] true to list sites with shared contents only. Defaults to false.
     * @param {Boolean} [config.multiple=false] `true` to allow selecting multiple sites.
     * @param {Function} config.callback The callback function invoked when sites are selected. The callback function will receive the following parameters:
     * @param {String/String[]} config.callback.names The names of the selected sites. In simple mode, the value is a string, in multiple mode it is an array.
     */
    open: function (config)
    {
        config = config || {};
        
        this.multiple = config.multiple == true;
        this.values = Ext.Array.from(config.values);
        this.readAccessOnly =  config.readAccessOnly == true; // false by default;
        this.sharedSitesOnly = config.sharedSitesOnly == true; // false by default;
        this._cbFn = config.callback || Ext.emptyFn;
        
        this._initialized = false;
        this._createDialogBox(config.icon, config.iconCls, config.title, config.helpMessage);
        this._box.show();
    },
    
    /**
     * Creates the dialog box if it is not already created
     * @param {String} icon The full path to icon (16x16 pixels) for the dialog box
     * @param {String} iconCls A css classname to set the icon of the dialog box
     * @param {String} title The title of the dialog box.
     * @param {String} helpMessage The help message to display on top of dialog box.
     * @private
     */
    _createDialogBox: function (icon, iconCls, title, helpMessage)
    {
        this._tree = Ext.create('Ametys.web.site.SitesTree', {
            border: true,
            flex: 1,
            checkMode: this.multiple,
            
            readAccessOnly: this.readAccessOnly,
            sharedSitesOnly: this.sharedSitesOnly,
            
            listeners : {
                selectionchange: Ext.bind(this._onSelectSite, this),
                load: {fn: this._onLoad, scope: this},
                itemappend: {fn: this._onItemAppend, scope: this}
            }
        });
        
        var defaultTitle = this.multiple ? "{{i18n PLUGINS_WEB_HELPER_CHOOSESITE_MULTIPLE_SELECT_TITLE}}" : "{{i18n PLUGINS_WEB_HELPER_CHOOSESITE_SIMPLE_SELECT_TITLE}}";
        var defaultHelpMessage = this.multiple ? "{{i18n PLUGINS_WEB_HELPER_CHOOSESITE_MULTIPLE_SELECT_DESCRIPTION}}" : "{{i18n PLUGINS_WEB_HELPER_CHOOSESITE_SIMPLE_SELECT_DESCRIPTION}}";
        
        this._box = Ext.create('Ametys.window.DialogBox', {
            title: title || defaultTitle,
            icon: icon,
            iconCls: icon ? null : iconCls || 'ametysicon-world91',
            width: 420,
            height: 500,
            scrollable: false,
            
            bodyStyle: {
            	padding: 0
            },
            cls: 'ametys-dialogbox',
            
            layout: {
                type: 'vbox',
                align : 'stretch',
                pack  : 'start'
            },
            
            items: [{
                    xtype: 'component',
                    cls: 'a-text',
                    html: helpMessage || defaultHelpMessage
                },
                this._tree
            ],
            
            closeAction: 'destroy',
            
            referenceHolder: true,
            defaultButton: 'validate',
            
            buttons : [{
            		reference: 'validate',
                    itemId: 'ok-btn',
                    disabled: true,
                    text :"{{i18n PLUGINS_WEB_HELPER_CHOOSESITE_OKBUTTON}}",
                    handler : Ext.bind(this._validate, this)
                }, {
                    text :"{{i18n PLUGINS_WEB_HELPER_CHOOSESITE_CANCELBUTTON}}",
                    handler: Ext.bind(function() {this._box.close();}, this)
                } 
            ]
        });
    },
    
    /**
     * This method update the dialog box depending on the current selection 
     * @private
     */
    _onSelectSite: function(sm, nodes)
    {
        var isValidSelection = this._isSelectionValid(nodes);
        this._box.down("button[itemId='ok-btn']").setDisabled(!isValidSelection);
    },
    
    /**
     * Select the site according to the input values
     * @param {Ext.data.TreeStore} store The tree store
     * @param {Ext.data.TreeModel[]} records The records
     * @param {Boolean} successful True if the operation was successful
     * @private
     */
    _onLoad: function(store, records, successful)
    {
        if (!this._initialized)
        {
            this._selectValues();
            this._initialized = true;
        }
    },
    
    /**
     * @private
     * Select the site according to the 'values' property during the initialization
     */
    _selectValues: function()
    {
    	if (this.values.length > 0)
        {
            Ametys.data.ServerComm.callMethod({
                role: 'org.ametys.web.repository.site.SiteDAO',
                methodName: 'getSitesInfos',
                parameters: [this.values],
                callback: {
                    scope: this,
                    handler: this._getSitesInfosCb
                },
                errorMessage: {
                    category: this.self.getName(),
                    msg: "{{i18n PLUGINS_WEB_HELPER_CHOOSESITE_ERROR}}"
                }
            });
        }

    	if (this.values.length == 0 || this.multiple)
    	{
    		var rootNode = this._tree.getRootNode();
        	this._tree.getSelectionModel().select(this._tree.getRootNode());
        	this._tree.getView().focusNode(rootNode);
    	}
    },
    
    /**
     * @private 
     * Callback after retrieving sites' properties. Select site in tree.
     * @param {Object} response The server response
     */
    _getSitesInfosCb: function(response)
    {
        Ext.Array.forEach(response.sites, function(site) {
            this._tree.expandNodeByPath(site.path, function(successful, node) {
                if (successful)
                {
                	if (this.multiple)
            		{
                		node.set('checked', true);
            		}
                	else
            		{
                		this._tree.getSelectionModel().select(node);
                		this._tree.getView().focusNode(node);
            		}
                }
            }, this);
        }, this);
    },
    
    /**
     * Check if selection is valid according to the configuration parameters
     * @param {Ext.data.TreeModel[]} nodes The selected nodes.
     * @return {boolean} true if the selection is valid
     * @private
     */
    _isSelectionValid : function(nodes)
    {
        if (nodes.length == 0)
        {
            return false;
        }
        
        for (var i=0; i < nodes.length; i++)
        {
            if (nodes[i].isRoot())
            {
                return false;
            }
        }
        
        return true;
    },
    
    /**
     * @private
     * Listener to the itemappend event of the tree.
     * Initialize the checkable status of each node
     */
    _onItemAppend: function(parenNode, node, index)
    {
        if (this.multiple && node && !node.isRoot())
        {
            node.set('checked', false); // add an empty checkbox
        }
    },
    
    /**
     * Retrieve the current tree values, and call the callback function from the initial configuration sent to #open
     * @private
     */
    _validate: function ()
    {
        var selection = this.multiple === false ? this._tree.getSelectionModel().getSelection() : this._tree.getChecked(),
            names;
            
        names = Ext.Array.map(selection, function(record) {
            return record.get('name');
        });
        
        this._box.close();
        if (this._cbFn)
        {
            if (this.multiple)
            {
                this._cbFn.call(this, names);
            }
            else
            {
                this._cbFn.call(this, names[0]);
            }
        }
    }
});