001/*
002 *  Copyright 2023 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.List;
019import java.util.Locale;
020import java.util.Map;
021import java.util.Set;
022
023import org.apache.avalon.framework.component.Component;
024import org.apache.avalon.framework.configuration.Configuration;
025import org.apache.avalon.framework.configuration.ConfigurationException;
026import org.apache.avalon.framework.configuration.DefaultConfiguration;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.avalon.framework.service.Serviceable;
030import org.apache.commons.lang3.StringUtils;
031import org.bouncycastle.util.Arrays;
032
033import org.ametys.cms.contenttype.ContentType;
034import org.ametys.cms.data.type.ModelItemTypeExtensionPoint;
035import org.ametys.cms.data.type.indexing.IndexableElementType;
036import org.ametys.cms.model.CMSDataContext;
037import org.ametys.plugins.core.ui.util.ConfigurationHelper;
038import org.ametys.runtime.i18n.I18nizableText;
039import org.ametys.runtime.model.ElementDefinition;
040import org.ametys.runtime.model.ItemParserHelper;
041import org.ametys.runtime.model.exception.UnknownTypeException;
042import org.ametys.runtime.model.type.DataContext;
043import org.ametys.runtime.plugin.component.AbstractLogEnabled;
044
045/**
046 * Helper for {@link CriterionDefinition}
047 */
048public class CriterionDefinitionHelper extends AbstractLogEnabled implements Component, Serviceable
049{
050    /** The component role. */
051    public static final String ROLE = CriterionDefinitionHelper.class.getName();
052    
053    /** The extension point containing all available criterion types */
054    protected ModelItemTypeExtensionPoint _criterionTypeExtensionPoint;
055    
056    public void service(ServiceManager manager) throws ServiceException
057    {
058        _criterionTypeExtensionPoint = (ModelItemTypeExtensionPoint) manager.lookup(ModelItemTypeExtensionPoint.ROLE_CRITERION_DEFINITION);
059    }
060    
061    /**
062     * Retrieves the type implementation of the given criterion type identifier
063     * @param <T> the type of the criterion type
064     * @param criterionTypeId the criterion type identifier
065     * @return the criterion type implementation
066     */
067    @SuppressWarnings("unchecked")
068    public <T> IndexableElementType<T> getCriterionDefinitionType(String criterionTypeId)
069    {
070        if (_criterionTypeExtensionPoint.hasExtension(criterionTypeId))
071        {
072            return (IndexableElementType<T>) _criterionTypeExtensionPoint.getExtension(criterionTypeId);
073        }
074        else
075        {
076            throw new UnknownTypeException("Unable to retrieve type with identifier '" + criterionTypeId + "'. This type is not available for criteria");
077        }
078    }
079    
080    /**
081     * Retrieves the default widget for the given criterion definition 
082     * @param criterionDefinition the criterion definition
083     * @return the default widget for the given criterion definition
084     */
085    public String getCriterionDefinitionDefaultWidget(CriterionDefinition criterionDefinition)
086    {
087        String defaultWidget = criterionDefinition.getType().getDefaultCriterionWidget(CMSDataContext.newInstance()
088                                                                                                     .withModelItem(criterionDefinition));
089        
090        return "edition.textarea".equals(defaultWidget) ? null : defaultWidget;
091    }
092    
093    /**
094     * Retrieves the default widget parameters for the given criterion definition 
095     * @param criterionDefinition the criterion definition
096     * @return the default widget parameters for the given criterion definition
097     */
098    public Map<String, I18nizableText> getCriterionDefinitionDefaultWidgetParameters(CriterionDefinition criterionDefinition)
099    {
100        return criterionDefinition.getType().getDefaultCriterionWidgetParameters(CMSDataContext.newInstance()
101                                                                                               .withModelItem(criterionDefinition));
102    }
103    
104    /**
105     * Wrap the given configuration to add content types
106     * @param originalConf the configuration to wrap
107     * @param contentTypes the content types to add in wrapped configuration
108     * @return the wrapped configuration
109     * @throws ConfigurationException if an error occurs
110     */
111    public Configuration wrapCriterionConfiguration(Configuration originalConf, Set<ContentType> contentTypes) throws ConfigurationException
112    {
113        DefaultConfiguration conf = new DefaultConfiguration(originalConf);
114        
115        conf.removeChild(conf.getChild("contentTypes"));
116        
117        DefaultConfiguration contentTypesConf = new DefaultConfiguration("contentTypes");
118        for (ContentType contentType : contentTypes)
119        {
120            DefaultConfiguration contentTypeConf = new DefaultConfiguration("type");
121            contentTypeConf.setAttribute("id", contentType.getId());
122            contentTypesConf.addChild(contentTypeConf);
123        }
124        
125        conf.addChild(contentTypesConf);
126        return conf;
127    }
128    
129    /**
130     * Get the label of a facet value for the given criterion.
131     * @param <T> the type of the facet criterion
132     * @param criterion the criterion
133     * @param value the facet value.
134     * @param currentLocale the current locale
135     * @return the label, or null if the value does not exist.
136     */
137    public <T> I18nizableText getFacetLabel(CriterionDefinition<T> criterion, String value, Locale currentLocale)
138    {
139        DataContext context = DataContext.newInstance()
140                .withModelItem(criterion)
141                .withLocale(currentLocale);
142        IndexableElementType<T> type = criterion.getType();
143        return type.getFacetLabel(value, context);
144    }
145    
146    /**
147     * Check if the given query value is empty 
148     * @param value the query value to check
149     * @return <code>true</code> if the given query value is empty, <code>false</code> otherwise
150     */
151    public boolean isQueryValueEmpty(Object value)
152    {
153        return value == null
154                || value instanceof String strValue && StringUtils.isEmpty(strValue)
155                || value instanceof List listValue && listValue.isEmpty()
156                || value.getClass().isArray() && Arrays.isNullOrEmpty((Object[]) value);
157    }
158    
159    /**
160     * Parses the criterion definition default value.
161     * @param defaultValueConfig the default value configuration.
162     * @param definition the element definition.
163     * @param defaultValueType the type of the default value
164     * @return the default value or <code>null</code> if none default value is defined.
165     * @throws ConfigurationException if the configuration is not valid.
166     */
167    public Object parseCriterionDefinitionDefaultValue(Configuration defaultValueConfig, ElementDefinition definition, String defaultValueType) throws ConfigurationException
168    {
169        return defaultValueType == null
170                ? ConfigurationHelper.parseObject(defaultValueConfig, StringUtils.EMPTY)
171                : ItemParserHelper.parseDefaultValue(defaultValueConfig, definition, defaultValueType);
172    }
173}