Project

General

Profile

Download (88.2 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2017 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.io.cdmLight;
10

    
11
import java.io.File;
12
import java.util.ArrayList;
13
import java.util.Collections;
14
import java.util.Comparator;
15
import java.util.HashSet;
16
import java.util.Iterator;
17
import java.util.List;
18
import java.util.Map;
19
import java.util.Map.Entry;
20
import java.util.Set;
21

    
22
import org.apache.commons.lang3.StringUtils;
23
import org.springframework.stereotype.Component;
24

    
25
import eu.etaxonomy.cdm.api.service.name.TypeDesignationSetManager;
26
import eu.etaxonomy.cdm.common.CdmUtils;
27
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
28
import eu.etaxonomy.cdm.filter.TaxonNodeFilter;
29
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
30
import eu.etaxonomy.cdm.io.common.CdmExportBase;
31
import eu.etaxonomy.cdm.io.common.ExportResult.ExportResultState;
32
import eu.etaxonomy.cdm.io.common.ICdmExport;
33
import eu.etaxonomy.cdm.io.common.TaxonNodeOutStreamPartitioner;
34
import eu.etaxonomy.cdm.io.common.XmlExportState;
35
import eu.etaxonomy.cdm.io.common.mapping.out.IExportTransformer;
36
import eu.etaxonomy.cdm.model.agent.AgentBase;
37
import eu.etaxonomy.cdm.model.agent.Person;
38
import eu.etaxonomy.cdm.model.agent.Team;
39
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
40
import eu.etaxonomy.cdm.model.common.Annotation;
41
import eu.etaxonomy.cdm.model.common.AnnotationType;
42
import eu.etaxonomy.cdm.model.common.CdmBase;
43
import eu.etaxonomy.cdm.model.common.DefinedTerm;
44
import eu.etaxonomy.cdm.model.common.ICdmBase;
45
import eu.etaxonomy.cdm.model.common.IIdentifiableEntity;
46
import eu.etaxonomy.cdm.model.common.Language;
47
import eu.etaxonomy.cdm.model.common.LanguageString;
48
import eu.etaxonomy.cdm.model.description.CommonTaxonName;
49
import eu.etaxonomy.cdm.model.description.DescriptionBase;
50
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
51
import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
52
import eu.etaxonomy.cdm.model.description.Distribution;
53
import eu.etaxonomy.cdm.model.description.Feature;
54
import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
55
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
56
import eu.etaxonomy.cdm.model.description.TaxonDescription;
57
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
58
import eu.etaxonomy.cdm.model.description.TextData;
59
import eu.etaxonomy.cdm.model.location.NamedArea;
60
import eu.etaxonomy.cdm.model.media.Media;
61
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
62
import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
63
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
64
import eu.etaxonomy.cdm.model.name.HomotypicalGroupNameComparator;
65
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
66
import eu.etaxonomy.cdm.model.name.Rank;
67
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
68
import eu.etaxonomy.cdm.model.name.TaxonName;
69
import eu.etaxonomy.cdm.model.name.TypeComparator;
70
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
71
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
72
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
73
import eu.etaxonomy.cdm.model.occurrence.GatheringEvent;
74
import eu.etaxonomy.cdm.model.occurrence.MediaSpecimen;
75
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
76
import eu.etaxonomy.cdm.model.reference.Reference;
77
import eu.etaxonomy.cdm.model.reference.ReferenceType;
78
import eu.etaxonomy.cdm.model.taxon.Synonym;
79
import eu.etaxonomy.cdm.model.taxon.Taxon;
80
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
81
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
82
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
83
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
84
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDtoByRankAndNameComparator;
85
import eu.etaxonomy.cdm.strategy.cache.TagEnum;
86
import eu.etaxonomy.cdm.strategy.cache.TaggedText;
87
import eu.etaxonomy.cdm.strategy.cache.reference.DefaultReferenceCacheStrategy;
88
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
89

    
90
/**
91
 * @author k.luther
92
 * @since 15.03.2017
93
 */
94
@Component
95
public class CdmLightClassificationExport
96
            extends CdmExportBase<CdmLightExportConfigurator, CdmLightExportState, IExportTransformer, File>
97
            implements ICdmExport<CdmLightExportConfigurator, CdmLightExportState>{
98

    
99

    
100
    private static final long serialVersionUID = 2518643632756927053L;
101
    private static final String STD_TEAM_CONCATINATION = ", ";
102
    private static final String FINAL_TEAM_CONCATINATION = " & ";
103

    
104

    
105
    private static final String IPNI_NAME_IDENTIFIER = "Ipni Name Identifier";
106
    private static final String TROPICOS_NAME_IDENTIFIER = "Tropicos Name Identifier";
107
    private static final String WFO_NAME_IDENTIFIER = "WFO Name Identifier";
108

    
109
    public CdmLightClassificationExport() {
110
        super();
111
        this.ioName = this.getClass().getSimpleName();
112

    
113
    }
114

    
115
    @Override
116
    public long countSteps(CdmLightExportState state) {
117
        TaxonNodeFilter filter = state.getConfig().getTaxonNodeFilter();
118
        return taxonNodeService.count(filter);
119
    }
120

    
121

    
122
    /**
123
     * {@inheritDoc}
124
     */
125
    @Override
126
    protected void doInvoke(CdmLightExportState state) {
127
        try {
128

    
129
            IProgressMonitor monitor = state.getConfig().getProgressMonitor();
130
            CdmLightExportConfigurator config = state.getConfig();
131
            config.setFieldsTerminatedBy(",");
132

    
133
//            if (config.getTaxonNodeFilter().getTaxonNodesFilter().isEmpty() && config.getTaxonNodeFilter().getClassificationFilter().isEmpty()){
134
//                //TODO
135
//                state.setEmptyData();
136
//                return;
137
//            }
138

    
139

    
140

    
141
//            for (LogicFilter<Classification> classificationFilter : config.getTaxonNodeFilter().getClassificationFilter()){
142
//                UUID classificationUuid = classificationFilter.getUuid();
143
//                Classification classification = getClassificationService().find(classificationUuid);
144
//                if (classification == null){
145
//                    String message = String.format("Classification for given classification UUID not found. No data imported for %s", classificationUuid.toString());
146
//                    state.getResult().addWarning(message);
147
//                }else{
148
//                    TaxonNode root = classification.getRootNode();
149
//                    UUID uuid = root.getUuid();
150
//                    root = getTaxonNodeService().load(uuid);
151
//                    handleSingleClassification(state, root.getUuid());
152
//                }
153
//            }
154

    
155

    
156
            @SuppressWarnings("unchecked")
157
            TaxonNodeOutStreamPartitioner<XmlExportState> partitioner
158
                  = TaxonNodeOutStreamPartitioner.NewInstance(
159
                          this, state, state.getConfig().getTaxonNodeFilter(),
160
                          100, monitor, null);
161

    
162

    
163
                monitor.subTask("Start partitioning");
164

    
165
                TaxonNode node = partitioner.next();
166
                while (node != null){
167
                    handleTaxonNode(state, node);
168
                    node = partitioner.next();
169
                }
170
              //create sortIndex for nodes
171
                for(Entry<Integer, List<TaxonNodeDto>> entry :state.getNodeChildrenMap().entrySet()){
172
                    List<TaxonNodeDto> children = entry.getValue();
173
                    Comparator<TaxonNodeDto> comp = state.getConfig().getComparator();
174
                    if (comp == null){
175
                        comp = new TaxonNodeDtoByRankAndNameComparator();
176
                    }
177
                    Collections.sort(children, comp);
178
                    int index = 0;
179
                    for (TaxonNodeDto child:children) {
180
                        if (state.getProcessor().hasRecord(CdmLightExportTable.TAXON, child.getTaxonUuid().toString())){
181
                            String[] csvLine = state.getProcessor().getRecord(CdmLightExportTable.TAXON,child.getTaxonUuid().toString());
182
                            csvLine[CdmLightExportTable.TAXON.getIndex(CdmLightExportTable.SORT_INDEX)] =  String.valueOf(index);
183
                            index++;
184
                        }
185

    
186
                    }
187
               }
188

    
189

    
190
//            for (LogicFilter<TaxonNode> taxonNodeFilter : config.getTaxonNodeFilter().getTaxonNodesFilter()){
191
//                UUID nodeUuid = taxonNodeFilter.getUuid();
192
//                handleSingleClassification(state, nodeUuid);
193
//            }
194
            state.getProcessor().createFinalResult(state);
195
        } catch (Exception e) {
196
            state.getResult().addException(e, "An unexpected error occurred in main method doInvoke() " +
197
                    e.getMessage());
198
        }
199
    }
200

    
201
    /**
202
     * @param state
203
     * @param classificationUuid
204
     */
205
    private void handleTaxonNode(CdmLightExportState state, TaxonNode taxonNode) {
206

    
207
            if (taxonNode == null){
208
                String message = "TaxonNode for given taxon node UUID not found. ";
209
                //TODO
210
                state.getResult().addWarning(message);
211
            }else{
212
                try {
213
                    TaxonNode root = taxonNode;
214
                    List<TaxonNodeDto> childNodes;
215
                    if (root.hasChildNodes()){
216
                        childNodes = new ArrayList();
217
                        for (TaxonNode child: root.getChildNodes()){
218
                            childNodes.add(new TaxonNodeDto(child));
219
                        }
220
                        state.getNodeChildrenMap().put(root.getId(),childNodes);
221
                    }
222
                    if (root.hasTaxon()){
223
                        handleTaxon(state, root);
224

    
225
                    }
226
                } catch (Exception e) {
227
                    state.getResult().addException(e, "An unexpected error occurred when handling classification " +
228
                            taxonNode.getUuid() + ": " + e.getMessage() + e.getStackTrace());
229
                }
230
            }
231
    }
232

    
233
    /**
234
     * @param state
235
     * @param taxon
236
     */
237
    private void handleTaxon(CdmLightExportState state, TaxonNode taxonNode) {
238
        try{
239
      //  Taxon taxon = taxonNode.getTaxon();
240
        if (taxonNode == null){
241
            state.getResult().addError ("The taxonNode was null.", "handleTaxon");
242
            state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
243
            return;
244
        }
245
        if (taxonNode.getTaxon() == null){
246
            state.getResult().addError ("There was a taxon node without a taxon: " + taxonNode.getUuid(), "handleTaxon");
247
            state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
248
        }else{
249
            Taxon taxon = HibernateProxyHelper.deproxy(taxonNode.getTaxon(), Taxon.class);
250

    
251
             try{
252
                TaxonName name = taxon.getName();
253
                handleName(state, name);
254
                for (Synonym syn : taxon.getSynonyms()){
255
                    handleSynonym(state, syn);
256
                }
257
                for (TaxonRelationship rel : taxon.getProParteAndPartialSynonymRelations()){
258
                    handleProPartePartialMisapplied(state, rel);
259
                }
260
                for (TaxonRelationship rel : taxon.getMisappliedNameRelations()){
261
                    handleProPartePartialMisapplied(state, rel);
262
                }
263

    
264
                CdmLightExportTable table = CdmLightExportTable.TAXON;
265
                String[] csvLine = new String[table.getSize()];
266

    
267
                csvLine[table.getIndex(CdmLightExportTable.TAXON_ID)] = getId(state, taxon);
268
                csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
269
                Taxon parent = (taxonNode.getParent()==null) ? null : taxonNode.getParent().getTaxon();
270
                csvLine[table.getIndex(CdmLightExportTable.PARENT_FK)] = getId(state, parent);
271
                csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE_FK)] = getId(state, taxon.getSec());
272
                if (taxon.getSec()!= null && taxon.getSec().getDatePublished() != null && taxon.getSec().getDatePublished().getFreeText() != null){
273
                    String sec_string = taxon.getSec().getTitleCache() + ". " + taxon.getSec().getDatePublished().getFreeText();
274
                    sec_string = sec_string.replace("..", ".");
275
                    csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = sec_string;
276
                }else{
277
                    csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = getTitleCache(taxon.getSec());
278
                }
279
                if (taxon.getSec() != null){
280
                    if (state.getReferenceFromStore(taxon.getSec().getId()) == null){
281
                        handleReference(state, taxon.getSec());
282
                    }
283
                }
284
                csvLine[table.getIndex(CdmLightExportTable.CLASSIFICATION_ID)] = getId(state, taxonNode.getClassification());
285
                csvLine[table.getIndex(CdmLightExportTable.CLASSIFICATION_TITLE)] = taxonNode.getClassification().getTitleCache();
286

    
287
                state.getProcessor().put(table, taxon, csvLine);
288
                handleDescriptions(state, taxon);
289
             }catch(Exception e){
290
                 state.getResult().addException (e, "An unexpected problem occurred when trying to export "
291
                         + "taxon with id " + taxon.getId());
292
                 state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
293
             }
294
       }
295

    
296
       taxonNode.removeNullValueFromChildren();
297
//       for (TaxonNode child: taxonNode.getChildNodes()){
298
//           handleTaxon(state, child);
299
//       }
300
        }catch (Exception e){
301
            state.getResult().addException(e, "An unexpected error occurred when handling the taxon node of " +
302
                    cdmBaseStr(taxonNode.getTaxon()) + ": " + e.getMessage());
303
        }
304
    }
