/*
 *  Copyright 2013 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 class provides a widget to select one or more pages.<br>
 * This embeds a drop down list with querying on title of pages and type-ahead support.<br>
 * A dialog box also allow to select pages in sitemap tree.<br>
 * See {@link Ametys.web.helper.ChoosePage}<br>
 * 
 * This widget is registered for fields of type Ametys.form.WidgetManager#TYPE_STRING
 */
Ext.define('Ametys.web.form.widget.SelectPage', {
	
    extend: 'Ametys.form.AbstractQueryableComboBox',
    
    statics: {
		
		/**
		 * @property {String} [SITE_CONTEXT_CURRENT="current"] Context of site for using current site only.
		 */
		SITE_CONTEXT_CURRENT: "current",
		/**
		 * @property {String} [SITE_CONTEXT_ALL="all"] Context of site for choosing site in a combo box of available sites.
		 */
		SITE_CONTEXT_ALL: "all",
		
		/**
		 * @property {String} [SITEMAP_CONTEXT_ALL="all"] Context of sitemap for choosing language in a combo box of available languages.
		 */
		SITEMAP_CONTEXT_ALL: "all",
		
		/**
		 * @property {String} [SITEMAP_CONTEXT_CURRENT="current"] Context of sitemap for using current sitemap only.
		 */
		SITEMAP_CONTEXT_CURRENT: "current",
		
		/**
         * Open the page tool on the given page.
         * @param {String} pageId The ID of the page to open.
         */
        openPage: function(pageId)
        {
            // Defer the call to let the focus happen before opening the tool.
            Ext.defer(Ametys.tool.ToolsManager.openTool, 1, Ametys.tool.ToolsManager, ['uitool-page', {id: pageId}]);
        }
	},
	
    /**
     * @cfg {String} [sitesField] The relative path to a sites widget.
     * If not empty, the select page widget will be disabled if several sites are selected
     */
    /**
     * @private
     * @property {String[]} _sitesFieldName The property related to {@link #cfg-sitesField}
     */

    /**
     * @cfg {String} [enableWithFieldName] The relative path to a widget whose value will enable or disable
     * this widget. See {@link #cfg-enableOnFieldValues} for the values checked.
     */
    /**
     * @private
     * @property {String[]} _enableWithFieldName The property related to {@link #cfg-enableWithFieldName}
     */
    
    /**
     * @cfg {String} [enableOnFieldValues] The value or list of values of the {@link #cfg-enableWithFieldName}
     * to enable this widget.
     */
    /**
     * @private
     * @property {String[]} _enableOnFieldValues The property related to {@link #cfg-enableOnFieldValues}
     */
	
    /**
     * @cfg {Boolean} [multiple=false] True to allow multi-selection and display checkboxes (defaults to false).
     */
    multiple: false,
    
    /**
     * @cfg {String} [boxTitle] The title of the dialog box.
     */
    /**
     * @cfg {String} [boxIcon] The title of the dialog box.
     */
    /**
     * @cfg {String} [helpMsg] The message displayed at the top of dialog box
     */
    
    /**
     * @cfg {Object} buttonConfig The configuration that will be transmitted to the button. The handler cannot be changed, moreover be aware of the behavior of #cfg-buttonText, #cfg-buttonIcon and #cfg-IconCls. 
     */
    
    /**
     * @cfg {String} [buttonText=""] The text of the select page button.
     * Note that if you supply a value for {@link #buttonConfig}, the buttonConfig.text
     * value will be used instead if available.
     */
    buttonText: '',
    /**
     * @cfg {String} buttonIcon The button icon path for the select button.
     * Note that if you supply a value for {@link #buttonConfig}, the buttonConfig.icon
     * value will be used instead if available.
     */
    buttonIcon: null,
    
    /**
     * @cfg {String} buttonIconCls The CSS class to apply to the select button 
     * Note that if you supply a value for {@link #buttonConfig}, the buttonConfig.icon
     * value will be used instead if available.
     */
    buttonIconCls: 'ametysicon-website38',
    
    /**
     * @cfg {String} buttonTooltip The button icon tooltip for the select button.
     */
    buttonTooltip: "{{i18n PLUGINS_WEB_WIDGET_SITEMAPWIDGET_SELECTPAGE}}",
    
    /**
     * @cfg {Number} [minChars=3] The minimum number of characters the user must type before autocomplete activates.
     */
    minChars: 3,
    
    /**
     * @cfg {Boolean} [openOnClick=true] Set to `false` to disable the opening of selected pages
     */
    openOnClick: true,
    
	/**
     * @cfg {String} [growMax=300] If not set to `false`, the max height in pixels of the box select
     */
    growMax: 300,
    
    /**
     * @property {Ext.button.Button} selectButton The select pages button, if any.
     * @protected
     */
    
    /**
	 * @cfg {Boolean} [triggerOnClick=false] Set to `true` to activate the trigger when clicking in empty space in the field.
	 */
    triggerOnClick: false,
    
    /**
	 * @cfg {Boolean} [hideTrigger=true] Set to `false` to show trigger
	 */
    /*hideTrigger: true,*/
    
    valueField: 'id',
    displayField: 'title',
    
    maxResult: 50,
    
    /**
     * @cfg {String} [siteContext=Ametys.web.form.widget.SelectPage.SITE_CONTEXT_CURRENT] The site context. 
     * Valid contexts are: 
     * <ul>
     *      <li>Ametys.web.form.widget.SelectPage.SITE_CONTEXT_CURRENT for current site only</li>
     *      <li>Ametys.web.form.widget.SelectPage.SITE_CONTEXT_ALL for all sites</li>
     * </ul>
     */
    
    /**
     * @cfg {String} [sitemapContext=Ametys.web.form.widget.SelectPage.SITEMAP_CONTEXT_ALL] The sitemap context.
     * Valid contexts are: 
     * <ul>
     *      <li>Ametys.web.form.widget.SelectPage.SITEMAP_CONTEXT_CURRENT for current sitemap only</li>
     *      <li>Ametys.web.form.widget.SelectPage.SITEMAP_CONTEXT_ALL for all languages</li>
     *      <li>a language code such as 'fr', 'en', .. for using a specifying language.</li>
     * </ul>
     */
    
    /**
     * @cfg {String} choosePageDialogTitle Title of the dialog box to choose page(s). See {@link Ametys.web.helper.ChoosePage#open}.
     */
    /**
     * @cfg {String} choosePageDialogIcon The full icon path for the dialog box to choose page(s). See {@link Ametys.web.helper.ChoosePage#open}. 
     */
    /**
     * @cfg {String} choosePageDialogHint The help message to display on top of dialog box to choose page(s). See {@link Ametys.web.helper.ChoosePage#open}. 
     */
    /**
     * @protected
     * @property {Boolean} _listenToClick True to have a listener when a page is clicked
     */
    _listenToClick: true,
    
    initComponent: function()
    {
        this.cls = 'x-form-selectpage-widget';
        
        // remember the desired allowBlank policy
        this._configuredAllowBlank = this.allowBlank;
        
        this._sitesFieldName = this.sitesField || null;
        if (this._sitesFieldName && this.form && Ext.isFunction(this.form.onRelativeFieldsChange))
        {
            this.form.onRelativeFieldsChange(this._sitesFieldName, this, this._sitesFieldChange);
        }
        
        this._enableWithFieldName = this.enableWithFieldName || null;
        this._enableOnFieldValues = this.enableOnFieldValues || null;
        if (this._enableOnFieldValues != null && !Ext.isArray(this._enableOnFieldValues))
        {
            this._enableOnFieldValues = this._enableOnFieldValues.split(",");
        }
        if (this._enableWithFieldName && this.form && Ext.isFunction(this.form.onRelativeFieldsChange))
        {
            this.form.onRelativeFieldsChange(this._enableWithFieldName, this, this._enableWithFieldChange);
        }
        
        this.callParent(arguments);
    },
    
    /**
     * @private
     * Event when the combobox itemlist is clicked to open the content if required
     * @param {Event} evt The click event
     * @param {Ext.Element} el The item list
     * @param {Object} o Options. Emtpy.
     */
    _onComboboxItemListClick: function(evt, el, o)
    {
        // Handle clickable entry, in order to open the corresponding content.
        var itemEl = evt.getTarget('.x-tagfield-item'),
            spanEl = itemEl ? evt.getTarget('span.clickable') : false,
            record;
            
        if (spanEl)
        {
            record = this.combobox.getRecordByListItemNode(itemEl);
            if (record)
            {
                Ametys.web.form.widget.SelectPage.openPage(record.getId());
            }
        }
    },
    
    initEvents: function()
    {
        this.callParent(arguments);
        
        if (this._listenToClick)
        {
            // Click listener on the combobox to deals with clickable entries.
            this.combobox.mon(this.combobox.itemList, 'click', this._onComboboxItemListClick, this);
        }
    },
    
    getItems: function()
    {
    	var items = this.callParent(arguments);
        
        // Button that opens the search dialog box.
        if (!this.readOnly)
        {
        	var buttonConfig = this.buttonConfig || {};
            Ext.applyIf(buttonConfig, {
                text: this.buttonText,
                icon: this.buttonIcon,
                iconCls: this.buttonIcon ? null : this.buttonIconCls,
                tooltip: this.buttonTooltip,
                handler: this.choosePage,
                scope: this
            });
            this.selectButton = Ext.create('Ext.button.Button', buttonConfig);
            items.push(this.selectButton);
        }
        
        return items;
    },
    
    getLabelTpl: function ()
    {
    	var labelTpl = [];
        
        if (this.openOnClick == true || this.openOnClick == 'true')
        {
        	labelTpl.push('<span class="clickable">{[values.title]}</span>');
        }
        else
        {
        	labelTpl.push('{[values.title]}');
        }
     
        return labelTpl;
    },
    
    /**
     * @private
     * Listener called when the value of the site field changes
     */
    _sitesFieldChange: function()
    {
        var sitesField = this.form.getRelativeField(this._sitesFieldName, this),
            siteContext = sitesField ? sitesField.getSiteContext() : null,
            sites = sitesField ? sitesField.getSiteValues() : null;
            
        this.siteFieldChanged(siteContext, sites);
    },

    /**
     * if no sitesField was given, call manually this method to update site context and sites
     * @param {String} siteContext site context
     * @param {String[]} sites list of sites
     */
    siteFieldChanged: function(siteContext, sites)
    {
        var enabled = siteContext == Ametys.web.form.widget.SelectSite.SITE_CONTEXT_CURRENT
            || (sites != null && sites.length == 1);
        
        if (!enabled)
        {
            this.disable();
            this.allowBlank = true;
            this.combobox.allowBlank = true;
            this.setValue(null);
            this.combobox.lastQuery = null;
            this.clearInvalid();
        }
        else 
        {
            var newSiteName = siteContext == Ametys.web.form.widget.SelectSite.SITE_CONTEXT_CURRENT ? Ametys.getAppParameters().siteName : sites[0];
            if (this.siteName != newSiteName && this.siteName /* the last part is mandatory to not reset the current value when the field is initialized */)
            {
                this.setValue(null);
                this.combobox.lastQuery = null;
            }
            
            this.siteName = newSiteName;
            
            if (this.isDisabled())
            {
                this.enable();
                this.allowBlank = this._configuredAllowBlank;
                this.combobox.allowBlank = this._configuredAllowBlank;
            }
        }
    },
    
    /**
     * Listener called when the value of the FO search mode changes
     */
    _enableWithFieldChange: function()
    {
        var fieldValue = this.form.getRelativeField(this._enableWithFieldName, this).getValue();
    
        if (this._enableOnFieldValues != null && !Ext.Array.contains(this._enableOnFieldValues, fieldValue))
        {
            this.disable();
            this.allowBlank = true;
            this.combobox.allowBlank = true;
            this.setValue(null);
            this.combobox.lastQuery = null;
            this.clearInvalid();
        }
        else
        {
            this.enable();
            this.allowBlank = this._configuredAllowBlank;
            this.combobox.allowBlank = this._configuredAllowBlank;
            this.reset();
        }
    },
    
    /**
     * Open the dialog box to select pages in sitemap
     */
    choosePage: function()
    {
    	var values = this.getValue();
    	values = values ? (Ext.isArray(values) ? Ext.Array.clone(values) : [values]) : [];
    	
    	var siteContext = (this.siteContext == Ametys.web.form.widget.SelectPage.SITE_CONTEXT_ALL) ? Ametys.web.helper.ContextToolbar.SITE_CONTEXT_ALL : Ametys.web.helper.ContextToolbar.SITE_CONTEXT_CURRENT;
    	
    	var defaultSitemapName;
    	var sitemapContext;
    	if (this.sitemapContext == Ametys.web.form.widget.SelectPage.SITEMAP_CONTEXT_CURRENT)
    	{
    		sitemapContext = this._getCurrentSitemapName();
    		defaultSitemapName = this._getCurrentSitemapName();
    	}
    	else if (this.sitemapContext == Ametys.web.form.widget.SelectPage.SITEMAP_CONTEXT_ALL)
    	{
    		sitemapContext = Ametys.web.helper.ContextToolbar.SITEMAP_CONTEXT_ALL;
    		defaultSitemapName = this._getCurrentSitemapName();
    	}
    	else
    	{
    		sitemapContext = this.sitemapContext;
    		defaultSitemapName = this.sitemapContext;
    	}
        
    	var config = {
            title: this.choosePageDialogTitle,
            iconCls: this.choosePageDialogIconCls,
            helpMessage: this.choosePageDialogHint,
            values: values,
            multiple: this.multiple,
            siteContext: siteContext,
            sitemapContext: sitemapContext,
            defaultSitemapName: defaultSitemapName,
            defaultSiteName: this.siteName,
            showSelectDecorators: this.showSelectDecorators,
            callback:  Ext.bind(this._choosePageCb, this)
        };
        
        this.triggerDialogBoxOpened = true;
        Ametys.web.helper.ChoosePage.open(config);
    },
    
    /**
     * This function is called after selecting pages
     * Sets the value of the field.
     * @param {String|String[]} pageIds The identifiers of selected pages 
     * @private
     */
    _choosePageCb: function(pageIds)
    {
        this.triggerDialogBoxOpened = false;
        if (pageIds !== undefined)
        {
        	pageIds = Ext.Array.from(pageIds);
        	this.setValue(pageIds);
        }
    },
    
    /**
     * Get the current language
     * @return the current language
     */
    _getCurrentSitemapName: function ()
    {
    	// First search in current selection
    	var pageTarget = Ametys.message.MessageBus.getCurrentSelectionMessage().getTarget(Ametys.message.MessageTarget.PAGE);
    	if (pageTarget != null)
    	{
    		return pageTarget.getParameters().lang;
    	}
    	
    	return Ametys.cms.language.LanguageDAO.getCurrentLanguage();
    },
    
    getStore: function()
    {
        return Ext.create('Ext.data.Store', {
            model: 'Ametys.web.form.widget.SelectPage.PageEntry',
            proxy: {
                type: 'ametys',
                plugin: 'web',
                url: 'search-pages',
                reader: {
                    type: 'json',
                    rootProperty: 'pages'
                }
            },
            
            pageSize: this.maxResult,
            
            remoteSort: true,
            sortOnLoad: true,
            sorters: [{property: 'title', direction:'ASC'}],
            
            listeners: {
                beforeload: {fn: this._onStoreBeforeLoad, scope: this}
            }
        });
    },
    
    /**
     * Set the request parameters before loading the store.
     * @param {Ext.data.Store} store The store.
     * @param {Ext.data.operation.Operation} operation The Ext.data.operation.Operation object that will be passed to the Proxy to load the Store.
     */
    _onStoreBeforeLoad: function(store, operation)
    {
    	var lang = null;
    	if (this.sitemapContext == Ametys.web.form.widget.SelectPage.SITEMAP_CONTEXT_CURRENT)
    	{
    		lang = this._getCurrentSitemapName();
    	}
    	else if (this.sitemapContext != Ametys.web.form.widget.SelectPage.SITEMAP_CONTEXT_ALL) 
    	{
    		lang = this.sitemapContext;
    	}
        else
        {
            lang = this._getCurrentSitemapName();
        }
    	
    	var siteName = this.siteName || (this.siteContext == Ametys.web.helper.ContextToolbar.SITE_CONTEXT_CURRENT ? Ametys.getAppParameters().siteName : null);
    	
        var query = operation.getParams().query;
        if (query)
        {
            query = '*' + query + '*';
        }
        
        operation.setParams( operation.getParams() || {} );
        operation.setParams( Ext.apply(operation.getParams(), {
        	'ids': Ext.isEmpty(operation.getParams().id) ? null : operation.getParams().id.split(','),
        	siteName: siteName,
        	lang: lang,
        	query: query
        }));
    }
});