001/*
002 *  Copyright 2024 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.cms.search.model;
017
018import java.util.Locale;
019import java.util.Map;
020
021import org.apache.avalon.framework.configuration.Configuration;
022import org.apache.avalon.framework.configuration.ConfigurationException;
023import org.apache.commons.lang3.BooleanUtils;
024
025import org.ametys.cms.data.type.indexing.IndexableElementType;
026import org.ametys.cms.model.CMSDataContext;
027import org.ametys.cms.search.QueryBuilder;
028import org.ametys.cms.search.query.Query;
029import org.ametys.cms.search.query.Query.Operator;
030import org.ametys.runtime.i18n.I18nizableText;
031import org.ametys.runtime.model.ElementDefinition;
032import org.ametys.runtime.model.Enumerator;
033import org.ametys.runtime.model.exception.BadItemTypeException;
034import org.ametys.runtime.plugin.component.ThreadSafeComponentManager;
035
036/**
037 * Interface for {@link ElementDefinition} that have specific behaviors for referencing criteria
038 * @param <T> Type of the element value
039 */
040public interface CriterionDefinitionAwareElementDefinition<T> extends ElementDefinition<T>
041{
042    /**
043     * Get the enumerator to use when rendering this property as a criterion
044     * @param configuration The enumerator configuration.
045     * @param enumeratorManager ComponentManager for the criterion's {@link Enumerator}
046     * @return The enumerator or null if the property's criterion is not enumerated.
047     * @throws ConfigurationException If an error occurs while initializing the enumerator
048     */
049    public default Enumerator getDefaultCriterionEnumerator(Configuration configuration, ThreadSafeComponentManager<Enumerator> enumeratorManager) throws ConfigurationException
050    {
051        return getEnumerator();
052    }
053    
054    /**
055     * Get the type to use when rendering the element as a criterion
056     * @return the type to use for a criterion
057     */
058    public IndexableElementType getDefaultCriterionType();
059    
060    /**
061     * Converts the given value to have the right typed for value to give to the {@link #getQuery(Object, Operator, String, Map)} method
062     * @param value the value to convert
063     * @param language The current search language.
064     * @param contextualParameters the search contextual parameters.
065     * @return the value, converted to a well typed value
066     * @throws BadItemTypeException if the given value can not be converted
067     */
068    public default Object convertQueryValue(Object value, String language, Map<String, Object> contextualParameters) throws BadItemTypeException
069    {
070        CMSDataContext context = CMSDataContext.newInstance()
071                                               .withMultilingualSearch(contextualParameters.containsKey(QueryBuilder.MULTILINGUAL_SEARCH))
072                                               .withSearchedValueEscaped(BooleanUtils.isTrue((Boolean) contextualParameters.get(QueryBuilder.VALUE_IS_ESCAPED)))
073                                               .withLocale(Locale.forLanguageTag(language))
074                                               .withModelItem(this);
075        
076        IndexableElementType type = getDefaultCriterionType();
077        return type.convertQueryValue(value, context);
078    }
079    
080    /**
081     * Get the {@link Query} associated to the given value.
082     * @param value the user-submitted value for this property.
083     * @param operator In advanced search mode, the operator chosen by the user. <code>null</code> to use the criterion-defined operator (simple search mode).
084     * @param language The current search language.
085     * @param contextualParameters the search contextual parameters.
086     * @return The {@link Query} associated to the given value.
087     */
088    public default Query getQuery(Object value, Operator operator, String language, Map<String, Object> contextualParameters)
089    {
090        CMSDataContext context = CMSDataContext.newInstance()
091                                               .withMultilingualSearch(contextualParameters.containsKey(QueryBuilder.MULTILINGUAL_SEARCH))
092                                               .withSearchedValueEscaped(BooleanUtils.isTrue((Boolean) contextualParameters.get(QueryBuilder.VALUE_IS_ESCAPED)))
093                                               .withLocale(Locale.forLanguageTag(language))
094                                               .withModelItem(this);
095        
096        IndexableElementType type = getDefaultCriterionType();
097        return type.getDefaultQuery(value, getName(), operator, false, context);
098    }
099    
100    /**
101     * Get the widget to use when rendering the property as a criterion
102     * @return The widget to use, or <code>null</code> if no specific widget is necessary.
103     */
104    public default String getDefaultCriterionWidget()
105    {
106        CMSDataContext context = CMSDataContext.newInstance()
107                                               .withModelItem(this);
108        
109        IndexableElementType type = getDefaultCriterionType();
110        return type.getDefaultCriterionWidget(context);
111    }
112    
113    /**
114     * Get the widget parameters to use when rendering the property as a criterion
115     * @param configuration The widget parameters configuration
116     * @return The widget parameters to use, or an empty Map if no specific widget parameters are necessary.
117     */
118    public default Map<String, I18nizableText> getDefaultCriterionWidgetParameters(Configuration configuration)
119    {
120        CMSDataContext context = CMSDataContext.newInstance()
121                                               .withModelItem(this);
122        
123        IndexableElementType type = getDefaultCriterionType();
124        return type.getDefaultCriterionWidgetParameters(context);
125    }
126    
127    /**
128     * Get the operator to use when rendering the property as a criterion
129     * @return The operator to use
130     */
131    public default Operator getDefaultCriterionOperator()
132    {
133        return Operator.EQ;
134    }
135    
136    @Override
137    public IndexableElementType<T> getType();
138}