305

    
306

    
307
    /**
308
     * @param state
309
     * @param taxon
310
     */
311
    private void handleDescriptions(CdmLightExportState state, CdmBase cdmBase) {
312
        try{
313
        if (cdmBase instanceof Taxon){
314
            Taxon taxon = HibernateProxyHelper.deproxy(cdmBase, Taxon.class);
315
            Set<TaxonDescription> descriptions = taxon.getDescriptions();
316
            List<DescriptionElementBase> simpleFacts = new ArrayList<>();
317
            List<DescriptionElementBase> specimenFacts = new ArrayList<>();
318
            List<DescriptionElementBase> distributionFacts = new ArrayList<>();
319
            List<DescriptionElementBase> commonNameFacts = new ArrayList<>();
320
            List<DescriptionElementBase> usageFacts = new ArrayList<>();
321
            for (TaxonDescription description: descriptions){
322
                if (description.getElements() != null){
323
                    for (DescriptionElementBase element: description.getElements()){
324
                        element = CdmBase.deproxy(element);
325
                        if (element.getFeature().equals(Feature.COMMON_NAME())){
326
                            commonNameFacts.add(element);
327
                        }else if (element.getFeature().equals(Feature.DISTRIBUTION())){
328
                            distributionFacts.add(element);
329
                        }else if (element instanceof IndividualsAssociation || isSpecimenFeature(element.getFeature())){
330
                            specimenFacts.add(element);
331
                        }else{
332
                            simpleFacts.add(element);
333
                        }
334
                    }
335
                }
336
            }
337
            if (!commonNameFacts.isEmpty()){
338
                handleCommonNameFacts(state, taxon, commonNameFacts);
339
            }
340
            if (!distributionFacts.isEmpty()){
341
                handleDistributionFacts(state, taxon, distributionFacts);
342
            }
343
            if (!specimenFacts.isEmpty()){
344
                handleSpecimenFacts(state, taxon, specimenFacts);
345
            }
346
            if (!simpleFacts.isEmpty()){
347
                handleSimpleFacts(state, taxon, simpleFacts);
348
            }
349
        } else if (cdmBase instanceof TaxonName){
350
            TaxonName name = CdmBase.deproxy(cdmBase, TaxonName.class);
351
            Set<TaxonNameDescription> descriptions = name.getDescriptions();
352
            List<DescriptionElementBase> simpleFacts = new ArrayList<>();
353
            for (TaxonNameDescription description: descriptions){
354
                if (description.getElements() != null){
355
                    for (DescriptionElementBase element: description.getElements()){
356
                        if (!element.getFeature().equals(Feature.PROTOLOGUE())){
357
                            simpleFacts.add(element);
358
                        }
359
                    }
360
                }
361
             }
362
            if (!simpleFacts.isEmpty()){
363
                handleSimpleFacts(state, name, simpleFacts);
364
            }
365
        }
366
        }catch (Exception e){
367
            state.getResult().addException(e, "An unexpected error occurred when handling description of" +
368
                    cdmBaseStr(cdmBase) + ": " + e.getMessage());
369
        }
370
    }
371

    
372

    
373
    /**
374
     * @param feature
375
     * @return
376
     */
377
    private boolean isSpecimenFeature(Feature feature) {
378
        //TODO allow user defined specimen features
379
        if (feature == null){
380
            return false;
381
        }else if (feature.isSupportsIndividualAssociation()){
382
            return true;
383
        }else{
384
            return feature.equals(Feature.SPECIMEN()) || feature.equals(Feature.INDIVIDUALS_ASSOCIATION())
385
                    || feature.equals(Feature.MATERIALS_EXAMINED()) || feature.equals(Feature.OBSERVATION())
386
                    || feature.equals(Feature.OCCURRENCE())
387
                     ;
388
        }
389
    }
390

    
391
    /**
392
     * @param state
393
     * @param taxon
394
     * @param simpleFacts
395
     */
396
    private void handleSimpleFacts(CdmLightExportState state, CdmBase cdmBase,
397
            List<DescriptionElementBase> simpleFacts) {
398
        try {
399
            CdmLightExportTable table = CdmLightExportTable.SIMPLE_FACT;
400
            CdmLightExportTable tableMedia = CdmLightExportTable.MEDIA;
401
            for (DescriptionElementBase element: simpleFacts){
402
                if (element.getModifyingText().isEmpty() && !element.getMedia().isEmpty()){
403
                    handleSimpleMediaFact(state, cdmBase, tableMedia, element);
404
                }else{
405
                    handleSingleSimpleFact(state, cdmBase, table, element);
406
                }
407
            }
408
        } catch (Exception e) {
409
            state.getResult().addException(e, "An unexpected error occurred when handling simple facts for " +
410
                    cdmBaseStr(cdmBase) + ": " + e.getMessage());
411
        }
412
    }
413

    
414
    /**
415
     * @param state
416
     * @param cdmBase
417
     * @param tableMedia
418
     * @param element
419
     */
420
    private void handleSimpleMediaFact(CdmLightExportState state, CdmBase cdmBase, CdmLightExportTable table,
421
            DescriptionElementBase element) {
422
        try {
423
            String[] csvLine;
424
            handleSource(state, element, CdmLightExportTable.MEDIA);
425

    
426
            if (element instanceof TextData){
427
               TextData textData = (TextData)element;
428
               csvLine = new String[table.getSize()];
429
               csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
430
               if (cdmBase instanceof Taxon){
431
                   csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
432
                   csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = "";
433
               }else if (cdmBase instanceof TaxonName){
434
                   csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = "";
435
                   csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, cdmBase);
436
               }
437

    
438

    
439
               String mediaUris = "";
440
               for (Media media: textData.getMedia()){
441
                   String mediaString = extractMediaUris(media.getRepresentations().iterator());
442
                   if (!StringUtils.isBlank(mediaString)){
443
                       mediaUris +=  mediaString + ";";
444
                   }
445
                   else{
446
                       state.getResult().addWarning("Empty Media object for "
447
                               + cdmBase.getUserFriendlyTypeName() + " " + cdmBase.getUuid()
448
                               + " (media: " + media.getUuid() + ")");
449
                   }
450
               }
451
               csvLine[table.getIndex(CdmLightExportTable.MEDIA_URI)] = mediaUris;
452

    
453
            }
454
        } catch (Exception e) {
455
            state.getResult().addException(e, "An unexpected error occurred when handling single simple fact " +
456
                    cdmBaseStr(element) + ": " + e.getMessage());
457
        }
458

    
459
    }
460

    
461
    /**
462
     * @param state
463
     * @param cdmBase
464
     * @param table
465
     * @param element
466
     */
467
    private void handleSingleSimpleFact(CdmLightExportState state, CdmBase cdmBase, CdmLightExportTable table,
468
            DescriptionElementBase element) {
469
        try {
470
            String[] csvLine;
471
            handleSource(state, element, CdmLightExportTable.SIMPLE_FACT);
472

    
473
            if (element instanceof TextData){
474
               TextData textData = (TextData)element;
475
               csvLine = new String[table.getSize()];
476
               csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
477
               if (cdmBase instanceof Taxon){
478
                   csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
479
                   csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = "";
480
               }else if (cdmBase instanceof TaxonName){
481
                   csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = "";
482
                   csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, cdmBase);
483
               }
484
               csvLine[table.getIndex(CdmLightExportTable.FACT_CATEGORY)] = textData.getFeature().getLabel();
485

    
486
               String mediaUris = "";
487
               for (Media media: textData.getMedia()){
488
                   String mediaString = extractMediaUris(media.getRepresentations().iterator());
489
                   if (!StringUtils.isBlank(mediaString)){
490
                       mediaUris +=  mediaString + ";";
491
                   }
492
                   else{
493
                       state.getResult().addWarning("Empty Media object for uuid: " +
494
                               cdmBase.getUuid() + " uuid of media: " + media.getUuid());
495
                   }
496
               }
497
               csvLine[table.getIndex(CdmLightExportTable.MEDIA_URI)] = mediaUris;
498
               if (textData.getFeature().equals(Feature.CITATION())){
499
                  // csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
500
                   state.getProcessor().put(table, textData, csvLine);
501
               }else if (!textData.getMultilanguageText().isEmpty()){
502
                   for (Language language: textData.getMultilanguageText().keySet()){
503
                       String[] csvLineLanguage = csvLine.clone();
504
                       LanguageString langString = textData.getLanguageText(language);
505
                       String text = langString.getText();
506
                       if (state.getConfig().isFilterIntextReferences()){
507
                           text = filterIntextReferences(langString.getText());
508
                       }
509
                       csvLineLanguage[table.getIndex(CdmLightExportTable.FACT_TEXT)] = text;
510
                       csvLineLanguage[table.getIndex(CdmLightExportTable.LANGUAGE)] = language.getLabel();
511
                       state.getProcessor().put(table, textData, csvLineLanguage);
512
                   }
513
               } else{
514
                   state.getProcessor().put(table, textData, csvLine);
515
               }
516
            }
517
        } catch (Exception e) {
518
            state.getResult().addException(e, "An unexpected error occurred when handling single simple fact " +
519
                    cdmBaseStr(element) + ": " + e.getMessage());
520
        }
