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.List;
020import java.util.Map;
021import java.util.Objects;
022
023import org.apache.cocoon.ProcessingException;
024import org.apache.cocoon.xml.AttributesImpl;
025import org.apache.commons.lang3.StringUtils;
026import org.xml.sax.ContentHandler;
027import org.xml.sax.SAXException;
028
029import org.ametys.core.util.SizeUtils.ExcludeFromSizeCalculation;
030import org.ametys.core.util.XMLUtils;
031import org.ametys.runtime.i18n.I18nizableText;
032import org.ametys.runtime.model.exception.BadItemTypeException;
033
034/**
035 * View reference to a group of model items 
036 */
037public class ModelViewItemGroup extends AbstractViewItemGroup implements ModelViewItem<ModelItemGroup>
038{
039    @ExcludeFromSizeCalculation
040    private ModelItemGroup _definition;
041    
042    /**
043     * Creates a {@link ModelViewItemGroup} with the items of the given {@link ModelItemGroup}
044     * @param modelItem the model item group
045     * @return the created {@link ModelViewItemGroup}
046     * @throws IllegalArgumentException if the model item is <code>null</code>
047     */
048    public static ModelViewItemGroup of(ModelItemGroup modelItem) throws IllegalArgumentException
049    {
050        if (modelItem == null)
051        {
052            throw new IllegalArgumentException("Unable to create the view from a null model");
053        }
054        else
055        {
056            return ViewHelper.createViewItemAccessor(List.of(modelItem));
057        }
058    }
059    
060    /**
061     * Creates a {@link ModelViewItemGroup} with the given items
062     * @param modelItem the model item containing items definitions
063     * @param itemPaths the paths of the items to put in the view item
064     * @return the created {@link ModelViewItemGroup}
065     * @throws IllegalArgumentException if the model item is <code>null</code> or if an item path is <code>null</code>, empty, or is not defined in the given model items
066     * @throws BadItemTypeException if a segment in a path (but not the last) does not represent a group item
067     */
068    public static ModelViewItemGroup of(ModelItemGroup modelItem, String... itemPaths) throws IllegalArgumentException, BadItemTypeException
069    {
070        if (modelItem == null)
071        {
072            throw new IllegalArgumentException("Unable to create the view from a null model");
073        }
074        else
075        {
076            return ViewHelper.createViewItemAccessor(List.of(modelItem), itemPaths);
077        }
078    }
079    
080    public ModelItemGroup getDefinition()
081    {
082        return _definition;
083    }
084    
085    public void setDefinition(ModelItemGroup definition)
086    {
087        if (definition == null)
088        {
089            throw new IllegalArgumentException("Try to set a null definition to the model view item group");
090        }
091        
092        _definition = definition;
093    }
094    
095    public String getName()
096    {
097        if (_definition != null)
098        {
099            return _definition.getName();
100        }
101        else
102        {
103            return null;
104        }
105    }
106    
107    @Override
108    public I18nizableText getLabel()
109    {
110        I18nizableText label = super.getLabel();
111        if (label != null)
112        {
113            return label;
114        }
115        
116        return getDefinition().getLabel();
117    }
118    
119    @Override
120    public I18nizableText getDescription()
121    {
122        I18nizableText desc = super.getDescription();
123        if (desc != null)
124        {
125            return desc;
126        }
127        
128        return getDefinition().getDescription();
129    }
130    
131    public Map<String, Object> toJSON(DefinitionContext context) throws ProcessingException
132    {
133        ModelItemGroup definition = getDefinition();
134        if (definition != null)
135        {
136            Map<String, Object> result = definition.toJSON(context, false);
137            if (!result.isEmpty())
138            {
139                // use overridden label and description if present  
140                result.put("label", getLabel());
141                result.put("description", getDescription());
142                result.put("role", getRole());
143                
144                if (StringUtils.isEmpty(getName()))
145                {
146                    result.put("unnamed-group", true);
147                }
148                
149                List<ViewItem> viewItems = _getChildrenWithoutSwitcher();
150                if (!viewItems.isEmpty())
151                {
152                    result.put("elements", ViewHelper.viewItemsToJSON(viewItems, context));
153                }
154            }
155            return result;
156        }
157        
158        return Map.of();
159    }
160    
161    @SuppressWarnings("static-access")
162    public void toSAX(ContentHandler contentHandler, DefinitionContext context) throws SAXException
163    {
164        ModelItemGroup definition = getDefinition();
165        if (definition != null)
166        {
167            AttributesImpl attributes = new AttributesImpl();
168            attributes.addCDATAAttribute("name", definition.getName());
169            attributes.addCDATAAttribute("plugin", definition.getPluginName());
170            attributes.addCDATAAttribute("path", definition.getPath());
171            
172            String typeId = definition.getType() != null ? definition.getType().getId() : ModelItemGroup.DEFAULT_TYPE_ID;
173            attributes.addCDATAAttribute("type", typeId);
174            
175            XMLUtils.startElement(contentHandler, "metadata", attributes);
176            
177            XMLUtils.createElementIfNotNull(contentHandler, "role", getRole());
178            XMLUtils.createI18nElementIfNotNull(contentHandler, "label", getLabel());
179            XMLUtils.createI18nElementIfNotNull(contentHandler, "description", getDescription());
180            
181            definition.toSAX(contentHandler, context);
182            
183            for (ViewItem viewItem : _getChildrenWithoutSwitcher())
184            {
185                viewItem.toSAX(contentHandler, context);
186            }
187            
188            XMLUtils.endElement(contentHandler, "metadata");
189        }
190    }
191    
192    private List<ViewItem> _getChildrenWithoutSwitcher()
193    {
194        ElementDefinition switcher = getDefinition().getSwitcher();
195        if (switcher == null)
196        {
197            return getViewItems();
198        }
199        
200        List<ViewItem> childrenWithoutSwitcher = new ArrayList<>();
201        for (ViewItem child : getViewItems())
202        {
203            if (child instanceof ViewElement)
204            {
205                ElementDefinition childDefinitonReference = ((ViewElement) child).getDefinition();
206                if (!switcher.equals(childDefinitonReference))
207                {
208                    childrenWithoutSwitcher.add(child);
209                }
210            }
211        }
212        
213        return childrenWithoutSwitcher;
214    }
215    
216    @Override
217    public void copyTo(ViewItem item)
218    {
219        super.copyTo(item);
220        
221        assert item instanceof ModelViewItemGroup;
222        ((ModelViewItemGroup) item).setDefinition(getDefinition());
223    }
224    
225    public ModelViewItemGroup createInstance()
226    {
227        return new ModelViewItemGroup();
228    }
229
230    @Override
231    public int hashCode()
232    {
233        final int prime = 31;
234        int result = super.hashCode();
235        result = prime * result + Objects.hash(_definition);
236        return result;
237    }
238
239    @Override
240    public boolean equals(Object obj)
241    {
242        if (this == obj)
243        {
244            return true;
245        }
246        if (!super.equals(obj))
247        {
248            return false;
249        }
250        if (getClass() != obj.getClass())
251        {
252            return false;
253        }
254        ModelViewItemGroup other = (ModelViewItemGroup) obj;
255        return Objects.equals(_definition, other._definition);
256    }
257    
258    @Override
259    public String toString()
260    {
261        return _definition.toString() + ": " + _children.toString();
262    }
263}