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