001/*
002 *  Copyright 2015 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;
017
018import java.util.ArrayList;
019import java.util.Collections;
020import java.util.HashMap;
021import java.util.HashSet;
022import java.util.List;
023import java.util.Map;
024import java.util.Set;
025
026import org.ametys.cms.search.ui.model.SearchUIColumn;
027import org.ametys.runtime.model.DefinitionContext;
028import org.ametys.runtime.model.View;
029import org.ametys.runtime.model.ViewHelper;
030import org.ametys.runtime.model.ViewItem;
031import org.ametys.runtime.model.ViewItemAccessor;
032import org.ametys.runtime.model.ViewItemContainer;
033
034/**
035 * Default implementation of a {@link SearchModel}.
036 */
037public class DefaultSearchModel implements SearchModel
038{
039    /** The content types of this search model. */
040    private Set<String> _contentTypes = new HashSet<>();
041    /** The content types excluded from this search model. */
042    private Set<String> _excludedContentTypes = new HashSet<>();
043    
044    /** The simple criteria */
045    private ViewItemContainer _criteria = new View();
046    /** The faceted criteria */
047    private ViewItemContainer _facetedCriteria = new View();
048    /** The result items */
049    private ViewItemContainer _resultItems = new View();
050    /** the workspace */
051    private String _workspace;
052    
053    /**
054     * Default constructor.
055     */
056    public DefaultSearchModel()
057    {
058        // Do nothing
059    }
060    
061    /**
062     * Constructor by copying an existing {@link SearchModel}.
063     * @param searchModelToCopy The {@link SearchModel} to copy
064     * @param contextualParameters The contextual parameters
065     */
066    public DefaultSearchModel(SearchModel searchModelToCopy, Map<String, Object> contextualParameters)
067    {
068        setContentTypes(new HashSet<>(searchModelToCopy.getContentTypes(contextualParameters)));
069        setExcludedContentTypes(new HashSet<>(searchModelToCopy.getExcludedContentTypes(contextualParameters)));
070        
071        ViewItemContainer criteriaToCopy = searchModelToCopy.getCriteria(contextualParameters);
072        if (criteriaToCopy != null)
073        {
074            View criteria = new View();
075            List<ViewItem> criteriaViewItems = ViewHelper.copyViewItems(criteriaToCopy.getViewItems());
076            criteria.addViewItems(criteriaViewItems);
077            setCriteria(criteria);
078        }
079        
080        ViewItemContainer facetedCriteriaToCopy = searchModelToCopy.getFacetedCriteria(contextualParameters);
081        if (facetedCriteriaToCopy != null)
082        {
083            View facetedCriteria = new View();
084            List<ViewItem> facetedCriteriaViewItems = ViewHelper.copyViewItems(facetedCriteriaToCopy.getViewItems());
085            facetedCriteria.addViewItems(facetedCriteriaViewItems);
086            setFacetedCriteria(facetedCriteria);
087        }
088        
089        ViewItemContainer resultItemsToCopy = searchModelToCopy.getResultItems(contextualParameters);
090        if (resultItemsToCopy != null)
091        {
092            View resultItems = new View();
093            List<ViewItem> resultViewItems = ViewHelper.copyViewItems(resultItemsToCopy.getViewItems());
094            resultItems.addViewItems(resultViewItems);
095            setResultItems(resultItems);
096        }
097        
098        setWorkspace(searchModelToCopy.getWorkspace(contextualParameters));
099    }
100    
101    public Set<String> getContentTypes(Map<String, Object> contextualParameters)
102    {
103        return Collections.unmodifiableSet(_contentTypes);
104    }
105    
106    /**
107     * Set the content types of the models
108     * @param cTypes The content types.
109     */
110    public void setContentTypes(Set<String> cTypes)
111    {
112        _contentTypes = new HashSet<>(cTypes);
113    }
114    
115    public Set<String> getExcludedContentTypes(Map<String, Object> contextualParameters)
116    {
117        return Collections.unmodifiableSet(_excludedContentTypes);
118    }
119    
120    /**
121     * Set the content types to exclude
122     * @param cTypes The content types to exclude
123     */
124    public void setExcludedContentTypes(Set<String> cTypes)
125    {
126        _excludedContentTypes = new HashSet<>(cTypes);
127    }
128    
129    public ViewItemContainer getCriteria(Map<String, Object> contextualParameters)
130    {
131        return _criteria;
132    }
133    
134    /**
135     * Add criteria to the simple criteria. The created criteria reference the given paths 
136     * @param criterionDefinitionHelper the criterion definition helper
137     * @param contextualParameters the contextual parameters
138     * @param references the paths to the items the criteria will reference 
139     */
140    public void addCriteria(SearchModelCriterionDefinitionHelper criterionDefinitionHelper, Map<String, Object> contextualParameters, String... references)
141    {
142        for (String reference : references)
143        {
144            SearchModelCriterionDefinition criterion = criterionDefinitionHelper.createReferencingCriterionDefinition(this, reference, getContentTypes(contextualParameters));
145            addCriterion(criterion, contextualParameters);
146        }
147    }
148    
149    /**
150     * Set the criteria
151     * @param criteria The criteria to set
152     */
153    public void setCriteria(ViewItemContainer criteria)
154    {
155        _criteria = criteria;
156    }
157    
158    public ViewItemContainer getFacetedCriteria(Map<String, Object> contextualParameters)
159    {
160        return _facetedCriteria;
161    }
162    
163    /**
164     * Add criteria to the faceted criteria. The created criteria reference the given paths 
165     * @param criterionDefinitionHelper the criterion definition helper
166     * @param contextualParameters the contextual parameters
167     * @param references the paths to the items the criteria will reference 
168     */
169    public void addFacetedCriteria(SearchModelCriterionDefinitionHelper criterionDefinitionHelper, Map<String, Object> contextualParameters, String... references)
170    {
171        for (String reference : references)
172        {
173            SearchModelCriterionDefinition criterion = criterionDefinitionHelper.createReferencingCriterionDefinition(this, reference, getContentTypes(contextualParameters));
174            addFacetedCriterion(criterion, contextualParameters);
175        }
176    }
177
178    /**
179     * Set the faceted criteria
180     * @param criteria The faceted criteria to set
181     */
182    public void setFacetedCriteria(ViewItemContainer criteria)
183    {
184        _facetedCriteria = criteria;
185    }
186    
187    public ViewItemContainer getResultItems(Map<String, Object> contextualParameters)
188    {
189        return _resultItems;
190    }
191    
192    /**
193     * Set the result items
194     * @param resultItems The result items to set
195     */
196    public void setResultItems(ViewItemContainer resultItems)
197    {
198        _resultItems = resultItems;
199    }
200    
201    public String getWorkspace(Map<String, Object> contextualParameters)
202    {
203        return _workspace;
204    }
205    
206    /**
207     * Set the workspace
208     * @param workspace The workspace to set
209     */
210    public void setWorkspace(String workspace)
211    {
212        _workspace = workspace;
213    }
214    
215    public Map<String, Object> toJSON(Map<String, Object> contextualParameters)
216    {
217        Map<String, Object> jsonObject = new HashMap<>();
218        
219        jsonObject.put("workspace", getWorkspace(contextualParameters));
220        
221        ViewItemContainer criteria = getCriteria(contextualParameters);
222        Map<String, Object> criteriaToJSON = ViewHelper.viewItemsToJSON(criteria.getViewItems(), DefinitionContext.newInstance());
223        jsonObject.put("simple-criteria", criteriaToJSON);
224        
225        jsonObject.put("columns", resultItemsToJSON(contextualParameters));
226        jsonObject.put("hasFacets", !getFacetedCriteria(contextualParameters).getViewItems().isEmpty());
227        
228        return jsonObject;
229    }
230    
231    public List<Object> resultItemsToJSON(Map<String, Object> contextualParameters)
232    {
233        ViewItemContainer resultItems = getResultItems(contextualParameters);
234        DefinitionContext context = DefinitionContext.newInstance();
235        if (resultItems instanceof View view)
236        {
237            context.withView(view);
238        }
239        return _resultItemsToJSON(resultItems, context);
240    }
241    
242    /**
243     * Converts the search model's result items on a JSON map
244     * @param viewItemAccessor The result items
245     * @param context The definition context
246     * @return the result items as a JSON map
247     */
248    protected List<Object> _resultItemsToJSON(ViewItemAccessor viewItemAccessor, DefinitionContext context)
249    {
250        List<Object> jsonObject = new ArrayList<>();
251        
252        for (ViewItem viewItem : viewItemAccessor.getViewItems())
253        {
254            if (viewItem instanceof SearchUIColumn searchUIColumn)
255            {
256                jsonObject.add(searchUIColumn.toJSON(context));
257            }
258            else if (viewItem instanceof ViewItemAccessor itemAccessor)
259            {
260                jsonObject.addAll(_resultItemsToJSON(itemAccessor, context));
261            }
262        }
263        
264        return jsonObject;
265    }
266}