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.impl;
017
018import java.util.Map;
019import java.util.Optional;
020import java.util.Set;
021
022import org.apache.cocoon.xml.AttributesImpl;
023import org.apache.cocoon.xml.XMLUtils;
024import org.xml.sax.ContentHandler;
025import org.xml.sax.SAXException;
026
027import org.ametys.cms.data.type.indexing.IndexableElementType;
028import org.ametys.cms.model.CMSDataContext;
029import org.ametys.cms.search.model.CriterionDefinitionAwareElementDefinition;
030import org.ametys.cms.search.model.SearchModel;
031import org.ametys.cms.search.model.SearchModelCriterionDefinition;
032import org.ametys.cms.search.query.Query;
033import org.ametys.cms.search.query.Query.LogicalOperator;
034import org.ametys.cms.search.query.Query.Operator;
035import org.ametys.runtime.model.DefinitionContext;
036import org.ametys.runtime.model.ElementDefinition;
037
038/**
039 * Default implementation for {@link SearchModelCriterionDefinition} searching on a model item.
040 * @param <T> Type of the criterion value
041 */
042public class ReferencingSearchModelCriterionDefinition<T> extends ReferencingCriterionDefinition<T> implements SearchModelCriterionDefinition<T>
043{
044    /** Prefix for name of referencing criterion definitions */
045    public static final String CRITERION_DEFINITION_PREFIX = "reference-";
046    
047    /** The criteria operator */
048    protected Operator _operator;
049    
050    /**
051     * Default constructor.
052     */
053    public ReferencingSearchModelCriterionDefinition()
054    {
055        // Nothing to do
056    }
057    
058    /**
059     * Constructor used to create a BO criterion definition on a referenced item
060     * @param reference the item referenced by this criterion
061     * @param referencePath the path of the criterion's reference
062     */
063    public ReferencingSearchModelCriterionDefinition(ElementDefinition reference, String referencePath)
064    {
065        super(reference, referencePath);
066    }
067    
068    @Override
069    public Set<String> getContentTypeIds(Map<String, Object> contextualParameters)
070    {
071        return getModel().getContentTypes(contextualParameters);
072    }
073    
074    @Override
075    public String getName()
076    {
077        return CRITERION_DEFINITION_PREFIX + getReferencePath() + "-" + getOperator().getName();
078    }
079    
080    @Override
081    public Query getQuery(Object value, Operator customOperator, Map<String, Object> allValues, String language, Map<String, Object> contextualParameters)
082    {
083        Operator operator = customOperator != null ? customOperator : getOperator();
084        return super.getQuery(value, operator, allValues, language, contextualParameters);
085    }
086    
087    public Operator getOperator()
088    {
089        return Optional.ofNullable(_operator)
090                       .orElseGet(this::_getDefaultOperator);
091    }
092    
093    /**
094     * Retrieves the default operator for the criterion 
095     * @return the default operator for the criterion
096     */
097    protected Operator _getDefaultOperator()
098    {
099        if (getEnumerator() != null)
100        {
101            return Operator.EQ;
102        }
103        else
104        {
105            ElementDefinition reference = getReference();
106            return reference instanceof CriterionDefinitionAwareElementDefinition criterionDefinitionAwareReference
107                    ? criterionDefinitionAwareReference.getDefaultCriterionOperator()
108                    : ((IndexableElementType) reference.getType()).getDefaultCriterionOperator(CMSDataContext.newInstance()
109                                                                                                             .withModelItem(reference));
110        }
111    }
112    
113    public void setOperator(Operator operator)
114    {
115        _operator = operator;
116    }
117    
118    public void setMultipleOperandOperator(LogicalOperator multipleOperand)
119    {
120        _multipleOperandOperator = multipleOperand;
121    }
122
123    @Override
124    protected Map<String, Object> _toJSON(DefinitionContext context)
125    {
126        Map<String, Object> json = super._toJSON(context);
127        json.put("criterionOperator", getOperator().toString().toLowerCase());
128        json.put("criterionMultipleOperand", getMultipleOperandOperator().name());
129        json.put("criterionProperty", getReferencePath());
130        return json;
131    }
132    
133    @Override
134    public void toSAX(ContentHandler contentHandler, DefinitionContext context) throws SAXException
135    {
136        super.toSAX(contentHandler, context);
137        
138        XMLUtils.createElement(contentHandler, "test-operator", getOperator().toString().toLowerCase());
139        XMLUtils.createElement(contentHandler, "multiple-operand", getMultipleOperandOperator().name());
140
141        AttributesImpl referenceAttributes = new AttributesImpl();
142        referenceAttributes.addCDATAAttribute("ref", getReferencePath());
143        XMLUtils.createElement(contentHandler, "item", referenceAttributes);
144    }
145    
146    @SuppressWarnings("unchecked")
147    public void copyTo(SearchModelCriterionDefinition<T> criterion, Map<String, Object> contextualParameters)
148    {
149        criterion.setModel(getModel());
150        
151        criterion.setName(getName());
152        criterion.setPluginName(getPluginName());
153        criterion.setLabel(getLabel());
154        criterion.setDescription(getDescription());
155        criterion.setWidget(getWidget());
156        criterion.setWidgetParameters(getWidgetParameters());
157        
158        criterion.setType(getType());
159        criterion.setMultiple(isMultiple());
160        
161        criterion.setEnumerator(getEnumerator());
162        criterion.setCustomEnumerator(getCustomEnumerator());
163        criterion.setEnumeratorConfiguration(getEnumeratorConfiguration());
164        
165        criterion.setValidator(getValidator());
166        criterion.setCustomValidator(getCustomValidator());
167        criterion.setValidatorConfiguration(getValidatorConfiguration());
168        
169        criterion.setParsedDefaultValues(getParsedDefaultValues());
170        
171        criterion.setOperator(getOperator());
172        criterion.setMultipleOperandOperator(getMultipleOperandOperator());
173        
174        if (criterion instanceof ReferencingSearchModelCriterionDefinition referencingCriterion)
175        {
176            referencingCriterion.setSolrFacetFieldName(getSolrFacetFieldName(contextualParameters));
177            referencingCriterion.setJoinedPaths(getJoinedPaths(contextualParameters));
178            
179            referencingCriterion.setReference(getReference());
180            referencingCriterion.setReferencePath(getReferencePath());
181            
182            referencingCriterion.setContentTypeIds(getContentTypeIds(contextualParameters));
183        }
184    }
185    
186    @Override
187    public SearchModel getModel()
188    {
189        return (SearchModel) super.getModel();
190    }
191}