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.lheo;
017
018import java.time.LocalDate;
019import java.time.format.DateTimeFormatter;
020import java.util.ArrayList;
021import java.util.List;
022
023import org.apache.avalon.framework.component.Component;
024import org.apache.cocoon.xml.AttributesImpl;
025import org.apache.cocoon.xml.XMLUtils;
026import org.apache.commons.lang3.StringUtils;
027import org.xml.sax.ContentHandler;
028import org.xml.sax.SAXException;
029
030import org.ametys.cms.repository.Content;
031import org.ametys.runtime.plugin.component.AbstractLogEnabled;
032
033import com.google.common.base.Splitter;
034
035/**
036 * Class utils for LHEO XML export
037 */
038public class LHEOUtils extends AbstractLogEnabled implements Component
039{
040    /** The Avalon role */
041    public static final String ROLE = LHEOUtils.class.getName();
042    
043    /**
044     * Create some LHEO elements for tag >coordonnees<
045     * <br>Contains the following XML tags:
046     * <br>[0,1] &lt;civilite&gt;
047     * <br>[0,1] &lt;nom&gt;
048     * <br>[0,1] &lt;prenom&gt;
049     * <br>[0,3] &lt;ligne&gt;
050     * @param contentHandler the content handler
051     * @param content the saxed content
052     * @param civility the civility. Can be null.
053     * @param lastname the lastname. Can be null.
054     * @param firstname the firstname. Can be null.
055     * @param address the address. Can be null.
056     * @throws SAXException if a saxing exception occurred
057     */
058    public void createCoordinateLHEOElementsPart1(ContentHandler contentHandler, Content content, String civility, String lastname, String firstname, String address) throws SAXException
059    {
060        List<String> lines = StringUtils.isNotBlank(address) ? Splitter.fixedLength(50).splitToList(address) : new ArrayList<>();
061        createCoordinateLHEOElementsPart1(contentHandler, content, civility, lastname, firstname, lines);
062    }
063    
064    /**
065     * Create some LHEO elements for tag &gt;coordonnees&lt;
066     * <br>Contains the following XML tags:
067     * <br>[0,1] &lt;civilite&gt;
068     * <br>[0,1] &lt;nom&gt;
069     * <br>[0,1] &lt;prenom&gt;
070     * <br>[0,3] &lt;ligne&gt;
071     * @param contentHandler the content handler
072     * @param content the saxed content
073     * @param civility the civility. Can be null.
074     * @param lastname the lastname. Can be null.
075     * @param firstname the firstname. Can be null.
076     * @param lines the address line. Can be empty.
077     * @throws SAXException if a saxing exception occurred
078     */
079    public void createCoordinateLHEOElementsPart1(ContentHandler contentHandler, Content content, String civility, String lastname, String firstname, List<String> lines) throws SAXException
080    {
081        // <civilite>
082        createLHEOElement(contentHandler, content, "civilite", civility, 1, 50);
083        
084        // <nom>
085        createLHEOElement(contentHandler, content, "nom", lastname, 1, 50);
086        
087        // <prenom>
088        createLHEOElement(contentHandler, content, "prenom", firstname, 1, 50);
089        
090        // <ligne>
091        int size = lines.size();
092        if (size > 3)
093        {
094            size = 3;
095            getLogger().warn("[" + content.getTitle() + " (" + content.getId() + ")] The value " + StringUtils.join(lines, "") + " can be set in 3 lines. It will be truncated.");
096        }
097        
098        for (int i = 0; i < size; i++)
099        {
100            createLHEOElement(contentHandler, content, "ligne", lines.get(i), 1, 50);
101        }
102    }
103    
104    /**
105     * Create some LHEO elements for tag &gt;coordonnees&lt;
106     * <br>Contains the following XML tags:
107     * <br>[0,1] &lt;telfixe&gt;
108     * <br>[0,1] &lt;portable&gt;
109     * <br>[0,1] &lt;fax&gt;
110     * <br>[0,1] &lt;courriel&gt;
111     * <br>[0,1] &lt;web&gt;
112     * @param contentHandler the content handler
113     * @param content the saxed content
114     * @param telFix the telFix. Can be null.
115     * @param portable the portable. Can be null.
116     * @param fax the fax. Can be null.
117     * @param mail the mail. Can be null.
118     * @param urlWeb the url web. Can be null.
119     * @throws SAXException if a saxing exception occurred
120     */
121    public void createCoordinateLHEOElementsPart2(ContentHandler contentHandler, Content content, String telFix, String portable, String fax, String mail, String urlWeb) throws SAXException
122    {
123        // <telfixe>
124        if (StringUtils.isNotBlank(telFix))
125        {
126            XMLUtils.startElement(contentHandler, "telfixe");
127            createLHEOElement(contentHandler, content, "numtel", telFix, 1, 25);
128            XMLUtils.endElement(contentHandler, "telfixe");
129        }
130        
131        // <portable>
132        if (StringUtils.isNotBlank(portable))
133        {
134            XMLUtils.startElement(contentHandler, "portable");
135            createLHEOElement(contentHandler, content, "numtel", portable, 1, 25);
136            XMLUtils.endElement(contentHandler, "portable");
137        }
138        
139        // <fax>
140        if (StringUtils.isNotBlank(fax))
141        {
142            XMLUtils.startElement(contentHandler, "fax");
143            createLHEOElement(contentHandler, content, "numtel", fax, 1, 25);
144            XMLUtils.endElement(contentHandler, "fax");
145        }
146        
147        // <courriel>
148        createLHEOElement(contentHandler, content, "courriel", mail, 3, 160);
149        
150        // <web>
151        if (StringUtils.isNotBlank(urlWeb))
152        {
153            XMLUtils.startElement(contentHandler, "web");
154            createLHEOElement(contentHandler, content, "urlweb", urlWeb, 3, 400);
155            XMLUtils.endElement(contentHandler, "web");
156        }
157    }
158    
159    /**
160     * Create some LHEO elements for tag &gt;adresse&lt;
161     * <br>Contains the following XML tags:
162     * <br>[0,1] &lt;ligne&gt;
163     * <br>[0,1] &lt;codepostal&gt;
164     * <br>[0,1] &lt;ville&gt;
165     * <br>[0,3] &lt;departement&gt;
166     * <br>[0,1] &lt;code-INSEE-commune&gt;
167     * <br>[0,1] &lt;code-INSEE-canton&gt;
168     * <br>[0,1] &lt;region&gt;
169     * <br>[0,1] &lt;pays&gt;
170     * <br>[0,1] &lt;geolocalisation&gt;
171     * @param contentHandler the content handler
172     * @param content the saxed content
173     * @param address the address. Is mandatory.
174     * @param zipCode the zip code. Is mandatory.
175     * @param town the town. Is mandatory.
176     * @param department the department. Can be null.
177     * @param codeINSEEtown the code INSEE for the town. Can be null.
178     * @param codeINSEEdistrict the code INSEE for the district. Can be null.
179     * @param zone the zone. Can be null.
180     * @param country the country. Can be null.
181     * @param latitude the latitude. Can be null.
182     * @param longitude the longitude. Can be null.
183     * @throws SAXException if a saxing exception occurred
184     */
185    public void createAddressLHEOElements(ContentHandler contentHandler, Content content, String address, String zipCode, String town, String department, String codeINSEEtown, String codeINSEEdistrict, String zone, String country, String latitude, String longitude) throws SAXException
186    {
187        List<String> lines = StringUtils.isNotBlank(address) ? Splitter.fixedLength(50).splitToList(address) : new ArrayList<>();
188        createAddressLHEOElements(contentHandler, content, lines, zipCode, town, department, codeINSEEtown, codeINSEEdistrict, zone, country, latitude, longitude);
189    }
190    
191    /**
192     * Create some LHEO elements for tag &gt;adresse&lt;
193     * <br>Contains the following XML tags:
194     * <br>[0,1] &lt;ligne&gt;
195     * <br>[0,1] &lt;codepostal&gt;
196     * <br>[0,1] &lt;ville&gt;
197     * <br>[0,3] &lt;departement&gt;
198     * <br>[0,1] &lt;code-INSEE-commune&gt;
199     * <br>[0,1] &lt;code-INSEE-canton&gt;
200     * <br>[0,1] &lt;region&gt;
201     * <br>[0,1] &lt;pays&gt;
202     * <br>[0,1] &lt;geolocalisation&gt;
203     * @param contentHandler the content handler
204     * @param content the saxed content
205     * @param lines the address lines. Is mandatory.
206     * @param zipCode the zip code. Is mandatory.
207     * @param town the town. Is mandatory.
208     * @param department the department. Can be null.
209     * @param codeINSEEtown the code INSEE for the town. Can be null.
210     * @param codeINSEEdistrict the code INSEE for the district. Can be null.
211     * @param zone the zone. Can be null.
212     * @param country the country. Can be null.
213     * @param latitude the latitude. Can be null.
214     * @param longitude the longitude. Can be null.
215     * @throws SAXException if a saxing exception occurred
216     */
217    public void createAddressLHEOElements(ContentHandler contentHandler, Content content, List<String> lines, String zipCode, String town, String department, String codeINSEEtown, String codeINSEEdistrict, String zone, String country, String latitude, String longitude) throws SAXException
218    {
219        // <ligne>
220        int size = lines.size();
221        if (size > 4)
222        {
223            size = 4;
224            getLogger().warn("[" + content.getTitle() + " (" + content.getId() + ")] The value " + StringUtils.join(lines, "") + " can be set in 4 lines. It will be truncated.");
225        }
226        
227        if (size != 0)
228        {
229            for (int i = 0; i < size; i++)
230            {
231                createLHEOElement(contentHandler, content, "ligne", lines.get(i), 1, 50);
232            }
233        }
234        else
235        {
236            getLogger().warn("[" + content.getTitle() + " (" + content.getId() + ")] The tag adresse must contain at least one line");
237        }
238        
239        // <codepostal>
240        createMandatoryLHEOElement(contentHandler, content, "codepostal", zipCode, 5, 5);
241        
242        // <ville>
243        createMandatoryLHEOElement(contentHandler, content, "ville", town, 1, 50);
244        
245        // <departement>
246        createLHEOElement(contentHandler, content, "departement", department, 2, 3);
247        
248        // <code-INSEE-commune>
249        createLHEOElement(contentHandler, content, "code-INSEE-commune", codeINSEEtown, 5, 5);
250        
251        // <code-INSEE-canton>
252        createLHEOElement(contentHandler, content, "code-INSEE-canton", codeINSEEdistrict, 4, 5);
253        
254        // <region>
255        createLHEOElement(contentHandler, content, "region", zone, 2, 2);
256        
257        // <pays>
258        createLHEOElement(contentHandler, content, "pays", country, 2, 2);
259        
260        // <geolocalisation>
261        if (StringUtils.isNotBlank(latitude) && StringUtils.isNotBlank(longitude))
262        {
263            XMLUtils.startElement(contentHandler, "geolocalisation");
264            
265            // <latitude>
266            createLHEOElement(contentHandler, content, "latitude", latitude, 0, 30);
267            
268            // <longitude>
269            createLHEOElement(contentHandler, content, "longitude", longitude, 0, 30);
270            
271            XMLUtils.endElement(contentHandler, "geolocalisation");
272        }
273    }
274    
275    /**
276     * Create LHEO elements for tag &gt;periode&lt;
277     * <br>Contains the following XML tags:
278     * <br>[1,1] &lt;debut&gt;
279     * <br>[1,1] &lt;fin&gt;
280     * @param contentHandler the content handler
281     * @param content the saxed content
282     * @param startDate the start date. Can be null. If null a warning will be logged.
283     * @param endDate the end date. Can be null. If null a warning will be logged.
284     * @throws SAXException if a saxing exception occurred
285     */
286    public void createPeriodLHEOElments(ContentHandler contentHandler, Content content, LocalDate startDate, LocalDate endDate) throws SAXException
287    {
288        if (startDate != null && endDate != null && startDate.isAfter(endDate))
289        {
290            getLogger().warn("[" + content.getTitle() + " (" + content.getId() + ")] <periode> : start date should not be greater than end date");
291        }
292        
293        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
294        
295        createMandatoryLHEOElement(contentHandler, content, "debut", startDate != null ? formatter.format(startDate) : null, 8, 8);
296        
297        createMandatoryLHEOElement(contentHandler, content, "fin", endDate != null ? formatter.format(endDate) : null, 8 , 8);
298    }
299    
300    /**
301     * Create the mandatory LHEO element
302     * @param contentHandler the content handler
303     * @param content the saxed content
304     * @param elementName the element name
305     * @param value the value to sax
306     * @throws SAXException if a saxing error occurred
307     */
308    public void createMandatoryLHEOElement(ContentHandler contentHandler, Content content, String elementName, String value) throws SAXException
309    {
310        createMandatoryLHEOElement(contentHandler, content, elementName, new AttributesImpl(),  value, 0, 0);
311    }
312    
313    /**
314     * Create the mandatory LHEO element
315     * @param contentHandler the content handler
316     * @param content the saxed content
317     * @param elementName the element name
318     * @param value the value to sax
319     * @param minLength the min length of the value (0 if there is no min length). If the value length is lower than minLength, a warning will be logged
320     * @param maxLength the max length of the value (0 if there is no max length). If the value length is greater than maxLength, a warning will be logged and the value will be troncated
321     * @throws SAXException if a saxing error occurred
322     */
323    public void createMandatoryLHEOElement(ContentHandler contentHandler, Content content, String elementName, String value, int minLength, int maxLength) throws SAXException
324    {
325        createMandatoryLHEOElement(contentHandler, content, elementName, new AttributesImpl(), value, minLength, maxLength);
326    }
327    
328    /**
329     * Create the mandatory LHEO element
330     * @param contentHandler the content handler
331     * @param content the saxed content
332     * @param elementName the element name
333     * @param attrs the attributes
334     * @param value the value to sax
335     * @throws SAXException if a saxing error occurred
336     */
337    public void createMandatoryLHEOElement(ContentHandler contentHandler, Content content, String elementName, AttributesImpl attrs, String value) throws SAXException
338    {
339        if (StringUtils.isBlank(value))
340        {
341            getLogger().warn("[" + content.getTitle() + " (" + content.getId() + ")] The value for tag " + elementName + " is mandatory");
342        }
343        else
344        {
345            createLHEOElement(contentHandler, content, elementName, value, 0, 0);
346        }
347    }
348    
349    /**
350     * Create the mandatory LHEO element
351     * @param contentHandler the content handler
352     * @param content the saxed content
353     * @param elementName the element name
354     * @param attrs the attributes
355     * @param value the value to sax
356     * @param minLength the min length of the value (0 if there is no min length). If the value length is lower than minLength, a warning will be logged
357     * @param maxLength the max length of the value (0 if there is no max length). If the value length is greater than maxLength, a warning will be logged and the value will be troncated
358     * @throws SAXException if a saxing error occurred
359     */
360    public void createMandatoryLHEOElement(ContentHandler contentHandler, Content content, String elementName, AttributesImpl attrs, String value, int minLength, int maxLength) throws SAXException
361    {
362        if (StringUtils.isBlank(value))
363        {
364            getLogger().warn("[" + content.getTitle() + " (" + content.getId() + ")] The value for tag " + elementName + " is mandatory");
365        }
366        else
367        {
368            createLHEOElement(contentHandler, content, elementName, value, minLength, maxLength);
369        }
370    }
371    
372    /**
373     * Create the LHEO element
374     * @param contentHandler the content handler
375     * @param content the saxed content
376     * @param elementName the element name
377     * @param value the value to sax
378     * @throws SAXException if a saxing error occurred
379     */
380    public void createLHEOElement(ContentHandler contentHandler, Content content, String elementName, String value) throws SAXException
381    {
382        createLHEOElement(contentHandler, content, elementName, new AttributesImpl(), value, 0, 0);
383    }
384    
385    /**
386     * Create the LHEO element
387     * @param contentHandler the content handler
388     * @param content the saxed content
389     * @param elementName the element name
390     * @param value the value to sax
391     * @param minLength the min length of the value (0 if there is no min length). If the value length is lower than minLength, a warning will be logged
392     * @param maxLength the max length of the value (0 if there is no max length). If the value length is greater than maxLength, a warning will be logged and the value will be troncated
393     * @throws SAXException if a saxing error occurred
394     */
395    public void createLHEOElement(ContentHandler contentHandler, Content content, String elementName, String value, int minLength, int maxLength) throws SAXException
396    {
397        createLHEOElement(contentHandler, content, elementName, new AttributesImpl(), value, minLength, maxLength);
398    }
399    
400    /**
401     * Create the LHEO element
402     * @param contentHandler the content handler
403     * @param content the saxed content
404     * @param elementName the element name
405     * @param attrs the attributes
406     * @param value the value to sax
407     * @throws SAXException if a saxing error occurred
408     */
409    public void createLHEOElement(ContentHandler contentHandler, Content content, String elementName, AttributesImpl attrs, String value) throws SAXException
410    {
411        if (StringUtils.isNotBlank(value))
412        {
413            XMLUtils.createElement(contentHandler, elementName, attrs, value);
414        }
415    }
416    
417    /**
418     * Create the LHEO element
419     * @param contentHandler the content handler
420     * @param content the saxed content
421     * @param elementName the element name
422     * @param attrs the attributes
423     * @param value the value to sax
424     * @param minLength the min length of the value (0 if there is no min length). If the value length is lower than minLength, a warning will be logged
425     * @param maxLength the max length of the value (0 if there is no max length). If the value length is greater than maxLength, a warning will be logged and the value will be troncated
426     * @throws SAXException if a saxing error occurred
427     */
428    public void createLHEOElement(ContentHandler contentHandler, Content content, String elementName, AttributesImpl attrs, String value, int minLength, int maxLength) throws SAXException
429    {
430        if (StringUtils.isNotBlank(value))
431        {
432            String computedValue = value;
433            int valueLength = computedValue.length();
434            if (minLength != 0 && maxLength != 0 && minLength == maxLength)
435            {
436                if (valueLength < minLength)
437                {
438                    getLogger().warn("[" + content.getTitle() + " (" + content.getId() + ")] The value for element " + elementName + " is supposed to contains exactly " + minLength + " characters.");
439                }
440                else
441                {
442                    getLogger().warn("[" + content.getTitle() + " (" + content.getId() + ")] The value for element " + elementName + " is supposed to contains exactly " + minLength + " characters. It will be troncated.");
443                    computedValue = StringUtils.substring(value, 0, maxLength);
444                }
445            }
446            else
447            {
448                if (maxLength != 0 && valueLength > maxLength)
449                {
450                    getLogger().warn("[" + content.getTitle() + " (" + content.getId() + ")] The value for element " + elementName + " is not supposed to contains more than " + maxLength + " characters. It will be troncated.");
451                    computedValue = StringUtils.substring(value, 0, maxLength);
452                }
453                
454                if (minLength != 0 && valueLength < minLength)
455                {
456                    getLogger().warn("[" + content.getTitle() + " (" + content.getId() + ")] The value for element " + elementName + " is not supposed to contains less than " + minLength + " characters.");
457                }
458            }
459            
460            XMLUtils.createElement(contentHandler, elementName, attrs, computedValue);
461        }
462    }
463}