Project

General

Profile

Download (80.3 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.HashSet;
15
import java.util.Iterator;
16
import java.util.List;
17
import java.util.Map;
18
import java.util.Set;
19

    
20
import org.apache.commons.lang3.StringUtils;
21
import org.springframework.stereotype.Component;
22

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

    
80
/**
81
 * @author k.luther
82
 * @date 15.03.2017
83
 */
84
@Component
85
public class CdmLightClassificationExport
86
            extends CdmExportBase<CdmLightExportConfigurator, CdmLightExportState, IExportTransformer, File>
87
            implements ICdmExport<CdmLightExportConfigurator, CdmLightExportState>{
88

    
89

    
90
    private static final long serialVersionUID = 2518643632756927053L;
91
    private static final String STD_TEAM_CONCATINATION = ", ";
92
    private static final String FINAL_TEAM_CONCATINATION = " & ";
93

    
94
    private static final String IPNI_NAME_IDENTIFIER = "Ipni Name Identifier";
95
    private static final String TROPICOS_NAME_IDENTIFIER = "Tropicos Name Identifier";
96
    private static final String WFO_NAME_IDENTIFIER = "WFO Name Identifier";
97

    
98
    public CdmLightClassificationExport() {
99
        super();
100
        this.ioName = this.getClass().getSimpleName();
101

    
102
    }
103

    
104
    /**
105
     * {@inheritDoc}
106
     */
107
    @Override
108
    protected void doInvoke(CdmLightExportState state) {
109
        try {
110

    
111
            IProgressMonitor monitor = state.getConfig().getProgressMonitor();
112
            CdmLightExportConfigurator config = state.getConfig();
113
            config.setFieldsTerminatedBy(",");
114

    
115
//            if (config.getTaxonNodeFilter().getTaxonNodesFilter().isEmpty() && config.getTaxonNodeFilter().getClassificationFilter().isEmpty()){
116
//                //TODO
117
//                state.setEmptyData();
118
//                return;
119
//            }
120

    
121

    
122

    
123
//            for (LogicFilter<Classification> classificationFilter : config.getTaxonNodeFilter().getClassificationFilter()){
124
//                UUID classificationUuid = classificationFilter.getUuid();
125
//                Classification classification = getClassificationService().find(classificationUuid);
126
//                if (classification == null){
127
//                    String message = String.format("Classification for given classification UUID not found. No data imported for %s", classificationUuid.toString());
128
//                    state.getResult().addWarning(message);
129
//                }else{
130
//                    TaxonNode root = classification.getRootNode();
131
//                    UUID uuid = root.getUuid();
132
//                    root = getTaxonNodeService().load(uuid);
133
//                    handleSingleClassification(state, root.getUuid());
134
//                }
135
//            }
136

    
137

    
138
            @SuppressWarnings("unchecked")
139
            TaxonNodeOutStreamPartitioner<XmlExportState> partitioner
140
              = TaxonNodeOutStreamPartitioner.NewInstance(
141
                    this, state, state.getConfig().getTaxonNodeFilter(),
142
                    100, monitor, null);
143

    
144

    
145
                monitor.subTask("Start partitioning");
146

    
147
                TaxonNode node = partitioner.next();
148
                while (node != null){
149
                  handleTaxonNode(state, node);
150
                  node = partitioner.next();
151
                }
152

    
153

    
154
//            for (LogicFilter<TaxonNode> taxonNodeFilter : config.getTaxonNodeFilter().getTaxonNodesFilter()){
155
//                UUID nodeUuid = taxonNodeFilter.getUuid();
156
//                handleSingleClassification(state, nodeUuid);
157
//            }
158
            state.getProcessor().createFinalResult(state);
159
        } catch (Exception e) {
160
            state.getResult().addException(e, "An unexpected error occurred in main method doInvoke() " +
161
                    e.getMessage());
162
        }
163
    }
164

    
165
    /**
166
     * @param state
167
     * @param classificationUuid
168
     */
169
    private void handleTaxonNode(CdmLightExportState state, TaxonNode taxonNode) {
170
        try {
171
//            TaxonNode taxonNode = getTaxonNodeService().find(taxonNodeUuid);
172

    
173
            if (taxonNode == null){
174
                String message = "TaxonNode for given taxon node UUID not found. ";
175
                //TODO
176
                state.getResult().addWarning(message);
177
            }else{
178
                TaxonNode root = taxonNode;
179
                if (root.hasTaxon()){
180
                    handleTaxon(state, root);
181
                }else{
182
//                    for (TaxonNode child : root.getChildNodes()){
183
//                        handleTaxon(state, child);
184
//                        //TODO progress monitor
185
//                    }
186
                }
187
            }
188
        } catch (Exception e) {
189
            state.getResult().addException(e, "An unexpected error occurred when handling classification " +
190
                    taxonNode.getUuid() + ": " + e.getMessage() + e.getStackTrace());
191
        }
192
    }
193

    
194
    /**
195
     * @param state
196
     * @param taxon
197
     */
198
    private void handleTaxon(CdmLightExportState state, TaxonNode taxonNode) {
199
        try{
200
      //  Taxon taxon = taxonNode.getTaxon();
201
        if (taxonNode == null){
202
            state.getResult().addError ("The taxonNode was null.", "handleTaxon");
203
            state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
204
            return;
205
        }
206
        if (taxonNode.getTaxon() == null){
207
            state.getResult().addError ("There was a taxon node without a taxon: " + taxonNode.getUuid(), "handleTaxon");
208
            state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
209
        }else{
210
            Taxon taxon = taxonNode.getTaxon();
211
             try{
212
                TaxonName name = taxon.getName();
213
                handleName(state, name);
214
                for (Synonym syn : taxon.getSynonyms()){
215
                    handleSynonym(state, syn);
216
                }
217

    
218

    
219
                CdmLightExportTable table = CdmLightExportTable.TAXON;
220
                String[] csvLine = new String[table.getSize()];
221

    
222
                csvLine[table.getIndex(CdmLightExportTable.TAXON_ID)] = getId(state, taxon);
223
                csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
224
                Taxon parent = (taxonNode.getParent()==null) ? null : taxonNode.getParent().getTaxon();
225
                csvLine[table.getIndex(CdmLightExportTable.PARENT_FK)] = getId(state, parent);
226
                csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE_FK)] = getId(state, taxon.getSec());
227
                csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = getTitleCache(taxon.getSec());
228
                csvLine[table.getIndex(CdmLightExportTable.CLASSIFICATION_ID)] = getId(state, taxonNode.getClassification());
229
                csvLine[table.getIndex(CdmLightExportTable.CLASSIFICATION_TITLE)] = taxonNode.getClassification().getTitleCache();
230

    
231
                state.getProcessor().put(table, taxon, csvLine);
232
                handleDescriptions(state, taxon);
233
             }catch(Exception e){
234
                 state.getResult().addException (e, "An unexpected problem occurred when trying to export "
235
                         + "taxon with id " + taxon.getId());
236
                 state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
237
             }
238
       }
239

    
240
       taxonNode.removeNullValueFromChildren();
241
//       for (TaxonNode child: taxonNode.getChildNodes()){
242
//           handleTaxon(state, child);
243
//       }
244
        }catch (Exception e){
245
            state.getResult().addException(e, "An unexpected error occurred when handling the taxon node of " +
246
                    cdmBaseStr(taxonNode.getTaxon()) + ": " + e.getMessage());
247
        }
248
    }
249

    
250
    /**
251
     * @param state
252
     * @param taxon
253
     */
254
    private void handleDescriptions(CdmLightExportState state, CdmBase cdmBase) {
255
        try{
256
        if (cdmBase instanceof Taxon){
257
            Taxon taxon = HibernateProxyHelper.deproxy(cdmBase, Taxon.class);
258
            Set<TaxonDescription> descriptions = taxon.getDescriptions();
259
            List<DescriptionElementBase> simpleFacts = new ArrayList<>();
260
            List<DescriptionElementBase> specimenFacts = new ArrayList<>();
261
            List<DescriptionElementBase> distributionFacts = new ArrayList<>();
262
            List<DescriptionElementBase> commonNameFacts = new ArrayList<>();
263
            List<DescriptionElementBase> usageFacts = new ArrayList<>();
264
            for (TaxonDescription description: descriptions){
265
                if (description.getElements() != null){
266
                    for (DescriptionElementBase element: description.getElements()){
267
                        element = CdmBase.deproxy(element);
268
                        if (element.getFeature().equals(Feature.COMMON_NAME())){
269
                            commonNameFacts.add(element);
270
                        }else if (element.getFeature().equals(Feature.DISTRIBUTION())){
271
                            distributionFacts.add(element);
272
                        }else if (element instanceof IndividualsAssociation || isSpecimenFeature(element.getFeature())){
273
                            specimenFacts.add(element);
274
                        }else{
275
                            simpleFacts.add(element);
276
                        }
277
                    }
278
                }
279
            }
280
            if (!commonNameFacts.isEmpty()){
281
                handleCommonNameFacts(state, taxon, commonNameFacts);
282
            }
283
            if (!distributionFacts.isEmpty()){
284
                handleDistributionFacts(state, taxon, distributionFacts);
285
            }
286
            if (!specimenFacts.isEmpty()){
287
                handleSpecimenFacts(state, taxon, specimenFacts);
288
            }
289
            if (!simpleFacts.isEmpty()){
290
                handleSimpleFacts(state, taxon, simpleFacts);
291
            }
292
        } else if (cdmBase instanceof TaxonName){
293
            TaxonName name = CdmBase.deproxy(cdmBase, TaxonName.class);
294
            Set<TaxonNameDescription> descriptions = name.getDescriptions();
295
            List<DescriptionElementBase> simpleFacts = new ArrayList<>();
296
            for (TaxonNameDescription description: descriptions){
297
                if (description.getElements() != null){
298
                    for (DescriptionElementBase element: description.getElements()){
299
                        if (!element.getFeature().equals(Feature.PROTOLOGUE())){
300
                            simpleFacts.add(element);
301
                        }
302
                    }
303
                }
304
             }
305
            if (!simpleFacts.isEmpty()){
306
                handleSimpleFacts(state, name, simpleFacts);
307
            }
308
        }
309
        }catch (Exception e){
310
            state.getResult().addException(e, "An unexpected error occurred when handling description of" +
311
                    cdmBaseStr(cdmBase) + ": " + e.getMessage());
312
        }
313
    }
