001/*
002 *  Copyright 2022 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.program;
017
018import java.lang.reflect.Array;
019import java.util.Arrays;
020import java.util.List;
021import java.util.Optional;
022import java.util.stream.Collectors;
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.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.avalon.framework.service.Serviceable;
030import org.apache.commons.lang3.StringUtils;
031
032import org.ametys.cms.contenttype.ContentType;
033import org.ametys.cms.contenttype.ContentTypeExtensionPoint;
034import org.ametys.cms.contenttype.MetadataType;
035import org.ametys.cms.contenttype.indexing.CustomIndexingField;
036import org.ametys.cms.data.ContentValue;
037import org.ametys.cms.repository.Content;
038import org.ametys.cms.repository.ContentAttributeTypeExtensionPoint;
039import org.ametys.odf.ODFHelper;
040import org.ametys.runtime.i18n.I18nizableText;
041import org.ametys.runtime.model.ModelItem;
042import org.ametys.runtime.model.type.ElementType;
043import org.ametys.runtime.plugin.component.AbstractLogEnabled;
044
045/**
046 * Indexing field for the order of degree
047 */
048public class SubProgramParentProgramIndexingField extends AbstractLogEnabled implements CustomIndexingField, Configurable, Serviceable
049{
050    /** The ODF Helper */
051    protected ODFHelper _odfHelper;
052    
053    /** The Content Type Extension Point */
054    protected ContentTypeExtensionPoint _ctypeEP;
055    
056    /** The Content Attribute Type Extension Point */
057    protected ContentAttributeTypeExtensionPoint _contentAttributeTypeEP;
058    
059    /** The field name */
060    private String _name;
061    /** The label field */
062    private I18nizableText _label;
063    /** The description field */
064    private I18nizableText _description;
065    /** The program attribute name to index for subProgram */
066    private String _programAttributeName;
067    /** The program attribute type to index for subProgram */
068    private String _programAttributeType;
069    
070    public void service(ServiceManager manager) throws ServiceException
071    {
072        _contentAttributeTypeEP = (ContentAttributeTypeExtensionPoint) manager.lookup(ContentAttributeTypeExtensionPoint.ROLE);
073        _ctypeEP = (ContentTypeExtensionPoint) manager.lookup(ContentTypeExtensionPoint.ROLE);
074        _odfHelper = (ODFHelper) manager.lookup(ODFHelper.ROLE);
075    }
076    
077    public void configure(Configuration configuration) throws ConfigurationException
078    {
079        _name = configuration.getAttribute("name");
080        _label = I18nizableText.parseI18nizableText(configuration.getChild("label"), "plugin.odf");
081        _description = I18nizableText.parseI18nizableText(configuration.getChild("description"), "plugin.odf");
082        
083        _programAttributeType = configuration.getAttribute("type");
084        if (StringUtils.isBlank(_programAttributeType))
085        {
086            throw new ConfigurationException("Attribute 'type' is mandatory for " + SubProgramParentProgramIndexingField.class.getName());
087        }
088        
089        _programAttributeName = configuration.getChild("program-attribute-name").getValue();
090        if (StringUtils.isBlank(_programAttributeName))
091        {
092            throw new ConfigurationException("Child 'program-attribute-name' is mandatory for " + SubProgramParentProgramIndexingField.class.getName());
093        }
094    }
095
096    public String getName()
097    {
098        return _name;
099    }
100
101    public I18nizableText getLabel()
102    {
103        return _label;
104    }
105
106    public I18nizableText getDescription()
107    {
108        return _description;
109    }
110
111    public MetadataType getType()
112    {
113        return MetadataType.valueOf(_programAttributeType.toUpperCase());
114    }
115
116    public Object[] getValues(Content content)
117    {
118        if (content instanceof SubProgram)
119        {
120            SubProgram subProgram = (SubProgram) content;
121            List<Object> values = _odfHelper.getParentPrograms(subProgram)
122                .stream()
123                .map(this::_getValues)
124                .flatMap(List::stream)
125                .collect(Collectors.toList());
126            
127            if (getType() == MetadataType.CONTENT)
128            {
129                List<String> collect = values.stream()
130                    .filter(ContentValue.class::isInstance)
131                    .map(ContentValue.class::cast)
132                    .map(ContentValue::getContentIfExists)
133                    .filter(Optional::isPresent)
134                    .map(o -> o.get().getId())
135                    .collect(Collectors.toList());
136                
137                return !collect.isEmpty() ? collect.toArray(new String[collect.size()]) : new String[0];
138            }
139            else
140            {
141                ContentType programCType = _ctypeEP.getExtension(ProgramFactory.PROGRAM_CONTENT_TYPE);
142                ModelItem modelItem = programCType.getModelItem(_programAttributeName);
143                ElementType attributeType = (ElementType) _contentAttributeTypeEP.getExtension(modelItem.getType().getId());
144                
145                return !values.isEmpty() ? values.toArray((Object[]) Array.newInstance(attributeType.getManagedClass(), values.size())) : (Object[]) Array.newInstance(attributeType.getManagedClass(), 0);
146            }
147        }
148        
149        return new Object[0];
150    }
151    
152    private List<Object> _getValues(Program program)
153    {
154        if (program.isMultiple(_programAttributeName))
155        {
156            Object[] values = program.getValue(_programAttributeName);
157            
158            return values != null ? Arrays.asList(values) : List.of();
159        }
160        else
161        {
162            Object value = program.getValue(_programAttributeName);
163            return value != null ? List.of(value) : List.of();
164        }
165    }
166}