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;
023import java.util.Set;
024
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.commons.lang3.LocaleUtils;
027
028import org.ametys.cms.contenttype.ContentType;
029import org.ametys.cms.search.model.impl.ReferencingCriterionDefinition;
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.runtime.i18n.I18nizableText;
034import org.ametys.runtime.model.DefinitionContext;
035import org.ametys.runtime.model.ElementDefinition;
036import org.ametys.runtime.model.Enumerator;
037import org.ametys.web.frontoffice.search.metamodel.RestrictedEnumerator;
038import org.ametys.web.frontoffice.search.metamodel.SearchServiceCriterionDefinition;
039import org.ametys.web.frontoffice.search.metamodel.SearchServiceCriterionDefinitionHelper;
040import org.ametys.web.frontoffice.search.metamodel.Searchable;
041
042/**
043 * {@link SearchServiceCriterionDefinition} for {@link ContentSearchable} searching on a model item.
044 * @param <T> Type of the criterion value
045 */
046public class ReferencingSearchServiceCriterionDefinition<T> extends ReferencingCriterionDefinition<T> implements SearchServiceCriterionDefinition<T>
047{
048    /** The search service criterion definition helper */
049    protected SearchServiceCriterionDefinitionHelper _searchServiceCriterionDefinitionHelper;
050
051    private Optional<Searchable> _searchable = Optional.empty();
052    
053    /**
054     * Constructor used to create a FO criterion definition on a referenced item
055     * @param reference the item referenced by this criterion
056     * @param referencePath the path of the criterion's reference
057     * @param baseContentType the content type defining the reference
058     */
059    public ReferencingSearchServiceCriterionDefinition(ElementDefinition reference, String referencePath, ContentType baseContentType)
060    {
061        super(reference, referencePath);
062        
063        if (baseContentType != null)
064        {
065            setContentTypeIds(Set.of(baseContentType.getId()));
066        }
067    }
068    
069    public Optional<Searchable> getSearchable()
070    {
071        return _searchable;
072    }
073    
074    public void setSearchable(Searchable searchable)
075    {
076        _searchable = Optional.ofNullable(searchable);
077    }
078    
079    /**
080     * Get the label of a facet value.
081     * @param value the facet value.
082     * @param contextualParameters the contextual parameters
083     * @return the label, or null if the value does not exist.
084     */
085    public Optional<I18nizableText> getFacetLabel(String value, Map<String, Object> contextualParameters)
086    {
087        Locale currentLocale = LocaleUtils.toLocale((String) contextualParameters.get("lang"));
088        return Optional.ofNullable(_getCriterionDefinitionHelper().getFacetLabel(this, value, currentLocale))
089                       .or(() -> Optional.of(new I18nizableText(value)));
090    }
091    
092    @Override
093    public List<I18nizableText> getContextPrefixLabels()
094    {
095        return Collections.singletonList(
096                Optional.of(getReference())
097                        .map(ElementDefinition::getModel)
098                        .filter(ContentType.class::isInstance)
099                        .map(ContentType.class::cast)
100                        .map(ContentType::getLabel)
101                        .orElse(new I18nizableText("plugin.web", "PLUGINS_WEB_SERVICE_SEARCH_SEARCHABLE_CONTENT_ALL_PREFIX_LABEL")));
102    }
103    
104    @Override
105    public boolean isMultiple()
106    {
107        return isEnumerated();
108    }
109    
110    @Override
111    public Query getEmptyValueQuery(String language, Map<String, Object> contextualParameters)
112    {
113        Query existQuery = getQuery(null, Operator.EXISTS, Collections.EMPTY_MAP, language, contextualParameters);
114        return new NotQuery(existQuery);
115    }
116    
117    public boolean isEnumerated()
118    {
119        return getEnumerator() != null;
120    }
121    
122    /**
123     * Determines if the current criterion definition is enumerated but can contain too much data
124     * @return <code>true</code> if the criterion definition can contain too much data, <code>false</code> otherwise
125     */
126    protected boolean isTooBigForStaticEnumerator() 
127    {
128        return false;
129    }
130    
131    public RestrictedEnumerator<T> getRestrictedEnumerator(Map<String, Object> contextualParameters)
132    {
133        Enumerator<T> enumerator = getEnumerator();
134        return enumerator != null
135                ? new RestrictedWrappedEnumerator<>(enumerator, getName())
136                : null;
137    }
138    
139    @Override
140    protected Map<String, Object> _toJSON(DefinitionContext context)
141    {
142        Map<String, Object> result = super._toJSON(context);
143        result.putAll(_getSearchServiceCriterionDefinitionHelper().getDefaultSearchServiceCriterionDefinitionJSON(this, isTooBigForStaticEnumerator()));
144        return result;
145    }
146    
147    /**
148     * Retrieves the search service criterion definition helper
149     * @return the search service criterion definition helper
150     */
151    protected SearchServiceCriterionDefinitionHelper _getSearchServiceCriterionDefinitionHelper()
152    {
153        if (_searchServiceCriterionDefinitionHelper == null)
154        {
155            try
156            {
157                _searchServiceCriterionDefinitionHelper = (SearchServiceCriterionDefinitionHelper) __serviceManager.lookup(SearchServiceCriterionDefinitionHelper.ROLE);
158            }
159            catch (ServiceException e)
160            {
161                throw new RuntimeException("Unable to lookup after the search service criterion definition helper", e);
162            }
163        }
164        
165        return _searchServiceCriterionDefinitionHelper;
166    }
167}