521
    }
522

    
523

    
524
    /**
525
     * @param text
526
     * @return
527
     */
528
    private String filterIntextReferences(String text) {
529
        /*
530
         * (<cdm:reference cdmId='fbd19251-efee-4ded-b780-915000f66d41' intextId='1352d42c-e201-4155-a02a-55360d3b563e'>Ridley in Fl. Malay Pen. 3 (1924) 22</cdm:reference>)
531
         */
532

    
533
       String newText = text.replaceAll("<cdm:reference cdmId='[a-z0-9\\-]*' intextId='[a-z0-9\\-]*'>","");
534
       newText = newText.replaceAll("</cdm:reference>","");
535

    
536
       newText = newText.replaceAll("<cdm:key cdmId='[a-z0-9\\-]*' intextId='[a-z0-9\\-]*'>","");
537
       newText = newText.replaceAll("</cdm:key>","");
538
       return newText;
539
    }
540

    
541
    /**
542
     * @param state
543
     * @param specimenFacts
544
     */
545
    private void handleSpecimenFacts(CdmLightExportState state, Taxon taxon, List<DescriptionElementBase> specimenFacts) {
546
        CdmLightExportTable table = CdmLightExportTable.SPECIMEN_FACT;
547

    
548
        for (DescriptionElementBase element: specimenFacts){
549
            try {
550
                String[] csvLine = new String[table.getSize()];
551
                csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
552
                csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, taxon);
553
                handleSource(state, element, table);
554
                csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_NOTES)] = createAnnotationsString(element.getAnnotations());
555

    
556
                if (element instanceof IndividualsAssociation){
557

    
558
                    IndividualsAssociation indAssociation = (IndividualsAssociation)element;
559
                    if (indAssociation.getAssociatedSpecimenOrObservation() == null){
560
                        state.getResult().addWarning("There is an individual association with no specimen associated (Taxon "+ taxon.getTitleCache() + "(" + taxon.getUuid() +"). Could not be exported.");
561
                        continue;
562
                    }else{
563
                        if (state.getSpecimenFromStore(indAssociation.getAssociatedSpecimenOrObservation().getId()) == null){
564
                            SpecimenOrObservationBase<?> specimenBase = HibernateProxyHelper.deproxy(indAssociation.getAssociatedSpecimenOrObservation(), SpecimenOrObservationBase.class);
565

    
566
                            handleSpecimen(state, specimenBase);
567
                            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_FK)] = getId(state, indAssociation.getAssociatedSpecimenOrObservation());
568

    
569
                        }
570
                    }
571
                } else if (element instanceof TextData){
572
                    TextData textData = HibernateProxyHelper.deproxy(element, TextData.class);
573
                    csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_DESCRIPTION)] = createMultilanguageString(textData.getMultilanguageText());
574
                }
575
                state.getProcessor().put(table, element, csvLine);
576
            } catch (Exception e) {
577
                state.getResult().addException(e, "An unexpected error occurred when handling single specimen fact " +
578
                        cdmBaseStr(element) + ": " + e.getMessage());
579
            }
580
        }
581
    }
582

    
583
    /**
584
     * @param multilanguageText
585
     * @return
586
     */
587
    private String createMultilanguageString(Map<Language, LanguageString> multilanguageText) {
588
       String text = "";
589
       int index = multilanguageText.size();
590
       for(LanguageString langString: multilanguageText.values()){
591
           text += langString.getText();
592
           if (index > 1){
593
               text += "; ";
594
           }
595
           index --;
596
       }
597

    
598
        return text;
599
    }
600

    
601
    /**
602
     * @param annotations
603
     * @return
604
     */
605
    private String createAnnotationsString(Set<Annotation> annotations) {
606
        StringBuffer strBuff = new StringBuffer();
607

    
608
        for (Annotation ann:annotations){
609
            if (ann.getAnnotationType() == null ||!ann.getAnnotationType().equals(AnnotationType.TECHNICAL())){
610
                strBuff.append(ann.getText());
611
                strBuff.append("; ");
612
            }
613
        }
614

    
615
        if (strBuff.length() > 2){
616
            return strBuff.substring(0, strBuff.length()-2);
617
        }else{
618
            return null;
619
        }
620
    }
621

    
622
    /**
623
     * @param state
624
     * @param taxon
625
     * @param element
626
     */
627
    private void handleSource(CdmLightExportState state, DescriptionElementBase element, CdmLightExportTable factsTable) {
628
        CdmLightExportTable table = CdmLightExportTable.FACT_SOURCES;
629
        try {
630
        Set<DescriptionElementSource> sources = element.getSources();
631

    
632
        for (DescriptionElementSource source: sources){
633

    
634
                String[] csvLine = new  String[table.getSize()];
635
                Reference ref = source.getCitation();
636
                if ((ref == null) && (source.getNameUsedInSource() == null)){
637
                    continue;
638
                }
639
                if (ref != null){
640
                    if (state.getReferenceFromStore(ref.getId()) == null){
641
                        handleReference(state, ref);
642

    
643
                    }
644
                    csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)] = getId(state, ref);
645
                }
646
                csvLine[table.getIndex(CdmLightExportTable.FACT_FK)] = getId(state, element);
647

    
648
                csvLine[table.getIndex(CdmLightExportTable.NAME_IN_SOURCE_FK)] = getId(state, source.getNameUsedInSource());
649
                csvLine[table.getIndex(CdmLightExportTable.FACT_TYPE)] = factsTable.getTableName();
650
                if ( StringUtils.isBlank(csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)])  && StringUtils.isBlank(csvLine[table.getIndex(CdmLightExportTable.NAME_IN_SOURCE_FK)])){
651
                    continue;
652
                }
653
                state.getProcessor().put(table, source, csvLine);
654

    
655
        }
656
        } catch (Exception e) {
657
            state.getResult().addException(e, "An unexpected error occurred when handling single source " +
658
                    cdmBaseStr(element) + ": " + e.getMessage());
659
        }
660

    
661
    }
662

    
663
    /**
664
     * @param state
665
     * @param distributionFacts
666
     */
667
    private void handleDistributionFacts(CdmLightExportState state, Taxon taxon, List<DescriptionElementBase> distributionFacts) {
668
        CdmLightExportTable table = CdmLightExportTable.GEOGRAPHIC_AREA_FACT;
669

    
670
        for (DescriptionElementBase element: distributionFacts){
671
            try {
672
                if (element instanceof Distribution){
673
                    String[] csvLine = new  String[table.getSize()];
674
                    Distribution distribution = (Distribution)element;
675
                    csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
676
                    handleSource(state, element, table);
677
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, taxon);
678
                    if (distribution.getArea() != null){
679
                        csvLine[table.getIndex(CdmLightExportTable.AREA_LABEL)] = distribution.getArea().getLabel();
680
                    }
681
                    if (distribution.getStatus() != null){
682
                        csvLine[table.getIndex(CdmLightExportTable.STATUS_LABEL)] = distribution.getStatus().getLabel();
683
                    }
684
                    state.getProcessor().put(table, distribution, csvLine);
685
                } else{
686
                    state.getResult().addError("The distribution description for the taxon " + taxon.getUuid() + " is not of type distribution. Could not be exported. UUID of the description element: " + element.getUuid());
687
                }
688
            } catch (Exception e) {
689
                state.getResult().addException(e, "An unexpected error occurred when handling single distribution " +
690
                        cdmBaseStr(element) + ": " + e.getMessage());
691
            }
692
        }
693
    }
694

    
695
    /**
696
     * @param state
697
     * @param commonNameFacts
698
     */
699
    private void handleCommonNameFacts(CdmLightExportState state, Taxon taxon, List<DescriptionElementBase> commonNameFacts) {
700
        CdmLightExportTable table = CdmLightExportTable.COMMON_NAME_FACT;
701

    
702
        for (DescriptionElementBase element: commonNameFacts){
703
            try {
704
                if (element instanceof CommonTaxonName){
705
                    String[] csvLine = new  String[table.getSize()];
706
                    CommonTaxonName commonName = (CommonTaxonName)element;
707
                    csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
708
                    handleSource(state, element, table);
709
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, taxon);
710
                    if (commonName.getName() != null){csvLine[table.getIndex(CdmLightExportTable.FACT_TEXT)] = commonName.getName();}
711
                    if (commonName.getLanguage() != null){csvLine[table.getIndex(CdmLightExportTable.LANGUAGE)] = commonName.getLanguage().getLabel();}
712
                    if (commonName.getArea() != null){ csvLine[table.getIndex(CdmLightExportTable.AREA_LABEL)] = commonName.getArea().getLabel();}
713
                    state.getProcessor().put(table, commonName, csvLine);
714
                } else{
715
                    state.getResult().addError("The distribution description for the taxon " + taxon.getUuid() + " is not of type distribution. Could not be exported. UUID of the description element: " + element.getUuid());
716
                }
717
            } catch (Exception e) {
718
                state.getResult().addException(e, "An unexpected error occurred when handling single common name " +
719
                        cdmBaseStr(element) + ": " + e.getMessage());
720
            }
721
        }
722
    }
723

    
724
    /**
725
     * @param sec
726
     * @return
727
     */
728
    private String getTitleCache(IIdentifiableEntity identEntity) {
729
        if (identEntity == null){
730
            return "";
731
        }
732
        //TODO refresh?
733
        return identEntity.getTitleCache();
734
    }
735

    
736
    /**
737
     * @param state
738
     * @param taxon
739
     * @return
740
     */
741
    private String getId(CdmLightExportState state, ICdmBase cdmBase) {
742
        if (cdmBase == null){
743
            return "";
744
        }
745
        //TODO make configurable
746
        return cdmBase.getUuid().toString();
747
    }
748

    
749
    /**
750
     * @param state
751
     * @param synonym
752
     */
