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        ElementDefinition reference = getReference();
100        return reference instanceof CriterionDefinitionAwareElementDefinition criterionDefinitionAwareReference
101                ? criterionDefinitionAwareReference.getDefaultCriterionOperator()
102                : ((IndexableElementType) reference.getType()).getDefaultCriterionOperator(CMSDataContext.newInstance()
103                                                                                                         .withModelItem(reference));
104    }
105    
106    public void setOperator(Operator operator)
107    {
108        _operator = operator;
109    }
110    
111    public void setMultipleOperandOperator(LogicalOperator multipleOperand)
112    {
113        _multipleOperandOperator = multipleOperand;
114    }
115
116    @Override
117    protected Map<String, Object> _toJSON(DefinitionContext context)
118    {
119        Map<String, Object> json = super._toJSON(context);
120        json.put("criterionOperator", getOperator().toString().toLowerCase());
121        json.put("criterionMultipleOperand", getMultipleOperandOperator().name());
122        json.put("criterionProperty", getReferencePath());
123        return json;
124    }
125    
126    @Override
127    public void toSAX(ContentHandler contentHandler, DefinitionContext context) throws SAXException
128    {
129        super.toSAX(contentHandler, context);
130        
131        XMLUtils.createElement(contentHandler, "test-operator", getOperator().toString().toLowerCase());
132        XMLUtils.createElement(contentHandler, "multiple-operand", getMultipleOperandOperator().name());
133
134        AttributesImpl referenceAttributes = new AttributesImpl();
135        referenceAttributes.addCDATAAttribute("ref", getReferencePath());
136        XMLUtils.createElement(contentHandler, "item", referenceAttributes);
137    }
138    
139    @SuppressWarnings("unchecked")
140    public void copyTo(SearchModelCriterionDefinition<T> criterion, Map<String, Object> contextualParameters)
141    {
142        criterion.setModel(getModel());
143        
144        criterion.setName(getName());
145        criterion.setPluginName(getPluginName());
146        criterion.setLabel(getLabel());
147        criterion.setDescription(getDescription());
148        criterion.setWidget(getWidget());
149        criterion.setWidgetParameters(getWidgetParameters());
150        
151        criterion.setType(getType());
152        criterion.setMultiple(isMultiple());
153        
154        criterion.setEnumerator(getEnumerator());
155        criterion.setCustomEnumerator(getCustomEnumerator());
156        criterion.setEnumeratorConfiguration(getEnumeratorConfiguration());
157        
158        criterion.setValidator(getValidator());
159        criterion.setCustomValidator(getCustomValidator());
160        criterion.setValidatorConfiguration(getValidatorConfiguration());
161        
162        criterion.setParsedDefaultValues(getParsedDefaultValues());
163        
164        criterion.setOperator(getOperator());
165        criterion.setMultipleOperandOperator(getMultipleOperandOperator());
166        
167        if (criterion instanceof ReferencingSearchModelCriterionDefinition referencingCriterion)
168        {
169            referencingCriterion.setSolrFacetFieldName(getSolrFacetFieldName(contextualParameters));
170            referencingCriterion.setJoinedPaths(getJoinedPaths(contextualParameters));
171            
172            referencingCriterion.setReference(getReference());
173            referencingCriterion.setReferencePath(getReferencePath());
174            
175            referencingCriterion.setContentTypeIds(getContentTypeIds(contextualParameters));
176        }
177    }
178    
179    @Override
180    public SearchModel getModel()
181    {
182        return (SearchModel) super.getModel();
183    }
184}