001/*
002 *  Copyright 2022 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.helper;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022import java.util.stream.Collectors;
023
024import org.apache.avalon.framework.component.Component;
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027import org.apache.avalon.framework.service.Serviceable;
028
029import org.ametys.core.ui.Callable;
030import org.ametys.plugins.forms.dao.FormDAO;
031import org.ametys.plugins.forms.question.FormQuestionType;
032import org.ametys.plugins.forms.question.sources.ChoiceSourceType;
033import org.ametys.plugins.forms.question.types.CheckBoxQuestionType;
034import org.ametys.plugins.forms.question.types.ChoicesListQuestionType;
035import org.ametys.plugins.forms.repository.Form;
036import org.ametys.plugins.forms.repository.FormQuestion;
037import org.ametys.plugins.forms.repository.type.Rule.QuestionRuleType;
038import org.ametys.plugins.forms.rights.FormsDirectoryRightAssignmentContext;
039import org.ametys.plugins.repository.AmetysObjectResolver;
040import org.ametys.runtime.i18n.I18nizableText;
041
042/**
043 * Helper for getting rules properties
044 */
045public class QuestionRuleHelper implements Serviceable, Component
046{
047    /** The Ametys object resolver */
048    protected AmetysObjectResolver _resolver;
049    
050    public void service(ServiceManager manager) throws ServiceException
051    {
052        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
053    }
054    
055    /**
056     * Get all choices list and booleans questions as source for the rule
057     * @param formId id of the current form
058     * @param questionId id of the current question
059     * @return a map containing the list of questions
060     */
061    @Callable (rights = FormDAO.HANDLE_FORMS_RIGHT_ID, rightContext = FormsDirectoryRightAssignmentContext.ID, paramIndex = 0)
062    public Map<String, Object> getSourceQuestions(String formId, String questionId)
063    {
064        Map<String, Object> results = new HashMap<>();
065        Form form = _resolver.resolveById(formId);
066        List<FormQuestion> questions = form.getQuestions()
067            .stream()
068            .filter(question -> this._isChoiceListWithNoTooManyOptions(question) || question.getType() instanceof CheckBoxQuestionType) // Question must be a choice list with not too many options
069            .filter(question -> !question.isModifiable()) // Question must be not modifiable
070            .filter(question -> !question.getId().equals(questionId)) // Remove the given question from the list
071            .collect(Collectors.toList());
072        List<Object> sources = new ArrayList<>();
073        for (FormQuestion question : questions)
074        {
075            Map<String, String> properties = new HashMap<>();
076            properties.put("label", question.getTitle());
077            properties.put("id", question.getId());
078            sources.add(properties);
079        }
080        results.put("data", sources);
081        
082        return results;
083    }
084    
085    private boolean _isChoiceListWithNoTooManyOptions(FormQuestion question)
086    {
087        FormQuestionType type = question.getType();
088        if (type instanceof ChoicesListQuestionType cLType)
089        {
090            ChoiceSourceType sourceType = cLType.getSourceType(question);
091            return !sourceType.remoteData();
092        }
093        
094        return false;
095    }
096    
097    /**
098     * Get all the available options for the selected question
099     * @param questionId id of the selected question
100     * @return a map containing the list of all the options as map (label for display and unique value)
101     */
102    @Callable (rights = FormDAO.HANDLE_FORMS_RIGHT_ID, rightContext = FormsDirectoryRightAssignmentContext.ID, paramIndex = 0)
103    public Map<String, Object> getSourceOptions(String questionId)
104    {
105        Map<String, Object> results = new HashMap<>();
106        FormQuestion formQuestion = _resolver.resolveById(questionId);
107        List<Object> options = new ArrayList<>();
108        if (formQuestion.getType() instanceof ChoicesListQuestionType type && !type.getSourceType(formQuestion).remoteData())
109        {
110            Map<String, I18nizableText> choices = type.getOptions(formQuestion);
111            for (String optionValue : choices.keySet())
112            {
113                Map<String, Object> choicesToJson = new HashMap<>();
114                choicesToJson.put("label", choices.get(optionValue));
115                choicesToJson.put("value", optionValue);
116                options.add(choicesToJson);
117            }
118            if (type.hasOtherOption(formQuestion))
119            {
120                Map<String, Object> choicesToJson = new HashMap<>();
121                choicesToJson.put("label", new I18nizableText("plugin.forms", "PLUGINS_FORMS_DISPLAY_OTHER_OPTION_COMBOBOX"));
122                choicesToJson.put("value", ChoicesListQuestionType.OTHER_OPTION_VALUE);
123                options.add(choicesToJson);
124            }
125        }
126        else
127        {
128            options.add(Map.of(
129                    "label", new I18nizableText("plugin.forms", "PLUGINS_FORMS_QUESTION_RULES_OPTION_CHECKED"),
130                    "value", "true"
131                    ));
132            
133            options.add(Map.of(
134                    "label", new I18nizableText("plugin.forms", "PLUGINS_FORMS_QUESTION_RULES_OPTION_UNCHECKED"),
135                    "value", "false"
136                    ));
137        }
138        results.put("data", options);
139        return results;
140    }
141    
142    /**
143     * Get the actions available to apply to this question 
144     * @return a list of actions (currently hide or show)
145     */
146    @Callable
147    public Map<String, Object> getRuleActions()
148    {
149        Map<String, Object> results = new HashMap<>();
150        
151        List<Object> actions = new ArrayList<>();
152        
153        actions.add(Map.of(
154            "label", QuestionRuleType.HIDE.getLabel(),
155            "value", QuestionRuleType.HIDE.name()
156        ));
157        
158        actions.add(Map.of(
159            "label", QuestionRuleType.SHOW.getLabel(),
160            "value", QuestionRuleType.SHOW.name()
161        ));
162        
163        results.put("data", actions);
164        return results;
165    }
166}