753
    private void handleSynonym(CdmLightExportState state, Synonym synonym) {
754
       try {
755
           if (isUnpublished(state.getConfig(), synonym)){
756
               return;
757
           }
758
           TaxonName name = synonym.getName();
759
           handleName(state, name);
760

    
761
           CdmLightExportTable table = CdmLightExportTable.SYNONYM;
762
           String[] csvLine = new String[table.getSize()];
763

    
764
           csvLine[table.getIndex(CdmLightExportTable.SYNONYM_ID)] = getId(state, synonym);
765
           csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, synonym.getAcceptedTaxon());
766
           csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
767
           csvLine[table.getIndex(CdmLightExportTable.SYN_SEC_REFERENCE_FK)] = getId(state, synonym.getSec());
768
           csvLine[table.getIndex(CdmLightExportTable.SYN_SEC_REFERENCE)] = getTitleCache(synonym.getSec());
769

    
770
           state.getProcessor().put(table, synonym, csvLine);
771
        } catch (Exception e) {
772
            state.getResult().addException(e, "An unexpected error occurred when handling synonym " +
773
                    cdmBaseStr(synonym) + ": " + e.getMessage());
774
        }
775
    }
776

    
777

    
778
    /**
779
     * Handles Misapplied names (including pro parte and partial as well as
780
     * pro parte and partial synonyms
781
     * @param state
782
     * @param rel
783
     */
784
    private void handleProPartePartialMisapplied(CdmLightExportState state, TaxonRelationship rel) {
785
        try {
786
            Taxon ppSyonym = rel.getFromTaxon();
787
            if (isUnpublished(state.getConfig(), ppSyonym)){
788
                return;
789
            }
790
            TaxonName name = ppSyonym.getName();
791
            handleName(state, name);
792

    
793
            CdmLightExportTable table = CdmLightExportTable.SYNONYM;
794
            String[] csvLine = new String[table.getSize()];
795

    
796
            csvLine[table.getIndex(CdmLightExportTable.SYNONYM_ID)] = getId(state, rel);
797
            csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, rel.getToTaxon());
798
            csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
799

    
800
            Reference secRef = ppSyonym.getSec();
801
            csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE_FK)] = getId(state, secRef);
802
            csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = getTitleCache(secRef);
803
            Reference synSecRef = rel.getCitation();
804
            csvLine[table.getIndex(CdmLightExportTable.SYN_SEC_REFERENCE_FK)] = getId(state, synSecRef);
805
            csvLine[table.getIndex(CdmLightExportTable.SYN_SEC_REFERENCE)] = getTitleCache(synSecRef);
806

    
807
            //pro parte type
808
            TaxonRelationshipType type = rel.getType();
809
            csvLine[table.getIndex(CdmLightExportTable.IS_PRO_PARTE)] = type.isProParte()? "1":"0";
810
            csvLine[table.getIndex(CdmLightExportTable.IS_PARTIAL)] = type.isPartial()? "1":"0";
811
            csvLine[table.getIndex(CdmLightExportTable.IS_MISAPPLIED)] = type.isAnyMisappliedName()? "1":"0";
812

    
813
            state.getProcessor().put(table, ppSyonym, csvLine);
814
         } catch (Exception e) {
815
             state.getResult().addException(e, "An unexpected error occurred when handling "
816
                     + "pro parte/partial synonym relationship " +
817
                     cdmBaseStr(rel) + ": " + e.getMessage());
818
         }
819

    
820
    }
821

    
822

    
823
    /**
824
     * @param state
825
     * @param name
826
     */
827
    private void handleName(CdmLightExportState state, TaxonName name) {
828
        if (name == null){
829
            return;
830
        }
831
        try {
832
            Rank rank = name.getRank();
833
            CdmLightExportTable table = CdmLightExportTable.SCIENTIFIC_NAME;
834
            name = HibernateProxyHelper.deproxy(name);
835
            String[] csvLine = new String[table.getSize()];
836

    
837
            csvLine[table.getIndex(CdmLightExportTable.NAME_ID)] = getId(state, name);
838
            if (name.getLsid() != null){
839
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = name.getLsid().getLsid();
840
            }else{
841
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = "";
842
            }
843

    
844
            handleIdentifier(state, name);
845
            handleDescriptions(state, name);
846

    
847
            csvLine[table.getIndex(CdmLightExportTable.RANK)] = getTitleCache(rank);
848
            if (rank != null){
849
                csvLine[table.getIndex(CdmLightExportTable.RANK_SEQUENCE)] = String.valueOf(rank.getOrderIndex());
850
                if (rank.isInfraGeneric()){
851
                    try {
852
                        csvLine[table.getIndex(CdmLightExportTable.INFRAGENERIC_RANK)] = name.getRank().getInfraGenericMarker();
853
                    } catch (UnknownCdmTypeException e) {
854
                        state.getResult().addError("Infrageneric marker expected but not available for rank " + name.getRank().getTitleCache());
855
                    }
856
                }
857
                if (rank.isInfraSpecific()){
858
                    csvLine[table.getIndex(CdmLightExportTable.INFRASPECIFIC_RANK)] = name.getRank().getAbbreviation();
859
                }
860
            }else{
861
                csvLine[table.getIndex(CdmLightExportTable.RANK_SEQUENCE)] = "";
862
            }
863
            if (name.isProtectedTitleCache()){
864
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_AUTHORS)] =name.getTitleCache();
865
            }else{
866
                //TODO: adapt the tropicos titlecache creation
867
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_AUTHORS)] = name.getTitleCache();
868
            }
869
            csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_NO_AUTHORS)] = name.getNameCache();
870
            csvLine[table.getIndex(CdmLightExportTable.GENUS_UNINOMIAL)] = name.getGenusOrUninomial();
871

    
872
            csvLine[table.getIndex(CdmLightExportTable.INFRAGENERIC_EPITHET)] = name.getInfraGenericEpithet();
873
            csvLine[table.getIndex(CdmLightExportTable.SPECIFIC_EPITHET)] = name.getSpecificEpithet();
874

    
875
            csvLine[table.getIndex(CdmLightExportTable.INFRASPECIFIC_EPITHET)] = name.getInfraSpecificEpithet();
876
            csvLine[table.getIndex(CdmLightExportTable.BAS_AUTHORTEAM_FK)] = getId(state,name.getBasionymAuthorship());
877
            if (name.getBasionymAuthorship() != null){
878
                if (state.getAuthorFromStore(name.getBasionymAuthorship().getId()) == null) {
879
                    handleAuthor(state, name.getBasionymAuthorship());
880
                }
881
            }
882
            csvLine[table.getIndex(CdmLightExportTable.BAS_EX_AUTHORTEAM_FK)] = getId(state, name.getExBasionymAuthorship());
883
            if (name.getExBasionymAuthorship() != null){
884
                if (state.getAuthorFromStore(name.getExBasionymAuthorship().getId()) == null) {
885
                    handleAuthor(state, name.getExBasionymAuthorship());
886
                }
887

    
888
            }
889
            csvLine[table.getIndex(CdmLightExportTable.COMB_AUTHORTEAM_FK)] = getId(state,name.getCombinationAuthorship());
890
            if (name.getCombinationAuthorship() != null){
891
                if (state.getAuthorFromStore(name.getCombinationAuthorship().getId()) == null) {
892
                    handleAuthor(state, name.getCombinationAuthorship());
893
                }
894
            }
895
            csvLine[table.getIndex(CdmLightExportTable.COMB_EX_AUTHORTEAM_FK)] = getId(state, name.getExCombinationAuthorship());
896
            if (name.getExCombinationAuthorship() != null){
897
                if (state.getAuthorFromStore(name.getExCombinationAuthorship().getId()) == null) {
898
                    handleAuthor(state, name.getExCombinationAuthorship());
899
                }
900

    
901
            }
902

    
903
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_TEAM_STRING)] = name.getAuthorshipCache();
904

    
905
            Reference nomRef = name.getNomenclaturalReference();
906

    
907
            if (nomRef != null){
908
                if (state.getReferenceFromStore(nomRef.getId()) == null){
909
                    handleReference(state, nomRef);
910
                }
911
                csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)] = getId(state, nomRef);
912
                csvLine[table.getIndex(CdmLightExportTable.PUBLICATION_TYPE)] = nomRef.getType().name();
913
                if (nomRef.getVolume() != null){
914
                    csvLine[table.getIndex(CdmLightExportTable.VOLUME_ISSUE)] = nomRef.getVolume();
915
                    csvLine[table.getIndex(CdmLightExportTable.COLLATION)] = createCollatation(name);
916
                }
917
                if (nomRef.getDatePublished() != null){
918
                    csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = nomRef.getTimePeriodPublishedString();
919
                    csvLine[table.getIndex(CdmLightExportTable.YEAR_PUBLISHED)] = nomRef.getDatePublished().getYear();
920
                    csvLine[table.getIndex(CdmLightExportTable.VERBATIM_DATE)] = nomRef.getDatePublished().getVerbatimDate();
921
                }
922
                if (name.getNomenclaturalMicroReference() != null){
923
                    csvLine[table.getIndex(CdmLightExportTable.DETAIL)] = name.getNomenclaturalMicroReference();
924
                }
925
                nomRef = HibernateProxyHelper.deproxy(nomRef);
926
                if (nomRef.getInReference() != null){
927
                    Reference inReference = nomRef.getInReference();
928
                    if (inReference.getDatePublished() != null && nomRef.getDatePublished() == null){
929
                        csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = inReference.getDatePublishedString();
930
                        csvLine[table.getIndex(CdmLightExportTable.YEAR_PUBLISHED)] = inReference.getDatePublished().getYear();
931
                    }
932
                    if (nomRef.getVolume() == null && inReference.getVolume() != null){
933
                        csvLine[table.getIndex(CdmLightExportTable.VOLUME_ISSUE)] = inReference.getVolume();
934
                        csvLine[table.getIndex(CdmLightExportTable.COLLATION)] = createCollatation(name);
935
                    }
936
                    if (inReference.getInReference() != null){
937
                        inReference = inReference.getInReference();
938
                    }
939
                    if (inReference.getAbbrevTitle() == null){
940
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils.Nz(inReference.getAbbrevTitleCache());
941
                    }else{
942
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils.Nz(inReference.getAbbrevTitle());
943
                    }
944
                    if (inReference.getTitle() == null){
945
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(inReference.getTitleCache());
946
                    }else{
947
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(inReference.getTitle());
948
                    }
949

    
950

    
951
                    TeamOrPersonBase<?> author = inReference.getAuthorship();
952
                    if (author != null && (nomRef.isOfType(ReferenceType.BookSection) || nomRef.isOfType(ReferenceType.Section))){
953
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = author.isProtectedTitleCache()? author.getTitleCache(): CdmUtils.Nz(author.getNomenclaturalTitle());
954
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = CdmUtils.Nz(author.getTitleCache());
955
                    }else{
956
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = "";
957
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = "";
958
                    }
959
                }else{
960
                    if (nomRef.getAbbrevTitle() == null){
961
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils.Nz(nomRef.getAbbrevTitleCache());
962
                    }else{
963
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils.Nz(nomRef.getAbbrevTitle());
964
                    }
965
                    if (nomRef.getTitle() == null){
966
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(nomRef.getTitleCache());
967
                    }else{
968
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(nomRef.getTitle());
969
                    }
970
                    TeamOrPersonBase<?> author = nomRef.getAuthorship();
971
                    if (author != null ){
972
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = author.isProtectedTitleCache()? author.getTitleCache(): CdmUtils.Nz(author.getNomenclaturalTitle());
973
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = CdmUtils.Nz(author.getTitleCache());
974
                    }else{
975
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = "";
976
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = "";
977
                    }
978

    
979
                }