314

    
315

    
316
    /**
317
     * @param feature
318
     * @return
319
     */
320
    private boolean isSpecimenFeature(Feature feature) {
321
        //TODO allow user defined specimen features
322
        if (feature == null){
323
            return false;
324
        }else if (feature.isSupportsIndividualAssociation()){
325
            return true;
326
        }else{
327
            return feature.equals(Feature.SPECIMEN()) || feature.equals(Feature.INDIVIDUALS_ASSOCIATION())
328
                    || feature.equals(Feature.MATERIALS_EXAMINED()) || feature.equals(Feature.OBSERVATION())
329
                    || feature.equals(Feature.OCCURRENCE())
330
                     ;
331
        }
332
    }
333

    
334
    /**
335
     * @param state
336
     * @param taxon
337
     * @param simpleFacts
338
     */
339
    private void handleSimpleFacts(CdmLightExportState state, CdmBase cdmBase,
340
            List<DescriptionElementBase> simpleFacts) {
341
        try {
342
            CdmLightExportTable table = CdmLightExportTable.SIMPLE_FACT;
343
            CdmLightExportTable tableMedia = CdmLightExportTable.MEDIA;
344
            for (DescriptionElementBase element: simpleFacts){
345
                if (element.getModifyingText().isEmpty() && !element.getMedia().isEmpty()){
346
                    handleSimpleMediaFact(state, cdmBase, tableMedia, element);
347
                }else{
348
                    handleSingleSimpleFact(state, cdmBase, table, element);
349
                }
350
            }
351
        } catch (Exception e) {
352
            state.getResult().addException(e, "An unexpected error occurred when handling simple facts for " +
353
                    cdmBaseStr(cdmBase) + ": " + e.getMessage());
354
        }
355
    }
356

    
357
    /**
358
     * @param state
359
     * @param cdmBase
360
     * @param tableMedia
361
     * @param element
362
     */
363
    private void handleSimpleMediaFact(CdmLightExportState state, CdmBase cdmBase, CdmLightExportTable table,
364
            DescriptionElementBase element) {
365
        try {
366
            String[] csvLine;
367
            handleSource(state, element, CdmLightExportTable.MEDIA);
368

    
369
            if (element instanceof TextData){
370
               TextData textData = (TextData)element;
371
               csvLine = new String[table.getSize()];
372
               csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
373
               if (cdmBase instanceof Taxon){
374
                   csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
375
                   csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = "";
376
               }else if (cdmBase instanceof TaxonName){
377
                   csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = "";
378
                   csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, cdmBase);
379
               }
380

    
381

    
382
               String mediaUris = "";
383
               for (Media media: textData.getMedia()){
384
                   String mediaString = extractMediaUris(media.getRepresentations().iterator());
385
                   if (!StringUtils.isBlank(mediaString)){
386
                       mediaUris +=  mediaString + ";";
387
                   }
388
                   else{
389
                       state.getResult().addWarning("Empty Media object for "
390
                               + cdmBase.getUserFriendlyTypeName() + " " + cdmBase.getUuid()
391
                               + " (media: " + media.getUuid() + ")");
392
                   }
393
               }
394
               csvLine[table.getIndex(CdmLightExportTable.MEDIA_URI)] = mediaUris;
395

    
396
            }
397
        } catch (Exception e) {
398
            state.getResult().addException(e, "An unexpected error occurred when handling single simple fact " +
399
                    cdmBaseStr(element) + ": " + e.getMessage());
400
        }
401

    
402
    }
403

    
404
    /**
405
     * @param state
406
     * @param cdmBase
407
     * @param table
408
     * @param element
409
     */
410
    private void handleSingleSimpleFact(CdmLightExportState state, CdmBase cdmBase, CdmLightExportTable table,
411
            DescriptionElementBase element) {
412
        try {
413
            String[] csvLine;
414
            handleSource(state, element, CdmLightExportTable.SIMPLE_FACT);
415

    
416
            if (element instanceof TextData){
417
               TextData textData = (TextData)element;
418
               csvLine = new String[table.getSize()];
419
               csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
420
               if (cdmBase instanceof Taxon){
421
                   csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
422
                   csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = "";
423
               }else if (cdmBase instanceof TaxonName){
424
                   csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = "";
425
                   csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, cdmBase);
426
               }
427
               csvLine[table.getIndex(CdmLightExportTable.FACT_CATEGORY)] = textData.getFeature().getLabel();
428

    
429
               String mediaUris = "";
430
               for (Media media: textData.getMedia()){
431
                   String mediaString = extractMediaUris(media.getRepresentations().iterator());
432
                   if (!StringUtils.isBlank(mediaString)){
433
                       mediaUris +=  mediaString + ";";
434
                   }
435
                   else{
436
                       state.getResult().addWarning("Empty Media object for uuid: " +
437
                               cdmBase.getUuid() + " uuid of media: " + media.getUuid());
438
                   }
439
               }
440
               csvLine[table.getIndex(CdmLightExportTable.MEDIA_URI)] = mediaUris;
441
               if (textData.getFeature().equals(Feature.CITATION())){
442
                  // csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
443
                   state.getProcessor().put(table, textData, csvLine);
444
               }else if (!textData.getMultilanguageText().isEmpty()){
445
                   for (Language language: textData.getMultilanguageText().keySet()){
446
                       String[] csvLineLanguage = csvLine.clone();
447
                       LanguageString langString = textData.getLanguageText(language);
448

    
449
                       csvLineLanguage[table.getIndex(CdmLightExportTable.FACT_TEXT)] = langString.getText();
450
                       csvLineLanguage[table.getIndex(CdmLightExportTable.LANGUAGE)] = language.getLabel();
451
                       state.getProcessor().put(table, textData, csvLineLanguage);
452
                   }
453
               } else{
454
                   state.getProcessor().put(table, textData, csvLine);
455
               }
456
            }
457
        } catch (Exception e) {
458
            state.getResult().addException(e, "An unexpected error occurred when handling single simple fact " +
459
                    cdmBaseStr(element) + ": " + e.getMessage());
460
        }
461
    }
462

    
463

    
464
    /**
465
     * @param state
466
     * @param specimenFacts
467
     */
468
    private void handleSpecimenFacts(CdmLightExportState state, Taxon taxon, List<DescriptionElementBase> specimenFacts) {
469
        CdmLightExportTable table = CdmLightExportTable.SPECIMEN_FACT;
470

    
471
        for (DescriptionElementBase element: specimenFacts){
472
            try {
473
                String[] csvLine = new String[table.getSize()];
474
                csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
475
                csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, taxon);
476
                handleSource(state, element, table);
477
                csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_NOTES)] = createAnnotationsString(element.getAnnotations());
478

    
479
                if (element instanceof IndividualsAssociation){
480

    
481
                    IndividualsAssociation indAssociation = (IndividualsAssociation)element;
482
                    if (indAssociation.getAssociatedSpecimenOrObservation() == null){
483
                        state.getResult().addWarning("There is an individual association with no specimen associated (Taxon "+ taxon.getTitleCache() + "(" + taxon.getUuid() +"). Could not be exported.");
484
                        continue;
485
                    }else{
486
                        if (state.getSpecimenFromStore(indAssociation.getAssociatedSpecimenOrObservation().getId()) == null){
487
                            SpecimenOrObservationBase<?> specimenBase = HibernateProxyHelper.deproxy(indAssociation.getAssociatedSpecimenOrObservation());
488

    
489
                            if (specimenBase instanceof SpecimenOrObservationBase){
490
                                SpecimenOrObservationBase derivedUnit = specimenBase;
491
                                handleSpecimen(state, derivedUnit);
492
                                csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_FK)] = getId(state, indAssociation.getAssociatedSpecimenOrObservation());
493
                            }else{
494
                                //field units are not supported
495
                                state.getResult().addError("The associated Specimen of taxon " + taxon.getUuid() + " is not an DerivedUnit. Could not be exported.");
496

    
497
                            }
498
                        }
499
                    }
500
                } else if (element instanceof TextData){
501
                    TextData textData = HibernateProxyHelper.deproxy(element, TextData.class);
502
                    csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_DESCRIPTION)] = createMultilanguageString(textData.getMultilanguageText());
