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.plugins.odforientation;
017
018import java.io.IOException;
019import java.util.Collections;
020import java.util.Locale;
021import java.util.Optional;
022
023import org.apache.avalon.framework.service.ServiceException;
024import org.apache.avalon.framework.service.ServiceManager;
025import org.apache.cocoon.ProcessingException;
026import org.apache.cocoon.environment.ObjectModelHelper;
027import org.apache.cocoon.environment.Request;
028import org.apache.cocoon.generation.ServiceableGenerator;
029import org.apache.cocoon.xml.AttributesImpl;
030import org.apache.cocoon.xml.XMLUtils;
031import org.apache.commons.lang3.LocaleUtils;
032import org.apache.commons.lang3.StringUtils;
033import org.xml.sax.SAXException;
034
035import org.ametys.cms.contenttype.ContentTypesHelper;
036import org.ametys.cms.repository.ContentTypeExpression;
037import org.ametys.cms.search.advanced.AbstractTreeNode;
038import org.ametys.cms.search.advanced.TreeLeaf;
039import org.ametys.core.util.LambdaUtils;
040import org.ametys.odf.orgunit.OrgUnit;
041import org.ametys.odf.orgunit.OrgUnitFactory;
042import org.ametys.odf.orgunit.RootOrgUnitProvider;
043import org.ametys.plugins.repository.AmetysObjectIterable;
044import org.ametys.plugins.repository.AmetysObjectResolver;
045import org.ametys.plugins.repository.query.QueryHelper;
046import org.ametys.plugins.repository.query.expression.Expression;
047import org.ametys.plugins.repository.query.expression.Expression.Operator;
048import org.ametys.runtime.model.View;
049import org.ametys.runtime.model.type.DataContext;
050import org.ametys.web.frontoffice.search.SearchService;
051import org.ametys.web.frontoffice.search.instance.SearchServiceInstance;
052import org.ametys.web.frontoffice.search.instance.SearchServiceInstanceManager;
053import org.ametys.web.repository.page.Page;
054import org.ametys.web.repository.page.Page.PageType;
055import org.ametys.web.repository.page.ZoneItem;
056import org.ametys.web.repository.page.ZoneItem.ZoneType;
057
058/**
059 * Generates the exhaustive list of orgunits
060 */
061public class OrgUnitsGenerator extends ServiceableGenerator
062{
063    private AmetysObjectResolver _resolver;
064    private RootOrgUnitProvider _rootOrgUnitProvider;
065    private ContentTypesHelper _cTypeHelper;
066    private SearchServiceInstanceManager _searchServiceInstanceManager;
067
068    @Override
069    public void service(ServiceManager serviceManager) throws ServiceException
070    {
071        super.service(serviceManager);
072        _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
073        _rootOrgUnitProvider = (RootOrgUnitProvider) serviceManager.lookup(RootOrgUnitProvider.ROLE);
074        _cTypeHelper = (ContentTypesHelper) serviceManager.lookup(ContentTypesHelper.ROLE);
075        _searchServiceInstanceManager = (SearchServiceInstanceManager) serviceManager.lookup(SearchServiceInstanceManager.ROLE);
076    }
077    
078    @Override
079    public void generate() throws IOException, SAXException, ProcessingException
080    {
081        Request request = ObjectModelHelper.getRequest(objectModel);
082        
083        String lang = parameters.getParameter("lang", (String) request.getAttribute("sitemapLanguage"));
084        Locale defaultLocale = LocaleUtils.toLocale(lang);
085        
086        ZoneItem zoneItem = (ZoneItem) request.getAttribute(ZoneItem.class.getName());
087        
088        String contentView = zoneItem.getServiceParameters().getValue("contentView");
089        View view = _cTypeHelper.getView(contentView, new String[] {OrgUnitFactory.ORGUNIT_CONTENT_TYPE}, new String[0]);
090        
091        
092        contentHandler.startDocument();
093        
094        XMLUtils.startElement(contentHandler, "orgunits");
095        
096        Expression expr = new ContentTypeExpression(Operator.EQ, OrgUnitFactory.ORGUNIT_CONTENT_TYPE);
097        String xPathQuery = QueryHelper.getXPathQuery(null, OrgUnitFactory.ORGUNIT_NODETYPE, expr);
098        AmetysObjectIterable<OrgUnit> orgUnits = _resolver.query(xPathQuery);
099        
100        orgUnits.stream().filter(ou -> !_rootOrgUnitProvider.isRoot(ou)).forEach(LambdaUtils.wrapConsumer(ou -> {
101            
102            AttributesImpl attrs = new AttributesImpl();
103            attrs.addCDATAAttribute("id", ou.getId());
104            
105            XMLUtils.startElement(contentHandler, "orgunit", attrs);
106            ou.dataToSAX(contentHandler, view, DataContext.newInstance().withLocale(defaultLocale).withEmptyValues(false));
107            XMLUtils.endElement(contentHandler, "orgunit");
108        }));
109        
110        _saxSearchForm(zoneItem);
111        
112        XMLUtils.endElement(contentHandler, "orgunits");
113        
114        contentHandler.endDocument();
115    }
116    
117    private void _saxSearchForm(ZoneItem zoneItem) throws SAXException
118    {
119        String criterionInputName = _getOrgUnitCriterionInputName(zoneItem);
120        if (criterionInputName != null)
121        {
122            XMLUtils.startElement(contentHandler, "search-form");
123            XMLUtils.createElement(contentHandler, "criterion", criterionInputName);
124            XMLUtils.endElement(contentHandler, "search-form");
125        }
126    }
127    
128    private String _getOrgUnitCriterionInputName(ZoneItem zoneItem)
129    {
130        String searchPageId = zoneItem.getServiceParameters().getValue("search-page");
131        if (StringUtils.isNotEmpty(searchPageId))
132        {
133            Page page = _resolver.resolveById(searchPageId);
134            if (page.getType() == PageType.CONTAINER) 
135            {
136                Optional< ? extends ZoneItem> searchZoneItem = page.getZones().stream()
137                    .flatMap(z -> z.getZoneItems().stream())
138                    .filter(zi -> zi.getType() == ZoneType.SERVICE)
139                    .filter(zi -> zi.getServiceId().equals(SearchService.ROLE))
140                    .findFirst();
141                    
142                if (searchZoneItem.isPresent())
143                {
144                    SearchServiceInstance serviceInstance = _searchServiceInstanceManager.get(searchZoneItem.get().getId());
145                    return serviceInstance.getCriterionTree()
146                            .map(AbstractTreeNode::getFlatLeaves)
147                            .orElseGet(Collections::emptyList)
148                            .stream()
149                            .map(TreeLeaf::getValue)
150                            .filter(c -> StringUtils.endsWith(c.getCriterionDefinition().getName(), "$org.ametys.plugins.odf.Content.abstractProgram$orgUnit"))
151                            .findFirst()
152                            .map(c -> c.getName())
153                            .orElseGet(null);
154                    
155                }
156            }
157        }
158        
159        return null;
160    }
161    
162}