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.odf.ose.export.impl.odf;
017
018import java.util.List;
019import java.util.Optional;
020import java.util.Set;
021
022import org.apache.avalon.framework.component.Component;
023import org.apache.avalon.framework.service.ServiceException;
024import org.apache.avalon.framework.service.ServiceManager;
025import org.apache.avalon.framework.service.Serviceable;
026
027import org.ametys.cms.repository.Content;
028import org.ametys.odf.ProgramItem;
029import org.ametys.odf.enumeration.OdfReferenceTableEntry;
030import org.ametys.odf.orgunit.OrgUnit;
031import org.ametys.odf.ose.db.ParameterizableQuery;
032import org.ametys.odf.ose.export.utils.ElementRetriever;
033import org.ametys.odf.program.Container;
034import org.ametys.plugins.odfpilotage.cost.entity.CostComputationData;
035import org.ametys.runtime.plugin.component.AbstractLogEnabled;
036
037/**
038 * Exporter for program elements.
039 * @param <T> The type of the element to export, should extend {@link Content} and {@link ProgramItem}
040 */
041public abstract class AbstractProgramElementExporter<T extends Content & ProgramItem> extends AbstractLogEnabled implements Component, Serviceable
042{
043    /** The retriever of elements from ODF */
044    protected ElementRetriever _elementRetriever;
045    
046    @Override
047    public void service(ServiceManager manager) throws ServiceException
048    {
049        _elementRetriever = (ElementRetriever) manager.lookup(ElementRetriever.ROLE);
050    }
051    
052    /**
053     * Get queries to export the given program element.
054     * @param programElement The program element to export
055     * @param oseCatalog The OSE catalog
056     * @param costData the result of cost computation of the catalog
057     * @return A {@link List} of {@link ParameterizableQuery} to export the program element, it can be empty if there is a problem (see logs)
058     */
059    public List<ParameterizableQuery> getQueries(T programElement, Long oseCatalog, CostComputationData costData)
060    {
061        // Structure : Remonter parent par parent pour obtenir le ou les structures rattachées (sur abstractProgram)
062        Set<OrgUnit> orgUnits = _elementRetriever.retrieveOrgUnits(programElement);
063        
064        // Get the step holder (étape porteuse en français dans le texte)
065        Set<Container> stepsHolder = _elementRetriever.retrieveStepsHolder(programElement);
066
067        // Get the period type on the current program element and parents
068        Set<OdfReferenceTableEntry> periodTypes = _elementRetriever.retrievePeriodTypes(programElement);
069        
070        if (stepsHolder.size() != 1 || orgUnits.size() != 1)
071        {
072            LogUtils.programElementImpossibilityStepsOrOrgunits(getLogger(), programElement, stepsHolder, orgUnits);
073            return List.of();
074        }
075        
076        Container stepHolder = _getFirstStepHolder(stepsHolder);
077        Set<Container> steps = _elementRetriever.retrieveSteps(programElement);
078        // step holder is not among steps => do not export the program element
079        if (!steps.contains(stepHolder))
080        {
081            LogUtils.programElementDebugIsNotContainedInSteps(getLogger(), programElement, stepHolder, steps);
082            return List.of();
083        }
084        
085        ProgramElementData data = new ProgramElementData();
086        Optional.of(periodTypes)
087            .map(this::_getFirstRefTableCode)
088            .ifPresentOrElse(
089                data::setPeriodType,
090                () -> LogUtils.programElementWarningPeriodTypes(getLogger(), programElement, periodTypes)
091            );
092        data.setStepHolder(stepHolder.getCode());
093        data.setOrgUnit(_getFirstOrgUnitCode(orgUnits));
094        data.setSteps(steps);
095        
096        return _getQueries(programElement, data, oseCatalog, costData);
097    }
098    
099    /**
100     * Get the queries to create the program element in the OSE database.
101     * @param programElement The program element
102     * @param data The calculated data attached to the program element
103     * @param oseCatalog The OSE catalog
104     * @param costData the result of cost computation of the catalog
105     * @return The list of queries
106     */
107    protected abstract List<ParameterizableQuery> _getQueries(T programElement, ProgramElementData data, Long oseCatalog, CostComputationData costData);
108    
109    private Container _getFirstStepHolder(Set<Container> stepsHolder)
110    {
111        return stepsHolder
112            .stream()
113            .findFirst()
114            .get();
115    }
116    
117    private String _getFirstOrgUnitCode(Set<OrgUnit> orgUnits)
118    {
119        return orgUnits
120            .stream()
121            .findFirst()
122            .map(OrgUnit::getUAICode)
123            .get();
124    }
125    
126    private String _getFirstRefTableCode(Set<OdfReferenceTableEntry> entries)
127    {
128        return entries
129            .stream()
130            .findFirst()
131            .map(OdfReferenceTableEntry::getCode)
132            .orElse(null);
133    }
134
135    /**
136     * An object to represent common computed data on the program element like orgunit, step holder, etc.
137     */
138    protected static class ProgramElementData
139    {
140        private String _orgUnitCode;
141        private String _stepHolderCode;
142        private Set<Container> _steps;
143        private String _periodTypeCode;
144        
145        /**
146         * Set the orgunit code of the program element.
147         * @param orgUnitCode The code of the orgunit
148         */
149        public void setOrgUnit(String orgUnitCode)
150        {
151            _orgUnitCode = orgUnitCode;
152        }
153
154        /**
155         * Set the step holder code of the program element.
156         * @param stepHolderCode The code of the step holder
157         */
158        public void setStepHolder(String stepHolderCode)
159        {
160            _stepHolderCode = stepHolderCode;
161        }
162
163        /**
164         * Set the period type code of the program element.
165         * @param periodTypeCode The code of the period type
166         */
167        public void setPeriodType(String periodTypeCode)
168        {
169            _periodTypeCode = periodTypeCode;
170        }
171
172        /**
173         * Set the steps attached to the program element.
174         * @param steps The steps
175         */
176        public void setSteps(Set<Container> steps)
177        {
178            _steps = steps;
179        }
180
181        /**
182         * Get the orgunit code of the program element.
183         * @return The code of the orgunit
184         */
185        public String getOrgUnit()
186        {
187            return _orgUnitCode;
188        }
189
190        /**
191         * Get the step holder code of the program element.
192         * @return The code of the step holder
193         */
194        public String getStepHolder()
195        {
196            return _stepHolderCode;
197        }
198
199        /**
200         * Get the period type code of the program element.
201         * @return The code of the period type
202         */
203        public String getPeriodType()
204        {
205            return _periodTypeCode;
206        }
207
208        /**
209         * Get the steps attached to the program element.
210         * @return The steps
211         */
212        public Set<Container> getSteps()
213        {
214            return _steps;
215        }
216    }
217}