503
                }
504
                state.getProcessor().put(table, element, csvLine);
505
            } catch (Exception e) {
506
                state.getResult().addException(e, "An unexpected error occurred when handling single specimen fact " +
507
                        cdmBaseStr(element) + ": " + e.getMessage());
508
            }
509
        }
510
    }
511

    
512
    /**
513
     * @param multilanguageText
514
     * @return
515
     */
516
    private String createMultilanguageString(Map<Language, LanguageString> multilanguageText) {
517
       String text = "";
518
       int index = multilanguageText.size();
519
       for(LanguageString langString: multilanguageText.values()){
520
           text += langString.getText();
521
           if (index > 1){
522
               text += "; ";
523
           }
524
           index --;
525
       }
526

    
527
        return text;
528
    }
529

    
530
    /**
531
     * @param annotations
532
     * @return
533
     */
534
    private String createAnnotationsString(Set<Annotation> annotations) {
535
        StringBuffer strBuff = new StringBuffer();
536

    
537
        for (Annotation ann:annotations){
538
            if (ann.getAnnotationType() == null ||!ann.getAnnotationType().equals(AnnotationType.TECHNICAL())){
539
                strBuff.append(ann.getText());
540
                strBuff.append("; ");
541
            }
542
        }
543

    
544
        if (strBuff.length() > 2){
545
            return strBuff.substring(0, strBuff.length()-2);
546
        }else{
547
            return null;
548
        }
549
    }
550

    
551
    /**
552
     * @param state
553
     * @param taxon
554
     * @param element
555
     */
556
    private void handleSource(CdmLightExportState state, DescriptionElementBase element, CdmLightExportTable factsTable) {
557
        CdmLightExportTable table = CdmLightExportTable.FACT_SOURCES;
558
        try {
559
        Set<DescriptionElementSource> sources = element.getSources();
560

    
561
        for (DescriptionElementSource source: sources){
562

    
563
                String[] csvLine = new  String[table.getSize()];
564
                Reference ref = source.getCitation();
565
                if ((ref == null) && (source.getNameUsedInSource() == null)){
566
                    continue;
567
                }
568
                if (ref != null){
569
                    if (state.getReferenceFromStore(ref.getId()) == null){
570
                        handleReference(state, ref);
571

    
572
                    }
573
                    csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)] = getId(state, ref);
574
                }
575
                csvLine[table.getIndex(CdmLightExportTable.FACT_FK)] = getId(state, element);
576

    
577
                csvLine[table.getIndex(CdmLightExportTable.NAME_IN_SOURCE_FK)] = getId(state, source.getNameUsedInSource());
578
                csvLine[table.getIndex(CdmLightExportTable.FACT_TYPE)] = factsTable.getTableName();
579
                if ( StringUtils.isBlank(csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)])  && StringUtils.isBlank(csvLine[table.getIndex(CdmLightExportTable.NAME_IN_SOURCE_FK)])){
580
                    continue;
581
                }
582
                state.getProcessor().put(table, source, csvLine);
583

    
584
        }
585
        } catch (Exception e) {
586
            state.getResult().addException(e, "An unexpected error occurred when handling single source " +
587
                    cdmBaseStr(element) + ": " + e.getMessage());
588
        }
589

    
590
    }
591

    
592
    /**
593
     * @param state
594
     * @param distributionFacts
595
     */
596
    private void handleDistributionFacts(CdmLightExportState state, Taxon taxon, List<DescriptionElementBase> distributionFacts) {
597
        CdmLightExportTable table = CdmLightExportTable.GEOGRAPHIC_AREA_FACT;
598

    
599
        for (DescriptionElementBase element: distributionFacts){
600
            try {
601
                if (element instanceof Distribution){
602
                    String[] csvLine = new  String[table.getSize()];
603
                    Distribution distribution = (Distribution)element;
604
                    csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
605
                    handleSource(state, element, table);
606
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, taxon);
607
                    if (distribution.getArea() != null){
608
                        csvLine[table.getIndex(CdmLightExportTable.AREA_LABEL)] = distribution.getArea().getLabel();
609
                    }
610
                    if (distribution.getStatus() != null){
611
                        csvLine[table.getIndex(CdmLightExportTable.STATUS_LABEL)] = distribution.getStatus().getLabel();
612
                    }
613
                    state.getProcessor().put(table, distribution, csvLine);
614
                } else{
615
                    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());
616
                }
617
            } catch (Exception e) {
618
                state.getResult().addException(e, "An unexpected error occurred when handling single distribution " +
619
                        cdmBaseStr(element) + ": " + e.getMessage());
620
            }
621
        }
622
    }
623

    
624
    /**
625
     * @param state
626
     * @param commonNameFacts
627
     */
628
    private void handleCommonNameFacts(CdmLightExportState state, Taxon taxon, List<DescriptionElementBase> commonNameFacts) {
629
        CdmLightExportTable table = CdmLightExportTable.COMMON_NAME_FACT;
630

    
631
        for (DescriptionElementBase element: commonNameFacts){
632
            try {
633
                if (element instanceof CommonTaxonName){
634
                    String[] csvLine = new  String[table.getSize()];
635
                    CommonTaxonName commonName = (CommonTaxonName)element;
636
                    csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
637
                    handleSource(state, element, table);
638
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, taxon);
639
                    if (commonName.getName() != null){csvLine[table.getIndex(CdmLightExportTable.FACT_TEXT)] = commonName.getName();}
640
                    if (commonName.getLanguage() != null){csvLine[table.getIndex(CdmLightExportTable.LANGUAGE)] = commonName.getLanguage().getLabel();}
641
                    if (commonName.getArea() != null){ csvLine[table.getIndex(CdmLightExportTable.AREA_LABEL)] = commonName.getArea().getLabel();}
642
                    state.getProcessor().put(table, commonName, csvLine);
643
                } else{
644
                    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());
645
                }
646
            } catch (Exception e) {
647
                state.getResult().addException(e, "An unexpected error occurred when handling single common name " +
648
                        cdmBaseStr(element) + ": " + e.getMessage());
649
            }
650
        }
651
    }
652

    
653
    /**
654
     * @param sec
655
     * @return
656
     */
657
    private String getTitleCache(IIdentifiableEntity identEntity) {
658
        if (identEntity == null){
659
            return "";
660
        }
661
        //TODO refresh?
662
        return identEntity.getTitleCache();
663
    }
664

    
665
    /**
666
     * @param state
667
     * @param taxon
668
     * @return
669
     */
670
    private String getId(CdmLightExportState state, ICdmBase cdmBase) {
671
        if (cdmBase == null){
672
            return "";
673
        }
674
        //TODO make configurable
675
        return cdmBase.getUuid().toString();
676
    }
677

    
678
    /**
679
     * @param state
680
     * @param syn
681
     */
682
    private void handleSynonym(CdmLightExportState state, Synonym syn) {
683
       try {
684

    
685
           TaxonName name = syn.getName();
686
           handleName(state, name);
687

    
688
           CdmLightExportTable table = CdmLightExportTable.SYNONYM;
689
           String[] csvLine = new String[table.getSize()];
690

    
691
           csvLine[table.getIndex(CdmLightExportTable.SYNONYM_ID)] = getId(state, syn);
692
           csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, syn.getAcceptedTaxon());
693
           csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
694
           csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE_FK)] = getId(state, syn.getSec());
695
           csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = getTitleCache(syn.getSec());
696
           if (syn.isProParte()) {
697
        	   csvLine[table.getIndex(CdmLightExportTable.IS_PRO_PARTE)] = "1";
698
           }else {
699
        	   csvLine[table.getIndex(CdmLightExportTable.IS_PRO_PARTE)] = "0";
700
           }
701
  
702
           state.getProcessor().put(table, syn, csvLine);
703
        } catch (Exception e) {
704
            state.getResult().addException(e, "An unexpected error occurred when handling synonym " +
705
                    cdmBaseStr(syn) + ": " + e.getMessage());
706
        }
707
    }
708

    
709
    /**
710
     * @param state
711
     * @param name
712
     */
713
    private void handleName(CdmLightExportState state, TaxonName name) {
714
        if (name == null){
715
            return;
716
        }
717
        try {
718
            Rank rank = name.getRank();
719
            CdmLightExportTable table = CdmLightExportTable.SCIENTIFIC_NAME;
720
            name = HibernateProxyHelper.deproxy(name);
721
            String[] csvLine = new String[table.getSize()];
722

    
723
            csvLine[table.getIndex(CdmLightExportTable.NAME_ID)] = getId(state, name);
724
            if (name.getLsid() != null){
725
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = name.getLsid().getLsid();
726
            }else{
727
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = "";
728
            }
729

    
730
            handleIdentifier(state, name);
731
            handleDescriptions(state, name);
732

    
733
            csvLine[table.getIndex(CdmLightExportTable.RANK)] = getTitleCache(rank);
734
            if (rank != null){
735
                csvLine[table.getIndex(CdmLightExportTable.RANK_SEQUENCE)] = String.valueOf(rank.getOrderIndex());
736
                if (rank.isInfraGeneric()){
737
                    try {
738
                        csvLine[table.getIndex(CdmLightExportTable.INFRAGENERIC_RANK)] = name.getRank().getInfraGenericMarker();
739
                    } catch (UnknownCdmTypeException e) {
740
                        state.getResult().addError("Infrageneric marker expected but not available for rank " + name.getRank().getTitleCache());
741
                    }
742
                }
743
                if (rank.isInfraSpecific()){
744
                    csvLine[table.getIndex(CdmLightExportTable.INFRASPECIFIC_RANK)] = name.getRank().getAbbreviation();
745
                }
746
            }else{
747
                csvLine[table.getIndex(CdmLightExportTable.RANK_SEQUENCE)] = "";
748
            }
749
            if (name.isProtectedTitleCache()){
750
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_AUTHORS)] =name.getTitleCache();
751
            }else{
752
                //TODO: adapt the tropicos titlecache creation
753
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_AUTHORS)] = name.getTitleCache();
754
            }
