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.content;
017
018import java.io.IOException;
019import java.util.Map;
020import java.util.Set;
021import java.util.regex.Pattern;
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.lang.StringUtils;
032import org.xml.sax.SAXException;
033
034import org.ametys.cms.repository.Content;
035import org.ametys.odf.course.Course;
036import org.ametys.odf.enumeration.OdfReferenceTableEntry;
037import org.ametys.odf.program.AbstractProgram;
038import org.ametys.odf.program.Program;
039import org.ametys.odf.program.SubProgram;
040import org.ametys.odf.skill.ODFSkillsHelper;
041
042/**
043 * SAX the skills hold by child courses of a {@link Program} or a not mutualised {@link SubProgram}
044 */
045public class ProgramSkillsGenerator extends ServiceableGenerator
046{
047    // FIXME Accept all view names starting with "main" to be able to make the ODF and ODF orientation skins coexist (whereas they use different main views)
048    private static final Set<Pattern> __ALLOWED_VIEW_NAMES = Set.of(Pattern.compile("main[a-z\\-]*"));
049    
050    private ODFSkillsHelper _skillsHelper;
051    
052    @Override
053    public void service(ServiceManager smanager) throws ServiceException
054    {
055        super.service(smanager);
056        _skillsHelper = (ODFSkillsHelper) smanager.lookup(ODFSkillsHelper.ROLE);
057    }
058    
059    public void generate() throws IOException, SAXException, ProcessingException
060    {
061        Request request = ObjectModelHelper.getRequest(objectModel);
062        Content content = (Content) request.getAttribute(Content.class.getName());
063
064        String viewName = request.getParameter("viewName");
065        
066        contentHandler.startDocument();
067        
068        if (StringUtils.isEmpty(viewName) || __ALLOWED_VIEW_NAMES.stream().anyMatch(p -> p.matcher(viewName).matches()))
069        {
070            if (content instanceof AbstractProgram abstractProgram)
071            {
072                Map<Content, Map<Content, Set<Content>>> skillsDistribution = _skillsHelper.getSkillsDistribution(abstractProgram, 2);
073                if (skillsDistribution != null)
074                {
075                    saxSkillsDistribution(skillsDistribution);
076                }
077            }
078            else
079            {
080                getLogger().warn("Cannot get the skills of a non program '" + content.getId() + "'");
081            }
082        }
083        
084        contentHandler.endDocument();
085    }
086    
087    /**
088     * SAX the skills distribution
089     * @param distribution the skills distribution
090     * @throws IOException if an I/O error occurred
091     * @throws SAXException if an error occurred while saxing
092     */
093    protected void saxSkillsDistribution(Map<Content, Map<Content, Set<Content>>> distribution) throws IOException, SAXException
094    {
095        XMLUtils.startElement(contentHandler, "skills");
096        
097        // Iterate on macro skills
098        for (Map.Entry<Content, Map<Content, Set<Content>>> macroSkillEntry : distribution.entrySet())
099        {
100            Content macroSkill = macroSkillEntry.getKey();
101            
102            AttributesImpl attrs = new AttributesImpl();
103            attrs.addCDATAAttribute("id", macroSkill.getId());
104            attrs.addCDATAAttribute("title", macroSkill.getTitle());
105            attrs.addCDATAAttribute("code", macroSkill.getValue(OdfReferenceTableEntry.CODE, false, ""));
106            
107            XMLUtils.startElement(contentHandler, "skillSet", attrs);
108            
109            // Iterate on micro skills
110            for (Map.Entry<Content, Set<Content>> microSkillEntry : macroSkillEntry.getValue().entrySet())
111            {
112                Content microSkill = microSkillEntry.getKey();
113                
114                attrs.clear();
115                attrs.addCDATAAttribute("id", microSkill.getId());
116                attrs.addCDATAAttribute("title", microSkill.getTitle());
117                attrs.addCDATAAttribute("code", microSkill.getValue(OdfReferenceTableEntry.CODE, false, StringUtils.EMPTY));
118                
119                XMLUtils.startElement(contentHandler, "skill", attrs);
120                
121                // Iterate on courses
122                for (Content course : microSkillEntry.getValue())
123                {
124                    attrs.clear();
125                    attrs.addCDATAAttribute("id", course.getId());
126                    attrs.addCDATAAttribute("title", course.getTitle());
127                    attrs.addCDATAAttribute("code", ((Course) course).getCode());
128                    
129                    XMLUtils.startElement(contentHandler, "course", attrs);
130                    
131                    XMLUtils.endElement(contentHandler, "course");
132                }
133                
134                XMLUtils.endElement(contentHandler, "skill");
135            }
136            
137            XMLUtils.endElement(contentHandler, "skillSet");
138        }
139        
140        XMLUtils.endElement(contentHandler, "skills");
141    }
142}