001/*
002 *  Copyright 2020 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.parameters.view;
017
018import java.io.IOException;
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024import java.util.Optional;
025import java.util.stream.Collectors;
026
027import org.apache.avalon.framework.component.Component;
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.avalon.framework.service.Serviceable;
031import org.apache.cocoon.ProcessingException;
032import org.apache.commons.collections4.MapUtils;
033import org.apache.commons.lang3.StringUtils;
034
035import org.ametys.cms.repository.Content;
036import org.ametys.core.observation.Event;
037import org.ametys.core.observation.ObservationManager;
038import org.ametys.core.ui.Callable;
039import org.ametys.core.user.CurrentUserProvider;
040import org.ametys.plugins.repository.AmetysObjectResolver;
041import org.ametys.plugins.repository.UnknownAmetysObjectException;
042import org.ametys.plugins.repository.data.holder.ModifiableModelAwareDataHolder;
043import org.ametys.runtime.i18n.I18nizableText;
044import org.ametys.runtime.model.ElementDefinition;
045import org.ametys.runtime.model.ModelItem;
046import org.ametys.runtime.model.SimpleViewItemGroup;
047import org.ametys.runtime.model.View;
048import org.ametys.runtime.model.ViewElement;
049import org.ametys.runtime.model.ViewItemGroup;
050import org.ametys.runtime.plugin.component.AbstractLogEnabled;
051import org.ametys.web.ObservationConstants;
052import org.ametys.web.parameters.ParametersManager;
053import org.ametys.web.repository.page.ModifiablePage;
054import org.ametys.web.repository.page.ModifiableZone;
055import org.ametys.web.repository.page.ModifiableZoneItem;
056import org.ametys.web.repository.page.Page;
057import org.ametys.web.repository.page.ZoneItem;
058import org.ametys.web.repository.page.ZoneItem.ZoneType;
059import org.ametys.web.repository.site.Site;
060import org.ametys.web.service.Service;
061import org.ametys.web.service.ServiceExtensionPoint;
062import org.ametys.web.skin.Skin;
063import org.ametys.web.skin.SkinTemplate;
064import org.ametys.web.skin.SkinTemplateZone;
065import org.ametys.web.skin.SkinsManager;
066
067/**
068 * Manager for view parameters
069 */
070public class ViewParametersDAO extends AbstractLogEnabled implements Component, Serviceable              
071{
072    /** Avalon Role */
073    public static final String ROLE = ViewParametersDAO.class.getName();
074    
075    /** The separator for model item name */
076    public static final String MODEL_ITEM_NAME_SEPARATOR = "$";
077    
078    /** The prefix for template view parameters */
079    public static final String PREFIX_TEMPLATE = "template";
080    
081    /** The prefix for zone view parameters */
082    public static final String PREFIX_ZONE = "zone";
083    
084    /** The prefix for zoneItem view parameters */
085    public static final String PREFIX_ZONE_ITEM = "zoneitem";
086    
087    /** The prefix for content view parameters */
088    public static final String PREFIX_CONTENT = "content";
089    
090    /** The prefix for service view parameters */
091    public static final String PREFIX_SERVICE = "service" + MODEL_ITEM_NAME_SEPARATOR + ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME;
092    
093    /** The Ametys object resolver */
094    protected AmetysObjectResolver _resolver;
095    
096    /** The skins manager */
097    protected SkinsManager _skinsManager;
098    
099    /** The service view parameters manager */
100    protected ServiceViewParametersManager _serviceViewParametersManager;
101    
102    /** The content view parameters manager */
103    protected ContentViewParametersManager _contentViewParametersManager;
104    
105    /** The service extension point */
106    protected ServiceExtensionPoint _serviceEP;
107    
108    /** The parameters manager */
109    protected ParametersManager _parametersManager;
110    
111    /** The observation manager */
112    protected ObservationManager _observationManager;
113    
114    /** The current user provider */
115    protected CurrentUserProvider _currentUserProvider;
116    
117    /** The view parameter manager */
118    protected ViewParametersManager _viewParametersManager;
119    
120    public void service(ServiceManager manager) throws ServiceException
121    {
122        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
123        _skinsManager = (SkinsManager) manager.lookup(SkinsManager.ROLE);
124        _serviceViewParametersManager = (ServiceViewParametersManager) manager.lookup(ServiceViewParametersManager.ROLE);
125        _contentViewParametersManager = (ContentViewParametersManager) manager.lookup(ContentViewParametersManager.ROLE);
126        _serviceEP = (ServiceExtensionPoint) manager.lookup(ServiceExtensionPoint.ROLE);
127        _parametersManager = (ParametersManager) manager.lookup(ParametersManager.ROLE);
128        _observationManager = (ObservationManager) manager.lookup(ObservationManager.ROLE);
129        _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE);
130        _viewParametersManager = (ViewParametersManager) manager.lookup(ViewParametersManager.ROLE);
131    }
132    
133    /**
134     * Get the definition of the created view of all view parameters
135     * @param pageId the page id
136     * @param zoneName the zone name (can be null)
137     * @param zoneItemId the zone item id (can be null)
138     * @return the JSON of view parameters
139     * @throws ProcessingException if a processing error occurred
140     */
141    @Callable
142    public Map<String, Object> getViewParametersDefinitions(String pageId, String zoneName, String zoneItemId) throws ProcessingException
143    {
144        Map<String, Object> response = new HashMap<>();
145        response.put("parameters", _createViewParametersDialogView(pageId, zoneName, zoneItemId).toJSON());
146        
147        return response;
148    }
149
150    /**
151     * Create the view of all view parameters
152     * @param pageId the page id
153     * @param zoneName the zone name (can be null)
154     * @param zoneItemId the zone item id (can be null)
155     * @return the view of all view parameters
156     */
157    protected View _createViewParametersDialogView(String pageId, String zoneName, String zoneItemId)
158    {
159        SimpleViewItemGroup mainGroup = new SimpleViewItemGroup();
160        mainGroup.setName("all-view-parameters-group");
161        mainGroup.setRole(ViewItemGroup.TAB_ROLE);
162        
163        ModifiablePage page = _getModifiablePage(pageId);
164        Site site = page.getSite();
165        Skin skin = _skinsManager.getSkin(site.getSkinId());
166        
167        SkinTemplate template = skin.getTemplate(page.getTemplate());
168        if (template != null)
169        {
170            _addTemplateViewItem(page, skin, template, mainGroup);
171    
172            Optional<ModifiableZoneItem> zoneItem = _getModifiableZoneItem(zoneItemId);
173            Optional<SkinTemplateZone> templateZone = _getSkinTemplateZone(template, zoneName, zoneItem);
174            if (templateZone.isPresent())
175            {
176                SkinTemplateZone skinTemplateZone = templateZone.get();
177                _addZoneViewItem(page, skin, template, skinTemplateZone, mainGroup);
178                
179                if (zoneItem.isPresent())
180                {
181                    _addZoneItemViewItem(skin, template, skinTemplateZone, zoneItem.get(), mainGroup);
182                }
183            }
184        }
185        
186        View view = new View();
187        view.addViewItem(mainGroup);
188        
189        return view;
190    }
191
192    /**
193     * Add template view item
194     * @param page the page (to determine inheritance)
195     * @param skin the skin
196     * @param template the template
197     * @param mainGroup the main group to add the template view
198     */
199    protected void _addTemplateViewItem(Page page, Skin skin, SkinTemplate template, SimpleViewItemGroup mainGroup)
200    {
201        String templateId = template.getId();
202        Optional<ViewParametersModel> templateViewParametersOptional = _viewParametersManager.getTemplateViewParametersModel(skin.getId(), templateId);
203        if (templateViewParametersOptional.isEmpty())
204        {
205            return;
206        }
207        
208        ViewParametersModel templateViewParameters = templateViewParametersOptional.get();
209        if (templateViewParameters.isNotEmpty())
210        {
211            SimpleViewItemGroup group = new SimpleViewItemGroup();
212            group.setName(templateId);
213            
214            Map<String, I18nizableText> parameters = new HashMap<>();
215            parameters.put("title", template.getLabel());
216            group.setLabel(new I18nizableText("plugin.web", "PLUGINS_WEB_VIEW_PARAMETERS_DIALOG_BOX_TEMPLATE_LABEL", parameters));
217            group.setRole(ViewItemGroup.FIELDSET_ROLE);
218            
219            Collection< ? extends ModelItem> inheritModelItems = templateViewParameters.getInheritedModelItems(page);
220
221            List< ? extends ModelItem> noInheritModelItems = templateViewParameters.getModelItems()
222                .stream()
223                .filter(m -> !inheritModelItems.contains(m))
224                .filter(m -> !(m.getName().equals(ViewParametersManager.TEMPLATE_INHERIT_MODEL_ITEM_NAME) && inheritModelItems.isEmpty()))
225                .collect(Collectors.toList());
226            
227            String prefix = PREFIX_TEMPLATE + MODEL_ITEM_NAME_SEPARATOR + template.getId() + MODEL_ITEM_NAME_SEPARATOR;
228            _viewParametersManager.includeModelItems(noInheritModelItems, prefix, group);
229
230            if (!inheritModelItems.isEmpty())
231            {
232                List<ModelItem> includeModelItems = _viewParametersManager.includeModelItems(inheritModelItems, prefix, group);
233                _viewParametersManager.setDisableConditions(prefix + ViewParametersManager.TEMPLATE_INHERIT_MODEL_ITEM_NAME, "false", includeModelItems);
234            }
235            
236            mainGroup.addViewItem(group);
237        }
238    }
239    
240    /**
241     * Add zone view item
242     * @param page the page (to determine inheritance)
243     * @param skin the skin
244     * @param template the template
245     * @param zone the zone
246     * @param mainGroup the main group to add the zone view
247     */
248    protected void _addZoneViewItem(Page page, Skin skin, SkinTemplate template, SkinTemplateZone zone, SimpleViewItemGroup mainGroup)
249    {
250        String zoneId = zone.getId();
251        Optional<ViewParametersModel> zoneViewParametersOptional = _viewParametersManager.getZoneViewParametersModel(skin.getId(), template.getId(), zoneId);
252        if (zoneViewParametersOptional.isEmpty())
253        {
254            return;
255        }
256        
257        ViewParametersModel zoneViewParameters = zoneViewParametersOptional.get();
258        if (zoneViewParameters.isNotEmpty())
259        {
260            SimpleViewItemGroup group = new SimpleViewItemGroup();
261            group.setName(zoneId);
262            
263            Map<String, I18nizableText> parameters = new HashMap<>();
264            parameters.put("title", zone.getLabel());
265            group.setLabel(new I18nizableText("plugin.web", "PLUGINS_WEB_VIEW_PARAMETERS_DIALOG_BOX_ZONE_LABEL", parameters));
266            group.setRole(ViewItemGroup.FIELDSET_ROLE);
267            
268            Collection< ? extends ModelItem> inheritModelItems = zoneViewParameters.getInheritedModelItems(page);
269
270            List< ? extends ModelItem> noInheritModelItems = zoneViewParameters.getModelItems()
271                    .stream()
272                    .filter(m -> !inheritModelItems.contains(m))
273                    .filter(m -> !(m.getName().equals(ViewParametersManager.ZONE_INHERIT_MODEL_ITEM_NAME) && inheritModelItems.isEmpty()))
274                    .collect(Collectors.toList());
275            
276            String prefix = PREFIX_ZONE + MODEL_ITEM_NAME_SEPARATOR + zoneId + MODEL_ITEM_NAME_SEPARATOR;
277            _viewParametersManager.includeModelItems(noInheritModelItems, prefix, group);
278            
279            if (!inheritModelItems.isEmpty())
280            {
281                List<ModelItem> includeModelItems = _viewParametersManager.includeModelItems(inheritModelItems, prefix, group);
282                _viewParametersManager.setDisableConditions(prefix + ViewParametersManager.ZONE_INHERIT_MODEL_ITEM_NAME, "false", includeModelItems);
283            }
284            
285            mainGroup.addViewItem(group);
286        }
287    }
288    
289    /**
290     * Add zone item view item and the service or content view items
291     * @param skin the skin
292     * @param template the template
293     * @param zone the zone
294     * @param zoneItem the zone item
295     * @param mainGroup the main group to add the zone item view
296     */
297    protected void _addZoneItemViewItem(Skin skin, SkinTemplate template, SkinTemplateZone zone, ZoneItem zoneItem, SimpleViewItemGroup mainGroup)
298    {
299        ModelItemViewsWrapper modelItemViews = new ModelItemViewsWrapper();
300        
301        String skinId = skin.getId();
302        Optional<ViewParametersModel> zoneItemViewParameters = _viewParametersManager.getZoneItemViewParametersModel(skinId, template.getId(), zone.getId());
303        modelItemViews.setZoneItemViewParameters(zoneItemViewParameters);
304        
305        ZoneType type = zoneItem.getType();
306        if (type == ZoneType.SERVICE)
307        {
308            _addServiceViewParameters(modelItemViews, zoneItem, skinId);
309        }
310        else if (type == ZoneType.CONTENT)
311        {
312            _addContentViewParameters(modelItemViews, zoneItem, skinId);
313        }
314        
315        _addZoneItemViewParameters(modelItemViews, zone, zoneItem, mainGroup);
316    }
317    
318    /**
319     * Add all view parameters of the zone item
320     * @param modelItemViews the model item views
321     * @param zone the zone
322     * @param zoneItem the zone item
323     * @param mainGroup the main group to add the zone item view
324     */
325    protected void _addZoneItemViewParameters(ModelItemViewsWrapper modelItemViews, SkinTemplateZone zone, ZoneItem zoneItem, SimpleViewItemGroup mainGroup)
326    {
327        if (modelItemViews.hasViewParameters())
328        {
329            SimpleViewItemGroup group = new SimpleViewItemGroup();
330            group.setName(zoneItem.getName());
331            group.setLabel(modelItemViews.getLabel());
332            group.setRole(ViewItemGroup.FIELDSET_ROLE);
333
334            if (modelItemViews.hasZoneItemViewParameters())
335            {
336                ViewParametersModel zoneItemViewParameters = modelItemViews.getZoneItemViewParameters().get();
337                
338                SimpleViewItemGroup zoneItemGroup = new SimpleViewItemGroup();
339                zoneItemGroup.setName(zoneItem.getName() + "_zoneItem");
340                
341                String prefix = PREFIX_ZONE_ITEM + MODEL_ITEM_NAME_SEPARATOR + zone.getId() + MODEL_ITEM_NAME_SEPARATOR;
342                _viewParametersManager.includeModelItems(zoneItemViewParameters.getModelItems(), prefix, zoneItemGroup);
343                
344                group.addViewItem(zoneItemGroup);
345            }
346            
347            if (modelItemViews.hasServiceOrContentViewParameters())
348            {
349                SimpleViewItemGroup serviceOrContentGroup = new SimpleViewItemGroup();
350                serviceOrContentGroup.setName(zoneItem.getName() + "_contentOrService");
351                
352                ViewElement viewElement = new ViewElement();
353                ElementDefinition<String> enumeratorViewDefinition = modelItemViews.getEnumeratorViewDefinition();
354                viewElement.setDefinition(enumeratorViewDefinition);
355                serviceOrContentGroup.addViewItem(viewElement);
356                
357                Map<String, ViewParametersModel> serviceOrContentViewParameters = modelItemViews.getServiceOrContentViewParameters();
358                for (String viewName : serviceOrContentViewParameters.keySet())
359                {
360                    ViewParametersModel viewParameters = serviceOrContentViewParameters.get(viewName);
361                    Collection< ? extends ModelItem> modelItems = viewParameters.getModelItems();
362                    
363                    String prefix = modelItemViews.getPrefix() + MODEL_ITEM_NAME_SEPARATOR + _viewParametersManager.normalizeViewName(viewName) + MODEL_ITEM_NAME_SEPARATOR;
364                    List<ModelItem> includeModelItems = _viewParametersManager.includeModelItems(modelItems, prefix, serviceOrContentGroup);
365                    _viewParametersManager.setDisableConditions(enumeratorViewDefinition.getName(), viewName, includeModelItems);
366                }
367                
368                group.addViewItem(serviceOrContentGroup);
369            }
370            
371            mainGroup.addViewItem(group);
372        }
373    }
374    
375    /**
376     * Add service view parameters to the model item views wrapper
377     * @param modelItemViews the model item views wrapper
378     * @param zoneItem the zone item
379     * @param skinId the skin id
380     */
381    protected void _addServiceViewParameters(ModelItemViewsWrapper modelItemViews, ZoneItem zoneItem, String skinId)
382    {
383        // The zone item contains a service
384        String serviceId = zoneItem.getServiceId();
385        Service service = _serviceEP.getExtension(serviceId);
386        
387        Map<String, I18nizableText> parameters = new HashMap<>();
388        parameters.put("title", service.getLabel());
389        modelItemViews.setLabel(new I18nizableText("plugin.web", "PLUGINS_WEB_VIEW_PARAMETERS_DIALOG_BOX_SERVICE_LABEL", parameters));
390        modelItemViews.setPrefix(PREFIX_SERVICE);
391        
392        ElementDefinition<String> serviceViewEnumerator = _viewParametersManager.getServiceViewEnumerator(serviceId);
393        if (serviceViewEnumerator != null)
394        {
395            modelItemViews.setEnumeratorViewDefinition(serviceViewEnumerator);
396            
397            Map<String, ViewParametersModel> serviceViewParametersModels = _viewParametersManager.getServiceViewParametersModels(skinId, serviceId);
398            for (String viewName : serviceViewParametersModels.keySet())
399            {
400                ViewParametersModel serviceViewParameters = serviceViewParametersModels.get(viewName);
401                modelItemViews.addServiceOrContentViewParameters(viewName, serviceViewParameters);
402            }
403        }
404    }
405    
406    /**
407     * Add content view parameters to the model item views wrapper
408     * @param modelItemViews the model item views wrapper
409     * @param zoneItem the zone item
410     * @param skinId the skin id
411     */
412    protected void _addContentViewParameters(ModelItemViewsWrapper modelItemViews, ZoneItem zoneItem, String skinId)
413    {
414        // The zone item contains a content
415        Content content = zoneItem.getContent();
416        List<String> parameters = new ArrayList<>();
417        parameters.add(content.getTitle());
418        modelItemViews.setLabel(new I18nizableText("plugin.web", "PLUGINS_WEB_VIEW_PARAMETERS_DIALOG_BOX_CONTENT_LABEL", parameters));
419        modelItemViews.setPrefix(PREFIX_CONTENT);
420        
421        ElementDefinition<String> elementDef = _viewParametersManager.getContentViewEnumerator(content);
422        modelItemViews.setEnumeratorViewDefinition(elementDef);
423        
424        Map<String, ViewParametersModel> contentViewParametersModels = _viewParametersManager.getContentViewParametersModels(skinId, content);
425        for (String viewName : contentViewParametersModels.keySet())
426        {
427            ViewParametersModel contentViewParameters = contentViewParametersModels.get(viewName);
428            modelItemViews.addServiceOrContentViewParameters(viewName, contentViewParameters);
429        }
430    }
431
432    /**
433     * Get the view parameters values
434     * @param pageId the page id
435     * @param zoneName the zone name (Can be null)
436     * @param zoneItemId the zone item id (Can be null)
437     * @return the values
438     */
439    @Callable
440    public Map<String, Object> getViewParametersValues(String pageId, String zoneName, String zoneItemId)
441    {
442        Map<String, Object> response = new HashMap<>();
443        Map<String, Object> values = new HashMap<>();
444
445        ModifiablePage page = _getModifiablePage(pageId);
446        Site site = page.getSite();
447        Skin skin = _skinsManager.getSkin(site.getSkinId());
448        
449        SkinTemplate template = skin.getTemplate(page.getTemplate());
450        if (template != null)
451        {
452            values.putAll(_getTemplateViewParametersValues(page, template));
453            
454            Optional<ModifiableZoneItem> zoneItem = _getModifiableZoneItem(zoneItemId);
455            Optional<SkinTemplateZone> templateZone = _getSkinTemplateZone(template, zoneName, zoneItem);
456            if (templateZone.isPresent())
457            {
458                SkinTemplateZone skinTemplateZone = templateZone.get();
459                values.putAll(_getZoneViewParametersValues(page, skinTemplateZone));
460    
461                if (zoneItem.isPresent())
462                {
463                    values.putAll(_getZoneItemViewParametersValues(page, skin, skinTemplateZone, zoneItem.get()));
464                }
465            }
466        }
467        
468        response.put("values", values);
469        return response;
470    }
471    
472    /**
473     * Get the template view parameters values
474     * @param page the page
475     * @param template the template
476     * @return the values
477     */
478    protected Map<String, Object> _getTemplateViewParametersValues(ModifiablePage page, SkinTemplate template)
479    {
480        Optional<ViewParametersModel> templateViewParameters = _viewParametersManager.getTemplateViewParametersModel(template);
481        if (templateViewParameters.isEmpty())
482        {
483            return MapUtils.EMPTY_SORTED_MAP;
484        }
485        
486        ModifiableModelAwareDataHolder pageViewParametersHolder = page.getTemplateParametersHolder();
487        Map<String, Object> templateValues = _parametersManager.getParametersValues(templateViewParameters.get().getModelItems(), pageViewParametersHolder, "");
488
489        String prefix = PREFIX_TEMPLATE + MODEL_ITEM_NAME_SEPARATOR + template.getId() + MODEL_ITEM_NAME_SEPARATOR;
490        return _parametersManager.addPrefixToParameters(templateValues, prefix);
491    }
492    
493    /**
494     * Get the zone view parameters values
495     * @param page the page
496     * @param skinZone the zone
497     * @return the values
498     */
499    protected Map<String, Object> _getZoneViewParametersValues(ModifiablePage page, SkinTemplateZone skinZone)
500    {
501        Optional<ViewParametersModel> zoneViewParameters = _viewParametersManager.getZoneViewParametersModel(skinZone);
502        if (zoneViewParameters.isEmpty())
503        {
504            return MapUtils.EMPTY_SORTED_MAP;
505        }
506        
507        String zoneName = skinZone.getId();
508        if (page.hasZone(zoneName))
509        {
510            ModifiableZone zone = page.getZone(zoneName);
511    
512            ModifiableModelAwareDataHolder zoneViewParametersHolder = zone.getZoneParametersHolder();
513            Map<String, Object> zoneValues = _parametersManager.getParametersValues(zoneViewParameters.get().getModelItems(), zoneViewParametersHolder, "");
514            
515            String prefix = PREFIX_ZONE + MODEL_ITEM_NAME_SEPARATOR + zoneName + MODEL_ITEM_NAME_SEPARATOR;
516            return _parametersManager.addPrefixToParameters(zoneValues, prefix);
517        }
518        
519        return MapUtils.EMPTY_SORTED_MAP;
520    }
521    
522    /**
523     * Get the zone item view parameters values
524     * @param page the page
525     * @param skin the skin
526     * @param skinZone the zone
527     * @param zoneItem the zone item
528     * @return the values
529     */
530    protected Map<String, Object> _getZoneItemViewParametersValues(ModifiablePage page, Skin skin, SkinTemplateZone skinZone, ModifiableZoneItem zoneItem)
531    {
532        Map<String, Object> values = new HashMap<>();
533        
534        ModifiableModelAwareDataHolder zoneItemViewParametersHolder = zoneItem.getZoneItemParametersHolder();
535        Optional<ViewParametersModel> zoneItemViewParameters = skinZone.getZoneItemViewParameters();
536        if (zoneItemViewParameters.isEmpty())
537        {
538            return MapUtils.EMPTY_SORTED_MAP;
539        }
540        
541        Map<String, Object> zoneItemValues = _parametersManager.getParametersValues(zoneItemViewParameters.get().getModelItems(), zoneItemViewParametersHolder, "");
542        String prefix = PREFIX_ZONE_ITEM + MODEL_ITEM_NAME_SEPARATOR + skinZone.getId() + MODEL_ITEM_NAME_SEPARATOR;
543        values.putAll(_parametersManager.addPrefixToParameters(zoneItemValues, prefix));
544        
545        if (zoneItem.getType() == ZoneType.SERVICE)
546        {
547            values.putAll(_getServiceViewParametersValues(skin, zoneItem));
548        }
549        else if (zoneItem.getType() == ZoneType.CONTENT)
550        {
551            values.putAll(_getContentViewParametersValues(skin, zoneItem));
552        }
553        
554        return values;
555    }
556    
557    /**
558     * Get the service view parameters values
559     * @param skin the skin
560     * @param zoneItem the zone item
561     * @return the values
562     */
563    protected Map<String, Object> _getServiceViewParametersValues(Skin skin, ModifiableZoneItem zoneItem)
564    {
565        Map<String, Object> values = new HashMap<>();
566        
567        ModifiableModelAwareDataHolder serviceParameters = zoneItem.getServiceParameters();
568        if (serviceParameters.hasDefinition(ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME))
569        {
570            values.put(ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME, serviceParameters.getValue(ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME));
571        }
572        
573        Map<String, ViewParametersModel> serviceViewParametersModels = _viewParametersManager.getServiceViewParametersModels(skin.getId(), zoneItem.getServiceId());
574        for (String viewName : serviceViewParametersModels.keySet())
575        {
576            ViewParametersModel serviceViewParameters = serviceViewParametersModels.get(viewName);
577            ModifiableModelAwareDataHolder serviceViewParametersHolder = zoneItem.getServiceViewParametersHolder(viewName);
578            
579            Map<String, Object> serviceValues = _parametersManager.getParametersValues(serviceViewParameters.getModelItems(), serviceViewParametersHolder, "");
580            String prefix = PREFIX_SERVICE + MODEL_ITEM_NAME_SEPARATOR + _viewParametersManager.normalizeViewName(viewName) + MODEL_ITEM_NAME_SEPARATOR;
581            values.putAll(_parametersManager.addPrefixToParameters(serviceValues, prefix));
582        }
583        
584        return values;
585    }
586    
587    /**
588     * Get the content view parameters values
589     * @param skin the skin
590     * @param zoneItem the zone item
591     * @return the values
592     */
593    protected Map<String, Object> _getContentViewParametersValues(Skin skin, ModifiableZoneItem zoneItem)
594    {
595        Map<String, Object> values = new HashMap<>();
596        
597        values.put(ViewParametersManager.CONTENT_VIEW_MODEL_ITEM_NAME, zoneItem.getViewName());
598        
599        Map<String, ViewParametersModel> contentViewParametersModels = _viewParametersManager.getContentViewParametersModels(skin.getId(), zoneItem.getContent());
600        for (String viewName : contentViewParametersModels.keySet())
601        {
602            ViewParametersModel contentViewParameters = contentViewParametersModels.get(viewName);
603            ModifiableModelAwareDataHolder contentViewParametersHolder = zoneItem.getContentViewParametersHolder(viewName);
604                
605            Map<String, Object> serviceValues = _parametersManager.getParametersValues(contentViewParameters.getModelItems(), contentViewParametersHolder, "");
606            String prefix = PREFIX_CONTENT + MODEL_ITEM_NAME_SEPARATOR + _viewParametersManager.normalizeViewName(viewName) + MODEL_ITEM_NAME_SEPARATOR;
607            values.putAll(_parametersManager.addPrefixToParameters(serviceValues, prefix));
608        }
609        
610        return values;
611    }
612    
613    /**
614     * Set view parameters values
615     * @param pageId the page id
616     * @param zoneName the zone name (Can be null)
617     * @param zoneItemId the zone item id (Can be null)
618     * @param parameterValues the parameter values
619     * @return results map
620     * @throws IOException If an error occurred
621     */
622    @Callable
623    public Map<String, Object> setViewParametersValues(String pageId, String zoneName, String zoneItemId, Map<String, Object> parameterValues) throws IOException
624    {
625        Map<String, Object> results = new HashMap<>();
626        Map<String, List<I18nizableText>> allErrors = new HashMap<>();
627        
628        ModifiablePage page = _getModifiablePage(pageId);
629        Site site = page.getSite();
630        Skin skin = _skinsManager.getSkin(site.getSkinId());
631        SkinTemplate template = skin.getTemplate(page.getTemplate());
632        
633        if (template != null)
634        {
635            allErrors.putAll(_setTemplateViewParameters(page, template, parameterValues));
636    
637            Optional<ModifiableZoneItem> zoneItem = _getModifiableZoneItem(zoneItemId);
638            Optional<SkinTemplateZone> templateZone = _getSkinTemplateZone(template, zoneName, zoneItem);
639            if (templateZone.isPresent())
640            {
641                SkinTemplateZone skinTemplateZone = templateZone.get();
642                allErrors.putAll(_setZoneViewParameters(page, skinTemplateZone, parameterValues));
643                
644                if (zoneItem.isPresent())
645                {
646                    allErrors.putAll(_setZoneItemViewParameters(page, skin, skinTemplateZone, zoneItem.get(), parameterValues));
647                }
648            }
649        }
650        
651        if (!allErrors.isEmpty())
652        {
653            results.put("errors", allErrors);
654            return results;
655        }
656        
657        page.saveChanges();
658        
659        Map<String, Object> eventParams = new HashMap<>();
660        eventParams.put(ObservationConstants.ARGS_PAGE, page);
661        _observationManager.notify(new Event(ObservationConstants.EVENT_VIEW_PARAMETERS_MODIFIED, _currentUserProvider.getUser(), eventParams));
662        
663        return results;
664    }
665    
666    /**
667     * Set template view parameters values
668     * @param page the page
669     * @param template the template
670     * @param parameterValues the parameter values
671     * @return the errors
672     */
673    protected Map<String, List<I18nizableText>> _setTemplateViewParameters(ModifiablePage page, SkinTemplate template, Map<String, Object> parameterValues)
674    {
675        Optional<ViewParametersModel> templateViewParameters = _viewParametersManager.getTemplateViewParametersModel(template);
676        if (templateViewParameters.isEmpty())
677        {
678            return MapUtils.EMPTY_SORTED_MAP;
679        }
680        
681        String templatePrefix = PREFIX_TEMPLATE + MODEL_ITEM_NAME_SEPARATOR + template.getId() + MODEL_ITEM_NAME_SEPARATOR;
682        Map<String, Object> templateParameters = _parametersManager.getParametersStartWithPrefix(parameterValues, templatePrefix);
683        
684        // Do this because can't set null value to boolean model item. FIXME CMS-10275
685        if (!templateParameters.containsKey(ViewParametersManager.TEMPLATE_INHERIT_MODEL_ITEM_NAME))
686        {
687            templateParameters.put(ViewParametersManager.TEMPLATE_INHERIT_MODEL_ITEM_NAME, true);
688        }
689        
690        ModifiableModelAwareDataHolder pageViewParametersHolder = page.getTemplateParametersHolder();
691        return _parametersManager.setParameterValues(pageViewParametersHolder, templateViewParameters.get().getModelItems(), templateParameters);
692    }
693    
694    /**
695     * Set zone view parameters values
696     * @param page the page
697     * @param skinZone the zone
698     * @param parameterValues the parameter values
699     * @return the errors
700     */
701    protected Map<String, List<I18nizableText>> _setZoneViewParameters(ModifiablePage page, SkinTemplateZone skinZone, Map<String, Object> parameterValues)
702    {
703        Optional<ViewParametersModel> zoneViewParameters = _viewParametersManager.getZoneViewParametersModel(skinZone);
704        if (zoneViewParameters.isEmpty())
705        {
706            return MapUtils.EMPTY_SORTED_MAP;
707        }
708
709        String zoneName = skinZone.getId();
710        ModifiableZone zone = page.hasZone(zoneName) ? page.getZone(zoneName) : page.createZone(zoneName);
711        
712        String zonePrefix = PREFIX_ZONE + MODEL_ITEM_NAME_SEPARATOR + zoneName + MODEL_ITEM_NAME_SEPARATOR;
713        Map<String, Object> zoneParameters = _parametersManager.getParametersStartWithPrefix(parameterValues, zonePrefix);
714        
715        // Do this because can't set null value to boolean model item. FIXME CMS-10275
716        if (!zoneParameters.containsKey(ViewParametersManager.ZONE_INHERIT_MODEL_ITEM_NAME))
717        {
718            zoneParameters.put(ViewParametersManager.ZONE_INHERIT_MODEL_ITEM_NAME, true);
719        }
720        
721        ModifiableModelAwareDataHolder zoneViewParametersHolder = zone.getZoneParametersHolder();
722        return _parametersManager.setParameterValues(zoneViewParametersHolder, zoneViewParameters.get().getModelItems(), zoneParameters);
723    }
724    
725    /**
726     * Set zone item view parameters values
727     * @param page the page
728     * @param skin the skin
729     * @param skinZone the zone
730     * @param zoneItem the zone item
731     * @param parameterValues the parameter values
732     * @return the errors
733     */
734    protected Map<String, List<I18nizableText>> _setZoneItemViewParameters(ModifiablePage page, Skin skin, SkinTemplateZone skinZone, ModifiableZoneItem zoneItem, Map<String, Object> parameterValues)
735    {
736        Map<String, List<I18nizableText>> allErrors = new HashMap<>();
737        
738        Optional<ViewParametersModel> zoneItemViewParameters = skinZone.getZoneItemViewParameters();
739        if (zoneItemViewParameters.isEmpty())
740        {
741            return allErrors;
742        }
743        
744        ModifiableModelAwareDataHolder zoneItemViewParametersHolder = zoneItem.getZoneItemParametersHolder();
745        
746        String zoneItemPrefix = PREFIX_ZONE_ITEM + MODEL_ITEM_NAME_SEPARATOR + skinZone.getId() + MODEL_ITEM_NAME_SEPARATOR;
747        Map<String, Object> zoneItemParameters = _parametersManager.getParametersStartWithPrefix(parameterValues, zoneItemPrefix);
748        
749        allErrors.putAll(_parametersManager.setParameterValues(zoneItemViewParametersHolder, zoneItemViewParameters.get().getModelItems(), zoneItemParameters));
750        
751        if (zoneItem.getType() == ZoneType.SERVICE)
752        {
753            allErrors.putAll(_setServiceViewParameters(skin, zoneItem, parameterValues));
754        }
755        else if (zoneItem.getType() == ZoneType.CONTENT)
756        {
757            allErrors.putAll(_setContentViewParameters(skin, zoneItem, parameterValues));
758        }
759        
760        return allErrors;
761    }
762    
763    /**
764     * Set service view parameters values
765     * @param skin the skin
766     * @param zoneItem the zone item
767     * @param parameterValues the parameter values
768     * @return the errors
769     */
770    protected Map<String, List<I18nizableText>> _setServiceViewParameters(Skin skin, ModifiableZoneItem zoneItem, Map<String, Object> parameterValues)
771    {
772        String viewName = (String) parameterValues.get(ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME);
773        if (StringUtils.isEmpty(viewName))
774        {
775            // We have a service with no view parameters
776            return MapUtils.EMPTY_SORTED_MAP;
777        }
778        
779        String serviceId = zoneItem.getServiceId();
780        ModifiableModelAwareDataHolder serviceParameters = zoneItem.getServiceParameters();
781        serviceParameters.setValue(ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME, viewName);
782        
783        Optional<ViewParametersModel> serviceViewParameters = _viewParametersManager.getServiceViewParametersModel(skin.getId(), serviceId, viewName);
784        if (serviceViewParameters.isEmpty())
785        {
786            return MapUtils.EMPTY_SORTED_MAP;
787        }
788        
789        ModifiableModelAwareDataHolder serviceViewParametersHolder = zoneItem.getServiceViewParametersHolder(viewName);
790        
791        String servicePrefix = PREFIX_SERVICE + MODEL_ITEM_NAME_SEPARATOR + _viewParametersManager.normalizeViewName(viewName) + MODEL_ITEM_NAME_SEPARATOR;
792        Map<String, Object> parameters = _parametersManager.getParametersStartWithPrefix(parameterValues, servicePrefix);
793        
794        return _parametersManager.setParameterValues(serviceViewParametersHolder, serviceViewParameters.get().getModelItems(), parameters);
795    }
796    
797    /**
798     * Set content view parameters values
799     * @param skin the skin
800     * @param zoneItem the zone item
801     * @param parameterValues the parameter values
802     * @return the errors
803     */
804    protected Map<String, List<I18nizableText>> _setContentViewParameters(Skin skin, ModifiableZoneItem zoneItem, Map<String, Object> parameterValues)
805    {
806        String viewName = (String) parameterValues.get(ViewParametersManager.CONTENT_VIEW_MODEL_ITEM_NAME);
807        if (StringUtils.isEmpty(viewName))
808        {
809            // We have a content with no view parameters
810            return MapUtils.EMPTY_SORTED_MAP;
811        }
812
813        Content content = zoneItem.getContent();
814        zoneItem.setViewName(viewName);
815        Optional<ViewParametersModel> contentViewParameters = _viewParametersManager.getContentViewParametersModel(skin.getId(), content, viewName);
816        if (contentViewParameters.isEmpty())
817        {
818            return MapUtils.EMPTY_SORTED_MAP;
819        }
820        
821        ModifiableModelAwareDataHolder contentViewParametersHolder = zoneItem.getContentViewParametersHolder(viewName);
822        
823        String contentPrefix = PREFIX_CONTENT + MODEL_ITEM_NAME_SEPARATOR + _viewParametersManager.normalizeViewName(viewName) + MODEL_ITEM_NAME_SEPARATOR;
824        Map<String, Object> contentParameters = _parametersManager.getParametersStartWithPrefix(parameterValues, contentPrefix);
825        
826        return _parametersManager.setParameterValues(contentViewParametersHolder, contentViewParameters.get().getModelItems(), contentParameters);
827    }
828    
829    /**
830     * Get the modifiable page from id
831     * @param pageId the page id
832     * @return the modifiable page
833     */
834    protected ModifiablePage _getModifiablePage(String pageId)
835    {
836        try
837        {
838            Page page = _resolver.resolveById(pageId);
839            if (!(page instanceof ModifiablePage))
840            {
841                throw new IllegalArgumentException("The non-modifiable page (" + pageId + ") can't have view parameters");
842            }
843            
844            return (ModifiablePage) page;
845            
846        }
847        catch (UnknownAmetysObjectException e)
848        {
849            throw new IllegalArgumentException("An error occured getting the modifiable page from id " + pageId, e);
850        }
851    }
852    
853    /**
854     * Get the modifiable zone item from id
855     * @param zoneItemId the zone item id
856     * @return the modifiable zone item
857     */
858    protected Optional<ModifiableZoneItem> _getModifiableZoneItem(String zoneItemId)
859    {
860        if (StringUtils.isNotBlank(zoneItemId))
861        {
862            try
863            {
864                ZoneItem zoneItem = _resolver.resolveById(zoneItemId);
865                if (!(zoneItem instanceof ModifiableZoneItem))
866                {
867                    throw new IllegalArgumentException("The non-modifiable zone item (" + zoneItemId + ") can't have view parameters");
868                }
869                
870                return Optional.of((ModifiableZoneItem) zoneItem);
871                
872            }
873            catch (UnknownAmetysObjectException e)
874            {
875                throw new IllegalArgumentException("An error occured getting the modifiable zone item from id " + zoneItemId, e);
876            }
877        }
878        
879        return Optional.empty();
880    }
881    
882    /**
883     * Get the skin template zone
884     * @param template the template
885     * @param zoneName the zone name
886     * @param zoneItem the zone item
887     * @return the skin template zone
888     */
889    protected Optional<SkinTemplateZone> _getSkinTemplateZone(SkinTemplate template, String zoneName, Optional<ModifiableZoneItem> zoneItem)
890    {
891        if (StringUtils.isNotBlank(zoneName))
892        {
893            return Optional.ofNullable(template.getZone(zoneName));
894        }
895        else if (zoneItem.isPresent())
896        {
897            String name = zoneItem.get().getZone().getName();
898            return Optional.ofNullable(template.getZone(name));
899        }
900        
901        return Optional.empty();
902    }
903    
904    /**
905     * Class representing a model item and its view parameters
906     */
907    static class ModelItemViewsWrapper
908    {
909        I18nizableText _label;
910        Optional<ViewParametersModel> _zoneItemViewParameters;
911        Map<String, ViewParametersModel> _contentOrServiceViewParameters;
912        ElementDefinition<String> _enumeratorViewDefinition;
913        String _prefix;
914        
915        ModelItemViewsWrapper()
916        {
917            this._label = null;
918            this._zoneItemViewParameters = null;
919            this._contentOrServiceViewParameters = new HashMap<>();
920            this._enumeratorViewDefinition = null;
921            this._prefix = StringUtils.EMPTY;
922        }
923        
924        I18nizableText getLabel()
925        {
926            return this._label;
927        }
928
929        void setLabel(I18nizableText label)
930        {
931            this._label = label;
932        }
933        
934        Optional<ViewParametersModel> getZoneItemViewParameters()
935        {
936            return this._zoneItemViewParameters;
937        }
938        
939        void setZoneItemViewParameters(Optional<ViewParametersModel> viewParameters)
940        {
941            this._zoneItemViewParameters = viewParameters;
942        }
943        
944        Map<String, ViewParametersModel> getServiceOrContentViewParameters()
945        {
946            return this._contentOrServiceViewParameters;
947        }
948        
949        void addServiceOrContentViewParameters(String viewName, ViewParametersModel serviceViewParameters)
950        {
951            this._contentOrServiceViewParameters.put(viewName, serviceViewParameters);
952        }
953
954        ElementDefinition<String> getEnumeratorViewDefinition()
955        {
956            return this._enumeratorViewDefinition;
957        }
958        
959        void setEnumeratorViewDefinition(ElementDefinition<String> elementDefinition)
960        {
961            this._enumeratorViewDefinition = elementDefinition;
962        }
963        
964        String getPrefix()
965        {
966            return this._prefix;
967        }
968        
969        void setPrefix(String prefix)
970        {
971            this._prefix = prefix;
972        }
973        
974        boolean hasZoneItemViewParameters()
975        {
976            return _zoneItemViewParameters.isPresent() && _zoneItemViewParameters.get().isNotEmpty();
977        }
978        
979        boolean hasServiceOrContentViewParameters()
980        {
981            boolean hasViewParameters = false;
982            for (ViewParametersModel viewParameters : _contentOrServiceViewParameters.values())
983            {
984                hasViewParameters = viewParameters.isNotEmpty() || hasViewParameters;
985            }
986            
987            return hasViewParameters;
988        }
989        
990        boolean hasViewParameters()
991        {
992            return hasZoneItemViewParameters() || hasServiceOrContentViewParameters();
993        }
994    }
995}