001/*
002 *  Copyright 2018 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.model;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.Collections;
021import java.util.LinkedHashMap;
022import java.util.List;
023import java.util.Map;
024
025import org.apache.cocoon.ProcessingException;
026
027import org.ametys.runtime.i18n.I18nizableText;
028import org.ametys.runtime.model.exception.BadItemTypeException;
029import org.ametys.runtime.util.ModifiableLabelable;
030
031/**
032 * View of items
033 */
034public class View implements ViewItemContainer, ModifiableLabelable
035{
036    private String _name;
037    private I18nizableText _label;
038    private I18nizableText _description;
039    private String _iconGlyph;
040    private String _iconDecorator;
041    private String _smallIcon;
042    private String _mediumIcon;
043    private String _largeIcon;
044    private boolean _isInternal;
045    
046    private List<ViewItem> _items = new ArrayList<>();
047    
048    /**
049     * Creates a {@link View} with the items of the given {@link Model}
050     * @param model the model
051     * @return the created {@link View}
052     * @throws IllegalArgumentException if the model is <code>null</code>
053     */
054    public static View of(Model model) throws IllegalArgumentException
055    {
056        if (model == null)
057        {
058            throw new IllegalArgumentException("Unable to create the view from a null model");
059        }
060        else
061        {
062            return ViewHelper.createViewItemContainer(List.of(model));
063        }
064    }
065    
066    /**
067     * Creates a {@link View} with the items of the given {@link Model}s
068     * @param models the models
069     * @return the created {@link View}
070     * @throws IllegalArgumentException if the models collection is empty
071     */
072    public static View of(Collection<Model> models) throws IllegalArgumentException
073    {
074        return ViewHelper.createViewItemContainer(models);
075    }
076    
077    /**
078     * Creates a {@link View} with the given items
079     * @param model the model containing items definitions
080     * @param itemPaths the paths of the items to put in the view
081     * @return the created {@link View}
082     * @throws IllegalArgumentException if the model is <code>null</code> or if an item path is <code>null</code>, empty, or is not defined in the given models
083     * @throws BadItemTypeException if a segment in a path (but not the last) does not represent a group item
084     */
085    public static View of(Model model, String... itemPaths) throws IllegalArgumentException, BadItemTypeException
086    {
087        if (model == null)
088        {
089            throw new IllegalArgumentException("Unable to create the view from a null model");
090        }
091        else
092        {
093            return ViewHelper.createViewItemContainer(List.of(model), itemPaths);
094        }
095    }
096    
097    /**
098     * Creates a {@link View} with the given items
099     * @param models the models containing items definitions
100     * @param itemPaths the paths of the items to put in the view
101     * @return the created {@link View}
102     * @throws IllegalArgumentException if the models collection is empty or if an item path is <code>null</code>, empty, or is not defined in the given models
103     * @throws BadItemTypeException if a segment in a path (but not the last) does not represent a group item
104     */
105    public static View of(Collection<Model> models, String... itemPaths) throws IllegalArgumentException, BadItemTypeException
106    {
107        return ViewHelper.createViewItemContainer(models, itemPaths);
108    }
109    
110    /**
111     * Creates a {@link View} with the given items. If the items are in a group, the hierarchy will be kept and the corresponding containers will be created
112     * @param modelItems the items to put in the view
113     * @return the created {@link View}
114     */
115    public static View of(ModelItem... modelItems)
116    {
117        View view = new View();
118        
119        for (ModelItem modelItem : modelItems)
120        {
121            ViewHelper.addViewItem(modelItem.getPath(), view, modelItem.getModel());
122        }
123        
124        return view;
125    }
126
127    public String getName()
128    {
129        return _name;
130    }
131
132    public void setName(String name)
133    {
134        _name = name;
135    }
136    
137    public I18nizableText getLabel()
138    {
139        return _label;
140    }
141
142    public void setLabel(I18nizableText label)
143    {
144        _label = label;
145    }
146    
147    public I18nizableText getDescription()
148    {
149        return _description;
150    }
151    
152    public void setDescription(I18nizableText description)
153    {
154        _description = description;
155    }
156    
157    /**
158     * Retrieves the CSS class to use for glyph icon
159     * @return the glyph name.
160     */
161    public String getIconGlyph()
162    {
163        return _iconGlyph;
164    }
165    
166    /**
167     * Set the CSS class to use for glyph icon
168     * @param iconGlyph the glyph name.
169     */
170    public void setIconGlyph(String iconGlyph)
171    {
172        _iconGlyph = iconGlyph;
173    }
174    
175    /**
176     * Retrieves the CSS class to use for decorator above the main icon
177     * @return the glyph name.
178     */
179    public String getIconDecorator()
180    {
181        return _iconDecorator;
182    }
183    
184    /**
185     * Set the CSS class to use for decorator above the main icon
186     * @param iconDecorator the glyph name.
187     */
188    public void setIconDecorator(String iconDecorator)
189    {
190        _iconDecorator = iconDecorator;
191    }
192    
193    /**
194     * Retrieves the URL of the small icon without the context path.
195     * @return the icon URL for the small image 16x16.
196     */
197    public String getSmallIcon()
198    {
199        return _smallIcon;
200    }
201    
202    /**
203     * Set the URL of the small icon.
204     * @param smallIcon the URL of the small icon, without the context path.
205     */
206    public void setSmallIcon(String smallIcon)
207    {
208        _smallIcon = smallIcon;
209    }
210    
211    /**
212     * Retrieves the URL of the small icon without the context path.
213     * @return the icon URL for the medium sized image 32x32.
214     */
215    public String getMediumIcon()
216    {
217        return _mediumIcon;
218    }
219    
220    /**
221     * Set the URL of the medium icon.
222     * @param mediumIcon the URL of the medium icon, without the context path.
223     */
224    public void setMediumIcon(String mediumIcon)
225    {
226        _mediumIcon = mediumIcon;
227    }
228    
229    /**
230     * Retrieves the URL of the small icon without the context path.
231     * @return the icon URL for the large image 48x48.
232     */
233    public String getLargeIcon()
234    {
235        return _largeIcon;
236    }
237    
238    /**
239     * Set the URL of the large icon.
240     * @param largeIcon the URL of the large icon, without the context path.
241     */
242    public void setLargeIcon(String largeIcon)
243    {
244        _largeIcon = largeIcon;
245    }
246    
247    /**
248     * Determines if the view is for internal use only
249     * @return <code>true</code> if the view is for internal use only, <code>false</code> otherwise
250     */
251    public boolean isInternal()
252    {
253        return _isInternal;
254    }
255
256    /**
257     * Set the internal status
258     * @param isInternal <code>true</code> to make the view for internal use only, <code>false</code> otherwise
259     */
260    public void setIsInternal(boolean isInternal)
261    {
262        _isInternal = isInternal;
263    }
264    
265    public List<ViewItem> getViewItems()
266    {
267        return Collections.unmodifiableList(this._items);
268    }
269    
270    public void addViewItem(ViewItem item)
271    {
272        _items.add(item);
273    }
274    
275    public void insertViewItem(ViewItem item, int index)
276    {
277        if (index >= 0 && index < _items.size())
278        {
279            _items.add(index, item);
280        }
281        else
282        {
283            throw new IllegalArgumentException("Unable to insert an item at index " + index + ". This group contains " + _items.size() + "items.");
284        }
285    }
286
287    /**
288     * Converts the view in a JSON map
289     * @return The view as a JSON map
290     * @throws ProcessingException If an error occurs when converting the view
291     */
292    public Map<String, Object> toJSON() throws ProcessingException
293    {
294        Map<String, Object> result = new LinkedHashMap<>();
295        
296        result.put("name", getName());
297        result.put("label", getLabel());
298        result.put("description", getDescription());
299        
300        result.put("icon-glyph", getIconGlyph());
301        result.put("icon-decorator", getIconDecorator());
302        result.put("small-icon-path", getSmallIcon());
303        result.put("medium-icon-path", getMediumIcon());
304        result.put("large-icon-path", getLargeIcon());
305    
306        List<Map<String, Object>> groups = new ArrayList<>();
307        for (ViewItem item : getViewItems())
308        {
309            if (item instanceof ViewElement)
310            {
311                result.putAll(item.toJSON());
312            }
313            else
314            {
315                groups.add(item.toJSON());
316            }
317        }
318        
319        if (!groups.isEmpty())
320        {
321            result.put("groups", groups);
322        }
323        
324        return result;
325    }
326    
327    /**
328     * Include the given view to the current one.
329     * Add the items of the view to include if they are not already present in the current view
330     * @param viewToInclude the view to include
331     */
332    public void includeView(View viewToInclude)
333    {
334        ViewHelper.addViewContainerItems(this, viewToInclude, this);
335    }
336}