001/*
002 *  Copyright 2023 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.ui.model.impl;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022import java.util.Optional;
023
024import org.apache.cocoon.ProcessingException;
025
026import org.ametys.cms.search.ui.model.SearchUIColumn;
027import org.ametys.cms.search.ui.model.SearchUIColumnHelper;
028import org.ametys.plugins.repository.model.CompositeDefinition;
029import org.ametys.plugins.repository.model.RepeaterDefinition;
030import org.ametys.runtime.model.DefinitionContext;
031import org.ametys.runtime.model.ModelItem;
032import org.ametys.runtime.model.ModelViewItem;
033import org.ametys.runtime.model.ModelViewItemGroup;
034import org.ametys.runtime.model.ViewItem;
035import org.ametys.runtime.model.ViewItemAccessor;
036
037/**
038 * This class represents a result column
039 */
040public class RepeaterSearchUIColumn extends ModelViewItemGroup<RepeaterDefinition> implements SearchUIColumn<RepeaterDefinition>
041{
042    private int _width = -1;
043    private boolean _hidden;
044    private boolean _editable = true;
045    private boolean _sortable = true;
046    private boolean _allowSortOnMultipleJoin;
047    private Optional<String> _defaultSorter = Optional.empty();
048    private Optional<String> _renderer = Optional.empty();
049    private Optional<String> _converter = Optional.empty();
050    
051    public int getWidth()
052    {
053        return _width > 0
054                ? _width
055                : SearchUIColumnHelper.getDefaultColumnWidth(this);
056    }
057    
058    public void setWidth (int width)
059    {
060        _width = width;
061    }
062    
063    public boolean isHidden()
064    {
065        return _hidden;
066    }
067    
068    public void setHidden (boolean hidden)
069    {
070        _hidden = hidden;
071    }
072    
073    public boolean isEditable()
074    {
075        return _editable && SearchUIColumnHelper.isEditionAllowed(this);
076    }
077    
078    public void setEditable (boolean editable)
079    {
080        _editable = editable;
081    }
082    
083    public boolean isSortable()
084    {
085        return _sortable && SearchUIColumnHelper.isSortAllowed(this);
086    }
087    
088    public void setSortable (boolean sortable)
089    {
090        _sortable = sortable;
091    }
092    
093    public boolean allowSortOnMultipleJoin()
094    {
095        return _allowSortOnMultipleJoin;
096    }
097    
098    public void setAllowSortOnMultipleJoin(boolean allowSortOnMultipleJoin)
099    {
100        _allowSortOnMultipleJoin = allowSortOnMultipleJoin;
101    }
102    
103    public String getDefaultSorter()
104    {
105        return isSortable()
106                ? _defaultSorter.orElse(null)
107                : null;
108    }
109    
110    public void setDefaultSorter(Optional<String> defaultSorter)
111    {
112        _defaultSorter = defaultSorter;
113    }
114    
115    public String getRenderer()
116    {
117        return _renderer
118                .orElse("Ametys.plugins.cms.search.SearchGridHelper.renderRepeater");
119    }
120    
121    public void setRenderer(Optional<String> renderer)
122    {
123        this._renderer = renderer;
124    }
125    
126    public String getConverter()
127    {
128        return _converter
129                .orElse("Ametys.plugins.cms.search.SearchGridHelper.convertRepeater");
130    }
131    
132    public void setConverter(Optional<String> converter)
133    {
134        this._converter = converter;
135    }
136    
137    @Override
138    public RepeaterSearchUIColumn createInstance()
139    {
140        return new RepeaterSearchUIColumn();
141    }
142
143    @Override
144    public Map<String, Object> toJSON(DefinitionContext context) throws ProcessingException
145    {
146        Map<String, Object> json = super.toJSON(context);
147
148        if (!json.isEmpty())
149        {
150            json.putAll(SearchUIColumnHelper.columnPropertiesToJSON(this));
151        }
152        return json;
153    }
154    
155    @Override
156    protected Map<String, Object> _childrenToJSON(DefinitionContext context) throws ProcessingException
157    {
158        Map<String, Object> result = new HashMap<>();
159        List<Map<String, Object>> subColumnsAsJSON = new ArrayList<>();
160        
161        ViewItemAccessor viewItemAccessor = getViewItems().isEmpty() ? _createRepeaterSearchUIColumn() : this;
162        for (ModelViewItem subColumn : _getSubColumns(viewItemAccessor))
163        {
164            subColumnsAsJSON.add(subColumn.toJSON(context));
165        }
166        
167        result.put("columns", subColumnsAsJSON);
168        return result;
169    }
170    
171    private RepeaterSearchUIColumn _createRepeaterSearchUIColumn()
172    {
173        RepeaterSearchUIColumn repeaterSearchUIColumn = new RepeaterSearchUIColumn();
174        repeaterSearchUIColumn.setDefinition(getDefinition());
175        
176        repeaterSearchUIColumn.addViewItems(_createViewItems(repeaterSearchUIColumn));
177        
178        return repeaterSearchUIColumn;
179    }
180    
181    private List<ViewItem> _createViewItems(ModelViewItemGroup group)
182    {
183        List<ViewItem> viewItems = new ArrayList<>();
184        
185        for (ModelItem modelItem : group.getDefinition().getModelItems())
186        {
187            if (modelItem instanceof CompositeDefinition compositeDefinition)
188            {
189                ModelViewItemGroup<CompositeDefinition> compositeViewItem = new ModelViewItemGroup<>();
190                compositeViewItem.setDefinition(compositeDefinition);
191                
192                compositeViewItem.addViewItems(_createViewItems(compositeViewItem));
193                
194                viewItems.add(compositeViewItem);
195            }
196            else
197            {
198                SearchUIColumn column = SearchUIColumnHelper.createModelItemColumn(modelItem);
199                viewItems.add(column);
200            }
201        }
202        
203        return viewItems;
204    }
205    
206    private List<ModelViewItem> _getSubColumns(ViewItemAccessor viewItemAccessor)
207    {
208        List<ModelViewItem> subColumns = new ArrayList<>();
209        
210        org.ametys.plugins.repository.model.ViewHelper.visitView(viewItemAccessor, 
211            (element, definition) -> {
212                // attribute
213                subColumns.add(element);
214            },
215            (group, definition) -> {
216                // composite
217                // CMS-10740 - explode composite to have all its children at first level
218                subColumns.addAll(_getSubColumns(group));
219            },
220            (group, definition) -> {
221                // repeater
222                subColumns.add(group);
223            },
224            group -> {
225                // group
226                subColumns.addAll(_getSubColumns(group));
227            }
228        );
229        
230        return subColumns;
231    }
232    
233    @Override
234    public void copyTo(ViewItem item)
235    {
236        super.copyTo(item);
237        
238        assert item instanceof RepeaterSearchUIColumn;
239        RepeaterSearchUIColumn column = (RepeaterSearchUIColumn) item;
240        
241        column.setWidth(_width);
242        column.setHidden(_hidden);
243        
244        column.setEditable(_editable);
245        column.setSortable(_sortable);
246        column.setAllowSortOnMultipleJoin(_allowSortOnMultipleJoin);
247        column.setDefaultSorter(_defaultSorter);
248        
249        column.setRenderer(_renderer);
250        column.setConverter(_converter);
251    }
252}