980
            }else{
981
                csvLine[table.getIndex(CdmLightExportTable.PUBLICATION_TYPE)] = "";
982
            }
983

    
984

    
985

    
986
            /*
987
            * Collation
988

    
989
            Detail
990

    
991

    
992
            TitlePageYear
993
            */
994
            Set<TaxonNameDescription> descriptions = name.getDescriptions();
995
            String protologueUriString = extractURIs(state, descriptions, Feature.PROTOLOGUE());
996

    
997
            csvLine[table.getIndex(CdmLightExportTable.PROTOLOGUE_URI)] = protologueUriString;
998

    
999
            if (name.getStatus() == null || name.getStatus().isEmpty()){
1000
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS)] = "";
1001
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS_ABBREV)] = "";
1002
            }else{
1003

    
1004
                String statusStringAbbrev = extractStatusString(state, name, true);
1005
                String statusString = extractStatusString(state, name, false);
1006

    
1007
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS)] = statusString.trim();
1008
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS_ABBREV)] = statusStringAbbrev.trim();
1009
            }
1010

    
1011
            HomotypicalGroup group =name.getHomotypicalGroup();
1012

    
1013
            if (state.getHomotypicalGroupFromStore(group.getId()) == null){
1014
                handleHomotypicalGroup(state, HibernateProxyHelper.deproxy(group, HomotypicalGroup.class));
1015
            }
1016
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_FK)] = getId(state, group);
1017
            List<TaxonName> typifiedNames = new ArrayList<>();
1018
            typifiedNames.addAll(group.getTypifiedNames());
1019
            Collections.sort(typifiedNames, new HomotypicalGroupNameComparator(null, true));
1020
            Integer  seqNumber= typifiedNames.indexOf(name);
1021
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_SEQ)] = String.valueOf(seqNumber);
1022
            state.getProcessor().put(table, name, csvLine);
1023

    
1024
            /*
1025
             *
1026
            Tropicos_ID
1027
            IPNI_ID
1028

    
1029

    
1030
            InfragenericRank
1031

    
1032

    
1033
            InfraspecificRank
1034
            Collation
1035
            Volume (Issue)
1036
            Detail
1037
            DatePublished
1038
            YearPublished
1039
            TitlePageYear
1040

    
1041

    
1042

    
1043
            HomotypicGroupSequenceNumber
1044

    
1045

    
1046
             *
1047
             */
1048
        } catch (Exception e) {
1049
            state.getResult().addException(e, "An unexpected error occurred when handling synonym " +
1050
                    cdmBaseStr(name) + ": " + e.getMessage());
1051
        }
1052
    }
1053

    
1054
    /**
1055
     * @return
1056
     */
1057
    private String createCollatation(TaxonName name) {
1058
        String collation = "";
1059
        if (name.getNomenclaturalReference() != null){
1060
            Reference ref = name.getNomenclaturalReference();
1061
            collation = getVolume(ref);
1062
        }
1063
        if (name.getNomenclaturalMicroReference() != null){
1064
            if (!StringUtils.isBlank(collation)){
1065
                collation += ":";
1066
            }
1067
            collation +=name.getNomenclaturalMicroReference();
1068
        }
1069

    
1070
        return collation;
1071
    }
1072

    
1073
    /**
1074
     * @param nomenclaturalReference
1075
     * @return
1076
     */
1077
    private String getVolume(Reference reference) {
1078
        if (reference.getVolume() != null){
1079
            return reference.getVolume();
1080
        }else if (reference.getInReference() != null){
1081
            if (reference.getInReference().getVolume() != null){
1082
                return reference.getInReference().getVolume();
1083
            }
1084
        }
1085
        return null;
1086
    }
1087

    
1088
    /**
1089
     * @param state
1090
     * @param name
1091
     */
1092
    private void handleIdentifier(CdmLightExportState state, TaxonName name) {
1093
        CdmLightExportTable table = CdmLightExportTable.IDENTIFIER;
1094
        String[] csvLine;
1095
        try {
1096
            Set<String>  IPNIidentifiers = name.getIdentifiers(DefinedTerm.IDENTIFIER_NAME_IPNI());
1097
            Set<String>  tropicosIdentifiers = name.getIdentifiers(DefinedTerm.IDENTIFIER_NAME_TROPICOS());
1098
            Set<String>  WFOIdentifiers = name.getIdentifiers(DefinedTerm.uuidWfoNameIdentifier);
1099
            if (!IPNIidentifiers.isEmpty()){
1100
                csvLine = new String[table.getSize()];
1101
                csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId( state, name);
1102
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = IPNI_NAME_IDENTIFIER;
1103
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_IDS)] = extractIdentifier(IPNIidentifiers);
1104
                state.getProcessor().put(table, name, csvLine);
1105
            }
1106
            if (!tropicosIdentifiers.isEmpty()){
1107
                csvLine = new String[table.getSize()];
1108
                csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId( state, name);
1109
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = TROPICOS_NAME_IDENTIFIER;
1110
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_IDS)] = extractIdentifier(tropicosIdentifiers);
1111
                state.getProcessor().put(table, name, csvLine);
1112
            }
1113
            if (!WFOIdentifiers.isEmpty()){
1114
                csvLine = new String[table.getSize()];
1115
                csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId( state, name);
1116
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = WFO_NAME_IDENTIFIER;
1117
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_IDS)] = extractIdentifier(WFOIdentifiers);
1118
                state.getProcessor().put(table, name, csvLine);
1119
            }
1120
        } catch (Exception e) {
1121
            state.getResult().addException(e, "An unexpected error occurred when handling identifiers for " +
1122
                    cdmBaseStr(name) + ": " + e.getMessage());
1123

    
1124
        }
1125
    }
1126

    
1127
    /**
1128
     * @param tropicosIdentifiers
1129
     */
1130
    private String extractIdentifier(Set<String> identifierSet) {
1131

    
1132
        String identifierString = "";
1133
        for (String identifier: identifierSet){
1134
            if (!StringUtils.isBlank(identifierString)){
1135
                identifierString += ", ";
1136
            }
1137
            identifierString += identifier;
1138
        }
1139

    
1140
        return identifierString;
1141
    }
1142

    
1143
    /**
1144
     * @param state
1145
     * @param descriptions
1146
     * @return
1147
     */
1148
    private String extractURIs(CdmLightExportState state,
1149
            Set<? extends DescriptionBase<?>> descriptionsSet, Feature feature) {
1150
        String mediaUriString = "";
1151
        SpecimenDescription specimenDescription;
1152
        TaxonDescription taxonDescription;
1153
        TaxonNameDescription nameDescription;
1154
        Set<DescriptionElementBase> elements = new HashSet<>();
1155
        for (DescriptionBase<?> description : descriptionsSet){
1156
            try {
1157
                if (!description.getElements().isEmpty()){
1158
                    if (description instanceof SpecimenDescription){
1159
                        specimenDescription = (SpecimenDescription)description;
1160
                        elements = specimenDescription.getElements();
1161
                    }else if (description instanceof TaxonDescription){
1162
                        taxonDescription = (TaxonDescription) description;
1163
                        elements = taxonDescription.getElements();
1164
                    } else if (description instanceof TaxonNameDescription){
1165
                        nameDescription = (TaxonNameDescription) description;
1166
                        elements = nameDescription.getElements();
1167
                    }
1168

    
1169
                    for (DescriptionElementBase element : elements){
1170
                        Feature entityFeature = HibernateProxyHelper.deproxy(element.getFeature());
1171
                        if (entityFeature.equals(feature)){
1172
                            if (!element.getMedia().isEmpty()){
1173
                                List<Media> media = element.getMedia();
1174
                                for (Media mediaElement: media){
1175
                                    Iterator<MediaRepresentation> it =  mediaElement.getRepresentations().iterator();
1176
                                    mediaUriString = extractMediaUris(it);
1177
                                }
1178
                            }
1179
                        }
1180
                    }
1181
                }
1182
            } catch (Exception e) {
1183
                state.getResult().addException(e, "An unexpected error occurred when extracting media URIs for " +
1184
                        cdmBaseStr(description) + ": " + e.getMessage());
1185
            }
1186
        }
1187
        return mediaUriString;
1188
    }
1189

    
1190
    /**
1191
     * @param state
1192
     * @param basionymAuthorship
1193
     */
1194
    private void handleAuthor(CdmLightExportState state, TeamOrPersonBase<?> author) {
1195
        try {
1196
            if (state.getAuthorFromStore(author.getId()) != null){
1197
                return;
1198
            }
1199
            state.addAuthorToStore(author);
1200
            CdmLightExportTable table = CdmLightExportTable.NOMENCLATURAL_AUTHOR;
1201
            String[] csvLine = new String[table.getSize()];
1202
            CdmLightExportTable tableAuthorRel = CdmLightExportTable.NOMENCLATURAL_AUTHOR_TEAM_RELATION;
1203
            String[] csvLineRel = new String[tableAuthorRel.getSize()];
1204
            String[] csvLineMember = new String[table.getSize()];
1205
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_ID)] = getId(state, author);
1206
            csvLine[table.getIndex(CdmLightExportTable.ABBREV_AUTHOR)] = author.isProtectedTitleCache()? author.getTitleCache(): author.getNomenclaturalTitle();
1207
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_TITLE)] = author.getTitleCache();
1208
            author = HibernateProxyHelper.deproxy(author);
1209
            if (author instanceof Person){
1210
                Person authorPerson = (Person)author;
1211
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_GIVEN_NAME)] = authorPerson.getGivenName();
1212
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_FAMILY_NAME)] = authorPerson.getFamilyName();
1213
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_PREFIX)] = authorPerson.getPrefix();
1214
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_SUFFIX)] = authorPerson.getSuffix();
1215
            } else{
1216
                // create an entry in rel table and all members in author table, check whether the team members already in author table
1217

    
1218
                Team authorTeam = (Team)author;
1219
                int index = 0;
1220
                for (Person member: authorTeam.getTeamMembers()){
1221
                    csvLineRel = new String[tableAuthorRel.getSize()];
1222
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_TEAM_FK)] = getId(state, authorTeam);
1223
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_FK)] = getId(state, member);
1224
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_TEAM_SEQ_NUMBER)] = String.valueOf(index);
1225
                    state.getProcessor().put(tableAuthorRel, authorTeam.getId() +":" +member.getId(), csvLineRel);
