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.Map;
019import java.util.Objects;
020
021import org.apache.cocoon.xml.AttributesImpl;
022import org.apache.commons.lang3.StringUtils;
023import org.apache.commons.lang3.Strings;
024import org.xml.sax.ContentHandler;
025import org.xml.sax.SAXException;
026
027import org.ametys.core.util.SizeUtils.ExcludeFromSizeCalculation;
028import org.ametys.core.util.XMLUtils;
029import org.ametys.plugins.core.ui.help.HelpLink;
030import org.ametys.runtime.i18n.I18nizableText;
031
032/**
033 * View reference to an element definition
034 */
035public class ViewElement implements ModelViewItem<ElementDefinition>
036{
037    @ExcludeFromSizeCalculation
038    private ElementDefinition _definition;
039    
040    @ExcludeFromSizeCalculation
041    private ViewItemAccessor _parent;
042    
043    private I18nizableText _label;
044    private I18nizableText _description;
045    
046    private DisabledItemRendering _disabledItemRendering = DisabledItemRendering.DEFAULT;
047    
048    public ElementDefinition getDefinition()
049    {
050        return _definition;
051    }
052
053    public void setDefinition(ElementDefinition definition)
054    {
055        if (definition == null)
056        {
057            throw new IllegalArgumentException("Try to set a null definition to the view element");
058        }
059        _definition = definition;
060    }
061    
062    public ViewItemAccessor getParent()
063    {
064        return _parent;
065    }
066    
067    public void setParent(ViewItemAccessor parent)
068    {
069        _parent = parent;
070    }
071    
072    public void setLabel(I18nizableText label)
073    {
074        _label = label;
075    }
076    
077    public void setDescription(I18nizableText description)
078    {
079        _description = description;
080    }
081
082    @Override
083    public I18nizableText getLabel()
084    {
085        return _label != null ? _label : getDefinition().getLabel();
086    }
087    
088    @Override
089    public I18nizableText getDescription()
090    {
091        return _description != null ? _description : getDefinition().getDescription();
092    }
093    
094    public DisabledItemRendering getDisabledItemRendering()
095    {
096        return _disabledItemRendering;
097    }
098    
099    public void setDisabledItemRendering(DisabledItemRendering disabledItemRendering)
100    {
101        _disabledItemRendering = disabledItemRendering;
102    }
103    
104    public Map<String, Object> toJSON(DefinitionContext context)
105    {
106        ElementDefinition definition = getDefinition();
107        if (definition != null)
108        {
109            Map<String, Object> result = definition.toJSON(context);
110            if (!result.isEmpty())
111            {
112                // use overridden label and description if present
113                result.put("label", getLabel());
114                result.put("description", getDescription());
115                
116                DisabledItemRendering disabledItemRendering = getDisabledItemRendering();
117                if (disabledItemRendering != DisabledItemRendering.DEFAULT)
118                {
119                    result.put("disabledItemRendering", disabledItemRendering.name().toLowerCase());
120                }
121    
122                Model model = definition.getModel();
123                if (model != null)
124                {
125                    String modelId = model.getId();
126                    String family = model.getFamilyId();
127                    
128                    String path = definition.getPath();
129                    //If there is a path, and it does not starts with '/', we add one at the beginning
130                    if (StringUtils.isNotBlank(path))
131                    {
132                        path = Strings.CS.prependIfMissing(path, ModelItem.ITEM_PATH_SEPARATOR);
133                    }
134                    String featureId = StringUtils.join(modelId, path);
135                    //Remove the starting '/' if present
136                    featureId = Strings.CS.removeStart(featureId, ModelItem.ITEM_PATH_SEPARATOR);
137        
138                    HelpLink help = new HelpLink(family, featureId, null);
139                    result.put("help", help);
140                }
141                
142                return result;
143            }
144        }
145        
146        return Map.of();
147    }
148    
149    @SuppressWarnings("static-access")
150    public void toSAX(ContentHandler contentHandler, DefinitionContext context) throws SAXException
151    {
152        ElementDefinition definition = getDefinition();
153        if (definition != null)
154        {
155            String tagName = context.getItemTagName().orElse(DEFAULT_ITEM_TAG_NAME);
156            
157            AttributesImpl attributes = new AttributesImpl();
158            attributes.addCDATAAttribute("name", definition.getName());
159            attributes.addCDATAAttribute("plugin", definition.getPluginName());
160            attributes.addCDATAAttribute("path", definition.getPath());
161            attributes.addCDATAAttribute("type", definition.getType().getId());
162            attributes.addCDATAAttribute("multiple", String.valueOf(definition.isMultiple()));
163            
164            DisabledItemRendering disabledItemRendering = getDisabledItemRendering();
165            if (disabledItemRendering != DisabledItemRendering.DEFAULT)
166            {
167                attributes.addCDATAAttribute("disabled", disabledItemRendering.name().toLowerCase());
168            }
169            
170            XMLUtils.startElement(contentHandler, tagName, attributes);
171            
172            XMLUtils.createI18nElementIfNotNull(contentHandler, "label", getLabel());
173            XMLUtils.createI18nElementIfNotNull(contentHandler, "description", getDescription());
174            
175            definition.toSAX(contentHandler, context);
176            
177            XMLUtils.endElement(contentHandler, tagName);
178        }
179    }
180    
181    public void copyTo(ViewItem item)
182    {
183        assert item instanceof ViewElement;
184        ViewElement viewElement = (ViewElement) item;
185
186        viewElement.setDefinition(getDefinition());
187        viewElement.setLabel(getLabel());
188        viewElement.setDescription(getDescription());
189        
190        viewElement.setDisabledItemRendering(getDisabledItemRendering());
191    }
192    
193    public ViewElement createInstance()
194    {
195        return new ViewElement();
196    }
197
198    @Override
199    public int hashCode()
200    {
201        return Objects.hash(_definition);
202    }
203
204    @Override
205    public boolean equals(Object obj)
206    {
207        if (this == obj)
208        {
209            return true;
210        }
211        if (obj == null)
212        {
213            return false;
214        }
215        if (getClass() != obj.getClass())
216        {
217            return false;
218        }
219        ViewElement other = (ViewElement) obj;
220        return Objects.equals(_definition, other._definition);
221    }
222
223    @Override
224    public boolean equals(Object obj, boolean checkDetails)
225    {
226        if (!equals(obj))
227        {
228            return false;
229        }
230        else if (checkDetails)
231        {
232            ViewElement other = (ViewElement) obj;
233            return Objects.equals(_label, other._label) && Objects.equals(_description, other._description);
234        }
235        else
236        {
237            return true;
238        }
239    }
240    
241    @Override
242    public String toString()
243    {
244        return _definition.toString();
245    }
246}