001/*
002 *  Copyright 2019 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.runtime.config;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.Comparator;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024import java.util.Map.Entry;
025
026import org.ametys.runtime.i18n.I18nizableText;
027import org.ametys.runtime.model.CategorizedElementDefinitionHelper;
028import org.ametys.runtime.model.CategorizedElementDefinitionWrapper;
029import org.ametys.runtime.model.ElementDefinition;
030import org.ametys.runtime.model.Model;
031import org.ametys.runtime.model.ModelItem;
032import org.ametys.runtime.model.ModelItemGroup;
033import org.ametys.runtime.model.ModelViewItem;
034import org.ametys.runtime.model.ModelViewItemGroup;
035import org.ametys.runtime.model.View;
036import org.ametys.runtime.model.ViewElement;
037import org.ametys.runtime.model.ViewItemGroup;
038
039/**
040 * Helper for {@link ConfigParameterDefinitionWrapper}
041 */
042public final class ConfigParameterDefinitionHelper
043{
044    private ConfigParameterDefinitionHelper()
045    {
046        //Nothing
047    }
048    
049    /**
050     * Get definitions of all elements parsed in this {@link CategorizedElementDefinitionWrapper} {@link Collection}, as a flat map.
051     * @param elements a {@link Collection} of {@link CategorizedElementDefinitionWrapper}
052     * @return a map with the definition name as key, containing all definitions
053     */
054    public static Map<String, ElementDefinition> getFlatDefinitions(Collection<ConfigParameterDefinitionWrapper> elements)
055    {
056        Map<String, ElementDefinition> flatDefinitions = new HashMap<>();
057        for (ConfigParameterDefinitionWrapper element : elements)
058        {
059            ElementDefinition definition = element.getDefinition();
060            flatDefinitions.put(definition.getName(), definition);
061        }
062        return flatDefinitions;
063    }
064    
065    /**
066     * Categorize the ModlItems based on the informations in the {@link CategorizedElementDefinitionWrapper} collection
067     * Category and groups are not sorted, only definitions, based on the position.
068     * Sorting of category and groups have to be done when the view is created (each usage can be different)
069     * @param elements collection of categorized elements
070     * @return a list of {@link ModelItem} with the correct tree (category/group/definitions)
071     */
072    public static List<ModelItem> categorizeConfigParameters(Collection<ConfigParameterDefinitionWrapper> elements)
073    {
074        Model model = ConfigManager.getInstance();
075        Map<I18nizableText, Map<I18nizableText, List<ConfigParameterDefinitionWrapper>>> categories = CategorizedElementDefinitionHelper.categorizeElementDefinitionWrappers(elements);
076        //This list is not sorted, only definition are sorted, not groups.
077        //Groups should be sorted elsewhere (when creating the view for example)
078        List<ModelItem> modelItems = new ArrayList<>();
079        for (Entry<I18nizableText, Map<I18nizableText, List<ConfigParameterDefinitionWrapper>>> categoryEntry : categories.entrySet())
080        {
081            ModelItemGroup category = new ModelItemGroup();
082            category.setModel(model);
083            category.setLabel(categoryEntry.getKey());
084            modelItems.add(category);
085            Map<I18nizableText, List<ConfigParameterDefinitionWrapper>> values = categoryEntry.getValue();
086            for (Entry<I18nizableText, List<ConfigParameterDefinitionWrapper>> groupEntry : values.entrySet())
087            {
088                ModelItemGroup group = new ModelItemGroup();
089                group.setModel(model);
090                group.setLabel(groupEntry.getKey());
091                category.addChild(group);
092                
093                for (ConfigParameterDefinitionWrapper orderedDefinition : groupEntry.getValue())
094                {
095                    ElementDefinition definition = orderedDefinition.getDefinition();
096                    definition.setParent(group);
097                    
098                    group.addChild(definition, orderedDefinition.isGroupSwitch());
099                }
100            }
101        }
102        return modelItems;
103    }
104    
105    /**
106     * Generate the view for a list of {@link ModelItem}, using comparators to sort the categories and the groups
107     * This works only on the very specific categories/group/fieldset hierarchy and an {@link IllegalArgumentException} will be thrown if the hierarchy is incorrect.
108     * @param categories list of {@link ModelItem}
109     * @param categoriesComparator {@link Comparator} used for the categories (can be null to keep order)
110     * @param groupsComparator {@link Comparator} for the groups (can be null to keep order)
111     * @param elementsComparator {@link Comparator} for the elements (can be null to keep order)
112     * @return A {@link View} ordered from the {@link ModelItem} using the {@link Comparator}
113     * @throws IllegalArgumentException the hierarchy of the categories/groups/elements is incorrect
114     */
115    public static View buildConfigParametersView(Collection<? extends ModelItem> categories, Comparator<? super ModelItem> categoriesComparator, Comparator<? super ModelItem> groupsComparator, Comparator<? super ModelItem> elementsComparator) throws IllegalArgumentException
116    {
117        View view = new View();
118        
119        Collection<? extends ModelItem> sorted = _sort(categories, categoriesComparator);
120        
121        for (ModelItem modelItem : sorted)
122        {
123            view.addViewItem(_buildCategoryViewItem(modelItem, groupsComparator, elementsComparator));
124        }
125        return view;
126    }
127    
128    private static ModelViewItemGroup _buildCategoryViewItem(ModelItem modelItem, Comparator<? super ModelItem> groupsComparator, Comparator<? super ModelItem> elementsComparator) throws IllegalArgumentException
129    {
130        if (modelItem instanceof ModelItemGroup)
131        {
132            ModelItemGroup category = (ModelItemGroup) modelItem;
133            ModelViewItemGroup categoryViewItem = new ModelViewItemGroup();
134            categoryViewItem.setRole(ViewItemGroup.TAB_ROLE);
135            categoryViewItem.setDefinition(category);
136            
137            Collection<? extends ModelItem> groups = _sort(category.getChildren(), groupsComparator);
138            
139            for (ModelItem group : groups)
140            {
141                categoryViewItem.addViewItem(_buildGroupViewItem(group, elementsComparator));
142            }
143            return categoryViewItem;
144        }
145        else
146        {
147            throw new IllegalArgumentException("Category " + modelItem.getPath() + " should be an instance of ModelItemGroup");
148        }
149    }
150    
151    private static ModelViewItemGroup _buildGroupViewItem(ModelItem modelItem, Comparator<? super ModelItem> elementsComparator) throws IllegalArgumentException
152    {
153        if (modelItem instanceof ModelItemGroup)
154        {
155            ModelItemGroup group = (ModelItemGroup) modelItem;
156            ModelViewItemGroup groupViewItem = new ModelViewItemGroup();
157            groupViewItem.setRole(ViewItemGroup.FIELDSET_ROLE);
158            groupViewItem.setDefinition(group);
159            
160            Collection<? extends ModelItem> items = _sort(group.getChildren(), elementsComparator);
161            
162            for (ModelItem item : items)
163            {
164                groupViewItem.addViewItem(_buildElementViewItem(item));
165            }
166            return groupViewItem;
167        }
168        else
169        {
170            throw new IllegalArgumentException("Group " + modelItem.getPath() + " should be an instance of ModelItemGroup");
171        }
172    }
173    
174    private static ModelViewItem _buildElementViewItem(ModelItem modelItem) throws IllegalArgumentException
175    {
176        if (modelItem instanceof ElementDefinition)
177        {
178            ElementDefinition definition = (ElementDefinition) modelItem;
179            
180            ViewElement parameterViewItem = new ViewElement();
181            parameterViewItem.setDefinition(definition);
182            return parameterViewItem;
183        }
184        else
185        {
186            throw new IllegalArgumentException("Item " + modelItem.getPath() + " should be an instance of ElementDefinition");
187        }
188    }
189    
190    /**
191     * sort a model item list using comparator
192     * @param items list of items to sort
193     * @param comparator a comparator, can be null to avoid sort
194     * @return a sorted list (or a copy of the list if the comparator is null)
195     */
196    private static Collection<? extends ModelItem> _sort(Collection<? extends ModelItem> items, Comparator<? super ModelItem> comparator)
197    {
198        if (comparator == null)
199        {
200            return items;
201        }
202        else
203        {
204            List<ModelItem> sorted = new ArrayList<>(items);
205            sorted.sort(comparator);
206            return sorted;
207        }
208    }
209}