755
            csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_NO_AUTHORS)] = name.getNameCache();
756
            csvLine[table.getIndex(CdmLightExportTable.GENUS_UNINOMIAL)] = name.getGenusOrUninomial();
757

    
758
            csvLine[table.getIndex(CdmLightExportTable.INFRAGENERIC_EPITHET)] = name.getInfraGenericEpithet();
759
            csvLine[table.getIndex(CdmLightExportTable.SPECIFIC_EPITHET)] = name.getSpecificEpithet();
760

    
761
            csvLine[table.getIndex(CdmLightExportTable.INFRASPECIFIC_EPITHET)] = name.getInfraSpecificEpithet();
762
            csvLine[table.getIndex(CdmLightExportTable.BAS_AUTHORTEAM_FK)] = getId(state,name.getBasionymAuthorship());
763
            if (name.getBasionymAuthorship() != null){
764
                if (state.getAuthorFromStore(name.getBasionymAuthorship().getId()) == null) {
765
                    handleAuthor(state, name.getBasionymAuthorship());
766
                }
767
            }
768
            csvLine[table.getIndex(CdmLightExportTable.BAS_EX_AUTHORTEAM_FK)] = getId(state, name.getExBasionymAuthorship());
769
            if (name.getExBasionymAuthorship() != null){
770
                if (state.getAuthorFromStore(name.getExBasionymAuthorship().getId()) == null) {
771
                    handleAuthor(state, name.getExBasionymAuthorship());
772
                }
773

    
774
            }
775
            csvLine[table.getIndex(CdmLightExportTable.COMB_AUTHORTEAM_FK)] = getId(state,name.getCombinationAuthorship());
776
            if (name.getCombinationAuthorship() != null){
777
                if (state.getAuthorFromStore(name.getCombinationAuthorship().getId()) == null) {
778
                    handleAuthor(state, name.getCombinationAuthorship());
779
                }
780
            }
781
            csvLine[table.getIndex(CdmLightExportTable.COMB_EX_AUTHORTEAM_FK)] = getId(state, name.getExCombinationAuthorship());
782
            if (name.getExCombinationAuthorship() != null){
783
                if (state.getAuthorFromStore(name.getExCombinationAuthorship().getId()) == null) {
784
                    handleAuthor(state, name.getExCombinationAuthorship());
785
                }
786

    
787
            }
788

    
789
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_TEAM_STRING)] = name.getAuthorshipCache();
790

    
791
            Reference nomRef = (Reference)name.getNomenclaturalReference();
792

    
793
            if (nomRef != null){
794
                if (state.getReferenceFromStore(nomRef.getId()) == null){
795
                    handleReference(state, nomRef);
796
                }
797
                csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)] = getId(state, nomRef);
798
                csvLine[table.getIndex(CdmLightExportTable.PUBLICATION_TYPE)] = nomRef.getType().name();
799
                if (nomRef.getVolume() != null){
800
                    csvLine[table.getIndex(CdmLightExportTable.VOLUME_ISSUE)] = nomRef.getVolume();
801
                    csvLine[table.getIndex(CdmLightExportTable.COLLATION)] = createCollatation(name);
802
                }
803
                if (nomRef.getDatePublished() != null){
804
                    csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = nomRef.getTimePeriodPublishedString();
805
                    csvLine[table.getIndex(CdmLightExportTable.YEAR_PUBLISHED)] = nomRef.getDatePublished().getYear();
806
                    csvLine[table.getIndex(CdmLightExportTable.VERBATIM_DATE)] = null;
807
                }
808
                if (name.getNomenclaturalMicroReference() != null){
809
                    csvLine[table.getIndex(CdmLightExportTable.DETAIL)] = name.getNomenclaturalMicroReference();
810
                }
811
                nomRef = HibernateProxyHelper.deproxy(nomRef);
812
                if (nomRef.getInReference() != null){
813
                    Reference inReference = nomRef.getInReference();
814
                    if (inReference.getDatePublished() != null && nomRef.getDatePublished() == null){
815
                        csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = inReference.getDatePublishedString();
816
                        csvLine[table.getIndex(CdmLightExportTable.YEAR_PUBLISHED)] = inReference.getDatePublished().getYear();
817
                    }
818
                    if (nomRef.getVolume() == null && inReference.getVolume() != null){
819
                        csvLine[table.getIndex(CdmLightExportTable.VOLUME_ISSUE)] = inReference.getVolume();
820
                        csvLine[table.getIndex(CdmLightExportTable.COLLATION)] = createCollatation(name);
821
                    }
822
                    if (inReference.getInReference() != null){
823
                        inReference = inReference.getInReference();
824
                    }
825
                    if (inReference.getAbbrevTitle() == null){
826
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils.Nz(inReference.getAbbrevTitleCache());
827
                    }else{
828
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils.Nz(inReference.getAbbrevTitle());
829
                    }
830
                    if (inReference.getTitle() == null){
831
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(inReference.getTitleCache());
832
                    }else{
833
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(inReference.getTitle());
834
                    }
835

    
836

    
837
                    TeamOrPersonBase<?> author = inReference.getAuthorship();
838
                    if (author != null && (nomRef.isOfType(ReferenceType.BookSection) || nomRef.isOfType(ReferenceType.Section))){
839
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = CdmUtils.Nz(author.getNomenclaturalTitle());
840
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = CdmUtils.Nz(author.getTitleCache());
841
                    }else{
842
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = "";
843
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = "";
844
                    }
845
                }else{
846
                    if (nomRef.getAbbrevTitle() == null){
847
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils.Nz(nomRef.getAbbrevTitleCache());
848
                    }else{
849
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils.Nz(nomRef.getAbbrevTitle());
850
                    }
851
                    if (nomRef.getTitle() == null){
852
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(nomRef.getTitleCache());
853
                    }else{
854
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(nomRef.getTitle());
855
                    }
856
                    TeamOrPersonBase<?> author = nomRef.getAuthorship();
857
                    if (author != null ){
858
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = CdmUtils.Nz(author.getNomenclaturalTitle());
859
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = CdmUtils.Nz(author.getTitleCache());
860
                    }else{
861
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = "";
862
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = "";
863
                    }
864

    
865
                }
866
            }else{
867
                csvLine[table.getIndex(CdmLightExportTable.PUBLICATION_TYPE)] = "";
868
            }
869

    
870

    
871

    
872
            /*
873
            * Collation
874

    
875
            Detail
876

    
877

    
878
            TitlePageYear
879
            */
880
            Set<TaxonNameDescription> descriptions = name.getDescriptions();
881
            String protologueUriString = extractURIs(state, descriptions, Feature.PROTOLOGUE());
882

    
883
            csvLine[table.getIndex(CdmLightExportTable.PROTOLOGUE_URI)] = protologueUriString;
884

    
885
            if (name.getStatus() == null || name.getStatus().isEmpty()){
886
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS)] = "";
887
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS_ABBREV)] = "";
888
            }else{
889

    
890
                String statusStringAbbrev = extractStatusString(state, name, true);
891
                String statusString = extractStatusString(state, name, false);
892

    
893
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS)] = statusString.trim();
894
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS_ABBREV)] = statusStringAbbrev.trim();
895
            }
896

    
897
            HomotypicalGroup group =name.getHomotypicalGroup();
898

    
899
            if (state.getHomotypicalGroupFromStore(group.getId()) == null){
900
                handleHomotypicalGroup(state, group);
901
            }
902
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_FK)] = getId(state, group);
903
            List<TaxonName> typifiedNames = new ArrayList<>();
904
            typifiedNames.addAll(group.getTypifiedNames());
905
            Collections.sort(typifiedNames, new HomotypicalGroupNameComparator(null, true));
906
            Integer  seqNumber= typifiedNames.indexOf(name);
907
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_SEQ)] = String.valueOf(seqNumber);
908
            state.getProcessor().put(table, name, csvLine);
909

    
910
            /*
911
             *
912
            Tropicos_ID
913
            IPNI_ID
914

    
915

    
916
            InfragenericRank
917

    
918

    
919
            InfraspecificRank
920
            Collation
921
            Volume (Issue)
922
            Detail
923
            DatePublished
924
            YearPublished
925
            TitlePageYear
926

    
927

    
928

    
929
            HomotypicGroupSequenceNumber
930

    
931

    
932
             *
933
             */
934
        } catch (Exception e) {
935
            state.getResult().addException(e, "An unexpected error occurred when handling synonym " +
936
                    cdmBaseStr(name) + ": " + e.getMessage());
937
        }
