001/*
002 *  Copyright 2018 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.odfpilotage.report.impl;
017
018import java.io.File;
019import java.io.FileOutputStream;
020import java.util.Iterator;
021import java.util.List;
022
023import javax.xml.transform.Result;
024import javax.xml.transform.TransformerFactory;
025import javax.xml.transform.sax.SAXTransformerFactory;
026import javax.xml.transform.sax.TransformerHandler;
027import javax.xml.transform.stream.StreamResult;
028
029import org.apache.cocoon.xml.AttributesImpl;
030import org.apache.cocoon.xml.XMLUtils;
031import org.apache.commons.io.FileUtils;
032import org.apache.commons.lang3.StringUtils;
033import org.xml.sax.SAXException;
034
035import org.ametys.cms.data.ContentDataHelper;
036import org.ametys.odf.course.Course;
037import org.ametys.odf.courselist.CourseList;
038import org.ametys.odf.courselist.CourseList.ChoiceType;
039import org.ametys.odf.coursepart.CoursePart;
040import org.ametys.odf.orgunit.OrgUnit;
041import org.ametys.odf.program.Container;
042import org.ametys.odf.program.Program;
043import org.ametys.odf.program.SubProgram;
044import org.ametys.plugins.odfpilotage.helper.PilotageHelper;
045import org.ametys.plugins.odfpilotage.report.impl.mcc.MCCAmetysObjectTree;
046import org.ametys.plugins.repository.AmetysObject;
047import org.ametys.plugins.repository.data.holder.group.ModelAwareRepeaterEntry;
048import org.ametys.plugins.repository.jcr.NameHelper;
049
050/**
051 * Class to generate a report based on MCC.
052 */
053public abstract class AbstractMCCReport extends AbstractReport
054{
055    /** Prefix of the sessions name */
056    protected static final String SESSION_NAME_PREFIX = "mccSession";
057    /** Name of the first session */
058    protected static final String FIRST_SESSION_NAME = SESSION_NAME_PREFIX + "1";
059    /** Name of the second session */
060    protected static final String SECOND_SESSION_NAME = SESSION_NAME_PREFIX + "2";
061    
062    @Override
063    protected void _launchByOrgUnit(String uaiCode, String catalog, String lang) throws Exception
064    {
065        // Initialize data
066        MCCAmetysObjectTree tree = _processMCC(uaiCode, lang, catalog);
067        
068        // Generate the XML file corresponding to the organization with the current org unit reference
069        _writeReportsMcc(tree);
070    }
071    
072    /**
073     * Processing of the MCC
074     * @param uaiCode the UAI code of the orgunit
075     * @param lang The language code
076     * @param catalog The catalogue
077     * @return {@link MCCAmetysObjectTree}
078     */
079    protected MCCAmetysObjectTree _processMCC(String uaiCode, String lang, String catalog)
080    {
081        MCCAmetysObjectTree tree = null;
082        
083        // Filter the programs with this uai code
084        OrgUnit orgUnit = _odfHelper.getOrgUnitByUAICode(uaiCode);
085        if (orgUnit != null)
086        {
087            getLogger().info("Rapport de pilotage construit sur la composante '{}' ({})", orgUnit.getTitle(), orgUnit.getUAICode());
088            List<Program> selectedPrograms = _odfHelper.getProgramsFromOrgUnit(orgUnit, catalog, lang);
089            tree = extractMCCAmetysObjectTree(orgUnit, selectedPrograms);
090        }
091        else
092        {
093            getLogger().error("Il n'existe pas de composante ayant pour code UAI '{}'", uaiCode);
094        }
095
096        return tree;
097    }
098    
099    /**
100     * Create the MCC report for one organization unit 
101     * @param tree The MCC tree
102     */
103    protected void _writeReportsMcc(MCCAmetysObjectTree tree)
104    {
105        SAXTransformerFactory factory = (SAXTransformerFactory) TransformerFactory.newInstance();
106        
107        for (MCCAmetysObjectTree child : tree.getChildren())
108        {
109            AmetysObject ao = child.getCurrent();
110            
111            // children are supposed to be programs
112            if (ao instanceof Program)
113            {
114                Program program = (Program) ao;
115                String fileName = _getReportFileName(program);
116                
117                // Delete old files
118                File xmlFile = new File(_tmpFolder, fileName + ".xml");
119                FileUtils.deleteQuietly(xmlFile);
120                
121                try (FileOutputStream fos = new FileOutputStream(xmlFile))
122                {
123                    TransformerHandler handler = factory.newTransformerHandler();
124                    
125                    // Prepare the transformation
126                    Result result = new StreamResult(fos);
127                    handler.setResult(result);
128                    handler.startDocument();
129                    
130                    // Write XML file
131                    AttributesImpl attrs = new AttributesImpl();
132                    attrs.addCDATAAttribute("type", getType());
133                    attrs.addCDATAAttribute("date", _reportHelper.getReadableCurrentDate());
134                    XMLUtils.startElement(handler, "report", attrs);
135                    
136                    // SAX other global informations
137                    saxGlobalInformations(handler, program);
138                    
139                    // SAX natures enseignement
140                    _reportHelper.saxNaturesEnseignement(handler, getLogger());
141                    _refTableHelper.saxItems(handler, PilotageHelper.MCC_MODALITE_SESSION1);
142                    _refTableHelper.saxItems(handler, PilotageHelper.MCC_MODALITE_SESSION2);
143                    _refTableHelper.saxItems(handler, PilotageHelper.MCC_SESSION_NATURE);
144                    
145                    // SAX tree
146                    saxTree(handler, child);
147                    
148                    XMLUtils.endElement(handler, "report");
149                    handler.endDocument();
150
151                    // Convert the report to configured output format
152                    convertReport(_tmpFolder, fileName, xmlFile);
153                }
154                catch (Exception e)
155                {
156                    getLogger().error("An error occured while generating 'MCC' report for program '{}' ({})", program.getTitle(), program.getCode(), e);
157                }
158                finally
159                {
160                    FileUtils.deleteQuietly(xmlFile);
161                }
162            }
163        }
164    }
165    
166    /**
167     * SAX the MCC tree for the report
168     * @param handler The handler
169     * @param tree The MCC tree
170     * @throws SAXException if an error occurs
171     */
172    protected void saxTree(TransformerHandler handler, MCCAmetysObjectTree tree) throws SAXException
173    {
174        AmetysObject ao = tree.getCurrent();
175        
176        if (ao instanceof OrgUnit)
177        {
178            saxOrgUnit(handler, (OrgUnit) ao, tree);
179        }
180        else if (ao instanceof Program)
181        {
182            saxProgram(handler, (Program) ao, tree);
183        }
184        else if (ao instanceof SubProgram)
185        {
186            saxSubProgram(handler, (SubProgram) ao, tree);
187        }
188        else if (ao instanceof Container)
189        {
190            saxContainer(handler, (Container) ao, tree);
191        }
192        else if (ao instanceof CourseList)
193        {
194            saxCourseList(handler, (CourseList) ao, tree);
195        }
196        else if (ao instanceof Course)
197        {
198            saxCourse(handler, (Course) ao, tree);
199        }
200    }
201
202    /**
203     * Sax an {@link OrgUnit}.
204     * @param handler The transformer handler
205     * @param orgunit The orgunit to sax
206     * @param tree The MCC tree
207     * @throws SAXException If an error occurs
208     */
209    protected void saxOrgUnit(TransformerHandler handler, OrgUnit orgunit, MCCAmetysObjectTree tree) throws SAXException
210    {
211        // id + name
212        AttributesImpl attrs = new AttributesImpl();
213        attrs.addCDATAAttribute("name", orgunit.getName());
214        attrs.addCDATAAttribute("title", orgunit.getTitle());
215
216        // Start tag + children + end tag
217        XMLUtils.startElement(handler, "orgunit", attrs);
218        saxTreeChildren(handler, tree);
219        XMLUtils.endElement(handler, "orgunit");
220    }
221
222    /**
223     * Sax a {@link Program}.
224     * @param handler The transformer handler
225     * @param program The program to sax
226     * @param tree The MCC tree
227     * @throws SAXException If an error occurs
228     */
229    protected void saxProgram(TransformerHandler handler, Program program, MCCAmetysObjectTree tree) throws SAXException
230    {
231        // id + name
232        AttributesImpl attrs = new AttributesImpl();
233        attrs.addCDATAAttribute("id", program.getId());
234        attrs.addCDATAAttribute("name", program.getName());
235
236        // Start tag + title
237        XMLUtils.startElement(handler, "program", attrs);
238        XMLUtils.createElement(handler, "title", program.getTitle());
239        XMLUtils.createElement(handler, "catalog", program.getCatalog());
240        
241        // VDI
242        XMLUtils.createElement(handler, "dip", _reportHelper.getCodeDIP(program));
243        XMLUtils.createElement(handler, "vdi", _reportHelper.getCodeVRSVDI(program));
244        XMLUtils.createElement(handler, "speciality", program.getSpeciality());
245
246        // Degree
247        String degreeId = program.getDegree();
248        if (StringUtils.isNotEmpty(degreeId))
249        {
250            AttributesImpl degreeAttrs = new AttributesImpl();
251            degreeAttrs.addCDATAAttribute("degree", _refTableHelper.getItemCode(degreeId));
252            XMLUtils.startElement(handler, "degree", degreeAttrs);
253            XMLUtils.createElement(handler, "label", _refTableHelper.getItemLabel(degreeId, program.getLanguage()));
254            XMLUtils.endElement(handler, "degree");
255        }
256        
257        // Domaine
258        _reportHelper.saxContentAttribute(handler, program, "domain", "domain");
259        
260        // Mention
261        String mentionId = program.getMention();
262        if (StringUtils.isNotEmpty(mentionId))
263        {
264            XMLUtils.createElement(handler, "mention", _refTableHelper.getItemLabel(mentionId, program.getLanguage()));
265        }
266        
267        // Code anu
268        Long codeAnu = _getCodeAnu(tree);
269        if (codeAnu != null)
270        {
271            XMLUtils.createElement(handler, "codeAnu", String.valueOf(codeAnu));
272        }
273        
274        // Contrôles de connaissances (rich text)
275        program.dataToSAX(handler, "knowledgeCheck");
276        
277        // Children
278        saxTreeChildren(handler, tree);
279        
280        // End tag
281        XMLUtils.endElement(handler, "program");
282    }
283
284    /**
285     * Sax a {@link SubProgram}.
286     * @param handler The transformer handler
287     * @param subProgram The subprogram to sax
288     * @param tree The MCC tree
289     * @throws SAXException If an error occurs
290     */
291    protected void saxSubProgram(TransformerHandler handler, SubProgram subProgram, MCCAmetysObjectTree tree) throws SAXException
292    {
293        // id + name
294        AttributesImpl attrs = new AttributesImpl();
295        attrs.addCDATAAttribute("id", subProgram.getId());
296        attrs.addCDATAAttribute("name", subProgram.getName());
297
298        // Start tag + title
299        XMLUtils.startElement(handler, "subprogram", attrs);
300        XMLUtils.createElement(handler, "title", subProgram.getTitle());
301        
302        // COD_PAR
303        XMLUtils.createElement(handler, "codePar", subProgram.getValue("codePar", false, StringUtils.EMPTY));
304
305        // Contrôles de connaissances (rich text)
306        subProgram.dataToSAX(handler, "knowledgeCheck");
307        
308        // Children
309        saxTreeChildren(handler, tree);
310        
311        // End tag
312        XMLUtils.endElement(handler, "subprogram");
313    }
314
315    /**
316     * Sax a {@link Container}.
317     * @param handler The transformer handler
318     * @param container The container to sax
319     * @param tree The MCC tree
320     * @throws SAXException If an error occurs
321     */
322    protected void saxContainer(TransformerHandler handler, Container container, MCCAmetysObjectTree tree) throws SAXException
323    {
324        // id + name
325        AttributesImpl attrs = new AttributesImpl();
326        attrs.addCDATAAttribute("id", container.getId());
327        attrs.addCDATAAttribute("name", container.getName());
328        
329        // Nature
330        String natureId = container.getNature();
331        if (StringUtils.isNotEmpty(natureId))
332        {
333            attrs.addCDATAAttribute("nature", _refTableHelper.getItemCode(natureId));
334        }
335
336        // Période
337        String periodId = container.getPeriod();
338        if (StringUtils.isNotEmpty(periodId))
339        {
340            attrs.addCDATAAttribute("periodCode", _refTableHelper.getItemCode(periodId));
341            attrs.addCDATAAttribute("periodValue", _refTableHelper.getItemLabel(periodId, container.getLanguage()));
342        }
343        
344        // ECTS
345        attrs.addCDATAAttribute("ects", String.valueOf(container.getEcts()));
346        
347        // Start tag + title
348        XMLUtils.startElement(handler, "container", attrs);
349        XMLUtils.createElement(handler, "title", container.getTitle());
350        
351        // ETP + VRS_ETP
352        XMLUtils.createElement(handler, "etp", container.getValue("etpCode", false, StringUtils.EMPTY));
353        XMLUtils.createElement(handler, "vrsEtp", container.getValue("vrsEtpCode", false, StringUtils.EMPTY));
354        
355        // DIP + VDI
356        XMLUtils.createElement(handler, "dip", _reportHelper.getCodeDIP(container));
357        XMLUtils.createElement(handler, "vdi", _reportHelper.getCodeVRSVDI(container));
358        
359        // Code (cdm)
360        XMLUtils.createElement(handler, "code", container.getCode());
361        
362        // Info particulières (rich text)
363        container.dataToSAX(handler, "controles");
364        
365        // Children
366        saxTreeChildren(handler, tree);
367        
368        // End tag
369        XMLUtils.endElement(handler, "container");
370    }
371
372    /**
373     * Sax a {@link CourseList}.
374     * @param handler The transformer handler
375     * @param courseList The course list to sax
376     * @param tree The MCC tree
377     * @throws SAXException If an error occurs
378     */
379    protected void saxCourseList(TransformerHandler handler, CourseList courseList, MCCAmetysObjectTree tree) throws SAXException
380    {
381        // id + name
382        AttributesImpl attrs = new AttributesImpl();
383        attrs.addCDATAAttribute("id", courseList.getId());
384        attrs.addCDATAAttribute("name", courseList.getName());
385        
386        // type
387        ChoiceType type = courseList.getType();
388        attrs.addCDATAAttribute(type.name().toLowerCase(), "true");
389        attrs.addCDATAAttribute("minCourses", String.valueOf(courseList.getMinNumberOfCourses()));
390
391        // Start tag + title
392        XMLUtils.startElement(handler, "courselist", attrs);
393        XMLUtils.createElement(handler, "title", courseList.getTitle());
394
395        // Children
396        saxTreeChildren(handler, tree);
397        
398        // End tag
399        XMLUtils.endElement(handler, "courselist");
400    }
401
402    /**
403     * Sax a {@link Course}.
404     * @param handler The transformer handler
405     * @param course The course to sax
406     * @param tree The MCC tree
407     * @throws SAXException If an error occurs
408     */
409    protected void saxCourse(TransformerHandler handler, Course course, MCCAmetysObjectTree tree) throws SAXException
410    {
411        // id + name
412        AttributesImpl attrs = new AttributesImpl();
413        attrs.addCDATAAttribute("id", course.getId());
414        attrs.addCDATAAttribute("name", course.getName());
415        
416        // type
417        attrs.addCDATAAttribute("type", _refTableHelper.getItemCode(course.getCourseType()));
418        
419        // ECTS
420        attrs.addCDATAAttribute("ects", String.valueOf(course.getEcts()));
421        
422        // Shared ?
423        attrs.addCDATAAttribute("partage", course.getParentCourseLists().size() > 1 ? "X" : "");
424        
425        // MODU weight
426        attrs.addCDATAAttribute("poidsModu", String.valueOf(course.getValue("poidsModu", false, 0D)));
427        
428        // Start tag + title
429        XMLUtils.startElement(handler, "course", attrs);
430        XMLUtils.createElement(handler, "title", course.getTitle());
431        
432        // short label
433        XMLUtils.createElement(handler, "shortLabel", course.getValue("shortLabel", false, StringUtils.EMPTY));
434        
435        // Code (cdm)
436        XMLUtils.createElement(handler, "code", course.getCode());
437        
438        // Is evaluated
439        XMLUtils.createElement(handler, "evaluated", course.getValue("isEvaluated", false, Boolean.FALSE) ? "X" : StringUtils.EMPTY);
440        
441        // Code Apogée
442        XMLUtils.createElement(handler,  "codeApogee", course.getValue("elpCode", false, StringUtils.EMPTY));
443        
444        // TODO besoin de etapePorteuse?
445        /**
446        if (course.hasValue("etapePorteuse"))
447        {
448            Content etapePorteuse = Optional.ofNullable((ContentValue) course.getValue("etapePorteuse"))
449                    .map(ContentValue::getContent)
450                    .orElse(null);
451
452            if (etapePorteuse != null && etapePorteuse.hasValue("etpCode"))
453            {
454                attr.addCDATAAttribute("etapePorteuse", etapePorteuse.getTitle());
455                attr.addCDATAAttribute("codeEtapePorteuse", etapePorteuse.getValue("etpCode"));
456            }
457        }
458        */
459        
460        saxCourseParts(handler, course);
461        
462        saxMCCs(handler, course, tree);
463        
464        saxTreeChildren(handler, tree);
465        
466        // End tag
467        XMLUtils.endElement(handler, "course");
468    }
469    
470    /**
471     * Iterate on tree's children.
472     * @param handler The transformer handler
473     * @param tree The MCC tree
474     * @throws SAXException If an error occurs 
475     */
476    protected void saxTreeChildren(TransformerHandler handler, MCCAmetysObjectTree tree) throws SAXException
477    {
478        for (MCCAmetysObjectTree child : tree.getChildren())
479        {
480            saxTree(handler, child);
481        }
482    }
483
484    /**
485     * Sax the {@link CoursePart}s containing in a {@link Course}.
486     * @param handler The transformer handler
487     * @param course The course with course parts to sax
488     * @throws SAXException If an error occurs
489     */
490    protected void saxCourseParts(TransformerHandler handler, Course course) throws SAXException
491    {
492        // Volume horaire
493        XMLUtils.startElement(handler, "volumeHoraire");
494        
495        // Heures d'enseignement
496        for (CoursePart coursePart : course.getCourseParts())
497        {
498            AttributesImpl attr = new AttributesImpl();
499            attr.addCDATAAttribute("nature", coursePart.getNature());
500            XMLUtils.createElement(handler, "volume", attr, String.valueOf(coursePart.getNumberOfHours()));
501        }
502        
503        XMLUtils.endElement(handler, "volumeHoraire");
504    }
505    
506    /**
507     * Sax the MCC sessions.
508     * @param handler The transformer handler
509     * @param course The concerned {@link Course} to sax the MCCs on
510     * @param tree The MCC tree
511     * @throws SAXException If an error occurs
512     */
513    protected abstract void saxMCCs(TransformerHandler handler, Course course, MCCAmetysObjectTree tree) throws SAXException;
514    
515    /**
516     * Generates SAX events for the details of a MCC session entry.
517     * @param handler The transformer handler
518     * @param sessionEntry The session repeater entry to SAX
519     * @throws SAXException If an error occurs
520     */
521    protected void saxSessionEntryDetails(TransformerHandler handler, ModelAwareRepeaterEntry sessionEntry) throws SAXException
522    {
523        // modalite
524        String modalite = _refTableHelper.getItemCode(ContentDataHelper.getContentIdFromContentData(sessionEntry, "modalite"));
525        if (StringUtils.isNotEmpty(modalite))
526        {
527            XMLUtils.createElement(handler, "modalite", modalite);
528        }
529        
530        // nature
531        String nature = _refTableHelper.getItemCode(ContentDataHelper.getContentIdFromContentData(sessionEntry, "nature"));
532        if (StringUtils.isNotEmpty(nature))
533        {
534            XMLUtils.createElement(handler, "nature", nature);
535        }
536        
537        // duree
538        long duree = sessionEntry.getValue("duree", false, 0L);
539        if (duree > 0)
540        {
541            AttributesImpl dureeAttrs = new AttributesImpl();
542            dureeAttrs.addCDATAAttribute("minutes", String.valueOf(duree));
543            XMLUtils.createElement(handler, "duree", _reportHelper.minute2hour((int) duree));
544        }
545
546        // nombre
547        String nombre = sessionEntry.getValue("nombre", false, StringUtils.EMPTY);
548        if (StringUtils.isNotEmpty(nombre))
549        {
550            XMLUtils.createElement(handler, "nombre", nombre);
551        }
552        // coefficient
553        String coeff = sessionEntry.getValue("coefficient", false, StringUtils.EMPTY);
554        if (StringUtils.isNotEmpty(coeff))
555        {
556            AttributesImpl coeffAttrs = new AttributesImpl();
557
558            if (coeff.indexOf('%') != -1)
559            {
560                coeffAttrs.addCDATAAttribute("pourcent", StringUtils.substringBefore(coeff, "%"));
561                XMLUtils.createElement(handler, "coefficient", coeffAttrs, coeff);
562            }
563            else if (coeff.indexOf('/') != -1)
564            {
565                coeffAttrs.addCDATAAttribute("num", StringUtils.substringBefore(coeff, "/"));
566                coeffAttrs.addCDATAAttribute("denom", StringUtils.substringAfter(coeff, "/"));
567                XMLUtils.createElement(handler, "coefficient", coeffAttrs, coeff);
568            }
569            else
570            {
571                XMLUtils.createElement(handler, "coefficient", coeffAttrs, coeff);
572            }
573        }
574
575        // remarque
576        String remarques = sessionEntry.getValue("remarques", false, StringUtils.EMPTY);
577        if (StringUtils.isNotEmpty(remarques))
578        {
579            XMLUtils.createElement(handler, "remarques", remarques);
580        }
581    }
582
583    /**
584     * Extract the tree of Ametys object of interested.
585     * @param ou the orgunit to extract the MCC from
586     * @param programs the list of associated programs
587     * @return {@link MCCAmetysObjectTree}
588     */
589    protected MCCAmetysObjectTree extractMCCAmetysObjectTree(OrgUnit ou, List<Program> programs)
590    {
591        MCCAmetysObjectTree tree = new MCCAmetysObjectTree(ou);
592        for (Program program : programs)
593        {
594            addProgram2MCCAmetysObjectTree(tree, program);
595        }
596        return tree;
597    }
598    
599    /**
600     * Add and populate the program to the {@link MCCAmetysObjectTree}
601     * @param tree The object tree
602     * @param program The program to add
603     */
604    protected void addProgram2MCCAmetysObjectTree(MCCAmetysObjectTree tree, Program program)
605    {
606        MCCAmetysObjectTree programTree = tree.addChild(program);
607        populateMCCAmetysObjectTree(programTree);
608    }
609    
610    /**
611     * Populate the MCC tree.
612     * @param tree The MCC tree
613     */
614    protected abstract void populateMCCAmetysObjectTree(MCCAmetysObjectTree tree);
615    
616    /**
617     * Recurse through containers and courses to find a code anu.
618     * @param tree The MCC tree
619     * @return Return the Code ANU
620     */
621    private Long _getCodeAnu(MCCAmetysObjectTree tree)
622    {
623        Long codeAnu = null;
624        
625        Iterator<MCCAmetysObjectTree> iterator = tree.getChildren().iterator();
626        while (iterator.hasNext() && codeAnu == null)
627        {
628            AmetysObject child = iterator.next().getCurrent();
629            long code = -1;
630            
631            if (child instanceof Container)
632            {
633                Container container = (Container) child;
634                code = container.getValue("CodeAnu", false, 0L);
635            }
636            else if (child instanceof Course)
637            {
638                Course course = (Course) child;
639                code = course.getValue("CodeAnu", false, 0L);
640            }
641            
642            if (code > 0)
643            {
644                codeAnu = code;
645            }
646        }
647        
648        if (codeAnu == null)
649        {
650            iterator = tree.getChildren().iterator();
651            while (iterator.hasNext() && codeAnu == null)
652            {
653                codeAnu = _getCodeAnu(iterator.next());
654            }
655        }
656        
657        return codeAnu;
658    }
659    
660    /**
661     * Get the report filename for a given program
662     * @param program The program
663     * @return the file name
664     */
665    protected String _getReportFileName(Program program)
666    {
667        StringBuilder sb = new StringBuilder();
668
669        sb.append(getType());
670        sb.append("-");
671        
672        // Catalog
673        sb.append(program.getCatalog());
674        sb.append("-");
675        
676        // Lang
677        sb.append(program.getLanguage());
678        sb.append("-");
679        
680        // Domain
681        String[] domains = program.getDomain();
682        for (String domainId : domains)
683        {
684            String domain = _refTableHelper.getItemCode(domainId);
685            if (StringUtils.isNotEmpty(domain))
686            {
687                sb.append(domain);
688                sb.append('-');
689            }
690        }
691
692        // Mention or title
693        String mentionId = program.getMention();
694        if (StringUtils.isBlank(mentionId))
695        {
696            sb.append(program.getTitle());
697        }
698        else
699        {
700            // Degree + mention
701            sb.append(_refTableHelper.getItemCode(program.getDegree()));
702            sb.append("-");
703            sb.append(_refTableHelper.getItemLabel(mentionId, program.getLanguage()));
704        }
705        
706        // CDM code
707        sb.append("-");
708        sb.append(program.getCode());
709        
710        // Date
711        sb.append("-");
712        sb.append(_currentFormattedDate);
713
714        return NameHelper.filterName(sb.toString());
715    }
716    
717    /**
718     * Sax the additional global informations of the report.
719     * @param handler The transformer handler
720     * @param program The program on which the report is launched
721     * @throws SAXException If an error occurs
722     */
723    protected abstract void saxGlobalInformations(TransformerHandler handler, Program program) throws SAXException;
724}