1226

    
1227
                    if (state.getAuthorFromStore(member.getId()) == null){
1228
                        state.addAuthorToStore(member);
1229
                        csvLineMember = new String[table.getSize()];
1230
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_ID)] = getId(state, member);
1231
                        csvLineMember[table.getIndex(CdmLightExportTable.ABBREV_AUTHOR)] = member.isProtectedTitleCache()? member.getTitleCache(): member.getNomenclaturalTitle();
1232
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_TITLE)] = member.getTitleCache();
1233
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_GIVEN_NAME)] = member.getGivenName();
1234
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_FAMILY_NAME)] = member.getFamilyName();
1235
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_PREFIX)] = member.getPrefix();
1236
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_SUFFIX)] = member.getSuffix();
1237
                        state.getProcessor().put(table, member, csvLineMember);
1238
                    }
1239
                    index++;
1240

    
1241
                }
1242
            }
1243
            state.getProcessor().put(table, author, csvLine);
1244
        } catch (Exception e) {
1245
            state.getResult().addException(e, "An unexpected error occurred when handling author " +
1246
                    cdmBaseStr(author) + ": " + e.getMessage());
1247
        }
1248
    }
1249

    
1250
    /**
1251
     * @param state
1252
     * @param name
1253
     * @param statusString
1254
     * @return
1255
     */
1256
    private String extractStatusString(CdmLightExportState state, TaxonName name, boolean abbrev) {
1257
        try {
1258
            Set<NomenclaturalStatus> status = name.getStatus();
1259
            if (status.isEmpty()){
1260
                return "";
1261
            }
1262
            String statusString = "";
1263
            for (NomenclaturalStatus nameStatus: status){
1264
                if (nameStatus != null){
1265
                    if (abbrev){
1266
                        if (nameStatus.getType() != null){
1267
                            statusString += nameStatus.getType().getIdInVocabulary();
1268
                        }
1269
                    }else{
1270
                        if (nameStatus.getType() != null){
1271
                            statusString += nameStatus.getType().getTitleCache();
1272
                        }
1273
                    }
1274
                    if (!abbrev){
1275

    
1276
                        if (nameStatus.getRuleConsidered() != null && !StringUtils.isBlank(nameStatus.getRuleConsidered())){
1277
                            statusString += " " + nameStatus.getRuleConsidered();
1278
                        }
1279
                        if (nameStatus.getCitation() != null){
1280
                            statusString += " " + nameStatus.getCitation().getTitleCache();
1281
                        }
1282
                        if (nameStatus.getCitationMicroReference() != null && !StringUtils.isBlank(nameStatus.getCitationMicroReference())){
1283
                            statusString += " " + nameStatus.getCitationMicroReference();
1284
                        }
1285
                    }
1286
                    statusString += " ";
1287
                }
1288
            }
1289
            return statusString;
1290
        } catch (Exception e) {
1291
            state.getResult().addException(e, "An unexpected error occurred when extracting status string for " +
1292
                    cdmBaseStr(name) + ": " + e.getMessage());
1293
            return "";
1294
        }
1295
    }
1296

    
1297
    /**
1298
     * @param group
1299
     */
1300
    private void handleHomotypicalGroup(CdmLightExportState state, HomotypicalGroup group) {
1301
        try {
1302
           state.addHomotypicalGroupToStore(group);
1303
            CdmLightExportTable table = CdmLightExportTable.HOMOTYPIC_GROUP;
1304
            String[] csvLine = new String[table.getSize()];
1305

    
1306
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_ID)] = getId(state, group);
1307
            List<TaxonName> typifiedNames = new ArrayList<>();
1308
            typifiedNames.addAll(group.getTypifiedNames());
1309
            Collections.sort(typifiedNames, new HomotypicalGroupNameComparator(null, true));
1310
            String typifiedNamesString = "";
1311
            for (TaxonName name: typifiedNames){
1312
                //Concatenated output string for homotypic group (names and citations) + status + some name relations (e.g. “non”)
1313
                //TODO: nameRelations, which and how to display
1314

    
1315

    
1316
                typifiedNamesString += name.getTitleCache()+ extractStatusString(state, name, true) + "; ";
1317
            }
1318
            typifiedNamesString = typifiedNamesString.substring(0, typifiedNamesString.length()-2);
1319
            if (typifiedNamesString != null){
1320
                csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_STRING)] = typifiedNamesString.trim();
1321
            }else{
1322
                csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_STRING)] = "";
1323
            }
1324
            Set<TypeDesignationBase> typeDesigantionSet = group.getTypeDesignations();
1325
            List<TypeDesignationBase> designationList = new ArrayList<>();
1326
            designationList.addAll(typeDesigantionSet);
1327
            Collections.sort(designationList, new TypeComparator());
1328
            StringBuffer typeDesignationString = new StringBuffer();
1329
            List<TaggedText> list = new ArrayList<TaggedText>();
1330
            if (!designationList.isEmpty()){
1331
                TypeDesignationSetManager manager = new TypeDesignationSetManager(group);
1332

    
1333
                list.addAll( manager.toTaggedTextWithCitation());
1334
            }
1335
            StringBuffer homotypicalGroupTypeDesignationString = new StringBuffer();
1336

    
1337
            for (TaggedText text:list){
1338
                if (text != null && text.getText() != null && (text.getText().equals("Type:") || text.getText().equals("NameType:"))){
1339
                  //do nothing
1340
                } else if (text.getType().equals(TagEnum.reference)){
1341
                    homotypicalGroupTypeDesignationString.append(text.getText());
1342
                }else if (text.getType().equals(TagEnum.typeDesignation)){
1343
                    homotypicalGroupTypeDesignationString.append(text.getText().replace(").", "").replace("(", "").replace(")", "") );
1344
                } else{
1345
                    homotypicalGroupTypeDesignationString.append(text.getText());
1346
                }
1347
            }
1348

    
1349

    
1350
            String typeDesignations= homotypicalGroupTypeDesignationString.toString();
1351
            typeDesignations = typeDesignations.trim();
1352

    
1353
            typeDesignations += ".";
1354
            typeDesignations = typeDesignations.replace("..", ".");
1355
            typeDesignations = typeDesignations.replace(". .", ".");
1356
            if (typeDesignations.equals(".")){
1357
                typeDesignations = null;
1358
            }
1359

    
1360
       /*     for (TypeDesignationBase typeDesignation: designationList){
1361
                //[Vorschlag Soll:]
1362
               // Sumatra Utara, Kab. Karo, around Sidikalang areas, 1000─1500 m, Dec 11, 2003, Nepenthes Team (Hernawati, P. Akhriadi & I. Petra), NP 354 (‘ANDA’–Holo, BO–Iso) [fide Akhriadi & al. 2004]
1363
                if (typeDesignation != null && typeDesignation.getTypeStatus() != null){
1364
                    typeDesignationString.append(typeDesignation.getTypeStatus().getTitleCache() + ":");
1365
                }
1366
                if (typeDesignation instanceof SpecimenTypeDesignation){
1367
                    if (((SpecimenTypeDesignation)typeDesignation).getTypeSpecimen() != null){
1368
                        typeDesignationString.append(" "+((SpecimenTypeDesignation)typeDesignation).getTypeSpecimen().getTitleCache());
1369
                        if (typeDesignationString.lastIndexOf(".") == typeDesignationString.length()){
1370
                            typeDesignationString.deleteCharAt(typeDesignationString.lastIndexOf("."));
1371
                        }
1372
                        handleSpecimen(state, ((SpecimenTypeDesignation)typeDesignation).getTypeSpecimen());
1373
                    }
1374
                }else{
1375
                    if (((NameTypeDesignation)typeDesignation).getTypeName() != null){
1376
                        typeDesignationString.append(((NameTypeDesignation)typeDesignation).getTypeName().getTitleCache());
1377
                    }
1378
                }
1379
                if(typeDesignation.getCitation() != null ){
1380
                    typeDesignationString.append(" [fide " + ((DefaultReferenceCacheStrategy)typeDesignation.getCitation().getCacheStrategy()).createShortCitation(typeDesignation.getCitation()) +"]");
1381
                }
1382
                //TODO...
1383
                /*
1384
                 * Sortierung:
1385
                1.  Status der Typen: a) holo, lecto, neo, syn, b) epi, paralecto, c) para (wenn überhaupt) – die jeweiligen iso immer direct mit dazu
1386
                2.  Land
1387
                3.  Sammler
1388
                4.  Nummer
1389

    
1390
                Aufbau der Typusinformationen:
1391
                Land: Lokalität mit Höhe und Koordinaten; Datum; Sammler Nummer (Herbar/Barcode, Typusart; Herbar/Barcode, Typusart …)
1392

    
1393

    
1394
            }*/
1395
           // typeDesignations = typeDesignationString.toString();
1396
            if (typeDesignations != null){
1397
                if (!typeDesignations.endsWith(".") ){
1398
                    typeDesignations =typeDesignations + ".";
1399
                }
1400
                csvLine[table.getIndex(CdmLightExportTable.TYPE_STRING)] = typeDesignations;
1401

    
1402
            }else{
1403
                csvLine[table.getIndex(CdmLightExportTable.TYPE_STRING)] = "";
1404
            }
1405
            state.getProcessor().put(table, String.valueOf(group.getId()), csvLine);
1406
        } catch (Exception e) {
1407
            e.printStackTrace();
1408
            state.getResult().addException(e, "An unexpected error occurred when handling homotypic group " +
1409
                    cdmBaseStr(group) + ": " + e.getMessage());
1410
        }
1411
    }
1412

    
1413
    /**
1414
     * @param name
1415
     * @return
1416
     */