938
    }
939

    
940
    /**
941
     * @return
942
     */
943
    private String createCollatation(TaxonName name) {
944
        String collation = "";
945
        if (name.getNomenclaturalReference() != null){
946
            Reference ref = (Reference) name.getNomenclaturalReference();
947
            collation = getVolume(ref);
948
        }
949
        if (name.getNomenclaturalMicroReference() != null){
950
            if (!StringUtils.isBlank(collation)){
951
                collation += ":";
952
            }
953
            collation +=name.getNomenclaturalMicroReference();
954
        }
955

    
956
        return collation;
957
    }
958

    
959
    /**
960
     * @param nomenclaturalReference
961
     * @return
962
     */
963
    private String getVolume(Reference reference) {
964
        if (reference.getVolume() != null){
965
            return reference.getVolume();
966
        }else if (reference.getInReference() != null){
967
            if (reference.getInReference().getVolume() != null){
968
                return reference.getInReference().getVolume();
969
            }
970
        }
971
        return null;
972
    }
973

    
974
    /**
975
     * @param state
976
     * @param name
977
     */
978
    private void handleIdentifier(CdmLightExportState state, TaxonName name) {
979
        CdmLightExportTable table = CdmLightExportTable.IDENTIFIER;
980
        String[] csvLine;
981
        try {
982
            Set<String>  IPNIidentifiers = name.getIdentifiers(DefinedTerm.IDENTIFIER_NAME_IPNI());
983
            Set<String>  tropicosIdentifiers = name.getIdentifiers(DefinedTerm.IDENTIFIER_NAME_TROPICOS());
984
            Set<String>  WFOIdentifiers = name.getIdentifiers(DefinedTerm.uuidWfoNameIdentifier);
985
            if (!IPNIidentifiers.isEmpty()){
986
                csvLine = new String[table.getSize()];
987
                csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId( state, name);
988
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = IPNI_NAME_IDENTIFIER;
989
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_IDS)] = extractIdentifier(IPNIidentifiers);
990
                state.getProcessor().put(table, name, csvLine);
991
            }
992
            if (!tropicosIdentifiers.isEmpty()){
993
                csvLine = new String[table.getSize()];
994
                csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId( state, name);
995
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = TROPICOS_NAME_IDENTIFIER;
996
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_IDS)] = extractIdentifier(tropicosIdentifiers);
997
                state.getProcessor().put(table, name, csvLine);
998
            }
999
            if (!WFOIdentifiers.isEmpty()){
1000
                csvLine = new String[table.getSize()];
1001
                csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId( state, name);
1002
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = WFO_NAME_IDENTIFIER;
1003
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_IDS)] = extractIdentifier(WFOIdentifiers);
1004
                state.getProcessor().put(table, name, csvLine);
1005
            }
1006
        } catch (Exception e) {
1007
            state.getResult().addException(e, "An unexpected error occurred when handling identifiers for " +
1008
                    cdmBaseStr(name) + ": " + e.getMessage());
1009

    
1010
        }
1011
    }
1012

    
1013
    /**
1014
     * @param tropicosIdentifiers
1015
     */
1016
    private String extractIdentifier(Set<String> identifierSet) {
1017

    
1018
        String identifierString = "";
1019
        for (String identifier: identifierSet){
1020
            if (!StringUtils.isBlank(identifierString)){
1021
                identifierString += ", ";
1022
            }
1023
            identifierString += identifier;
1024
        }
1025

    
1026
        return identifierString;
1027
    }
1028

    
1029
    /**
1030
     * @param state
1031
     * @param descriptions
1032
     * @return
1033
     */
1034
    private String extractURIs(CdmLightExportState state,
1035
            Set<? extends DescriptionBase<?>> descriptionsSet, Feature feature) {
1036
        String mediaUriString = "";
1037
        SpecimenDescription specimenDescription;
1038
        TaxonDescription taxonDescription;
1039
        TaxonNameDescription nameDescription;
1040
        Set<DescriptionElementBase> elements = new HashSet<>();
1041
        for (DescriptionBase<?> description : descriptionsSet){
1042
            try {
1043
                if (!description.getElements().isEmpty()){
1044
                    if (description instanceof SpecimenDescription){
1045
                        specimenDescription = (SpecimenDescription)description;
1046
                        elements = specimenDescription.getElements();
1047
                    }else if (description instanceof TaxonDescription){
1048
                        taxonDescription = (TaxonDescription) description;
1049
                        elements = taxonDescription.getElements();
1050
                    } else if (description instanceof TaxonNameDescription){
1051
                        nameDescription = (TaxonNameDescription) description;
1052
                        elements = nameDescription.getElements();
1053
                    }
1054

    
1055
                    for (DescriptionElementBase element : elements){
1056
                        Feature entityFeature = HibernateProxyHelper.deproxy(element.getFeature());
1057
                        if (entityFeature.equals(feature)){
1058
                            if (!element.getMedia().isEmpty()){
1059
                                List<Media> media = element.getMedia();
1060
                                for (Media mediaElement: media){
1061
                                    Iterator<MediaRepresentation> it =  mediaElement.getRepresentations().iterator();
1062
                                    mediaUriString = extractMediaUris(it);
1063
                                }
1064
                            }
1065
                        }
1066
                    }
1067
                }
1068
            } catch (Exception e) {
1069
                state.getResult().addException(e, "An unexpected error occurred when extracting media URIs for " +
1070
                        cdmBaseStr(description) + ": " + e.getMessage());
1071
            }
1072
        }
1073
        return mediaUriString;
1074
    }
1075

    
1076
    /**
1077
     * @param state
1078
     * @param basionymAuthorship
1079
     */
1080
    private void handleAuthor(CdmLightExportState state, TeamOrPersonBase<?> author) {
1081
        try {
1082
            if (state.getAuthorFromStore(author.getId()) != null){
1083
                return;
1084
            }
1085
            state.addAuthorToStore(author);
1086
            CdmLightExportTable table = CdmLightExportTable.NOMENCLATURAL_AUTHOR;
1087
            String[] csvLine = new String[table.getSize()];
1088
            CdmLightExportTable tableAuthorRel = CdmLightExportTable.NOMENCLATURAL_AUTHOR_TEAM_RELATION;
1089
            String[] csvLineRel = new String[tableAuthorRel.getSize()];
1090
            String[] csvLineMember = new String[table.getSize()];
1091
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_ID)] = getId(state, author);
1092
            csvLine[table.getIndex(CdmLightExportTable.ABBREV_AUTHOR)] = author.getNomenclaturalTitle();
1093
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_TITLE)] = author.getTitleCache();
1094
            author = HibernateProxyHelper.deproxy(author);
1095
            if (author instanceof Person){
1096
                Person authorPerson = (Person)author;
1097
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_FIRST_NAME)] = authorPerson.getFirstname();
1098
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_LASTNAME)] = authorPerson.getLastname();
1099
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_PREFIX)] = authorPerson.getPrefix();
1100
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_SUFFIX)] = authorPerson.getSuffix();
1101
            } else{
1102
                // create an entry in rel table and all members in author table, check whether the team members already in author table
1103

    
1104
                Team authorTeam = (Team)author;
1105
                int index = 0;
1106
                for (Person member: authorTeam.getTeamMembers()){
1107
                    csvLineRel = new String[tableAuthorRel.getSize()];
1108
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_TEAM_FK)] = getId(state, authorTeam);
1109
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_FK)] = getId(state, member);
1110
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_TEAM_SEQ_NUMBER)] = String.valueOf(index);
1111
                    state.getProcessor().put(tableAuthorRel, authorTeam.getId() +":" +member.getId(), csvLineRel);
1112

    
1113
                    if (state.getAuthorFromStore(member.getId()) == null){
1114
                        state.addAuthorToStore(member);
1115
                        csvLineMember = new String[table.getSize()];
1116
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_ID)] = getId(state, member);
1117
                        csvLineMember[table.getIndex(CdmLightExportTable.ABBREV_AUTHOR)] = member.getNomenclaturalTitle();
1118
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_TITLE)] = member.getTitleCache();
1119
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_FIRST_NAME)] = member.getFirstname();
1120
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_LASTNAME)] = member.getLastname();
1121
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_PREFIX)] = member.getPrefix();
1122
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_SUFFIX)] = member.getSuffix();
1123
                        state.getProcessor().put(table, member, csvLineMember);
1124
                    }
1125
                    index++;
1126

    
1127
                }
1128
            }
1129
            state.getProcessor().put(table, author, csvLine);
1130
        } catch (Exception e) {
1131
            state.getResult().addException(e, "An unexpected error occurred when handling author " +
1132
                    cdmBaseStr(author) + ": " + e.getMessage());
1133
        }
1134
    }
1135

    
1136
    /**
1137
     * @param state
1138
     * @param name
1139
     * @param statusString
1140
     * @return
1141
     */
