001/*
002 *  Copyright 2014 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.web.clientsideelement.styles;
017
018import java.util.Collections;
019import java.util.Date;
020import java.util.HashMap;
021import java.util.List;
022import java.util.Map;
023
024import org.apache.avalon.framework.configuration.Configuration;
025import org.apache.avalon.framework.configuration.ConfigurationException;
026import org.apache.avalon.framework.service.ServiceException;
027import org.apache.avalon.framework.service.ServiceManager;
028import org.apache.commons.lang3.StringUtils;
029import org.apache.excalibur.source.Source;
030import org.apache.excalibur.source.SourceResolver;
031
032import org.ametys.cms.clientsideelement.styles.StaticHTMLEditorStyleExtension;
033import org.ametys.cms.clientsideelement.styles.Style;
034import org.ametys.cms.clientsideelement.styles.StyleCategory;
035import org.ametys.web.repository.site.Site;
036import org.ametys.web.repository.site.SiteManager;
037import org.ametys.web.skin.Skin;
038import org.ametys.web.skin.SkinConfigurationHelper;
039import org.ametys.web.skin.SkinsManager;
040
041/**
042 * Based on a configuration like the StaticHTMLEditorStyleExtension but the file is located inside the current skin directory (skin/conf/edition-styles.xml).
043 */
044public class SkinHTMLEditorStyleExtension extends StaticHTMLEditorStyleExtension
045{
046    /** The assocation skinId lastUpdateDate ; to know for a given skin when its conf file was read for the last time */
047    protected Map<String, Long> _lastUpdates = new HashMap<>();
048    /** The assocation skinId Style ; to know for a given skin its style */
049    protected Map<String, StyleCategory> _paraStyleCategories = new HashMap<>();
050    /** The assocation skinId Style ; to know for a given skin its style */
051    protected Map<String, StyleCategory> _tableStyleCategories = new HashMap<>();
052    /** The assocation skinId Style ; to know for a given skin its style */
053    protected Map<String, StyleCategory> _imageStyleCategories = new HashMap<>();
054    /** The assocation skinId Style ; to know for a given skin its style */
055    protected Map<String, StyleCategory> _linkStyleCategories = new HashMap<>();
056    /** The assocation skinId Style ; to know for a given skin its style */
057    protected Map<String, StyleCategory> _ulStyleCategories = new HashMap<>();
058    /** The assocation skinId Style ; to know for a given skin its style */
059    protected Map<String, StyleCategory> _olStyleCategories = new HashMap<>();
060    
061    /** The excalibur source resolver */
062    protected SourceResolver _sourceResolver;
063    /** The sites manager */
064    protected SiteManager _siteManager;
065    /** The skins manager */
066    protected SkinsManager _skinsManager;
067    /** The helper for inheritable skin configuration */
068    protected SkinConfigurationHelper _skinConfigurationHelper;
069    
070    @Override
071    public void service(ServiceManager manager) throws ServiceException
072    {
073        super.service(manager);
074        _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
075        _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE);
076        _skinsManager = (SkinsManager) manager.lookup(SkinsManager.ROLE);
077        _skinConfigurationHelper = (SkinConfigurationHelper) manager.lookup(SkinConfigurationHelper.ROLE);
078    }
079    
080    @Override
081    public void configure(Configuration configuration) throws ConfigurationException
082    {
083        // Do nothing
084    }
085    
086    @Override
087    protected String _getImport(Configuration configuration, Map<String, Object> contextualParameters)
088    {
089        String siteId = (String) contextualParameters.get("siteName");
090        if (siteId == null)
091        {
092            getLogger().info("Cannot determine the current skin because cannot determine current site. Continue as if there is no HTML skin styles.");
093            return null;
094        }
095
096        Site site = _siteManager.getSite(siteId);
097        String skinId = site.getSkinId();
098
099        String boURL = "/skins/" + skinId + "/resources/";
100        
101        String uri = configuration.getValue(null);
102        return StringUtils.isBlank(uri) ? null : boURL + uri;
103    }
104
105    
106    @Override
107    public StyleCategory getPara(Map<String, Object> contextualParameters)
108    {
109        String currentSkin = _updateStyleCategories(contextualParameters);
110        return _paraStyleCategories.get(currentSkin);
111    }
112    @Override
113    public StyleCategory getImage(Map<String, Object> contextualParameters)
114    {
115        String currentSkin = _updateStyleCategories(contextualParameters);
116        return _imageStyleCategories.get(currentSkin);
117    }
118    @Override
119    public StyleCategory getLink(Map<String, Object> contextualParameters)
120    {
121        String currentSkin = _updateStyleCategories(contextualParameters);
122        return _linkStyleCategories.get(currentSkin);
123    }
124    @Override
125    public StyleCategory getOrderedList(Map<String, Object> contextualParameters)
126    {
127        String currentSkin = _updateStyleCategories(contextualParameters);
128        return _olStyleCategories.get(currentSkin);
129    }
130    @Override
131    public StyleCategory getTable(Map<String, Object> contextualParameters)
132    {
133        String currentSkin = _updateStyleCategories(contextualParameters);
134        return _tableStyleCategories.get(currentSkin);
135    }
136    @Override
137    public StyleCategory getUnorderedList(Map<String, Object> contextualParameters)
138    {
139        String currentSkin = _updateStyleCategories(contextualParameters);
140        return _ulStyleCategories.get(currentSkin);
141    }
142    
143    /**
144     * Update if necessary the values associated with the current skin
145     * @param contextualParameters Contextuals parameters transmitted by the environment.
146     * @return The current skin 
147     */
148    protected String _updateStyleCategories(Map<String, Object> contextualParameters)
149    {
150        String siteId = (String) contextualParameters.get("siteName");
151        if (siteId == null)
152        {
153            getLogger().info("Cannot determine the current skin because cannot determine current site. Continue as if there is no HTML skin styles.");
154            return null;
155        }
156
157        Site site = _siteManager.getSite(siteId);
158        String skinId = site.getSkinId();
159
160        String url = "skin:" + skinId + "://conf/edition-styles.xml"; 
161        
162        Source configurationFile = null;
163        try
164        {
165            configurationFile = _sourceResolver.resolveURI(url);
166            if (configurationFile.exists())
167            {
168                Long lastUpdate = _lastUpdates.get(skinId);
169                
170                if (lastUpdate == null || lastUpdate < configurationFile.getLastModified())
171                {
172                    Skin skin = _skinsManager.getSkin(skinId);
173                    Configuration configuration = _skinConfigurationHelper.getInheritanceMergedConfiguration(skin, "conf/edition-styles.xml", this.getClass().getResourceAsStream("skin-htmleditor-style-merge.xsl"));
174                    
175                    StyleCategory paraStyleCategory = _configureStyleCategory(configuration.getChild("para"), "skin." + skinId, null, contextualParameters);
176                    StyleCategory imageStyleCategory = _configureStyleCategory(configuration.getChild("image"), "skin." + skinId, IMAGE_DEFAULT_ICONS, contextualParameters);
177                    StyleCategory tableStyleCategory = _configureStyleCategory(configuration.getChild("table"), "skin." + skinId, TABLE_DEFAULT_ICONS, contextualParameters);
178                    StyleCategory linkStyleCategory = _configureStyleCategory(configuration.getChild("link"), "skin." + skinId, LINK_DEFAULT_ICONS, contextualParameters);
179                    StyleCategory ulStyleCategory = _configureStyleCategory(configuration.getChild("unorderedlist"), "skin." + skinId, UL_DEFAULT_ICONS, contextualParameters);
180                    StyleCategory olStyleCategory = _configureStyleCategory(configuration.getChild("orderedlist"), "skin." + skinId, OL_DEFAULT_ICONS, contextualParameters);
181                    
182                    _paraStyleCategories.put(skinId, paraStyleCategory);
183                    _imageStyleCategories.put(skinId, imageStyleCategory);
184                    _tableStyleCategories.put(skinId, tableStyleCategory);
185                    _linkStyleCategories.put(skinId, linkStyleCategory);
186                    _ulStyleCategories.put(skinId, ulStyleCategory);
187                    _olStyleCategories.put(skinId, olStyleCategory);
188                    
189                    _lastUpdates.put(skinId, configurationFile.getLastModified());
190                }
191            }
192            else
193            {
194                _defaultValues(skinId);
195            }
196        }
197        catch (Exception e)
198        {
199            _defaultValues(skinId);
200            if (getLogger().isWarnEnabled())
201            {
202                getLogger().warn("Cannot read the configuration file " + url + ". Continue as if file was not existing", e);
203            }
204        }
205        
206        return skinId;
207    }
208    
209    /**
210     * Set default values for the given skin
211     * @param skinId The skin
212     */
213    protected void _defaultValues(String skinId)
214    {
215        List<Style> emptyList = Collections.emptyList();
216        _paraStyleCategories.put(skinId, new StyleCategory(Collections.EMPTY_SET, Collections.EMPTY_SET, emptyList));
217        _lastUpdates.put(skinId, new Date().getTime());
218    }
219}