001/*
002 *  Copyright 2021 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.plugins.forms.question.sources;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022
023import org.apache.avalon.framework.configuration.Configurable;
024import org.apache.avalon.framework.configuration.Configuration;
025import org.apache.avalon.framework.configuration.ConfigurationException;
026import org.apache.avalon.framework.service.ServiceException;
027import org.apache.avalon.framework.service.ServiceManager;
028import org.apache.avalon.framework.service.Serviceable;
029import org.apache.commons.lang3.StringUtils;
030
031import org.ametys.core.util.JSONUtils;
032import org.ametys.plugins.forms.question.types.ChoicesListQuestionType;
033import org.ametys.plugins.forms.repository.FormEntry;
034import org.ametys.plugins.forms.repository.FormQuestion;
035import org.ametys.runtime.i18n.I18nizableText;
036import org.ametys.runtime.model.ModelItem;
037import org.ametys.runtime.model.type.ModelItemTypeConstants;
038import org.ametys.runtime.plugin.component.AbstractLogEnabled;
039import org.ametys.runtime.plugin.component.PluginAware;
040
041/**
042 * Static class for creating {@link ChoiceSourceType} from xml congig
043 */
044public abstract class AbstractSourceType extends AbstractLogEnabled implements ChoiceSourceType, Serviceable, Configurable, PluginAware
045{
046    /** The question param key */
047    public static final String QUESTION_PARAM_KEY = "question";
048    
049    /** JSON helper */
050    protected JSONUtils _jsonUtils;
051    
052    /** Forms */
053    protected String _pluginName;
054    /** Id of source type */
055    protected String _id;
056    /** Label of source type */
057    protected I18nizableText _label;
058    
059    public void service(ServiceManager manager) throws ServiceException
060    {
061        _jsonUtils = (JSONUtils) manager.lookup(JSONUtils.ROLE);
062    }
063    
064    public void setPluginInfo(String pluginName, String featureName, String id)
065    {
066        _pluginName = pluginName;
067    }
068
069    public void configure(Configuration configuration) throws ConfigurationException
070    {
071        _id = configuration.getAttribute("id");
072        
073        Configuration childLabel = configuration.getChild("label");
074        _label = I18nizableText.getI18nizableTextValue(childLabel, "plugin." + _pluginName, childLabel.getValue());
075    }
076
077    public String getId()
078    {
079        return _id;
080    }
081
082    public I18nizableText getLabel()
083    {
084        return _label;
085    }
086    
087    public List<String> getFieldToDisableIfFormPublished()
088    {
089        return new ArrayList<>();
090    }
091    
092    public String getStorageType(FormQuestion question)
093    {
094        return ModelItemTypeConstants.STRING_TYPE_ID;
095    }
096    
097    public String getJSRenderer()
098    {
099        return "Ametys.plugins.forms.helper.SearchEntriesGridHelper.renderStringChoiceList";
100    }
101    
102    public String getJSConverter()
103    {
104        return null;
105    }
106    
107    public Object removeEmptyOrOtherValue(Object value)
108    {
109        if (value == null)
110        {
111            return null;
112        }
113        
114        if (value.getClass().isArray())
115        {
116            List<String> newVal = new ArrayList<>();
117            for (String val : (String[]) value)
118            {
119                if (StringUtils.isNotBlank(val) && !val.equals(ChoicesListQuestionType.OTHER_OPTION_VALUE))
120                {
121                    newVal.add(val);
122                }
123            }
124            
125            if (newVal.isEmpty())
126            {
127                return null;
128            }
129            
130            return newVal.toArray(new String[newVal.size()]);
131        }
132        else if (StringUtils.isNotBlank((String) value) && !value.equals(ChoicesListQuestionType.OTHER_OPTION_VALUE))
133        {
134            return value;
135        }
136        
137        return null;
138    }
139    
140    /**
141     * Get question from params
142     * @param params the params
143     * @return the form question
144     */
145    protected FormQuestion _getQuestionFromParam(Map<String, Object> params)
146    {
147        return (FormQuestion) params.get(QUESTION_PARAM_KEY);
148    }
149    
150    public Object valueToJSONForClient(Object value, FormQuestion question, FormEntry entry, ModelItem modelItem) throws Exception
151    {
152        return _getComputedStringValue(value, question, entry);
153    }
154    
155    /**
156     * Get computed string value for choice list
157     * @param valueToJSONForClient the value for this question
158     * @param question the question
159     * @param entry the entry
160     * @return the computed value
161     * @throws Exception if an error occurred during computing
162     */
163    protected Object _getComputedStringValue(Object valueToJSONForClient, FormQuestion question, FormEntry entry) throws Exception
164    {
165        String name = question.getNameForForm();
166        ChoicesListQuestionType type = (ChoicesListQuestionType) question.getType();
167        
168        if (entry.isMultiple(name))
169        {
170            List<Map<String, Object>> values = new ArrayList<>();
171            if (valueToJSONForClient != null)
172            {
173                for (Object val : (List) valueToJSONForClient)
174                {
175                    Map<String, Object> transformedValue = new HashMap<>();
176                    transformedValue.put("value", val);
177                    
178                    Map<String, Object> enumParam = new HashMap<>();
179                    enumParam.put(AbstractSourceType.QUESTION_PARAM_KEY, question);
180                    transformedValue.put("label", type.getSourceType(question).getEntry(new ChoiceOption(val), enumParam));
181                    
182                    values.add(transformedValue);
183                }
184            }
185            
186            if (type.hasOtherOption(question))
187            {
188                String otherValue = entry.getValue(ChoicesListQuestionType.OTHER_PREFIX_DATA_NAME + name);
189                if (StringUtils.isNotBlank(otherValue))
190                {
191                    Map<String, Object> transformedValue = new HashMap<>();
192                    transformedValue.put("value", otherValue);
193                    transformedValue.put("label", otherValue);
194                    
195                    values.add(transformedValue);
196                }
197            }
198            
199            return values;
200        }
201        else
202        {
203            Map<String, Object> transformedValue = new HashMap<>();
204
205            if (type.hasOtherOption(question) && StringUtils.isNotBlank(entry.getValue(ChoicesListQuestionType.OTHER_PREFIX_DATA_NAME + name)))
206            {
207                String otherValue = entry.getValue(ChoicesListQuestionType.OTHER_PREFIX_DATA_NAME + name);
208                transformedValue.put("value", otherValue);
209                transformedValue.put("label", otherValue);
210            }
211            else if (valueToJSONForClient != null)
212            {
213                transformedValue.put("value", valueToJSONForClient);
214                
215                Map<String, Object> enumParam = new HashMap<>();
216                enumParam.put(AbstractSourceType.QUESTION_PARAM_KEY, question);
217                transformedValue.put("label", type.getSourceType(question).getEntry(new ChoiceOption(valueToJSONForClient), enumParam));
218            }
219                
220            
221            return transformedValue;
222        }
223    }
224    
225    /**
226     * Get computed complex value as user or content for choice list
227     * @param valueToJSONForClient the value for this question
228     * @param question the question
229     * @param entry the entry
230     * @return the computed value
231     * @throws Exception if an error occurred
232     */
233    protected Object _getComputedComplexValue(Object valueToJSONForClient, FormQuestion question, FormEntry entry) throws Exception
234    {
235        String name = question.getNameForForm();
236        ChoicesListQuestionType type = (ChoicesListQuestionType) question.getType();
237        
238        if (!type.hasOtherOption(question))
239        {
240            return valueToJSONForClient;
241        }
242        
243        if (entry.isMultiple(name))
244        {
245            String otherValue = entry.getValue(ChoicesListQuestionType.OTHER_PREFIX_DATA_NAME + name);
246            if (StringUtils.isNotBlank(otherValue))
247            {
248                Map<String, Object> transformedValue = new HashMap<>();
249                transformedValue.put("value", otherValue);
250                transformedValue.put("isOther", true);
251                
252                @SuppressWarnings("unchecked")
253                List<Object> computedVal = valueToJSONForClient != null ? (List<Object>) valueToJSONForClient : new ArrayList<>();
254                computedVal.add(transformedValue);
255                
256                return computedVal;
257            }
258        }
259        else
260        {
261            String otherValue = entry.getValue(ChoicesListQuestionType.OTHER_PREFIX_DATA_NAME + name);
262            if (StringUtils.isNotBlank(otherValue))
263            {
264                Map<String, Object> transformedValue = new HashMap<>();
265                transformedValue.put("value", otherValue);
266                transformedValue.put("isOther", true);
267                
268                return transformedValue;
269            }
270        }
271        
272        return valueToJSONForClient;
273    }
274}