1142
    private String extractStatusString(CdmLightExportState state, TaxonName name, boolean abbrev) {
1143
        try {
1144
            Set<NomenclaturalStatus> status = name.getStatus();
1145
            if (status.isEmpty()){
1146
                return "";
1147
            }
1148
            String statusString = "";
1149
            for (NomenclaturalStatus nameStatus: status){
1150
                if (nameStatus != null){
1151
                    if (abbrev){
1152
                        if (nameStatus.getType() != null){
1153
                            statusString += nameStatus.getType().getIdInVocabulary();
1154
                        }
1155
                    }else{
1156
                        if (nameStatus.getType() != null){
1157
                            statusString += nameStatus.getType().getTitleCache();
1158
                        }
1159
                    }
1160
                    if (!abbrev){
1161

    
1162
                        if (nameStatus.getRuleConsidered() != null && !StringUtils.isBlank(nameStatus.getRuleConsidered())){
1163
                            statusString += " " + nameStatus.getRuleConsidered();
1164
                        }
1165
                        if (nameStatus.getCitation() != null){
1166
                            statusString += " " + nameStatus.getCitation().getTitleCache();
1167
                        }
1168
                        if (nameStatus.getCitationMicroReference() != null && !StringUtils.isBlank(nameStatus.getCitationMicroReference())){
1169
                            statusString += " " + nameStatus.getCitationMicroReference();
1170
                        }
1171
                    }
1172
                    statusString += " ";
1173
                }
1174
            }
1175
            return statusString;
1176
        } catch (Exception e) {
1177
            state.getResult().addException(e, "An unexpected error occurred when extracting status string for " +
1178
                    cdmBaseStr(name) + ": " + e.getMessage());
1179
            return "";
1180
        }
1181
    }
1182

    
1183
    /**
1184
     * @param group
1185
     */
1186
    private void handleHomotypicalGroup(CdmLightExportState state, HomotypicalGroup group) {
1187
        try {
1188
            state.addHomotypicalGroupToStore(group);
1189
            CdmLightExportTable table = CdmLightExportTable.HOMOTYPIC_GROUP;
1190
            String[] csvLine = new String[table.getSize()];
1191

    
1192
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_ID)] = getId(state, group);
1193
            List<TaxonName> typifiedNames = new ArrayList<>();
1194
            typifiedNames.addAll(group.getTypifiedNames());
1195
            Collections.sort(typifiedNames, new HomotypicalGroupNameComparator(null, true));
1196
            String typifiedNamesString = "";
1197
            for (TaxonName name: typifiedNames){
1198
                //Concatenated output string for homotypic group (names and citations) + status + some name relations (e.g. “non”)
1199
                //TODO: nameRelations, which and how to display
1200

    
1201

    
1202
                typifiedNamesString += name.getTitleCache()+ extractStatusString(state, name, true) + "; ";
1203
            }
1204
            typifiedNamesString = typifiedNamesString.substring(0, typifiedNamesString.length()-2);
1205
            if (typifiedNamesString != null){
1206
                csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_STRING)] = typifiedNamesString.trim();
1207
            }else{
1208
                csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_STRING)] = "";
1209
            }
1210
            Set<TypeDesignationBase> typeDesigantions = group.getTypeDesignations();
1211
            List<TypeDesignationBase> designationList = new ArrayList<>();
1212
            designationList.addAll(typeDesigantions);
1213
            Collections.sort(designationList, new TypeComparator());
1214
            StringBuffer typeDesignationString = new StringBuffer();
1215
            for (TypeDesignationBase typeDesignation: typeDesigantions){
1216
                if (typeDesignation != null && typeDesignation.getTypeStatus() != null){
1217
                    typeDesignationString.append(typeDesignation.getTypeStatus().getTitleCache() + ": ");
1218
                }
1219
                if (typeDesignation instanceof SpecimenTypeDesignation){
1220
                    if (((SpecimenTypeDesignation)typeDesignation).getTypeSpecimen() != null){
1221
                        typeDesignationString.append(((SpecimenTypeDesignation)typeDesignation).getTypeSpecimen().getTitleCache());
1222
                        handleSpecimen(state, ((SpecimenTypeDesignation)typeDesignation).getTypeSpecimen());
1223
                    }
1224
                }else{
1225
                    if (((NameTypeDesignation)typeDesignation).getTypeName() != null){
1226
                        typeDesignationString.append(((NameTypeDesignation)typeDesignation).getTypeName().getTitleCache());
1227
                    }
1228
                }
1229
                if(typeDesignation.getCitation() != null ){
1230
                    typeDesignationString.append(", "+typeDesignation.getCitation().getTitleCache());
1231
                }
1232
                //TODO...
1233
                /*
1234
                 * Sortierung:
1235
                1.  Status der Typen: a) holo, lecto, neo, syn, b) epi, paralecto, c) para (wenn überhaupt) – die jeweiligen iso immer direct mit dazu
1236
                2.  Land
1237
                3.  Sammler
1238
                4.  Nummer
1239

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

    
1243
                 */
1244
            }
1245
            String typeDesignations = typeDesignationString.toString();
1246
            if (typeDesignations != null){
1247
                csvLine[table.getIndex(CdmLightExportTable.TYPE_STRING)] = typeDesignations;
1248
            }else{
1249
                csvLine[table.getIndex(CdmLightExportTable.TYPE_STRING)] = "";
1250
            }
1251
            state.getProcessor().put(table, String.valueOf(group.getId()), csvLine);
1252
        } catch (Exception e) {
1253
            state.getResult().addException(e, "An unexpected error occurred when handling homotypic group " +
1254
                    cdmBaseStr(group) + ": " + e.getMessage());
1255
        }
1256
    }
1257

    
1258
    /**
1259
     * @param name
1260
     * @return
1261
     */
1262
    private String getTropicosTitleCache(CdmLightExportState state, TaxonName name) {
1263
        try {
1264
            String basionymStart = "(";
1265
            String basionymEnd = ") ";
1266
            String exAuthorSeperator = " ex ";
1267
            TeamOrPersonBase<?> combinationAuthor = name.getCombinationAuthorship();
1268
            TeamOrPersonBase<?> exCombinationAuthor = name.getExCombinationAuthorship();
1269
            TeamOrPersonBase<?> basionymAuthor = name.getBasionymAuthorship();
1270
            TeamOrPersonBase<?> exBasionymAuthor = name.getExBasionymAuthorship();
1271

    
1272
            String combinationAuthorString = "";
1273
            if (combinationAuthor != null){
1274
                combinationAuthor = HibernateProxyHelper.deproxy(combinationAuthor);
1275
                if (combinationAuthor instanceof Team){
1276
                    combinationAuthorString = createTropicosTeamTitle(combinationAuthor);
1277
                }else{
1278
                    Person person = HibernateProxyHelper.deproxy(combinationAuthor, Person.class);
1279
                    combinationAuthorString = createTropicosAuthorString(person);
1280
                }
1281
            }
1282
            String exCombinationAuthorString = "";
1283
            if (exCombinationAuthor != null){
1284
                exCombinationAuthor = HibernateProxyHelper.deproxy(exCombinationAuthor);
1285
                if (exCombinationAuthor instanceof Team){
1286
                   exCombinationAuthorString = createTropicosTeamTitle(exCombinationAuthor);
1287
                }else{
1288
                    Person person = HibernateProxyHelper.deproxy(exCombinationAuthor, Person.class);
1289
                    exCombinationAuthorString = createTropicosAuthorString(person);
1290
                }
1291
            }
1292

    
1293
            String basionymAuthorString = "";
1294
            if (basionymAuthor != null){
1295
                basionymAuthor = HibernateProxyHelper.deproxy(basionymAuthor);
1296
                if (basionymAuthor instanceof Team){
1297
                    basionymAuthorString =  createTropicosTeamTitle(basionymAuthor);
1298
                }else{
1299
                    Person person = HibernateProxyHelper.deproxy(basionymAuthor, Person.class);
1300
                    basionymAuthorString = createTropicosAuthorString(person);
1301
                }
1302
            }
1303

    
1304
            String exBasionymAuthorString = "";
1305

    
1306
            if (exBasionymAuthor != null){
1307
                exBasionymAuthor = HibernateProxyHelper.deproxy(exBasionymAuthor);
1308
                if (exBasionymAuthor instanceof Team){
1309
                    exBasionymAuthorString = createTropicosTeamTitle(exBasionymAuthor);
1310

    
1311
                }else{
1312
                    Person person = HibernateProxyHelper.deproxy(exBasionymAuthor, Person.class);
1313
                    exBasionymAuthorString = createTropicosAuthorString(person);
1314
                }
1315
            }
1316
            String completeAuthorString =  name.getNameCache() + " ";
1317

    
1318
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString) || !CdmUtils.isBlank(basionymAuthorString)) ? basionymStart: "";
1319
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString)) ? (CdmUtils.Nz(exBasionymAuthorString) + exAuthorSeperator): "" ;
1320
            completeAuthorString += (!CdmUtils.isBlank(basionymAuthorString))? CdmUtils.Nz(basionymAuthorString):"";
1321
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString) || !CdmUtils.isBlank(basionymAuthorString)) ?  basionymEnd:"";
1322
            completeAuthorString += (!CdmUtils.isBlank(exCombinationAuthorString)) ? (CdmUtils.Nz(exCombinationAuthorString) + exAuthorSeperator): "" ;
1323
            completeAuthorString += (!CdmUtils.isBlank(combinationAuthorString))? CdmUtils.Nz(combinationAuthorString):"";
1324

    
1325

    
1326
            return completeAuthorString;
