001/*
002 *  Copyright 2025 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.trash.element;
017
018import java.util.HashMap;
019import java.util.LinkedHashSet;
020import java.util.Map;
021import java.util.Optional;
022import java.util.Set;
023import java.util.stream.Collectors;
024import java.util.stream.Stream;
025
026import javax.jcr.Node;
027import javax.jcr.RepositoryException;
028
029import org.ametys.cms.data.ametysobject.ModifiableModelAwareDataAwareAmetysObject;
030import org.ametys.cms.data.holder.ModifiableIndexableDataHolder;
031import org.ametys.cms.data.holder.impl.DefaultModifiableModelAwareDataHolder;
032import org.ametys.cms.trash.model.TrashElementModel;
033import org.ametys.plugins.repository.AmetysObjectIterable;
034import org.ametys.plugins.repository.AmetysRepositoryException;
035import org.ametys.plugins.repository.data.repositorydata.impl.JCRRepositoryData;
036import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject;
037import org.ametys.plugins.repository.query.QueryHelper;
038import org.ametys.plugins.repository.query.expression.AndExpression;
039import org.ametys.plugins.repository.query.expression.BooleanExpression;
040import org.ametys.plugins.repository.query.expression.Expression;
041import org.ametys.plugins.repository.query.expression.Expression.Operator;
042import org.ametys.plugins.repository.query.expression.StringExpression;
043import org.ametys.plugins.repository.trash.TrashElement;
044import org.ametys.runtime.model.ViewItemAccessor;
045import org.ametys.runtime.model.exception.BadItemTypeException;
046import org.ametys.runtime.model.type.DataContext;
047
048/**
049 * Class representing a {@link DefaultTrashElement}
050 */
051public class DefaultTrashElement extends DefaultTraversableAmetysObject<TrashElementFactory> implements TrashElement, ModifiableModelAwareDataAwareAmetysObject
052{
053    /**
054     * Constructor.
055     * 
056     * @param node the JCR Node.
057     * @param parentPath the parent path
058     * @param factory the corresponding factory.
059     */
060    public DefaultTrashElement(Node node, String parentPath, TrashElementFactory factory)
061    {
062        super(node, parentPath, factory);
063    }
064    
065    public ModifiableIndexableDataHolder getDataHolder()
066    {
067        JCRRepositoryData repositoryData = new JCRRepositoryData(getNode());
068        return new DefaultModifiableModelAwareDataHolder(repositoryData, this._getFactory().getModel(), Optional.empty(), Optional.empty(), Optional.of(this));
069    }
070
071    public Map<String, Object> dataToJSON(ViewItemAccessor viewItemAccessor, DataContext context) throws BadItemTypeException
072    {
073        Map<String, Object> json = new HashMap<>(ModifiableModelAwareDataAwareAmetysObject.super.dataToJSON(viewItemAccessor, context));
074        json.put("id", getId());
075        return json;
076    }
077    
078    public String getAmetysObjectId()
079    {
080        return getValue(TrashElementModel.DELETED_OBJECT);
081    }
082
083    public Set<TrashElement> getLinkedElement(boolean hiddenOnly)
084    {
085        return Optional.<String[]> ofNullable(getValue(TrashElementModel.LINKED_OBJECTS))
086            .map(Stream::of)
087            .orElseGet(Stream::of)
088            .map(objectId -> {
089                Expression filter = new StringExpression(TrashElementModel.DELETED_OBJECT, Operator.EQ, objectId);
090                if (hiddenOnly)
091                {
092                    filter = new AndExpression(filter, new BooleanExpression(TrashElementModel.HIDDEN, true));
093                }
094                return QueryHelper.getXPathQuery(
095                        null, TrashElementFactory.TRASH_ELEMENT_NODETYPE,
096                        filter);
097            })
098            .map(query -> {
099                try
100                {
101                    return _getFactory()._getResolver().<TrashElement> query(query, getNode().getSession());
102                }
103                catch (RepositoryException e)
104                {
105                    throw new AmetysRepositoryException(e);
106                }
107            })
108            .flatMap(AmetysObjectIterable::stream)
109            .collect(Collectors.<TrashElement> toSet());
110    }
111
112    public void addLinkedObjects(String... linkedObjectsIds)
113    {
114        if (linkedObjectsIds == null || linkedObjectsIds.length == 0)
115        {
116            return;
117        }
118        
119        String[] previousObjects = getValue(TrashElementModel.LINKED_OBJECTS);
120        Set<String> objects = new LinkedHashSet<>();
121        if (previousObjects != null)
122        {
123            for (String id : previousObjects)
124            {
125                objects.add(id);
126            }
127        }
128        
129        for (String id : linkedObjectsIds)
130        {
131            objects.add(id);
132        }
133        
134        setValue(TrashElementModel.LINKED_OBJECTS, objects.toArray(new String[0]));
135    }
136
137    public void setHidden(boolean hidden)
138    {
139        setValue(TrashElementModel.HIDDEN, hidden);
140    }
141}