1417
    private String getTropicosTitleCache(CdmLightExportState state, TaxonName name) {
1418
        try {
1419
            String basionymStart = "(";
1420
            String basionymEnd = ") ";
1421
            String exAuthorSeperator = " ex ";
1422
            TeamOrPersonBase<?> combinationAuthor = name.getCombinationAuthorship();
1423
            TeamOrPersonBase<?> exCombinationAuthor = name.getExCombinationAuthorship();
1424
            TeamOrPersonBase<?> basionymAuthor = name.getBasionymAuthorship();
1425
            TeamOrPersonBase<?> exBasionymAuthor = name.getExBasionymAuthorship();
1426

    
1427
            String combinationAuthorString = "";
1428
            if (combinationAuthor != null){
1429
                combinationAuthor = HibernateProxyHelper.deproxy(combinationAuthor);
1430
                if (combinationAuthor instanceof Team){
1431
                    combinationAuthorString = createTropicosTeamTitle(combinationAuthor);
1432
                }else{
1433
                    Person person = HibernateProxyHelper.deproxy(combinationAuthor, Person.class);
1434
                    combinationAuthorString = createTropicosAuthorString(person);
1435
                }
1436
            }
1437
            String exCombinationAuthorString = "";
1438
            if (exCombinationAuthor != null){
1439
                exCombinationAuthor = HibernateProxyHelper.deproxy(exCombinationAuthor);
1440
                if (exCombinationAuthor instanceof Team){
1441
                   exCombinationAuthorString = createTropicosTeamTitle(exCombinationAuthor);
1442
                }else{
1443
                    Person person = HibernateProxyHelper.deproxy(exCombinationAuthor, Person.class);
1444
                    exCombinationAuthorString = createTropicosAuthorString(person);
1445
                }
1446
            }
1447

    
1448
            String basionymAuthorString = "";
1449
            if (basionymAuthor != null){
1450
                basionymAuthor = HibernateProxyHelper.deproxy(basionymAuthor);
1451
                if (basionymAuthor instanceof Team){
1452
                    basionymAuthorString =  createTropicosTeamTitle(basionymAuthor);
1453
                }else{
1454
                    Person person = HibernateProxyHelper.deproxy(basionymAuthor, Person.class);
1455
                    basionymAuthorString = createTropicosAuthorString(person);
1456
                }
1457
            }
1458

    
1459
            String exBasionymAuthorString = "";
1460

    
1461
            if (exBasionymAuthor != null){
1462
                exBasionymAuthor = HibernateProxyHelper.deproxy(exBasionymAuthor);
1463
                if (exBasionymAuthor instanceof Team){
1464
                    exBasionymAuthorString = createTropicosTeamTitle(exBasionymAuthor);
1465

    
1466
                }else{
1467
                    Person person = HibernateProxyHelper.deproxy(exBasionymAuthor, Person.class);
1468
                    exBasionymAuthorString = createTropicosAuthorString(person);
1469
                }
1470
            }
1471
            String completeAuthorString =  name.getNameCache() + " ";
1472

    
1473
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString) || !CdmUtils.isBlank(basionymAuthorString)) ? basionymStart: "";
1474
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString)) ? (CdmUtils.Nz(exBasionymAuthorString) + exAuthorSeperator): "" ;
1475
            completeAuthorString += (!CdmUtils.isBlank(basionymAuthorString))? CdmUtils.Nz(basionymAuthorString):"";
1476
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString) || !CdmUtils.isBlank(basionymAuthorString)) ?  basionymEnd:"";
1477
            completeAuthorString += (!CdmUtils.isBlank(exCombinationAuthorString)) ? (CdmUtils.Nz(exCombinationAuthorString) + exAuthorSeperator): "" ;
1478
            completeAuthorString += (!CdmUtils.isBlank(combinationAuthorString))? CdmUtils.Nz(combinationAuthorString):"";
1479

    
1480

    
1481
            return completeAuthorString;
1482
        } catch (Exception e) {
1483
            state.getResult().addException(e, "An unexpected error occurred when handling tropicos title cache for " +
1484
                    cdmBaseStr(name) + ": " + e.getMessage());
1485
            return null;
1486
        }
1487
    }
1488

    
1489
    /**
1490
     * @param combinationAuthor
1491
     * @return
1492
     */
1493
    private String createTropicosTeamTitle(TeamOrPersonBase<?> combinationAuthor) {
1494
        String combinationAuthorString;
1495
        Team team = HibernateProxyHelper.deproxy(combinationAuthor, Team.class);
1496
        Team tempTeam = Team.NewInstance();
1497
        for (Person teamMember:team.getTeamMembers()){
1498
            combinationAuthorString = createTropicosAuthorString(teamMember);
1499
            Person tempPerson = Person.NewTitledInstance(combinationAuthorString);
1500
            tempTeam.addTeamMember(tempPerson);
1501
        }
1502
        combinationAuthorString = tempTeam.generateTitle();
1503
        return combinationAuthorString;
1504
    }
1505

    
1506
    /**
1507
     * @param teamMember
1508
     */
1509
    private String createTropicosAuthorString(Person teamMember) {
1510
        String nomAuthorString = "";
1511
        String[] splittedAuthorString = null;
1512
        if (teamMember == null){
1513
            return nomAuthorString;
1514
        }
1515

    
1516
        if (teamMember.getGivenName() != null){
1517
            String givenNameString = teamMember.getGivenName().replaceAll("\\.", "\\. ");
1518
            splittedAuthorString = givenNameString.split("\\s");
1519
            for (String split: splittedAuthorString){
1520
                if (!StringUtils.isBlank(split)){
1521
                    nomAuthorString += split.substring(0, 1);
1522
                    nomAuthorString += ".";
1523
                }
1524
            }
1525
        }
1526
        if (teamMember.getFamilyName() != null){
1527
            String familyNameString = teamMember.getFamilyName().replaceAll("\\.", "\\. ");
1528
            splittedAuthorString = familyNameString.split("\\s");
1529
            for (String split: splittedAuthorString){
1530
                nomAuthorString += " " +split;
1531
            }
1532
        }
1533
        if (isBlank(nomAuthorString.trim())){
1534
            if (teamMember.getTitleCache() != null) {
1535
                String titleCacheString = teamMember.getTitleCache().replaceAll("\\.", "\\. ");
1536
                splittedAuthorString = titleCacheString.split("\\s");
1537
            }else{
1538
                splittedAuthorString = new String[0];
1539
            }
1540

    
1541
            int index = 0;
1542
            for (String split: splittedAuthorString){
1543
                if ( index < splittedAuthorString.length-1 && (split.length()==1 || split.endsWith("."))){
1544
                    nomAuthorString += split;
1545
                }else{
1546
                    nomAuthorString = nomAuthorString +" "+ split;
1547
                }
1548
                index++;
1549
            }
1550
        }
1551
        return nomAuthorString.trim();
1552
    }
1553

    
1554
    /**
1555
     * @param state
1556
     * @param name
1557
     */
1558
    private void handleReference(CdmLightExportState state, Reference reference) {
1559
        try {
1560
            state.addReferenceToStore(reference);
1561
            CdmLightExportTable table = CdmLightExportTable.REFERENCE;
1562
            reference = HibernateProxyHelper.deproxy(reference,Reference.class);
1563
            String[] csvLine = new String[table.getSize()];
1564
            csvLine[table.getIndex(CdmLightExportTable.REFERENCE_ID)] = getId(state, reference);
1565
            //TODO short citations correctly
1566
            String shortCitation = ((DefaultReferenceCacheStrategy)reference.getCacheStrategy()).createShortCitation(reference);  //Should be Author(year) like in Taxon.sec
1567
            csvLine[table.getIndex(CdmLightExportTable.BIBLIO_SHORT_CITATION)] = shortCitation;
1568
            //TODO get preferred title
1569
            csvLine[table.getIndex(CdmLightExportTable.REF_TITLE)] = reference.isProtectedTitleCache()? reference.getTitleCache() : reference.getTitle();
1570
            csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_TITLE)] = reference.isProtectedAbbrevTitleCache()? reference.getAbbrevTitleCache(): reference.getAbbrevTitle();
1571
            csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = reference.getDatePublishedString();
1572
            //TBC
1573
            csvLine[table.getIndex(CdmLightExportTable.EDITION)] = reference.getEdition();
1574
            csvLine[table.getIndex(CdmLightExportTable.EDITOR)] = reference.getEditor();
1575
            csvLine[table.getIndex(CdmLightExportTable.ISBN)] = reference.getIsbn();
1576
            csvLine[table.getIndex(CdmLightExportTable.ISSN)] = reference.getIssn();
1577
            csvLine[table.getIndex(CdmLightExportTable.ORGANISATION)] = reference.getOrganization();
1578
            csvLine[table.getIndex(CdmLightExportTable.PAGES)] = reference.getPages();
1579
            csvLine[table.getIndex(CdmLightExportTable.PLACE_PUBLISHED)] = reference.getPlacePublished();
1580
            csvLine[table.getIndex(CdmLightExportTable.PUBLISHER)] = reference.getPublisher();
1581
            csvLine[table.getIndex(CdmLightExportTable.REF_ABSTRACT)] = reference.getReferenceAbstract();
1582
            csvLine[table.getIndex(CdmLightExportTable.SERIES_PART)] = reference.getSeriesPart();
1583
            csvLine[table.getIndex(CdmLightExportTable.VOLUME)] = reference.getVolume();
1584
            csvLine[table.getIndex(CdmLightExportTable.YEAR)] = reference.getYear();
1585

    
1586
            if ( reference.getAuthorship() != null){
1587
                csvLine[table.getIndex(CdmLightExportTable.AUTHORSHIP_TITLE)] = createFullAuthorship(reference);
1588
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_FK)] = getId(state,reference.getAuthorship());
1589
            }
1590

    
1591
            csvLine[table.getIndex(CdmLightExportTable.IN_REFERENCE)] = getId(state, reference.getInReference());
1592
            if (reference.getInReference() != null && state.getReferenceFromStore(reference.getInReference().getId()) == null){
1593
                handleReference(state, reference.getInReference());
1594
            }
1595
            if ( reference.getInstitution() != null){ csvLine[table.getIndex(CdmLightExportTable.INSTITUTION)] = reference.getInstitution().getTitleCache();}
1596
            if ( reference.getLsid() != null){ csvLine[table.getIndex(CdmLightExportTable.LSID)] = reference.getLsid().getLsid();}
1597
            if ( reference.getSchool() != null){ csvLine[table.getIndex(CdmLightExportTable.SCHOOL)] = reference.getSchool().getTitleCache();}
1598
            if ( reference.getUri() != null){ csvLine[table.getIndex(CdmLightExportTable.URI)] = reference.getUri().toString();}
1599
            csvLine[table.getIndex(CdmLightExportTable.REF_TYPE)] = reference.getType().getKey();
1600

    
1601
            state.getProcessor().put(table, reference, csvLine);
1602
        } catch (Exception e) {
1603
            state.getResult().addException(e, "An unexpected error occurred when handling reference " +
1604
                    cdmBaseStr(reference) + ": " + e.getMessage());
1605
        }
1606

    
1607
    }
1608

    
1609

    
1610

    
1611

    
1612
    /**
1613
     * @param reference
1614
     * @return
1615
     */
