/*
 *  Copyright 2017 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 a image. The image can be file or a glyph.
 * 
 * This widget is registered for fields of type Ametys.form.WidgetManager#TYPE_FILE.<br>
 * 
 * This widget is configurable:<br>
 * - Use {@link #cfg-allowExtensions} to restrict files by extensions such as 'pdf', 'xml', 'png'.... <br>
 * - Use {@link #cfg-allowSources} to specify the authorized file sources (eg: 'external' for local resource, 'resource' for shared resource). Separated by comma.<br>
 * See the subclasses of {@link Ametys.form.widget.File.FileSource} and {@link Ametys.form.widget.Illustration.GlyphSource} for the available sources.<br>
 */
Ext.define('Ametys.form.widget.Illustration', {
	
	extend: 'Ametys.form.widget.File',
	
	/**
	 * @cfg {String[]} _cssLinkElmtIds The id of CSS link elements inserted dynamically. 
	 */
	_cssLinkElmtIds: [],
    
    /**
     * @cfg {String|String[]} [allowGlyphSources] The allowed sources for glyphes in a Array or separated by coma.
     */
    
	statics: {
    	
    	/**
         * @property {Object} _glyphSources The glyph sources
         * @private
         */
        _glyphSources: [],
        
        /**
         * Register a new glyph source
         * @param {String} source The glyph sources
         * @param {Ametys.form.widget.Illustration.GlyphSource} className The object class associated with this source
         */
    	registerGlyphSource: function (source, className)
        {
        	this._glyphSources[source] = className;
        },
        
        /**
         * Get the object class associated with the given glyph source type
         * @param {String} source The glyph source
         * @return {Ametys.form.widget.Illustration.GlyphSource} The glyph source class
         */
        getGlyphSource: function (source)
        {
        	return this._glyphSources[source];
        }
	},
	
	constructor: function (config)
    {
        config.filter = 'image'; // force image filter
        
		this.glyphSources = [];
        
        if (!Ext.isEmpty(config['allowGlyphSources']))
        {
            this.glyphSources = Ext.isArray(config['allowGlyphSources']) ? config['allowGlyphSources'] : config['allowGlyphSources'].split(',');
        }
		
		this.callParent(arguments);
		
		delete config.allowGlyphSources;
    },
    
    initComponent: function (config)
    {
    	// Preview Glyph
    	this.glyph = Ext.create('Ext.Component', {
            cls: this.imgWithBorderCls + ' ' + this.glyphCls,
            hidden: true,
            width: 48 + 6, // image width + padding
            height: 48 + 6, // image height + padding
            style: {
                fontSize: this.imagePreviewMaxWidth - 10 + 'px'
            }
        });
    	
    	this.items = [];
    	this.items.push(this.glyph);
    	
    	this.callParent(arguments);
    	
    	this.on('hide', this._removeStylesheets, this);
    	this.on('destroy', this._removeStylesheets, this);
    },
	
	// Override to allow only glyph sources
	_prepareFileSources: function(config)
    {
        if (Ext.isEmpty(config['allowSources']) && Ext.isEmpty(config['allowGlyphSources']))
        {
            /**
             * @protected
             * @cfg {String[]} [defaultSources=[Ametys.form.widget.File.External.SOURCE]] The sources to use when {#cfg-allowSources} is null or empty
             */
            this.fileSources = config.defaultSources || [Ametys.form.widget.File.External.SOURCE];
        }
		else if (Ext.isEmpty(config['allowSources']))
		{
            this.fileSources = [];
        }
        else
        {
            this.fileSources = Ext.isArray(config['allowSources']) ? config['allowSources'] : config['allowSources'].split(',');
        }
        delete config.allowSources;
    },
		
	getBtnConfig: function ()
    {
		// Menu
		if ((this.fileSources.length + this.glyphSources.length) > 1)
    	{
    		var menuItems = this._getMenuItemsForFileSources();
    		menuItems = Ext.Array.merge(menuItems, this._getMenuItemsForGlyphSources());
            
    		return {
    			text: this.getInitialConfig('buttonText') ||  Ametys.form.widget.File.filters[this.fileFilter].buttonMenuText, 
                tooltip: this.getInitialConfig('buttonTooltip') ||  Ametys.form.widget.File.filters[this.fileFilter].buttonMenuTooltip, 
                iconCls: this.getInitialConfig('buttonIconCls')  ||  Ametys.form.widget.File.filters[this.fileFilter].buttonMenuIconCls,
                
                menu: menuItems,
                
                disabled: this.disabled
            }
    	}
		// Only a file
    	else if (this.fileSources.length == 1)
    	{
    		var source = Ametys.form.widget.File.getFileSource(this.fileSources[0]);
        	var btnCfg = source.getBtnConfig (this.getInitialConfig(), this.fileFilter);
        	
    		return Ext.apply(btnCfg, {
                handler: this._selectFile,
                scope: this,
                
                disabled: this.disabled
            });
    	}
		// Only a glyph
    	else
    	{
    		var source = Ametys.form.widget.Illustration.getGlyphSource(this.glyphSources[0]);
        	var btnCfg = source.getBtnConfig (this.getInitialConfig());
    		return Ext.apply(btnCfg, {
                handler: this._selectGlyph,
                scope: this,
                
                disabled: this.disabled
            });
    	}
    },
    
    /**
     * @private
     * Get the configuration for menu items for the available glyph sources
     * @return {Object} The menu items
     */
    _getMenuItemsForGlyphSources: function()
    {
        var items = [];
        
        for (var i=0; i < this.glyphSources.length; i++)
        {
            var source = Ametys.form.widget.Illustration.getGlyphSource(this.glyphSources[i]);
            var itemCfg = source.getMenuItemConfig (this.getInitialConfig());
            
            items.push(Ext.apply(itemCfg, {
                xtype: 'menuitem',
                itemId: 'menuitem-glyph-source-' + source.getId(),
                handler: this._selectGlyph,
                scope: this,
                hidden: true
            }));
        }
        return items;
    },
    
    /**
     * Get CSS files
     */
    afterRender: function()
    {
    	this.callParent(arguments);
    
    	this._cssLinkElmtIds = [];
        
    	// Iterate over glyph sources
    	for (var i=0; i < this.glyphSources.length; i++)
		{
    		var source = Ametys.form.widget.Illustration.getGlyphSource(this.glyphSources[i]);
            source.isAvailable(Ext.bind(this._isSourceAvailable, this, [source], 1))
		}
    },
    
    /**
     * 
     * @param {Boolean} available True if the source is availble
     * @param {Ametys.form.widget.Illustration.GlyphSource} source The source
     */
    _isSourceAvailable: function(available, source)
    {
        if (available)
        {
            source.getCSSFiles(Ext.bind(this._createStyleSheet, this));
            
            var menuitem = this.down("#menuitem-glyph-source-" + source.getId())
            if (menuitem)
            {
                menuitem.setVisible(true);
            }
        }
    },
    
    /**
     * @private
     * Remove css in a link tag according to _cssLinkElmtIds array of ids
     */
    _removeStylesheets: function()
    {
    	Ext.Array.forEach(this._cssLinkElmtIds, function (elmtId) {
    		var styleEl = document.getElementById(elmtId);
            if (styleEl)
            {
                styleEl.parentNode.removeChild(styleEl);
            }
    	});
    	
    	this._cssLinkElmtIds = [];
    },
    
    /**
     * @private
     * Insert a &lt;link&gt; element into the &lt;head&gt; element for each CSS files for glyphes
     * @param {Object} response CSS urls to load
     */
    _createStyleSheet: function (response)
    {
        var head = document.getElementsByTagName('head')[0];
        
        var me = this;
        Ext.Array.forEach(response.cssFiles, function (href) {
            me._cssLinkElmtIds.push(cssId);
            
            var cssId = me.getId() + '-css-glyph-' + i;
            var styleEl = document.createElement('link');
            styleEl.setAttribute('type', 'text/css');
            styleEl.setAttribute('rel', 'stylesheet');
            styleEl.setAttribute('id', cssId);
            styleEl.setAttribute('href', href);
            head.appendChild(styleEl);
        });
    },
    
    /**
     * @private
     * Select a glyph.
     * @param {Ext.Button} btn The button calling this function
     */
    _selectGlyph: function (btn)
    {
    	var source = Ametys.form.widget.Illustration.getGlyphSource(btn.source);
    	source.handler(this.getInitialConfig(), Ext.bind(this._insertGlyphCb, this));
    },
    
    /**
     * @private
     * Callback function, called when a glyph is selected in the dialog.
     */
    _insertGlyphCb: function (glyph)
    {
    	if (glyph == null)
        {
            return;
        }
        
    	this.setValue({
        	id: glyph,
        	type: 'glyph'
        });
    },
    
    _updateUI: function()
    {
    	var value = this.value;
    	if (value && value.type == 'glyph')
    	{
    		if (!this.readOnly)
            {
                this.deleteButton.show();
                this.button.hide();
            }
            
            this._updateGlyphUI(value.id);
    	}
    	else
    	{
    		this.glyph.hide();
    		this.callParent(arguments);
    	}
    },
    
    /**
     * @private
     * Construct the glyph and update the display field
     * @param {String} glyph The CSS class of glyph
     */
    _updateGlyphUI: function(glyph)
    {
    	if (this.img) 
        {
    		this.img.setVisible(false);
    	}
        
    	this.glyph.update('<span class="' + glyph + '"></span>');
    	this.glyph.setVisible(true);
        
        this.displayField.setHeight(21);
    	this.displayField.update(glyph);
    }
    
});