001/*
002 *  Copyright 2019 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.web.frontoffice.search.instance.model;
017
018import java.util.List;
019import java.util.Map;
020import java.util.stream.Collectors;
021
022import org.slf4j.Logger;
023import org.slf4j.LoggerFactory;
024
025import org.ametys.cms.search.advanced.WrappedValue;
026import org.ametys.web.frontoffice.search.metamodel.SearchCriterionDefinition;
027
028/**
029 * The mode of a {@link FOSearchCriterion}
030 */
031public enum FOSearchCriterionMode
032{
033    /**
034     * The criterion is static, i.e. valued by the webmaster and is not a proposed criterion to the final user.
035     */
036    STATIC
037    {
038        @Override
039        public FoWrappedValue getValue(FOSearchCriterion searchCriterion, Map<String, Object> userCriteria, Map<String, Object> contextualParameters)
040        {
041            Object staticValue = searchCriterion.getStaticValue().get();
042            FoWrappedValue result = new FoWrappedValue(staticValue);
043            __LOGGER.debug("Value for static criterion '{}': {}", searchCriterion.getId(), result);
044            return result;
045        }
046    },
047    
048    /**
049     * The criterion is proposed to the final user.
050     */
051    USER_INPUT
052    {
053        @Override
054        public FoWrappedValue getValue(FOSearchCriterion searchCriterion, Map<String, Object> userCriteria, Map<String, Object> contextualParameters)
055        {
056            String criterionId = searchCriterion.getId();
057            Object val = userCriteria.get(criterionId);
058            SearchCriterionDefinition criterionDefinition = searchCriterion.getCriterionDefinition();
059            if (val != null)
060            {
061                boolean requestEmptyValue = val.equals(NONE_VALUE) 
062                        && !searchCriterion.isMandatory()
063                        && criterionDefinition.isEnumerated();
064                
065                FoWrappedValue result = new FoWrappedValue(val, requestEmptyValue);
066                __LOGGER.debug("Value from user for criterion '{}': {}", criterionId, result);
067                return result;
068            }
069            
070            // val is null
071            // no need to build a collection of all existing entries of the enumerated values as all are allowed, and empty is allowed too => avoid an unnecessary query on the indexed field
072            __LOGGER.debug("Value from user for criterion '{}': null", criterionId);
073            return new FoWrappedValue(null);
074        }
075    },
076    
077    /**
078     * The criterion is proposed to the final user, with a restricted enumeration of choices.
079     */
080    RESTRICTED_USER_INPUT
081    {
082        @Override
083        public FoWrappedValue getValue(FOSearchCriterion searchCriterion, Map<String, Object> userCriteria, Map<String, Object> contextualParameters)
084        {
085            String criterionId = searchCriterion.getId();
086            Object val = userCriteria.get(criterionId);
087            if (val != null)
088            {
089                boolean requestEmptyValue = val.equals(NONE_VALUE) && !searchCriterion.isMandatory();
090                FoWrappedValue result = new FoWrappedValue(val, requestEmptyValue);
091                __LOGGER.debug("Value from user for (restricted) criterion '{}': {}", criterionId, result);
092                return result;
093            }
094            else
095            {
096                // The criterion was not filled by the visitor
097                // Consider it as the 'All' option to filter results matching with at least one value in the restricted values
098                List<Object> vals = searchCriterion
099                        .getRestrictedValues()
100                        .get()
101                        .values()
102                        .keySet()
103                        .stream()
104                        .collect(Collectors.toList());
105                
106                boolean requestEmptyValue = !searchCriterion.isMandatory();
107                FoWrappedValue result = new FoWrappedValue(vals, requestEmptyValue);
108                __LOGGER.debug("Value for criterion '{}' (computed because not filled by user but is restricted): {}", criterionId, result);
109                return result;
110            }
111        }
112    },
113    
114    /**
115     * The criterion is proposed for content profiled by user group tag.
116     */
117    PROFILED_GROUPS_TAGS_INPUT
118    {
119        @Override
120        public FoWrappedValue getValue(FOSearchCriterion searchCriterion, Map<String, Object> userCriteria, Map<String, Object> contextualParameters)
121        {
122            return new FoWrappedValue(PROFILED_GROUPS_TAGS_VALUE);
123        }
124    };
125    
126    /** The none value */
127    public static final String NONE_VALUE = "__ametys_none";
128    
129    /** The profiled groups tags value */
130    public static final String PROFILED_GROUPS_TAGS_VALUE = "__ametys_profiled_groups_tags";
131    
132    static final Logger __LOGGER = LoggerFactory.getLogger(FOSearchCriterionMode.class);
133
134    /**
135     * Gets the value from the {@link FOSearchCriterion criterion} and the final user criteria.
136     * @param searchCriterion The {@link FOSearchCriterion} which is in this mode
137     * @param finalUserCriteria The criteria from the final user
138     * @param contextualParameters The contextual parameters
139     * @return the value
140     */
141    public abstract FoWrappedValue getValue(FOSearchCriterion searchCriterion, Map<String, Object> finalUserCriteria, Map<String, Object> contextualParameters);
142    
143    /**
144     * <code>true</code> if the criterion is static
145     * @return <code>true</code> if the criterion is static
146     */
147    public boolean isStatic()
148    {
149        return this.equals(STATIC) || this.equals(PROFILED_GROUPS_TAGS_INPUT);
150    }
151    
152    /**
153     * A {@link WrappedValue}, being the return type of {@link FOSearchCriterionMode#getValue}. It can notify for enumerated criteria if empty value need to be requested, through {@link #requestEmptyValue()}
154     */
155    public static final class FoWrappedValue extends WrappedValue
156    {
157        private final boolean _requestEmptyValue;
158        
159        private FoWrappedValue(Object value)
160        {
161            super(value);
162            _requestEmptyValue = false;
163        }
164        
165        private FoWrappedValue(Object values, boolean requestEmptyValue)
166        {
167            super(values);
168            _requestEmptyValue = requestEmptyValue;
169        }
170        
171        /**
172         * <code>true</code> if the wrapped value is from enumerated and no mandatory data. The caller has selected none value or all value for restricted user input.
173         * @return <code>true</code> if the wrapped value is from enumerated and no mandatory data. The caller has selected none value or all value for restricted user input.
174         */
175        public boolean requestEmptyValue()
176        {
177            return _requestEmptyValue;
178        }
179        
180        @Override
181        public String toString()
182        {
183            return super.toString() + "{requestEmptyValue:" + _requestEmptyValue + "}";
184        }
185    }
186}