1327
        } catch (Exception e) {
1328
            state.getResult().addException(e, "An unexpected error occurred when handling tropicos title cache for " +
1329
                    cdmBaseStr(name) + ": " + e.getMessage());
1330
            return null;
1331
        }
1332
    }
1333

    
1334
    /**
1335
     * @param combinationAuthor
1336
     * @return
1337
     */
1338
    private String createTropicosTeamTitle(TeamOrPersonBase<?> combinationAuthor) {
1339
        String combinationAuthorString;
1340
        Team team = HibernateProxyHelper.deproxy(combinationAuthor, Team.class);
1341
        Team tempTeam = Team.NewInstance();
1342
        for (Person teamMember:team.getTeamMembers()){
1343
            combinationAuthorString = createTropicosAuthorString(teamMember);
1344
            Person tempPerson = Person.NewTitledInstance(combinationAuthorString);
1345
            tempTeam.addTeamMember(tempPerson);
1346
        }
1347
        combinationAuthorString = tempTeam.generateTitle();
1348
        return combinationAuthorString;
1349
    }
1350

    
1351
    /**
1352
     * @param teamMember
1353
     */
1354
    private String createTropicosAuthorString(Person teamMember) {
1355
        String nomAuthorString = "";
1356
        String[] splittedAuthorString = null;
1357
        if (teamMember == null){
1358
            return nomAuthorString;
1359
        }
1360

    
1361
        if (teamMember.getFirstname() != null){
1362
            String firstNameString = teamMember.getFirstname().replaceAll("\\.", "\\. ");
1363
            splittedAuthorString = firstNameString.split("\\s");
1364
            for (String split: splittedAuthorString){
1365
                if (!StringUtils.isBlank(split)){
1366
                    nomAuthorString += split.substring(0, 1);
1367
                    nomAuthorString += ".";
1368
                }
1369
            }
1370
        }
1371
        if (teamMember.getLastname() != null){
1372
            String lastNameString = teamMember.getLastname().replaceAll("\\.", "\\. ");
1373
            splittedAuthorString = lastNameString.split("\\s");
1374
            for (String split: splittedAuthorString){
1375
                nomAuthorString += " " +split;
1376
            }
1377
        }
1378
        if (StringUtils.isBlank(nomAuthorString.trim())){
1379
            if (teamMember.getTitleCache() != null) {
1380
                String titleCacheString = teamMember.getTitleCache().replaceAll("\\.", "\\. ");
1381
                splittedAuthorString = titleCacheString.split("\\s");
1382
            }
1383

    
1384

    
1385
            int index = 0;
1386
            for (String split: splittedAuthorString){
1387
                if ( index < splittedAuthorString.length-1 && (split.length()==1 || split.endsWith("."))){
1388
                    nomAuthorString += split;
1389
                }else{
1390
                    nomAuthorString = nomAuthorString +" "+ split;
1391
                }
1392
                index++;
1393
            }
1394
        }
1395
        return nomAuthorString.trim();
1396
    }
1397

    
1398
    /**
1399
     * @param state
1400
     * @param name
1401
     */
1402
    private void handleReference(CdmLightExportState state, Reference reference) {
1403
        try {
1404
            state.addReferenceToStore(reference);
1405
            CdmLightExportTable table = CdmLightExportTable.REFERENCE;
1406

    
1407
            String[] csvLine = new String[table.getSize()];
1408
            csvLine[table.getIndex(CdmLightExportTable.REFERENCE_ID)] = getId(state, reference);
1409
            //TODO short citations correctly
1410
            String shortCitation = createShortCitation(reference);  //Should be Author(year) like in Taxon.sec
1411
            csvLine[table.getIndex(CdmLightExportTable.BIBLIO_SHORT_CITATION)] = shortCitation;
1412
            //TODO get preferred title
1413
            csvLine[table.getIndex(CdmLightExportTable.REF_TITLE)] = reference.getTitle();
1414
            csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_TITLE)] = reference.getAbbrevTitle();
1415
            csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = reference.getDatePublishedString();
1416
            //TBC
1417
            csvLine[table.getIndex(CdmLightExportTable.EDITION)] = reference.getEdition();
1418
            csvLine[table.getIndex(CdmLightExportTable.EDITOR)] = reference.getEditor();
1419
            csvLine[table.getIndex(CdmLightExportTable.ISBN)] = reference.getIsbn();
1420
            csvLine[table.getIndex(CdmLightExportTable.ISSN)] = reference.getIssn();
1421
            csvLine[table.getIndex(CdmLightExportTable.ORGANISATION)] = reference.getOrganization();
1422
            csvLine[table.getIndex(CdmLightExportTable.PAGES)] = reference.getPages();
1423
            csvLine[table.getIndex(CdmLightExportTable.PLACE_PUBLISHED)] = reference.getPlacePublished();
1424
            csvLine[table.getIndex(CdmLightExportTable.PUBLISHER)] = reference.getPublisher();
1425
            csvLine[table.getIndex(CdmLightExportTable.REF_ABSTRACT)] = reference.getReferenceAbstract();
1426
            csvLine[table.getIndex(CdmLightExportTable.SERIES_PART)] = reference.getSeriesPart();
1427
            csvLine[table.getIndex(CdmLightExportTable.VOLUME)] = reference.getVolume();
1428
            csvLine[table.getIndex(CdmLightExportTable.YEAR)] = reference.getYear();
1429
            if ( reference.getAuthorship() != null){
1430
                csvLine[table.getIndex(CdmLightExportTable.AUTHORSHIP_TITLE)] = reference.getAuthorship().getTitleCache();
1431
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_FK)] = getId(state,reference.getAuthorship());
1432
            }
1433

    
1434
            csvLine[table.getIndex(CdmLightExportTable.IN_REFERENCE)] = getId(state, reference.getInReference());
1435
            if (reference.getInReference() != null && state.getReferenceFromStore(reference.getInReference().getId()) == null){
1436
                handleReference(state, reference.getInReference());
1437
            }
1438
            if ( reference.getInstitution() != null){ csvLine[table.getIndex(CdmLightExportTable.INSTITUTION)] = reference.getInstitution().getTitleCache();}
1439
            if ( reference.getLsid() != null){ csvLine[table.getIndex(CdmLightExportTable.LSID)] = reference.getLsid().getLsid();}
1440
            if ( reference.getSchool() != null){ csvLine[table.getIndex(CdmLightExportTable.SCHOOL)] = reference.getSchool().getTitleCache();}
1441
            if ( reference.getUri() != null){ csvLine[table.getIndex(CdmLightExportTable.URI)] = reference.getUri().toString();}
1442
            csvLine[table.getIndex(CdmLightExportTable.REF_TYPE)] = reference.getType().getKey();
1443

    
1444
            state.getProcessor().put(table, reference, csvLine);
1445
        } catch (Exception e) {
1446
            state.getResult().addException(e, "An unexpected error occurred when handling reference " +
1447
                    cdmBaseStr(reference) + ": " + e.getMessage());
1448
        }
1449

    
1450
    }
1451

    
1452

    
1453
    /**
1454
     * @param reference
1455
     * @return
1456
     */
1457
    private String createShortCitation(Reference reference) {
1458
        TeamOrPersonBase<?> authorship = reference.getAuthorship();
1459
        String shortCitation = "";
1460
        if (authorship == null) {
1461
            return null;
1462
        }
1463
        authorship = HibernateProxyHelper.deproxy(authorship);
1464
        if (authorship instanceof Person){ shortCitation = ((Person)authorship).getLastname();}
1465
        else if (authorship instanceof Team){
1466

    
1467
            Team authorTeam = HibernateProxyHelper.deproxy(authorship, Team.class);
1468
            int index = 0;
1469

    
1470
            for (Person teamMember : authorTeam.getTeamMembers()){
1471
                index++;
1472
                String concat = concatString(authorTeam, authorTeam.getTeamMembers(), index);
1473
                shortCitation += concat + teamMember.getLastname();
1474
            }
1475

    
1476
        }
1477
        if (reference.getYear() != null){
1478
            shortCitation = shortCitation + " (" + reference.getYear() + ")";
1479
        }
1480
        return shortCitation;
1481
    }
1482

    
1483
    private static String concatString(Team team, List<Person> teamMembers, int i) {
1484
        String concat;
1485
        if (i <= 1){
1486
            concat = "";
1487
        }else if (i < teamMembers.size() || ( team.isHasMoreMembers() && i == teamMembers.size())){
1488
            concat = STD_TEAM_CONCATINATION;
1489
        }else{
1490
            concat = FINAL_TEAM_CONCATINATION;
1491
        }
1492
        return concat;
1493
    }
1494

    
1495
    /*
1496
     * TypeDesignation table
1497
     * Specimen_Fk
1498
     *  EditName_Fk
1499
     *   TypeVerbatimCitation
1500
     *   TypeCategory
1501
     *   TypeDesignatedByString
1502
     *   TypeDesignatedByRef_Fk
1503
     */
