001/*
002 *  Copyright 2018 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.metamodel.impl;
017
018import java.util.Collections;
019import java.util.List;
020import java.util.Locale;
021import java.util.Map;
022import java.util.Optional;
023
024import org.apache.avalon.framework.component.Component;
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027
028import org.ametys.cms.contenttype.ContentType;
029import org.ametys.cms.search.model.SearchCriterionHelper;
030import org.ametys.cms.search.query.NotQuery;
031import org.ametys.cms.search.query.Query;
032import org.ametys.cms.search.query.Query.Operator;
033import org.ametys.cms.search.ui.model.SearchUICriterion;
034import org.ametys.runtime.i18n.I18nizableText;
035import org.ametys.runtime.parameter.Validator;
036import org.ametys.web.frontoffice.search.metamodel.SearchCriterionDefinition;
037import org.ametys.web.frontoffice.search.metamodel.Searchable;
038
039/**
040 * {@link SearchCriterionDefinition} for {@link ContentSearchable} proposing a search criterion (based on a {@link SearchUICriterion}).
041 */
042public class ContentSearchCriterionDefinition extends AbstractDefaultSearchCriterionDefinition
043{
044    /** The service manager */
045    protected static ServiceManager __serviceManager;
046    /** The SearchUICriterion */
047    protected SearchUICriterion _searchUICriterion;
048    /** The content type on which this criterion definition applies. Can be empty if it applies to all types of contents. */
049    protected Optional<ContentType> _contentType;
050
051    /**
052     * Default constructor
053     * @param id The id
054     * @param pluginName The plugin name
055     * @param searchable the {@link Searchable}
056     * @param criterion The linked {@link SearchUICriterion}
057     * @param contentType The content type on which this criterion definition applies. Can be empty if it applies to all types of contents.
058     * @param validator The validator
059     */
060    public ContentSearchCriterionDefinition(
061            String id,
062            String pluginName,
063            Optional<Searchable> searchable,
064            SearchUICriterion criterion,
065            Optional<ContentType> contentType,
066            Optional<Validator> validator)
067    {
068        super(
069                id,
070                pluginName,
071                criterion.getLabel(),
072                criterion.getType(),
073                Optional.ofNullable(criterion.getWidget()),
074                Optional.ofNullable(criterion.getWidgetParameters()),
075                Optional.ofNullable(criterion.getEnumerator()),
076                validator.isPresent() ? validator : Optional.ofNullable(criterion.getValidator()),
077                Optional.ofNullable(criterion.getDefaultValue()),
078                searchable
079        );
080        _searchUICriterion = criterion;
081        _contentType = contentType;
082    }
083    
084    /**
085     * Get the label of a facet value.
086     * @param value the facet value.
087     * @param contextualParameters the contextual parameters
088     * @return the label, or null if the value does not exist.
089     */
090    public Optional<I18nizableText> getFacetLabel(String value, Map<String, Object> contextualParameters)
091    {
092        Locale currentLocale = new Locale((String) contextualParameters.get("lang"));
093        
094        try
095        {
096            SearchCriterionHelper searchCriterionHelper = (SearchCriterionHelper) __serviceManager.lookup(SearchCriterionHelper.ROLE);
097            
098            return Optional.of(getSearchUICriterion())
099                    .map(criterion -> searchCriterionHelper.getFacetLabel(criterion, value, currentLocale))
100                    .or(() -> Optional.of(new I18nizableText(value)));
101        }
102        catch (ServiceException e)
103        {
104            return Optional.of(new I18nizableText(value));
105        }
106    }
107    
108    /**
109     * Gets the {@link SearchUICriterion} associated to this definition
110     * @return the {@link SearchUICriterion} associated to this definition
111     */
112    public SearchUICriterion getSearchUICriterion()
113    {
114        return _searchUICriterion;
115    }
116    
117    @Override
118    public List<I18nizableText> getContextPrefixLabels()
119    {
120        return Collections.singletonList(
121                _contentType
122                    .map(ContentType::getLabel)
123                    .orElse(new I18nizableText("plugin.web", "PLUGINS_WEB_SERVICE_SEARCH_SEARCHABLE_CONTENT_ALL_PREFIX_LABEL")));
124    }
125    
126    @Override
127    public Map<String, Object> toJSON() throws Exception
128    {
129        Map<String, Object> json = super.toJSON();
130        json.put("multiple", _searchUICriterion.isMultiple());
131        return json;
132    }
133    
134    @Override
135    public Query getQuery(Object value, Operator operator, String language, Map<String, Object> contextualParameters)
136    {
137        return _searchUICriterion.getQuery(value, operator, Collections.EMPTY_MAP, language, contextualParameters);
138    }
139    
140    @Override
141    public Query getEmptyValueQuery(String language, Map<String, Object> contextualParameters)
142    {
143        Query existQuery = _searchUICriterion.getQuery(null, Operator.EXISTS, Collections.EMPTY_MAP, language, contextualParameters);
144        return new NotQuery(existQuery);
145    }
146    
147    /**
148     * Set the service manager
149     * The {@link ServiceManager} is used in the criterion definition to get the search criterion helper
150     * {@link SearchCriterionDefinition} is not a {@link Component} and can't have a {@link ServiceManager} itself. Another {@link Component} has to set it
151     * @param manager the service manager to set
152     */
153    public static void setServiceManager(ServiceManager manager)
154    {
155        __serviceManager = manager;
156    }
157}