1616
    private String createFullAuthorship(Reference reference) {
1617
        TeamOrPersonBase<?> authorship = reference.getAuthorship();
1618
        String fullAuthorship = "";
1619
        if (authorship == null) {
1620
            return null;
1621
        }
1622
        authorship = HibernateProxyHelper.deproxy(authorship);
1623
        if (authorship instanceof Person){
1624
            fullAuthorship = ((Person)authorship).getTitleCache();
1625

    
1626
        }
1627
        else if (authorship instanceof Team){
1628

    
1629
            Team authorTeam = HibernateProxyHelper.deproxy(authorship, Team.class);
1630
            int index = 0;
1631

    
1632
            for (Person teamMember : authorTeam.getTeamMembers()){
1633
                index++;
1634
                String concat = concatString(authorTeam, authorTeam.getTeamMembers(), index);
1635
                fullAuthorship += concat + teamMember.getTitleCache();
1636
            }
1637

    
1638
        }
1639

    
1640
        return fullAuthorship;
1641
    }
1642

    
1643
    private static String concatString(Team team, List<Person> teamMembers, int i) {
1644
        String concat;
1645
        if (i <= 1){
1646
            concat = "";
1647
        }else if (i < teamMembers.size() || ( team.isHasMoreMembers() && i == teamMembers.size())){
1648
            concat = STD_TEAM_CONCATINATION;
1649
        }else{
1650
            concat = FINAL_TEAM_CONCATINATION;
1651
        }
1652
        return concat;
1653
    }
1654

    
1655
    /*
1656
     * TypeDesignation table
1657
     * Specimen_Fk
1658
     *  EditName_Fk
1659
     *   TypeVerbatimCitation
1660
     *   TypeCategory
1661
     *   TypeDesignatedByString
1662
     *   TypeDesignatedByRef_Fk
1663
     */
1664

    
1665
    private void handleSpecimenTypeDesignations(CdmLightExportState state, TaxonName name){
1666
       try {
1667
           Set<SpecimenTypeDesignation> typeDesignations = name.getSpecimenTypeDesignations();
1668
           CdmLightExportTable table = CdmLightExportTable.TYPE_DESIGNATION;
1669
           String nameId = getId(state, name);
1670
           String[] csvLine = new String[table.getSize()];
1671
            for (SpecimenTypeDesignation specimenType: typeDesignations){
1672
                csvLine = new String[table.getSize()];
1673
                DerivedUnit specimen = specimenType.getTypeSpecimen();
1674
                if (state.getSpecimenFromStore(specimen.getId()) == null){
1675
                    handleSpecimen(state, specimen);
1676
                }
1677
                csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_FK)] = getId(state, specimenType.getTypeSpecimen());
1678
                csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = nameId;
1679
                csvLine[table.getIndex(CdmLightExportTable.TYPE_VERBATIM_CITATION)] = specimenType.getTypeSpecimen().generateTitle();
1680
                //TODO: add link to existing Vorcabulary
1681
                csvLine[table.getIndex(CdmLightExportTable.TYPE_CATEGORY)] = "";
1682
                csvLine[table.getIndex(CdmLightExportTable.TYPE_DESIGNATED_BY_STRING)] = specimenType.getCitation().getTitleCache();
1683
                csvLine[table.getIndex(CdmLightExportTable.TYPE_DESIGNATED_BY_REF_FK)] = getId(state, specimenType.getCitation());
1684
            }
1685
        } catch (Exception e) {
1686
            state.getResult().addException(e, "An unexpected error occurred when handling specimen type designations for " +
1687
                    cdmBaseStr(name) + ": " + e.getMessage());
1688
        }
1689
    }
1690

    
1691
    /**
1692
     * @param state
1693
     * @param specimen
1694
     */
1695
    private void handleSpecimen(CdmLightExportState state, SpecimenOrObservationBase specimen) {
1696
        try {
1697
            state.addSpecimenToStore(specimen);
1698
            CdmLightExportTable table = CdmLightExportTable.SPECIMEN;
1699
            String specimenId = getId(state, specimen);
1700
            String[] csvLine = new String[table.getSize()];
1701

    
1702
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_ID)] = specimenId;
1703
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_CITATION)] = specimen.getTitleCache();
1704
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_IMAGE_URIS)] = extractURIs(state, specimen.getDescriptions(), Feature.IMAGE());
1705
            if (specimen instanceof DerivedUnit){
1706
                    DerivedUnit derivedUnit = (DerivedUnit)specimen;
1707
                    if (derivedUnit.getCollection() != null){ csvLine[table.getIndex(CdmLightExportTable.HERBARIUM_ABBREV)] = derivedUnit.getCollection().getCode();}
1708

    
1709
                if (specimen instanceof MediaSpecimen){
1710
                    MediaSpecimen mediaSpecimen = (MediaSpecimen) specimen;
1711
                    Iterator<MediaRepresentation> it = mediaSpecimen.getMediaSpecimen().getRepresentations().iterator();
1712
                    String mediaUris = extractMediaUris(it);
1713
                    csvLine[table.getIndex(CdmLightExportTable.MEDIA_SPECIMEN_URL)] = mediaUris;
1714

    
1715
                }
1716

    
1717
                if (derivedUnit.getDerivedFrom() != null){
1718
                    for (SpecimenOrObservationBase<?> original: derivedUnit.getDerivedFrom().getOriginals()){
1719
                        //TODO: What to do if there are more then one FieldUnit??
1720
                        if (original instanceof FieldUnit){
1721
                            FieldUnit fieldUnit = (FieldUnit)original;
1722
                            csvLine[table.getIndex(CdmLightExportTable.COLLECTOR_NUMBER)] = fieldUnit.getFieldNumber();
1723

    
1724
                            GatheringEvent gathering = fieldUnit.getGatheringEvent();
1725
                            if (gathering != null){
1726
                                if (gathering.getLocality() != null){ csvLine[table.getIndex(CdmLightExportTable.LOCALITY)] = gathering.getLocality().getText();}
1727
                                if (gathering.getCountry() != null){csvLine[table.getIndex(CdmLightExportTable.COUNTRY)] = gathering.getCountry().getLabel();}
1728
                                csvLine[table.getIndex(CdmLightExportTable.COLLECTOR_STRING)] = createCollectorString(state, gathering, fieldUnit);
1729

    
1730
                                if (gathering.getGatheringDate() != null){csvLine[table.getIndex(CdmLightExportTable.COLLECTION_DATE)] = gathering.getGatheringDate().toString();}
1731
                                if (!gathering.getCollectingAreas().isEmpty()){
1732
                                    int index = 0;
1733
                                    csvLine[table.getIndex(CdmLightExportTable.FURTHER_AREAS)] = "0";
1734
                                    for (NamedArea area: gathering.getCollectingAreas()){
1735
                                        if (index == 0){
1736
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY1)] = area.getTermType().getKey();
1737
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME1)] = area.getLabel();
1738
                                        }
1739
                                        if (index == 1){
1740
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY2)] = area.getTermType().getKey();
1741
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME2)] = area.getLabel();
1742
                                        }
1743
                                        if (index == 2){
1744
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY3)] = area.getTermType().getKey();
1745
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME3)] = area.getLabel();
1746
                                        }
1747
                                        if (index == 3){
1748
                                            csvLine[table.getIndex(CdmLightExportTable.FURTHER_AREAS)] = "1";
1749
                                            break;
1750
                                        }
1751
                                        index++;
1752
                                    }
1753
                                }
1754
                            }
1755
                        }
1756
                    }
1757
                }else{
1758
                    state.getResult().addError("The specimen with uuid " + specimen.getUuid() + " is not an DerivedUnit. Could not be exported.");
1759
                }
1760
            }
1761

    
1762
            state.getProcessor().put(table, specimen, csvLine);
1763
        } catch (Exception e) {
1764
            state.getResult().addException(e, "An unexpected error occurred when handling specimen " +
1765
                    cdmBaseStr(specimen) + ": " + e.getMessage());
1766
        }
1767
    }
1768

    
1769
    /**
1770
     * @param it
1771
     */
1772
    private String extractMediaUris(Iterator<MediaRepresentation> it) {
1773

    
1774
        String mediaUriString = "";
1775
        boolean first = true;
1776
        while(it.hasNext()){
1777
            MediaRepresentation rep = it.next();
1778
            List<MediaRepresentationPart> parts = rep.getParts();
1779
            for (MediaRepresentationPart part: parts){
1780
                if (first){
1781
                    if (part.getUri() != null){
1782
                        mediaUriString += part.getUri().toString();
1783
                        first = false;
1784
                    }
1785
                }else{
1786
                    if (part.getUri() != null){
1787
                        mediaUriString += ", " +part.getUri().toString();
1788
                    }
1789
                }
1790
            }
1791
        }
1792

    
1793
        return mediaUriString;
1794
    }
1795

    
1796
    /**
1797
     * @param gathering
1798
     * @return
1799
     */
1800
    private String createCollectorString(CdmLightExportState state, GatheringEvent gathering, FieldUnit fieldUnit) {
1801
        try {
1802
            String collectorString = "";
1803
            AgentBase<?> collectorA = CdmBase.deproxy(gathering.getCollector());
1804
            if (gathering.getCollector() != null){
1805
               if (collectorA instanceof TeamOrPersonBase
1806
                       && state.getConfig().isHighLightPrimaryCollector()){
1807

    
1808
                   Person primaryCollector = fieldUnit.getPrimaryCollector();
1809
                   if (collectorA instanceof Team){
1810
                       Team collectorTeam = (Team)collectorA;
1811
                       boolean isFirst = true;
1812
                       for (Person member: collectorTeam.getTeamMembers()){
1813
                           if (!isFirst){
1814
                               collectorString += "; ";
1815
                           }
1816
                           if (member.equals(primaryCollector)){
1817
                               //highlight
1818
                               collectorString += "<b>" + member.getTitleCache() + "</b>";
1819
                           }else{
1820
                               collectorString += member.getTitleCache();
1821
                           }
1822
                       }
1823
                   }
1824
               } else{
1825
                   collectorString = collectorA.getTitleCache();
1826
               }
1827
           }
1828
           return collectorString;
1829
        } catch (Exception e) {
1830
            state.getResult().addException(e, "An unexpected error occurred when creating collector string for " +
1831
                    cdmBaseStr(fieldUnit) + ": " + e.getMessage());
1832
            return "";
1833
        }
1834
    }
1835

    
1836

    
1837
    /**
1838
     * Returns a string representation of the {@link CdmBase cdmBase} object
1839
     * for result messages.
1840
     */
1841
    private String cdmBaseStr(CdmBase cdmBase) {
1842
        if (cdmBase == null){
1843
            return "-no object available-";
1844
        }else{
1845
            return cdmBase.getClass().getSimpleName() + ": " + cdmBase.getUuid();
1846
        }
1847
    }
1848

    
1849
    /**
1850
     * {@inheritDoc}
1851
     */
1852
    @Override
1853
    protected boolean doCheck(CdmLightExportState state) {
1854
        return false;
1855
    }
1856

    
1857
    /**
1858
     * {@inheritDoc}
1859
     */
1860
    @Override
1861
    protected boolean isIgnore(CdmLightExportState state) {
1862
        return false;
1863
    }
1864

    
1865
}
(1-1/5)