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