1504

    
1505
    private void handleSpecimenTypeDesignations(CdmLightExportState state, TaxonName name){
1506
       try {
1507
           Set<SpecimenTypeDesignation> typeDesignations = name.getSpecimenTypeDesignations();
1508
           CdmLightExportTable table = CdmLightExportTable.TYPE_DESIGNATION;
1509
           String nameId = getId(state, name);
1510
           String[] csvLine = new String[table.getSize()];
1511
            for (SpecimenTypeDesignation specimenType: typeDesignations){
1512
                csvLine = new String[table.getSize()];
1513
                DerivedUnit specimen = specimenType.getTypeSpecimen();
1514
                if (state.getSpecimenFromStore(specimen.getId()) == null){
1515
                    handleSpecimen(state, specimen);
1516
                }
1517
                csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_FK)] = getId(state, specimenType.getTypeSpecimen());
1518
                csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = nameId;
1519
                csvLine[table.getIndex(CdmLightExportTable.TYPE_VERBATIM_CITATION)] = specimenType.getTypeSpecimen().generateTitle();
1520
                //TODO: add link to existing Vorcabulary
1521
                csvLine[table.getIndex(CdmLightExportTable.TYPE_CATEGORY)] = "";
1522
                csvLine[table.getIndex(CdmLightExportTable.TYPE_DESIGNATED_BY_STRING)] = specimenType.getCitation().getTitleCache();
1523
                csvLine[table.getIndex(CdmLightExportTable.TYPE_DESIGNATED_BY_REF_FK)] = getId(state, specimenType.getCitation());
1524
            }
1525
        } catch (Exception e) {
1526
            state.getResult().addException(e, "An unexpected error occurred when handling specimen type designations for " +
1527
                    cdmBaseStr(name) + ": " + e.getMessage());
1528
        }
1529
    }
1530

    
1531
    /**
1532
     * @param state
1533
     * @param specimen
1534
     */
1535
    private void handleSpecimen(CdmLightExportState state, SpecimenOrObservationBase specimen) {
1536
        try {
1537
            state.addSpecimenToStore(specimen);
1538
            CdmLightExportTable table = CdmLightExportTable.SPECIMEN;
1539
            String specimenId = getId(state, specimen);
1540
            String[] csvLine = new String[table.getSize()];
1541

    
1542
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_ID)] = specimenId;
1543
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_CITATION)] = specimen.getTitleCache();
1544
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_IMAGE_URIS)] = extractURIs(state, specimen.getDescriptions(), Feature.IMAGE());
1545
            if (specimen instanceof DerivedUnit){
1546
                    DerivedUnit derivedUnit = (DerivedUnit)specimen;
1547
                    if (derivedUnit.getCollection() != null){ csvLine[table.getIndex(CdmLightExportTable.HERBARIUM_ABBREV)] = derivedUnit.getCollection().getCode();}
1548

    
1549
                if (specimen instanceof MediaSpecimen){
1550
                    MediaSpecimen mediaSpecimen = (MediaSpecimen) specimen;
1551
                    Iterator<MediaRepresentation> it = mediaSpecimen.getMediaSpecimen().getRepresentations().iterator();
1552
                    String mediaUris = extractMediaUris(it);
1553
                    csvLine[table.getIndex(CdmLightExportTable.MEDIA_SPECIMEN_URL)] = mediaUris;
1554

    
1555
                }
1556

    
1557
                if (derivedUnit.getDerivedFrom() != null){
1558
                    for (SpecimenOrObservationBase<?> original: derivedUnit.getDerivedFrom().getOriginals()){
1559
                        //TODO: What to do if there are more then one FieldUnit??
1560
                        if (original instanceof FieldUnit){
1561
                            FieldUnit fieldUnit = (FieldUnit)original;
1562
                            csvLine[table.getIndex(CdmLightExportTable.COLLECTOR_NUMBER)] = fieldUnit.getFieldNumber();
1563

    
1564
                            GatheringEvent gathering = fieldUnit.getGatheringEvent();
1565
                            if (gathering != null){
1566
                                if (gathering.getLocality() != null){ csvLine[table.getIndex(CdmLightExportTable.LOCALITY)] = gathering.getLocality().getText();}
1567
                                if (gathering.getCountry() != null){csvLine[table.getIndex(CdmLightExportTable.COUNTRY)] = gathering.getCountry().getLabel();}
1568
                                csvLine[table.getIndex(CdmLightExportTable.COLLECTOR_STRING)] = createCollectorString(state, gathering, fieldUnit);
1569
                                addCollectingAreas(state, gathering);
1570
                                if (gathering.getGatheringDate() != null){csvLine[table.getIndex(CdmLightExportTable.COLLECTION_DATE)] = gathering.getGatheringDate().toString();}
1571
                                if (!gathering.getCollectingAreas().isEmpty()){
1572
                                    int index = 0;
1573
                                    csvLine[table.getIndex(CdmLightExportTable.FURTHER_AREAS)] = "0";
1574
                                    for (NamedArea area: gathering.getCollectingAreas()){
1575
                                        if (index == 0){
1576
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY1)] = area.getTermType().getKey();
1577
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME1)] = area.getLabel();
1578
                                        }
1579
                                        if (index == 1){
1580
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY2)] = area.getTermType().getKey();
1581
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME2)] = area.getLabel();
1582
                                        }
1583
                                        if (index == 2){
1584
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY3)] = area.getTermType().getKey();
1585
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME3)] = area.getLabel();
1586
                                        }
1587
                                        if (index == 3){
1588
                                            csvLine[table.getIndex(CdmLightExportTable.FURTHER_AREAS)] = "1";
1589
                                            break;
1590
                                        }
1591
                                        index++;
1592
                                    }
1593
                                }
1594
                            }
1595
                        }
1596
                    }
1597
                }
1598
            }
1599

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

    
1607
    /**
1608
     * @param it
1609
     */
1610
    private String extractMediaUris(Iterator<MediaRepresentation> it) {
1611

    
1612
        String mediaUriString = "";
1613
        boolean first = true;
1614
        while(it.hasNext()){
1615
            MediaRepresentation rep = it.next();
1616
            List<MediaRepresentationPart> parts = rep.getParts();
1617
            for (MediaRepresentationPart part: parts){
1618
                if (first){
1619
                    if (part.getUri() != null){
1620
                        mediaUriString += part.getUri().toString();
1621
                        first = false;
1622
                    }
1623
                }else{
1624
                    if (part.getUri() != null){
1625
                        mediaUriString += ", " +part.getUri().toString();
1626
                    }
1627
                }
1628
            }
1629
        }
1630

    
1631
        return mediaUriString;
1632
    }
1633

    
1634
    /**
1635
     * @param state
1636
     * @param gathering
1637
     */
1638
    private void addCollectingAreas(CdmLightExportState state, GatheringEvent gathering) {
1639
        // TODO implement !!!
1640

    
1641
        if (!gathering.getCollectingAreas().isEmpty()){
1642
            state.getResult().addWarning("Collecting areas not yet implemented but gathering " +
1643
                    cdmBaseStr(gathering) + " has collecting areas.");
1644
        }
1645

    
1646
    }
1647

    
1648
    /**
1649
     * @param gathering
1650
     * @return
1651
     */
1652
    private String createCollectorString(CdmLightExportState state, GatheringEvent gathering, FieldUnit fieldUnit) {
1653
        try {
1654
            String collectorString = "";
1655
            AgentBase<?> collectorA = CdmBase.deproxy(gathering.getCollector());
1656
            if (gathering.getCollector() != null){
1657
               if (collectorA instanceof TeamOrPersonBase
1658
                       && state.getConfig().isHighLightPrimaryCollector()){
1659

    
1660
                   Person primaryCollector = fieldUnit.getPrimaryCollector();
1661
                   if (collectorA instanceof Team){
1662
                       Team collectorTeam = (Team)collectorA;
1663
                       boolean isFirst = true;
1664
                       for (Person member: collectorTeam.getTeamMembers()){
1665
                           if (!isFirst){
1666
                               collectorString += "; ";
1667
                           }
1668
                           if (member.equals(primaryCollector)){
1669
                               //highlight
1670
                               collectorString += "<b>" + member.getTitleCache() + "</b>";
1671
                           }else{
1672
                               collectorString += member.getTitleCache();
1673
                           }
1674
                       }
1675
                   }
1676
               } else{
1677
                   collectorString = collectorA.getTitleCache();
1678
               }
1679
           }
1680
           return collectorString;
1681
        } catch (Exception e) {
1682
            state.getResult().addException(e, "An unexpected error occurred when creating collector string for " +
1683
                    cdmBaseStr(fieldUnit) + ": " + e.getMessage());
1684
            return "";
1685
        }
1686
    }
1687

    
1688

    
1689
    /**
1690
     * Returns a string representation of the {@link CdmBase cdmBase} object
1691
     * for result messages.
1692
     */
1693
    private String cdmBaseStr(CdmBase cdmBase) {
1694
        if (cdmBase == null){
1695
            return "-no object available-";
1696
        }else{
1697
            return cdmBase.getClass().getSimpleName() + ": " + cdmBase.getUuid();
1698
        }
1699
    }
1700

    
1701
    /**
1702
     * {@inheritDoc}
1703
     */
1704
    @Override
1705
    protected boolean doCheck(CdmLightExportState state) {
1706
        return false;
1707
    }
1708

    
1709
    /**
1710
     * {@inheritDoc}
1711
     */
1712
    @Override
1713
    protected boolean isIgnore(CdmLightExportState state) {
1714
        return false;
1715
    }
1716

    
1717
}
(1-1/5)