001/*
002 *  Copyright 2019 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.Comparator;
020import java.util.List;
021
022import org.apache.avalon.framework.service.ServiceException;
023import org.apache.avalon.framework.service.ServiceManager;
024import org.apache.cocoon.ProcessingException;
025import org.apache.cocoon.environment.ObjectModelHelper;
026import org.apache.cocoon.environment.Request;
027import org.apache.cocoon.generation.ServiceableGenerator;
028import org.apache.cocoon.xml.AttributesImpl;
029import org.apache.cocoon.xml.XMLUtils;
030import org.apache.commons.lang3.StringUtils;
031import org.xml.sax.SAXException;
032
033import org.ametys.cms.repository.Content;
034import org.ametys.odf.ODFHelper;
035import org.ametys.odf.ProgramItem;
036import org.ametys.plugins.repository.AmetysObjectResolver;
037
038/**
039 * Generates additional information about a ODF content
040 *
041 */
042public class AdditionalOdfContentPropertiesGenerator extends ServiceableGenerator
043{
044    private static final ListProgramItemComparator __LIST_PROGRAM_ITEM_COMPARATOR = new ListProgramItemComparator();
045    
046    /** The AmetysObject resolver. */
047    protected AmetysObjectResolver _resolver;
048    /** The ODF helper */
049    protected ODFHelper _odfHelper;
050    
051    @Override
052    public void service(ServiceManager serviceManager) throws ServiceException
053    {
054        super.service(serviceManager);
055        _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
056        _odfHelper = (ODFHelper) serviceManager.lookup(ODFHelper.ROLE);
057    }
058    
059    @Override
060    public void generate() throws IOException, SAXException, ProcessingException
061    {
062        Request request = ObjectModelHelper.getRequest(objectModel);
063        
064        String contentId = parameters.getParameter("contentId", request.getParameter("contentId"));
065        
066        Content content = null;
067        if (StringUtils.isNotEmpty(contentId))
068        {
069            content = _resolver.resolveById(contentId);
070        }
071        else
072        {
073            content = (Content) request.getAttribute(Content.class.getName());
074        }
075        
076        contentHandler.startDocument();
077        XMLUtils.startElement(contentHandler, "odf");
078        
079        if (content instanceof ProgramItem)
080        {
081            XMLUtils.startElement(contentHandler, "programItem");
082            saxProgramItemProperties((ProgramItem) content);
083            XMLUtils.endElement(contentHandler, "programItem");
084        }
085        
086        XMLUtils.endElement(contentHandler, "odf");
087        contentHandler.startDocument();
088        contentHandler.endDocument();
089    }
090    
091    /**
092     * SAX specifics properties for a program item
093     * @param programItem the program item
094     * @throws SAXException if an error occurs while saxing
095     */
096    protected void saxProgramItemProperties(ProgramItem programItem) throws SAXException
097    {
098        _saxProgramItemAncestorPaths(programItem);
099        _saxChildProgramItems(programItem);
100    }
101    
102    /**
103     * SAX all paths of program item
104     * @param programItem The program item
105     * @throws SAXException if an error occurs while saxing
106     */
107    protected void _saxProgramItemAncestorPaths(ProgramItem programItem) throws SAXException
108    {
109        if (_odfHelper.hasParentProgramItems(programItem))
110        {
111            List<List<ProgramItem>> ancestorPaths = _odfHelper.getPathOfAncestors(programItem);
112            
113            if (!ancestorPaths.isEmpty())
114            {
115                // Sort the list to display it
116                ancestorPaths.sort(__LIST_PROGRAM_ITEM_COMPARATOR);
117                XMLUtils.startElement(contentHandler, "ancestors");
118                for (List<ProgramItem> ancestorPath : ancestorPaths)
119                {
120                    XMLUtils.startElement(contentHandler, "path");
121                    for (ProgramItem ancestor : ancestorPath)
122                    {
123                        _saxProgramItem(ancestor);
124                    }
125                    XMLUtils.endElement(contentHandler, "path");
126                }
127                    
128                XMLUtils.endElement(contentHandler, "ancestors");
129            }
130        }
131    }
132    
133    /**
134     * SAX the child program items
135     * @param programItem the program item
136     * @throws SAXException if an error occurs while saxing
137     */
138    protected void _saxChildProgramItems(ProgramItem programItem) throws SAXException
139    {
140        List<ProgramItem> children = _odfHelper.getChildProgramItems(programItem);
141        
142        if (!children.isEmpty())
143        {
144            XMLUtils.startElement(contentHandler, "children");
145            for (ProgramItem child : children)
146            {
147                _saxProgramItem(child);
148            }
149            XMLUtils.endElement(contentHandler, "children");
150        }
151    }
152    
153    /**
154     * Sax a program item
155     * @param item the program item
156     * @throws SAXException if an error occurs while saxing
157     */
158    protected void _saxProgramItem(ProgramItem item) throws SAXException
159    {
160        Content content = (Content) item;
161        AttributesImpl attrs = new AttributesImpl();
162        attrs.addCDATAAttribute("id", content.getId());
163        attrs.addCDATAAttribute("code", item.getCode());
164        XMLUtils.createElement(contentHandler, "item", attrs, content.getTitle());
165    }
166
167    /**
168     * Comparator of {@link List} composing of {@link ProgramItem} by title.
169     */
170    private static class ListProgramItemComparator implements Comparator<List<ProgramItem>>
171    {
172        public int compare(List<ProgramItem> l1, List<ProgramItem> l2)
173        {
174            int l1Size = l1.size();
175            int l2Size = l2.size();
176            
177            for (int i = 0; i < l1Size; i++)
178            {
179                if (l2Size <= i)
180                {
181                    // l1 is greater than l2
182                    return 1;
183                }
184                else
185                {
186                    // Compare title
187                    int comparing = ((Content) l1.get(i)).getTitle().compareTo(((Content) l2.get(i)).getTitle());
188                    if (comparing != 0)
189                    {
190                        return comparing;
191                    }
192                }
193            }
194            
195            // Lists are the same at the end of reading l1
196            // Then compare size of the lists
197            return Integer.compare(l1Size, l2Size);
198        }
199    }
200}