001/*
002 *  Copyright 2020 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.plugins.odfpilotage.enumerators;
017
018import java.util.Collections;
019import java.util.Map;
020import java.util.Optional;
021import java.util.stream.Collectors;
022import java.util.stream.Stream;
023
024import org.apache.avalon.framework.configuration.Configurable;
025import org.apache.avalon.framework.configuration.Configuration;
026import org.apache.avalon.framework.configuration.ConfigurationException;
027import org.apache.avalon.framework.context.Context;
028import org.apache.avalon.framework.context.ContextException;
029import org.apache.avalon.framework.context.Contextualizable;
030import org.apache.avalon.framework.service.ServiceException;
031import org.apache.avalon.framework.service.ServiceManager;
032import org.apache.avalon.framework.service.Serviceable;
033import org.apache.cocoon.components.ContextHelper;
034import org.apache.commons.lang3.StringUtils;
035
036import org.ametys.cms.data.ContentValue;
037import org.ametys.cms.repository.Content;
038import org.ametys.cms.repository.ContentTypeExpression;
039import org.ametys.odf.course.Course;
040import org.ametys.odf.program.Container;
041import org.ametys.odf.program.ContainerFactory;
042import org.ametys.plugins.odfpilotage.helper.PilotageHelper;
043import org.ametys.plugins.repository.AmetysObjectIterable;
044import org.ametys.plugins.repository.AmetysObjectResolver;
045import org.ametys.plugins.repository.UnknownAmetysObjectException;
046import org.ametys.plugins.repository.query.QueryHelper;
047import org.ametys.plugins.repository.query.expression.AndExpression;
048import org.ametys.plugins.repository.query.expression.Expression.Operator;
049import org.ametys.plugins.repository.query.expression.StringExpression;
050import org.ametys.runtime.i18n.I18nizableText;
051import org.ametys.runtime.model.Enumerator;
052
053/**
054 * {@link Enumerator} for the steps holder
055 */
056public class StepHolderEnumerator implements Enumerator<ContentValue>, Serviceable, Contextualizable, Configurable, org.ametys.runtime.parameter.Enumerator
057{
058    private Context _context;
059    private AmetysObjectResolver _resolver;
060    private PilotageHelper _pilotageHelper;
061    
062    /**
063     * If <code>true</code> and the context is not an ELP, we get all the steps.
064     */
065    private boolean _usedForSearch;
066    
067    public void contextualize(Context context) throws ContextException
068    {
069        _context = context;
070    }
071    
072    public void configure(Configuration configuration) throws ConfigurationException
073    {
074        Configuration customConf = configuration.getChild("enumeration").getChild("custom-enumerator");
075        _usedForSearch = customConf.getChild("used-for-search").getValueAsBoolean(false);
076    }
077    
078    public void service(ServiceManager manager) throws ServiceException
079    {
080        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
081        _pilotageHelper = (PilotageHelper) manager.lookup(PilotageHelper.ROLE);
082    }
083
084    public I18nizableText getEntry(ContentValue value) throws Exception
085    {
086        try
087        {
088            return _getDisplayName((Container) value.getContent());
089        }
090        catch (UnknownAmetysObjectException e)
091        {
092            // Ignore.
093        }
094        
095        return null;
096    }
097    
098    public I18nizableText getEntry(String value) throws Exception
099    {
100        try
101        {
102            return _getDisplayName(_resolver.resolveById(value));
103        }
104        catch (UnknownAmetysObjectException e)
105        {
106            // Ignore.
107        }
108        
109        return null;
110    }
111
112    public Map<ContentValue, I18nizableText> getTypedEntries() throws Exception
113    {
114        Optional<Course> course = Optional.of(_context)
115            .map(ContextHelper::getRequest)
116            .map(r -> r.getAttribute(Content.class.getName()))
117            .filter(Course.class::isInstance)
118            .map(Course.class::cast);
119            
120        // course est nul si on est hors contexte de l'édition
121        Stream<Container> containers = course.isPresent()
122            ? _pilotageHelper.getSteps(course.get()).stream()
123            : (_usedForSearch ? _getAllSteps() : Stream.empty());
124        
125        return containers
126            .collect(Collectors.toMap(ContentValue::new, this::_getDisplayName));
127    }
128
129    @SuppressWarnings("unchecked")
130    public Map<Object, I18nizableText> getEntries() throws Exception
131    {
132        return (Map<Object, I18nizableText>) (Object) getTypedEntries();
133    }
134
135    private Stream<Container> _getAllSteps()
136    {
137        return _pilotageHelper.getYearId()
138            .map(anneeId -> new StringExpression("nature", Operator.EQ, anneeId))
139            .map(anneeExpression -> new AndExpression(new ContentTypeExpression(Operator.EQ, ContainerFactory.CONTAINER_CONTENT_TYPE), anneeExpression))
140            .map(expression -> QueryHelper.getXPathQuery(null, ContainerFactory.CONTAINER_NODETYPE, expression))
141            .map(_resolver::<Container>query)
142            .map(AmetysObjectIterable::stream)
143            .orElseGet(() -> Stream.of());
144    }
145    
146    private I18nizableText _getDisplayName(Container container)
147    {
148        StringBuilder displayName = new StringBuilder();
149        
150        // Display code
151        displayName.append("[");
152        displayName.append(container.getCode());
153        displayName.append("] ");
154        
155        // Display etpCode if it is present
156        String etpCode = container.getValue("etpCode");
157        if (StringUtils.isNotBlank(etpCode))
158        {
159            displayName.append("[");
160            displayName.append(etpCode);
161            displayName.append("] ");
162        }
163        
164        displayName.append(container.getTitle());
165        
166        return new I18nizableText(displayName.toString());
167    }
168
169    // TODO NEWATTRIBUTEAPI: remove this method when org.ametys.runtime.parameter.Enumerator will be removed
170    public Map<String, Object> getConfiguration()
171    {
172        return Collections.EMPTY_MAP;
173    }
174}