Project

General

Profile

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

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

    
90

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

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

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

    
103
    }
104

    
105
    @Override
106
    public long countSteps(CdmLightExportState state) {
107
        TaxonNodeFilter filter = state.getConfig().getTaxonNodeFilter();
108
        return taxonNodeService.count(filter);
109
    }
110

    
111

    
112
    /**
113
     * {@inheritDoc}
114
     */
115
    @Override
116
    protected void doInvoke(CdmLightExportState state) {
117
        try {
118

    
119
            IProgressMonitor monitor = state.getConfig().getProgressMonitor();
120
            CdmLightExportConfigurator config = state.getConfig();
121
            config.setFieldsTerminatedBy(",");
122

    
123
//            if (config.getTaxonNodeFilter().getTaxonNodesFilter().isEmpty() && config.getTaxonNodeFilter().getClassificationFilter().isEmpty()){
124
//                //TODO
125
//                state.setEmptyData();
126
//                return;
127
//            }
128

    
129

    
130

    
131
//            for (LogicFilter<Classification> classificationFilter : config.getTaxonNodeFilter().getClassificationFilter()){
132
//                UUID classificationUuid = classificationFilter.getUuid();
133
//                Classification classification = getClassificationService().find(classificationUuid);
134
//                if (classification == null){
135
//                    String message = String.format("Classification for given classification UUID not found. No data imported for %s", classificationUuid.toString());
136
//                    state.getResult().addWarning(message);
137
//                }else{
138
//                    TaxonNode root = classification.getRootNode();
139
//                    UUID uuid = root.getUuid();
140
//                    root = getTaxonNodeService().load(uuid);
141
//                    handleSingleClassification(state, root.getUuid());
142
//                }
143
//            }
144

    
145

    
146
            @SuppressWarnings("unchecked")
147
            TaxonNodeOutStreamPartitioner<XmlExportState> partitioner
148
              = TaxonNodeOutStreamPartitioner.NewInstance(
149
                    this, state, state.getConfig().getTaxonNodeFilter(),
150
                    100, monitor, null);
151

    
152

    
153
                monitor.subTask("Start partitioning");
154

    
155
                TaxonNode node = partitioner.next();
156
                while (node != null){
157
                  handleTaxonNode(state, node);
158
                  node = partitioner.next();
159
                }
160

    
161

    
162
//            for (LogicFilter<TaxonNode> taxonNodeFilter : config.getTaxonNodeFilter().getTaxonNodesFilter()){
163
//                UUID nodeUuid = taxonNodeFilter.getUuid();
164
//                handleSingleClassification(state, nodeUuid);
165
//            }
166
            state.getProcessor().createFinalResult(state);
167
        } catch (Exception e) {
168
            state.getResult().addException(e, "An unexpected error occurred in main method doInvoke() " +
169
                    e.getMessage());
170
        }
171
    }
172

    
173
    /**
174
     * @param state
175
     * @param classificationUuid
176
     */
177
    private void handleTaxonNode(CdmLightExportState state, TaxonNode taxonNode) {
178
        try {
179
//            TaxonNode taxonNode = getTaxonNodeService().find(taxonNodeUuid);
180

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

    
202
    /**
203
     * @param state
204
     * @param taxon
205
     */
206
    private void handleTaxon(CdmLightExportState state, TaxonNode taxonNode) {
207
        try{
208
      //  Taxon taxon = taxonNode.getTaxon();
209
        if (taxonNode == null){
210
            state.getResult().addError ("The taxonNode was null.", "handleTaxon");
211
            state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
212
            return;
213
        }
214
        if (taxonNode.getTaxon() == null){
215
            state.getResult().addError ("There was a taxon node without a taxon: " + taxonNode.getUuid(), "handleTaxon");
216
            state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
217
        }else{
218
            Taxon taxon = HibernateProxyHelper.deproxy(taxonNode.getTaxon(), Taxon.class);
219

    
220
             try{
221
                TaxonName name = taxon.getName();
222
                handleName(state, name);
223
                for (Synonym syn : taxon.getSynonyms()){
224
                    handleSynonym(state, syn);
225
                }
226

    
227

    
228
                CdmLightExportTable table = CdmLightExportTable.TAXON;
229
                String[] csvLine = new String[table.getSize()];
230

    
231
                csvLine[table.getIndex(CdmLightExportTable.TAXON_ID)] = getId(state, taxon);
232
                csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
233
                Taxon parent = (taxonNode.getParent()==null) ? null : taxonNode.getParent().getTaxon();
234
                csvLine[table.getIndex(CdmLightExportTable.PARENT_FK)] = getId(state, parent);
235
                csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE_FK)] = getId(state, taxon.getSec());
236
                csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = getTitleCache(taxon.getSec());
237
                csvLine[table.getIndex(CdmLightExportTable.CLASSIFICATION_ID)] = getId(state, taxonNode.getClassification());
238
                csvLine[table.getIndex(CdmLightExportTable.CLASSIFICATION_TITLE)] = taxonNode.getClassification().getTitleCache();
239

    
240
                state.getProcessor().put(table, taxon, csvLine);
241
                handleDescriptions(state, taxon);
242
             }catch(Exception e){
243
                 state.getResult().addException (e, "An unexpected problem occurred when trying to export "
244
                         + "taxon with id " + taxon.getId());
245
                 state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
246
             }
247
       }
248

    
249
       taxonNode.removeNullValueFromChildren();
250
//       for (TaxonNode child: taxonNode.getChildNodes()){
251
//           handleTaxon(state, child);
252
//       }
253
        }catch (Exception e){
254
            state.getResult().addException(e, "An unexpected error occurred when handling the taxon node of " +
255
                    cdmBaseStr(taxonNode.getTaxon()) + ": " + e.getMessage());
256
        }
257
    }
258

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

    
324

    
325
    /**
326
     * @param feature
327
     * @return
328
     */
329
    private boolean isSpecimenFeature(Feature feature) {
330
        //TODO allow user defined specimen features
331
        if (feature == null){
332
            return false;
333
        }else if (feature.isSupportsIndividualAssociation()){
334
            return true;
335
        }else{
336
            return feature.equals(Feature.SPECIMEN()) || feature.equals(Feature.INDIVIDUALS_ASSOCIATION())
337
                    || feature.equals(Feature.MATERIALS_EXAMINED()) || feature.equals(Feature.OBSERVATION())
338
                    || feature.equals(Feature.OCCURRENCE())
339
                     ;
340
        }
341
    }
342

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

    
366
    /**
367
     * @param state
368
     * @param cdmBase
369
     * @param tableMedia
370
     * @param element
371
     */
372
    private void handleSimpleMediaFact(CdmLightExportState state, CdmBase cdmBase, CdmLightExportTable table,
373
            DescriptionElementBase element) {
374
        try {
375
            String[] csvLine;
376
            handleSource(state, element, CdmLightExportTable.MEDIA);
377

    
378
            if (element instanceof TextData){
379
               TextData textData = (TextData)element;
380
               csvLine = new String[table.getSize()];
381
               csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
382
               if (cdmBase instanceof Taxon){
383
                   csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
384
                   csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = "";
385
               }else if (cdmBase instanceof TaxonName){
386
                   csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = "";
387
                   csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, cdmBase);
388
               }
389

    
390

    
391
               String mediaUris = "";
392
               for (Media media: textData.getMedia()){
393
                   String mediaString = extractMediaUris(media.getRepresentations().iterator());
394
                   if (!StringUtils.isBlank(mediaString)){
395
                       mediaUris +=  mediaString + ";";
396
                   }
397
                   else{
398
                       state.getResult().addWarning("Empty Media object for "
399
                               + cdmBase.getUserFriendlyTypeName() + " " + cdmBase.getUuid()
400
                               + " (media: " + media.getUuid() + ")");
401
                   }
402
               }
403
               csvLine[table.getIndex(CdmLightExportTable.MEDIA_URI)] = mediaUris;
404

    
405
            }
406
        } catch (Exception e) {
407
            state.getResult().addException(e, "An unexpected error occurred when handling single simple fact " +
408
                    cdmBaseStr(element) + ": " + e.getMessage());
409
        }
410

    
411
    }
412

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

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

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

    
458
                       csvLineLanguage[table.getIndex(CdmLightExportTable.FACT_TEXT)] = langString.getText();
459
                       csvLineLanguage[table.getIndex(CdmLightExportTable.LANGUAGE)] = language.getLabel();
460
                       state.getProcessor().put(table, textData, csvLineLanguage);
461
                   }
462
               } else{
463
                   state.getProcessor().put(table, textData, csvLine);
464
               }
465
            }
466
        } catch (Exception e) {
467
            state.getResult().addException(e, "An unexpected error occurred when handling single simple fact " +
468
                    cdmBaseStr(element) + ": " + e.getMessage());
469
        }
470
    }
471

    
472

    
473
    /**
474
     * @param state
475
     * @param specimenFacts
476
     */
477
    private void handleSpecimenFacts(CdmLightExportState state, Taxon taxon, List<DescriptionElementBase> specimenFacts) {
478
        CdmLightExportTable table = CdmLightExportTable.SPECIMEN_FACT;
479

    
480
        for (DescriptionElementBase element: specimenFacts){
481
            try {
482
                String[] csvLine = new String[table.getSize()];
483
                csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
484
                csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, taxon);
485
                handleSource(state, element, table);
486
                csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_NOTES)] = createAnnotationsString(element.getAnnotations());
487

    
488
                if (element instanceof IndividualsAssociation){
489

    
490
                    IndividualsAssociation indAssociation = (IndividualsAssociation)element;
491
                    if (indAssociation.getAssociatedSpecimenOrObservation() == null){
492
                        state.getResult().addWarning("There is an individual association with no specimen associated (Taxon "+ taxon.getTitleCache() + "(" + taxon.getUuid() +"). Could not be exported.");
493
                        continue;
494
                    }else{
495
                        if (state.getSpecimenFromStore(indAssociation.getAssociatedSpecimenOrObservation().getId()) == null){
496
                            SpecimenOrObservationBase<?> specimenBase = HibernateProxyHelper.deproxy(indAssociation.getAssociatedSpecimenOrObservation());
497

    
498
                            if (specimenBase instanceof SpecimenOrObservationBase){
499
                                SpecimenOrObservationBase derivedUnit = specimenBase;
500
                                handleSpecimen(state, derivedUnit);
501
                                csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_FK)] = getId(state, indAssociation.getAssociatedSpecimenOrObservation());
502
                            }else{
503
                                //field units are not supported
504
                                state.getResult().addError("The associated Specimen of taxon " + taxon.getUuid() + " is not an DerivedUnit. Could not be exported.");
505

    
506
                            }
507
                        }
508
                    }
509
                } else if (element instanceof TextData){
510
                    TextData textData = HibernateProxyHelper.deproxy(element, TextData.class);
511
                    csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_DESCRIPTION)] = createMultilanguageString(textData.getMultilanguageText());
512
                }
513
                state.getProcessor().put(table, element, csvLine);
514
            } catch (Exception e) {
515
                state.getResult().addException(e, "An unexpected error occurred when handling single specimen fact " +
516
                        cdmBaseStr(element) + ": " + e.getMessage());
517
            }
518
        }
519
    }
520

    
521
    /**
522
     * @param multilanguageText
523
     * @return
524
     */
525
    private String createMultilanguageString(Map<Language, LanguageString> multilanguageText) {
526
       String text = "";
527
       int index = multilanguageText.size();
528
       for(LanguageString langString: multilanguageText.values()){
529
           text += langString.getText();
530
           if (index > 1){
531
               text += "; ";
532
           }
533
           index --;
534
       }
535

    
536
        return text;
537
    }
538

    
539
    /**
540
     * @param annotations
541
     * @return
542
     */
543
    private String createAnnotationsString(Set<Annotation> annotations) {
544
        StringBuffer strBuff = new StringBuffer();
545

    
546
        for (Annotation ann:annotations){
547
            if (ann.getAnnotationType() == null ||!ann.getAnnotationType().equals(AnnotationType.TECHNICAL())){
548
                strBuff.append(ann.getText());
549
                strBuff.append("; ");
550
            }
551
        }
552

    
553
        if (strBuff.length() > 2){
554
            return strBuff.substring(0, strBuff.length()-2);
555
        }else{
556
            return null;
557
        }
558
    }
559

    
560
    /**
561
     * @param state
562
     * @param taxon
563
     * @param element
564
     */
565
    private void handleSource(CdmLightExportState state, DescriptionElementBase element, CdmLightExportTable factsTable) {
566
        CdmLightExportTable table = CdmLightExportTable.FACT_SOURCES;
567
        try {
568
        Set<DescriptionElementSource> sources = element.getSources();
569

    
570
        for (DescriptionElementSource source: sources){
571

    
572
                String[] csvLine = new  String[table.getSize()];
573
                Reference ref = source.getCitation();
574
                if ((ref == null) && (source.getNameUsedInSource() == null)){
575
                    continue;
576
                }
577
                if (ref != null){
578
                    if (state.getReferenceFromStore(ref.getId()) == null){
579
                        handleReference(state, ref);
580

    
581
                    }
582
                    csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)] = getId(state, ref);
583
                }
584
                csvLine[table.getIndex(CdmLightExportTable.FACT_FK)] = getId(state, element);
585

    
586
                csvLine[table.getIndex(CdmLightExportTable.NAME_IN_SOURCE_FK)] = getId(state, source.getNameUsedInSource());
587
                csvLine[table.getIndex(CdmLightExportTable.FACT_TYPE)] = factsTable.getTableName();
588
                if ( StringUtils.isBlank(csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)])  && StringUtils.isBlank(csvLine[table.getIndex(CdmLightExportTable.NAME_IN_SOURCE_FK)])){
589
                    continue;
590
                }
591
                state.getProcessor().put(table, source, csvLine);
592

    
593
        }
594
        } catch (Exception e) {
595
            state.getResult().addException(e, "An unexpected error occurred when handling single source " +
596
                    cdmBaseStr(element) + ": " + e.getMessage());
597
        }
598

    
599
    }
600

    
601
    /**
602
     * @param state
603
     * @param distributionFacts
604
     */
605
    private void handleDistributionFacts(CdmLightExportState state, Taxon taxon, List<DescriptionElementBase> distributionFacts) {
606
        CdmLightExportTable table = CdmLightExportTable.GEOGRAPHIC_AREA_FACT;
607

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

    
633
    /**
634
     * @param state
635
     * @param commonNameFacts
636
     */
637
    private void handleCommonNameFacts(CdmLightExportState state, Taxon taxon, List<DescriptionElementBase> commonNameFacts) {
638
        CdmLightExportTable table = CdmLightExportTable.COMMON_NAME_FACT;
639

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

    
662
    /**
663
     * @param sec
664
     * @return
665
     */
666
    private String getTitleCache(IIdentifiableEntity identEntity) {
667
        if (identEntity == null){
668
            return "";
669
        }
670
        //TODO refresh?
671
        return identEntity.getTitleCache();
672
    }
673

    
674
    /**
675
     * @param state
676
     * @param taxon
677
     * @return
678
     */
679
    private String getId(CdmLightExportState state, ICdmBase cdmBase) {
680
        if (cdmBase == null){
681
            return "";
682
        }
683
        //TODO make configurable
684
        return cdmBase.getUuid().toString();
685
    }
686

    
687
    /**
688
     * @param state
689
     * @param synonym
690
     */
691
    private void handleSynonym(CdmLightExportState state, Synonym synonym) {
692
       try {
693
           if (isUnpublished(state.getConfig(), synonym)){
694
               return;
695
           }
696
           TaxonName name = synonym.getName();
697
           handleName(state, name);
698

    
699
           CdmLightExportTable table = CdmLightExportTable.SYNONYM;
700
           String[] csvLine = new String[table.getSize()];
701

    
702
           csvLine[table.getIndex(CdmLightExportTable.SYNONYM_ID)] = getId(state, synonym);
703
           csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, synonym.getAcceptedTaxon());
704
           csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
705
           csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE_FK)] = getId(state, synonym.getSec());
706
           csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = getTitleCache(synonym.getSec());
707
           if (synonym.isProParte()) {
708
        	   csvLine[table.getIndex(CdmLightExportTable.IS_PRO_PARTE)] = "1";
709
           }else {
710
        	   csvLine[table.getIndex(CdmLightExportTable.IS_PRO_PARTE)] = "0";
711
           }
712

    
713
           state.getProcessor().put(table, synonym, csvLine);
714
        } catch (Exception e) {
715
            state.getResult().addException(e, "An unexpected error occurred when handling synonym " +
716
                    cdmBaseStr(synonym) + ": " + e.getMessage());
717
        }
718
    }
719

    
720

    
721
    /**
722
     * @param state
723
     * @param name
724
     */
725
    private void handleName(CdmLightExportState state, TaxonName name) {
726
        if (name == null){
727
            return;
728
        }
729
        try {
730
            Rank rank = name.getRank();
731
            CdmLightExportTable table = CdmLightExportTable.SCIENTIFIC_NAME;
732
            name = HibernateProxyHelper.deproxy(name);
733
            String[] csvLine = new String[table.getSize()];
734

    
735
            csvLine[table.getIndex(CdmLightExportTable.NAME_ID)] = getId(state, name);
736
            if (name.getLsid() != null){
737
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = name.getLsid().getLsid();
738
            }else{
739
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = "";
740
            }
741

    
742
            handleIdentifier(state, name);
743
            handleDescriptions(state, name);
744

    
745
            csvLine[table.getIndex(CdmLightExportTable.RANK)] = getTitleCache(rank);
746
            if (rank != null){
747
                csvLine[table.getIndex(CdmLightExportTable.RANK_SEQUENCE)] = String.valueOf(rank.getOrderIndex());
748
                if (rank.isInfraGeneric()){
749
                    try {
750
                        csvLine[table.getIndex(CdmLightExportTable.INFRAGENERIC_RANK)] = name.getRank().getInfraGenericMarker();
751
                    } catch (UnknownCdmTypeException e) {
752
                        state.getResult().addError("Infrageneric marker expected but not available for rank " + name.getRank().getTitleCache());
753
                    }
754
                }
755
                if (rank.isInfraSpecific()){
756
                    csvLine[table.getIndex(CdmLightExportTable.INFRASPECIFIC_RANK)] = name.getRank().getAbbreviation();
757
                }
758
            }else{
759
                csvLine[table.getIndex(CdmLightExportTable.RANK_SEQUENCE)] = "";
760
            }
761
            if (name.isProtectedTitleCache()){
762
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_AUTHORS)] =name.getTitleCache();
763
            }else{
764
                //TODO: adapt the tropicos titlecache creation
765
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_AUTHORS)] = name.getTitleCache();
766
            }
767
            csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_NO_AUTHORS)] = name.getNameCache();
768
            csvLine[table.getIndex(CdmLightExportTable.GENUS_UNINOMIAL)] = name.getGenusOrUninomial();
769

    
770
            csvLine[table.getIndex(CdmLightExportTable.INFRAGENERIC_EPITHET)] = name.getInfraGenericEpithet();
771
            csvLine[table.getIndex(CdmLightExportTable.SPECIFIC_EPITHET)] = name.getSpecificEpithet();
772

    
773
            csvLine[table.getIndex(CdmLightExportTable.INFRASPECIFIC_EPITHET)] = name.getInfraSpecificEpithet();
774
            csvLine[table.getIndex(CdmLightExportTable.BAS_AUTHORTEAM_FK)] = getId(state,name.getBasionymAuthorship());
775
            if (name.getBasionymAuthorship() != null){
776
                if (state.getAuthorFromStore(name.getBasionymAuthorship().getId()) == null) {
777
                    handleAuthor(state, name.getBasionymAuthorship());
778
                }
779
            }
780
            csvLine[table.getIndex(CdmLightExportTable.BAS_EX_AUTHORTEAM_FK)] = getId(state, name.getExBasionymAuthorship());
781
            if (name.getExBasionymAuthorship() != null){
782
                if (state.getAuthorFromStore(name.getExBasionymAuthorship().getId()) == null) {
783
                    handleAuthor(state, name.getExBasionymAuthorship());
784
                }
785

    
786
            }
787
            csvLine[table.getIndex(CdmLightExportTable.COMB_AUTHORTEAM_FK)] = getId(state,name.getCombinationAuthorship());
788
            if (name.getCombinationAuthorship() != null){
789
                if (state.getAuthorFromStore(name.getCombinationAuthorship().getId()) == null) {
790
                    handleAuthor(state, name.getCombinationAuthorship());
791
                }
792
            }
793
            csvLine[table.getIndex(CdmLightExportTable.COMB_EX_AUTHORTEAM_FK)] = getId(state, name.getExCombinationAuthorship());
794
            if (name.getExCombinationAuthorship() != null){
795
                if (state.getAuthorFromStore(name.getExCombinationAuthorship().getId()) == null) {
796
                    handleAuthor(state, name.getExCombinationAuthorship());
797
                }
798

    
799
            }
800

    
801
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_TEAM_STRING)] = name.getAuthorshipCache();
802

    
803
            Reference nomRef = (Reference)name.getNomenclaturalReference();
804

    
805
            if (nomRef != null){
806
                if (state.getReferenceFromStore(nomRef.getId()) == null){
807
                    handleReference(state, nomRef);
808
                }
809
                csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)] = getId(state, nomRef);
810
                csvLine[table.getIndex(CdmLightExportTable.PUBLICATION_TYPE)] = nomRef.getType().name();
811
                if (nomRef.getVolume() != null){
812
                    csvLine[table.getIndex(CdmLightExportTable.VOLUME_ISSUE)] = nomRef.getVolume();
813
                    csvLine[table.getIndex(CdmLightExportTable.COLLATION)] = createCollatation(name);
814
                }
815
                if (nomRef.getDatePublished() != null){
816
                    csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = nomRef.getTimePeriodPublishedString();
817
                    csvLine[table.getIndex(CdmLightExportTable.YEAR_PUBLISHED)] = nomRef.getDatePublished().getYear();
818
                    csvLine[table.getIndex(CdmLightExportTable.VERBATIM_DATE)] = null;
819
                }
820
                if (name.getNomenclaturalMicroReference() != null){
821
                    csvLine[table.getIndex(CdmLightExportTable.DETAIL)] = name.getNomenclaturalMicroReference();
822
                }
823
                nomRef = HibernateProxyHelper.deproxy(nomRef);
824
                if (nomRef.getInReference() != null){
825
                    Reference inReference = nomRef.getInReference();
826
                    if (inReference.getDatePublished() != null && nomRef.getDatePublished() == null){
827
                        csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = inReference.getDatePublishedString();
828
                        csvLine[table.getIndex(CdmLightExportTable.YEAR_PUBLISHED)] = inReference.getDatePublished().getYear();
829
                    }
830
                    if (nomRef.getVolume() == null && inReference.getVolume() != null){
831
                        csvLine[table.getIndex(CdmLightExportTable.VOLUME_ISSUE)] = inReference.getVolume();
832
                        csvLine[table.getIndex(CdmLightExportTable.COLLATION)] = createCollatation(name);
833
                    }
834
                    if (inReference.getInReference() != null){
835
                        inReference = inReference.getInReference();
836
                    }
837
                    if (inReference.getAbbrevTitle() == null){
838
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils.Nz(inReference.getAbbrevTitleCache());
839
                    }else{
840
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils.Nz(inReference.getAbbrevTitle());
841
                    }
842
                    if (inReference.getTitle() == null){
843
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(inReference.getTitleCache());
844
                    }else{
845
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(inReference.getTitle());
846
                    }
847

    
848

    
849
                    TeamOrPersonBase<?> author = inReference.getAuthorship();
850
                    if (author != null && (nomRef.isOfType(ReferenceType.BookSection) || nomRef.isOfType(ReferenceType.Section))){
851
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = CdmUtils.Nz(author.getNomenclaturalTitle());
852
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = CdmUtils.Nz(author.getTitleCache());
853
                    }else{
854
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = "";
855
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = "";
856
                    }
857
                }else{
858
                    if (nomRef.getAbbrevTitle() == null){
859
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils.Nz(nomRef.getAbbrevTitleCache());
860
                    }else{
861
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils.Nz(nomRef.getAbbrevTitle());
862
                    }
863
                    if (nomRef.getTitle() == null){
864
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(nomRef.getTitleCache());
865
                    }else{
866
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(nomRef.getTitle());
867
                    }
868
                    TeamOrPersonBase<?> author = nomRef.getAuthorship();
869
                    if (author != null ){
870
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = CdmUtils.Nz(author.getNomenclaturalTitle());
871
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = CdmUtils.Nz(author.getTitleCache());
872
                    }else{
873
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = "";
874
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = "";
875
                    }
876

    
877
                }
878
            }else{
879
                csvLine[table.getIndex(CdmLightExportTable.PUBLICATION_TYPE)] = "";
880
            }
881

    
882

    
883

    
884
            /*
885
            * Collation
886

    
887
            Detail
888

    
889

    
890
            TitlePageYear
891
            */
892
            Set<TaxonNameDescription> descriptions = name.getDescriptions();
893
            String protologueUriString = extractURIs(state, descriptions, Feature.PROTOLOGUE());
894

    
895
            csvLine[table.getIndex(CdmLightExportTable.PROTOLOGUE_URI)] = protologueUriString;
896

    
897
            if (name.getStatus() == null || name.getStatus().isEmpty()){
898
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS)] = "";
899
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS_ABBREV)] = "";
900
            }else{
901

    
902
                String statusStringAbbrev = extractStatusString(state, name, true);
903
                String statusString = extractStatusString(state, name, false);
904

    
905
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS)] = statusString.trim();
906
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS_ABBREV)] = statusStringAbbrev.trim();
907
            }
908

    
909
            HomotypicalGroup group =name.getHomotypicalGroup();
910

    
911
            if (state.getHomotypicalGroupFromStore(group.getId()) == null){
912
                handleHomotypicalGroup(state, group);
913
            }
914
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_FK)] = getId(state, group);
915
            List<TaxonName> typifiedNames = new ArrayList<>();
916
            typifiedNames.addAll(group.getTypifiedNames());
917
            Collections.sort(typifiedNames, new HomotypicalGroupNameComparator(null, true));
918
            Integer  seqNumber= typifiedNames.indexOf(name);
919
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_SEQ)] = String.valueOf(seqNumber);
920
            state.getProcessor().put(table, name, csvLine);
921

    
922
            /*
923
             *
924
            Tropicos_ID
925
            IPNI_ID
926

    
927

    
928
            InfragenericRank
929

    
930

    
931
            InfraspecificRank
932
            Collation
933
            Volume (Issue)
934
            Detail
935
            DatePublished
936
            YearPublished
937
            TitlePageYear
938

    
939

    
940

    
941
            HomotypicGroupSequenceNumber
942

    
943

    
944
             *
945
             */
946
        } catch (Exception e) {
947
            state.getResult().addException(e, "An unexpected error occurred when handling synonym " +
948
                    cdmBaseStr(name) + ": " + e.getMessage());
949
        }
950
    }
951

    
952
    /**
953
     * @return
954
     */
955
    private String createCollatation(TaxonName name) {
956
        String collation = "";
957
        if (name.getNomenclaturalReference() != null){
958
            Reference ref = (Reference) name.getNomenclaturalReference();
959
            collation = getVolume(ref);
960
        }
961
        if (name.getNomenclaturalMicroReference() != null){
962
            if (!StringUtils.isBlank(collation)){
963
                collation += ":";
964
            }
965
            collation +=name.getNomenclaturalMicroReference();
966
        }
967

    
968
        return collation;
969
    }
970

    
971
    /**
972
     * @param nomenclaturalReference
973
     * @return
974
     */
975
    private String getVolume(Reference reference) {
976
        if (reference.getVolume() != null){
977
            return reference.getVolume();
978
        }else if (reference.getInReference() != null){
979
            if (reference.getInReference().getVolume() != null){
980
                return reference.getInReference().getVolume();
981
            }
982
        }
983
        return null;
984
    }
985

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

    
1022
        }
1023
    }
1024

    
1025
    /**
1026
     * @param tropicosIdentifiers
1027
     */
1028
    private String extractIdentifier(Set<String> identifierSet) {
1029

    
1030
        String identifierString = "";
1031
        for (String identifier: identifierSet){
1032
            if (!StringUtils.isBlank(identifierString)){
1033
                identifierString += ", ";
1034
            }
1035
            identifierString += identifier;
1036
        }
1037

    
1038
        return identifierString;
1039
    }
1040

    
1041
    /**
1042
     * @param state
1043
     * @param descriptions
1044
     * @return
1045
     */
1046
    private String extractURIs(CdmLightExportState state,
1047
            Set<? extends DescriptionBase<?>> descriptionsSet, Feature feature) {
1048
        String mediaUriString = "";
1049
        SpecimenDescription specimenDescription;
1050
        TaxonDescription taxonDescription;
1051
        TaxonNameDescription nameDescription;
1052
        Set<DescriptionElementBase> elements = new HashSet<>();
1053
        for (DescriptionBase<?> description : descriptionsSet){
1054
            try {
1055
                if (!description.getElements().isEmpty()){
1056
                    if (description instanceof SpecimenDescription){
1057
                        specimenDescription = (SpecimenDescription)description;
1058
                        elements = specimenDescription.getElements();
1059
                    }else if (description instanceof TaxonDescription){
1060
                        taxonDescription = (TaxonDescription) description;
1061
                        elements = taxonDescription.getElements();
1062
                    } else if (description instanceof TaxonNameDescription){
1063
                        nameDescription = (TaxonNameDescription) description;
1064
                        elements = nameDescription.getElements();
1065
                    }
1066

    
1067
                    for (DescriptionElementBase element : elements){
1068
                        Feature entityFeature = HibernateProxyHelper.deproxy(element.getFeature());
1069
                        if (entityFeature.equals(feature)){
1070
                            if (!element.getMedia().isEmpty()){
1071
                                List<Media> media = element.getMedia();
1072
                                for (Media mediaElement: media){
1073
                                    Iterator<MediaRepresentation> it =  mediaElement.getRepresentations().iterator();
1074
                                    mediaUriString = extractMediaUris(it);
1075
                                }
1076
                            }
1077
                        }
1078
                    }
1079
                }
1080
            } catch (Exception e) {
1081
                state.getResult().addException(e, "An unexpected error occurred when extracting media URIs for " +
1082
                        cdmBaseStr(description) + ": " + e.getMessage());
1083
            }
1084
        }
1085
        return mediaUriString;
1086
    }
1087

    
1088
    /**
1089
     * @param state
1090
     * @param basionymAuthorship
1091
     */
1092
    private void handleAuthor(CdmLightExportState state, TeamOrPersonBase<?> author) {
1093
        try {
1094
            if (state.getAuthorFromStore(author.getId()) != null){
1095
                return;
1096
            }
1097
            state.addAuthorToStore(author);
1098
            CdmLightExportTable table = CdmLightExportTable.NOMENCLATURAL_AUTHOR;
1099
            String[] csvLine = new String[table.getSize()];
1100
            CdmLightExportTable tableAuthorRel = CdmLightExportTable.NOMENCLATURAL_AUTHOR_TEAM_RELATION;
1101
            String[] csvLineRel = new String[tableAuthorRel.getSize()];
1102
            String[] csvLineMember = new String[table.getSize()];
1103
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_ID)] = getId(state, author);
1104
            csvLine[table.getIndex(CdmLightExportTable.ABBREV_AUTHOR)] = author.getNomenclaturalTitle();
1105
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_TITLE)] = author.getTitleCache();
1106
            author = HibernateProxyHelper.deproxy(author);
1107
            if (author instanceof Person){
1108
                Person authorPerson = (Person)author;
1109
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_FIRST_NAME)] = authorPerson.getFirstname();
1110
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_LASTNAME)] = authorPerson.getLastname();
1111
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_PREFIX)] = authorPerson.getPrefix();
1112
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_SUFFIX)] = authorPerson.getSuffix();
1113
            } else{
1114
                // create an entry in rel table and all members in author table, check whether the team members already in author table
1115

    
1116
                Team authorTeam = (Team)author;
1117
                int index = 0;
1118
                for (Person member: authorTeam.getTeamMembers()){
1119
                    csvLineRel = new String[tableAuthorRel.getSize()];
1120
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_TEAM_FK)] = getId(state, authorTeam);
1121
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_FK)] = getId(state, member);
1122
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_TEAM_SEQ_NUMBER)] = String.valueOf(index);
1123
                    state.getProcessor().put(tableAuthorRel, authorTeam.getId() +":" +member.getId(), csvLineRel);
1124

    
1125
                    if (state.getAuthorFromStore(member.getId()) == null){
1126
                        state.addAuthorToStore(member);
1127
                        csvLineMember = new String[table.getSize()];
1128
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_ID)] = getId(state, member);
1129
                        csvLineMember[table.getIndex(CdmLightExportTable.ABBREV_AUTHOR)] = member.getNomenclaturalTitle();
1130
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_TITLE)] = member.getTitleCache();
1131
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_FIRST_NAME)] = member.getFirstname();
1132
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_LASTNAME)] = member.getLastname();
1133
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_PREFIX)] = member.getPrefix();
1134
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_SUFFIX)] = member.getSuffix();
1135
                        state.getProcessor().put(table, member, csvLineMember);
1136
                    }
1137
                    index++;
1138

    
1139
                }
1140
            }
1141
            state.getProcessor().put(table, author, csvLine);
1142
        } catch (Exception e) {
1143
            state.getResult().addException(e, "An unexpected error occurred when handling author " +
1144
                    cdmBaseStr(author) + ": " + e.getMessage());
1145
        }
1146
    }
1147

    
1148
    /**
1149
     * @param state
1150
     * @param name
1151
     * @param statusString
1152
     * @return
1153
     */
1154
    private String extractStatusString(CdmLightExportState state, TaxonName name, boolean abbrev) {
1155
        try {
1156
            Set<NomenclaturalStatus> status = name.getStatus();
1157
            if (status.isEmpty()){
1158
                return "";
1159
            }
1160
            String statusString = "";
1161
            for (NomenclaturalStatus nameStatus: status){
1162
                if (nameStatus != null){
1163
                    if (abbrev){
1164
                        if (nameStatus.getType() != null){
1165
                            statusString += nameStatus.getType().getIdInVocabulary();
1166
                        }
1167
                    }else{
1168
                        if (nameStatus.getType() != null){
1169
                            statusString += nameStatus.getType().getTitleCache();
1170
                        }
1171
                    }
1172
                    if (!abbrev){
1173

    
1174
                        if (nameStatus.getRuleConsidered() != null && !StringUtils.isBlank(nameStatus.getRuleConsidered())){
1175
                            statusString += " " + nameStatus.getRuleConsidered();
1176
                        }
1177
                        if (nameStatus.getCitation() != null){
1178
                            statusString += " " + nameStatus.getCitation().getTitleCache();
1179
                        }
1180
                        if (nameStatus.getCitationMicroReference() != null && !StringUtils.isBlank(nameStatus.getCitationMicroReference())){
1181
                            statusString += " " + nameStatus.getCitationMicroReference();
1182
                        }
1183
                    }
1184
                    statusString += " ";
1185
                }
1186
            }
1187
            return statusString;
1188
        } catch (Exception e) {
1189
            state.getResult().addException(e, "An unexpected error occurred when extracting status string for " +
1190
                    cdmBaseStr(name) + ": " + e.getMessage());
1191
            return "";
1192
        }
1193
    }
1194

    
1195
    /**
1196
     * @param group
1197
     */
1198
    private void handleHomotypicalGroup(CdmLightExportState state, HomotypicalGroup group) {
1199
        try {
1200
            state.addHomotypicalGroupToStore(group);
1201
            CdmLightExportTable table = CdmLightExportTable.HOMOTYPIC_GROUP;
1202
            String[] csvLine = new String[table.getSize()];
1203

    
1204
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_ID)] = getId(state, group);
1205
            List<TaxonName> typifiedNames = new ArrayList<>();
1206
            typifiedNames.addAll(group.getTypifiedNames());
1207
            Collections.sort(typifiedNames, new HomotypicalGroupNameComparator(null, true));
1208
            String typifiedNamesString = "";
1209
            for (TaxonName name: typifiedNames){
1210
                //Concatenated output string for homotypic group (names and citations) + status + some name relations (e.g. “non”)
1211
                //TODO: nameRelations, which and how to display
1212

    
1213

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

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

    
1255
                 */
1256
            }
1257
            String typeDesignations = typeDesignationString.toString();
1258
            if (typeDesignations != null){
1259
                csvLine[table.getIndex(CdmLightExportTable.TYPE_STRING)] = typeDesignations;
1260
            }else{
1261
                csvLine[table.getIndex(CdmLightExportTable.TYPE_STRING)] = "";
1262
            }
1263
            state.getProcessor().put(table, String.valueOf(group.getId()), csvLine);
1264
        } catch (Exception e) {
1265
            state.getResult().addException(e, "An unexpected error occurred when handling homotypic group " +
1266
                    cdmBaseStr(group) + ": " + e.getMessage());
1267
        }
1268
    }
1269

    
1270
    /**
1271
     * @param name
1272
     * @return
1273
     */
1274
    private String getTropicosTitleCache(CdmLightExportState state, TaxonName name) {
1275
        try {
1276
            String basionymStart = "(";
1277
            String basionymEnd = ") ";
1278
            String exAuthorSeperator = " ex ";
1279
            TeamOrPersonBase<?> combinationAuthor = name.getCombinationAuthorship();
1280
            TeamOrPersonBase<?> exCombinationAuthor = name.getExCombinationAuthorship();
1281
            TeamOrPersonBase<?> basionymAuthor = name.getBasionymAuthorship();
1282
            TeamOrPersonBase<?> exBasionymAuthor = name.getExBasionymAuthorship();
1283

    
1284
            String combinationAuthorString = "";
1285
            if (combinationAuthor != null){
1286
                combinationAuthor = HibernateProxyHelper.deproxy(combinationAuthor);
1287
                if (combinationAuthor instanceof Team){
1288
                    combinationAuthorString = createTropicosTeamTitle(combinationAuthor);
1289
                }else{
1290
                    Person person = HibernateProxyHelper.deproxy(combinationAuthor, Person.class);
1291
                    combinationAuthorString = createTropicosAuthorString(person);
1292
                }
1293
            }
1294
            String exCombinationAuthorString = "";
1295
            if (exCombinationAuthor != null){
1296
                exCombinationAuthor = HibernateProxyHelper.deproxy(exCombinationAuthor);
1297
                if (exCombinationAuthor instanceof Team){
1298
                   exCombinationAuthorString = createTropicosTeamTitle(exCombinationAuthor);
1299
                }else{
1300
                    Person person = HibernateProxyHelper.deproxy(exCombinationAuthor, Person.class);
1301
                    exCombinationAuthorString = createTropicosAuthorString(person);
1302
                }
1303
            }
1304

    
1305
            String basionymAuthorString = "";
1306
            if (basionymAuthor != null){
1307
                basionymAuthor = HibernateProxyHelper.deproxy(basionymAuthor);
1308
                if (basionymAuthor instanceof Team){
1309
                    basionymAuthorString =  createTropicosTeamTitle(basionymAuthor);
1310
                }else{
1311
                    Person person = HibernateProxyHelper.deproxy(basionymAuthor, Person.class);
1312
                    basionymAuthorString = createTropicosAuthorString(person);
1313
                }
1314
            }
1315

    
1316
            String exBasionymAuthorString = "";
1317

    
1318
            if (exBasionymAuthor != null){
1319
                exBasionymAuthor = HibernateProxyHelper.deproxy(exBasionymAuthor);
1320
                if (exBasionymAuthor instanceof Team){
1321
                    exBasionymAuthorString = createTropicosTeamTitle(exBasionymAuthor);
1322

    
1323
                }else{
1324
                    Person person = HibernateProxyHelper.deproxy(exBasionymAuthor, Person.class);
1325
                    exBasionymAuthorString = createTropicosAuthorString(person);
1326
                }
1327
            }
1328
            String completeAuthorString =  name.getNameCache() + " ";
1329

    
1330
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString) || !CdmUtils.isBlank(basionymAuthorString)) ? basionymStart: "";
1331
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString)) ? (CdmUtils.Nz(exBasionymAuthorString) + exAuthorSeperator): "" ;
1332
            completeAuthorString += (!CdmUtils.isBlank(basionymAuthorString))? CdmUtils.Nz(basionymAuthorString):"";
1333
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString) || !CdmUtils.isBlank(basionymAuthorString)) ?  basionymEnd:"";
1334
            completeAuthorString += (!CdmUtils.isBlank(exCombinationAuthorString)) ? (CdmUtils.Nz(exCombinationAuthorString) + exAuthorSeperator): "" ;
1335
            completeAuthorString += (!CdmUtils.isBlank(combinationAuthorString))? CdmUtils.Nz(combinationAuthorString):"";
1336

    
1337

    
1338
            return completeAuthorString;
1339
        } catch (Exception e) {
1340
            state.getResult().addException(e, "An unexpected error occurred when handling tropicos title cache for " +
1341
                    cdmBaseStr(name) + ": " + e.getMessage());
1342
            return null;
1343
        }
1344
    }
1345

    
1346
    /**
1347
     * @param combinationAuthor
1348
     * @return
1349
     */
1350
    private String createTropicosTeamTitle(TeamOrPersonBase<?> combinationAuthor) {
1351
        String combinationAuthorString;
1352
        Team team = HibernateProxyHelper.deproxy(combinationAuthor, Team.class);
1353
        Team tempTeam = Team.NewInstance();
1354
        for (Person teamMember:team.getTeamMembers()){
1355
            combinationAuthorString = createTropicosAuthorString(teamMember);
1356
            Person tempPerson = Person.NewTitledInstance(combinationAuthorString);
1357
            tempTeam.addTeamMember(tempPerson);
1358
        }
1359
        combinationAuthorString = tempTeam.generateTitle();
1360
        return combinationAuthorString;
1361
    }
1362

    
1363
    /**
1364
     * @param teamMember
1365
     */
1366
    private String createTropicosAuthorString(Person teamMember) {
1367
        String nomAuthorString = "";
1368
        String[] splittedAuthorString = null;
1369
        if (teamMember == null){
1370
            return nomAuthorString;
1371
        }
1372

    
1373
        if (teamMember.getFirstname() != null){
1374
            String firstNameString = teamMember.getFirstname().replaceAll("\\.", "\\. ");
1375
            splittedAuthorString = firstNameString.split("\\s");
1376
            for (String split: splittedAuthorString){
1377
                if (!StringUtils.isBlank(split)){
1378
                    nomAuthorString += split.substring(0, 1);
1379
                    nomAuthorString += ".";
1380
                }
1381
            }
1382
        }
1383
        if (teamMember.getLastname() != null){
1384
            String lastNameString = teamMember.getLastname().replaceAll("\\.", "\\. ");
1385
            splittedAuthorString = lastNameString.split("\\s");
1386
            for (String split: splittedAuthorString){
1387
                nomAuthorString += " " +split;
1388
            }
1389
        }
1390
        if (StringUtils.isBlank(nomAuthorString.trim())){
1391
            if (teamMember.getTitleCache() != null) {
1392
                String titleCacheString = teamMember.getTitleCache().replaceAll("\\.", "\\. ");
1393
                splittedAuthorString = titleCacheString.split("\\s");
1394
            }
1395

    
1396

    
1397
            int index = 0;
1398
            for (String split: splittedAuthorString){
1399
                if ( index < splittedAuthorString.length-1 && (split.length()==1 || split.endsWith("."))){
1400
                    nomAuthorString += split;
1401
                }else{
1402
                    nomAuthorString = nomAuthorString +" "+ split;
1403
                }
1404
                index++;
1405
            }
1406
        }
1407
        return nomAuthorString.trim();
1408
    }
1409

    
1410
    /**
1411
     * @param state
1412
     * @param name
1413
     */
1414
    private void handleReference(CdmLightExportState state, Reference reference) {
1415
        try {
1416
            state.addReferenceToStore(reference);
1417
            CdmLightExportTable table = CdmLightExportTable.REFERENCE;
1418

    
1419
            String[] csvLine = new String[table.getSize()];
1420
            csvLine[table.getIndex(CdmLightExportTable.REFERENCE_ID)] = getId(state, reference);
1421
            //TODO short citations correctly
1422
            String shortCitation = createShortCitation(reference);  //Should be Author(year) like in Taxon.sec
1423
            csvLine[table.getIndex(CdmLightExportTable.BIBLIO_SHORT_CITATION)] = shortCitation;
1424
            //TODO get preferred title
1425
            csvLine[table.getIndex(CdmLightExportTable.REF_TITLE)] = reference.getTitle();
1426
            csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_TITLE)] = reference.getAbbrevTitle();
1427
            csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = reference.getDatePublishedString();
1428
            //TBC
1429
            csvLine[table.getIndex(CdmLightExportTable.EDITION)] = reference.getEdition();
1430
            csvLine[table.getIndex(CdmLightExportTable.EDITOR)] = reference.getEditor();
1431
            csvLine[table.getIndex(CdmLightExportTable.ISBN)] = reference.getIsbn();
1432
            csvLine[table.getIndex(CdmLightExportTable.ISSN)] = reference.getIssn();
1433
            csvLine[table.getIndex(CdmLightExportTable.ORGANISATION)] = reference.getOrganization();
1434
            csvLine[table.getIndex(CdmLightExportTable.PAGES)] = reference.getPages();
1435
            csvLine[table.getIndex(CdmLightExportTable.PLACE_PUBLISHED)] = reference.getPlacePublished();
1436
            csvLine[table.getIndex(CdmLightExportTable.PUBLISHER)] = reference.getPublisher();
1437
            csvLine[table.getIndex(CdmLightExportTable.REF_ABSTRACT)] = reference.getReferenceAbstract();
1438
            csvLine[table.getIndex(CdmLightExportTable.SERIES_PART)] = reference.getSeriesPart();
1439
            csvLine[table.getIndex(CdmLightExportTable.VOLUME)] = reference.getVolume();
1440
            csvLine[table.getIndex(CdmLightExportTable.YEAR)] = reference.getYear();
1441
            if ( reference.getAuthorship() != null){
1442
                csvLine[table.getIndex(CdmLightExportTable.AUTHORSHIP_TITLE)] = reference.getAuthorship().getTitleCache();
1443
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_FK)] = getId(state,reference.getAuthorship());
1444
            }
1445

    
1446
            csvLine[table.getIndex(CdmLightExportTable.IN_REFERENCE)] = getId(state, reference.getInReference());
1447
            if (reference.getInReference() != null && state.getReferenceFromStore(reference.getInReference().getId()) == null){
1448
                handleReference(state, reference.getInReference());
1449
            }
1450
            if ( reference.getInstitution() != null){ csvLine[table.getIndex(CdmLightExportTable.INSTITUTION)] = reference.getInstitution().getTitleCache();}
1451
            if ( reference.getLsid() != null){ csvLine[table.getIndex(CdmLightExportTable.LSID)] = reference.getLsid().getLsid();}
1452
            if ( reference.getSchool() != null){ csvLine[table.getIndex(CdmLightExportTable.SCHOOL)] = reference.getSchool().getTitleCache();}
1453
            if ( reference.getUri() != null){ csvLine[table.getIndex(CdmLightExportTable.URI)] = reference.getUri().toString();}
1454
            csvLine[table.getIndex(CdmLightExportTable.REF_TYPE)] = reference.getType().getKey();
1455

    
1456
            state.getProcessor().put(table, reference, csvLine);
1457
        } catch (Exception e) {
1458
            state.getResult().addException(e, "An unexpected error occurred when handling reference " +
1459
                    cdmBaseStr(reference) + ": " + e.getMessage());
1460
        }
1461

    
1462
    }
1463

    
1464

    
1465
    /**
1466
     * @param reference
1467
     * @return
1468
     */
1469
    private String createShortCitation(Reference reference) {
1470
        TeamOrPersonBase<?> authorship = reference.getAuthorship();
1471
        String shortCitation = "";
1472
        if (authorship == null) {
1473
            return null;
1474
        }
1475
        authorship = HibernateProxyHelper.deproxy(authorship);
1476
        if (authorship instanceof Person){ shortCitation = ((Person)authorship).getLastname();}
1477
        else if (authorship instanceof Team){
1478

    
1479
            Team authorTeam = HibernateProxyHelper.deproxy(authorship, Team.class);
1480
            int index = 0;
1481

    
1482
            for (Person teamMember : authorTeam.getTeamMembers()){
1483
                index++;
1484
                String concat = concatString(authorTeam, authorTeam.getTeamMembers(), index);
1485
                shortCitation += concat + teamMember.getLastname();
1486
            }
1487

    
1488
        }
1489
        if (reference.getYear() != null){
1490
            shortCitation = shortCitation + " (" + reference.getYear() + ")";
1491
        }
1492
        return shortCitation;
1493
    }
1494

    
1495
    private static String concatString(Team team, List<Person> teamMembers, int i) {
1496
        String concat;
1497
        if (i <= 1){
1498
            concat = "";
1499
        }else if (i < teamMembers.size() || ( team.isHasMoreMembers() && i == teamMembers.size())){
1500
            concat = STD_TEAM_CONCATINATION;
1501
        }else{
1502
            concat = FINAL_TEAM_CONCATINATION;
1503
        }
1504
        return concat;
1505
    }
1506

    
1507
    /*
1508
     * TypeDesignation table
1509
     * Specimen_Fk
1510
     *  EditName_Fk
1511
     *   TypeVerbatimCitation
1512
     *   TypeCategory
1513
     *   TypeDesignatedByString
1514
     *   TypeDesignatedByRef_Fk
1515
     */
1516

    
1517
    private void handleSpecimenTypeDesignations(CdmLightExportState state, TaxonName name){
1518
       try {
1519
           Set<SpecimenTypeDesignation> typeDesignations = name.getSpecimenTypeDesignations();
1520
           CdmLightExportTable table = CdmLightExportTable.TYPE_DESIGNATION;
1521
           String nameId = getId(state, name);
1522
           String[] csvLine = new String[table.getSize()];
1523
            for (SpecimenTypeDesignation specimenType: typeDesignations){
1524
                csvLine = new String[table.getSize()];
1525
                DerivedUnit specimen = specimenType.getTypeSpecimen();
1526
                if (state.getSpecimenFromStore(specimen.getId()) == null){
1527
                    handleSpecimen(state, specimen);
1528
                }
1529
                csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_FK)] = getId(state, specimenType.getTypeSpecimen());
1530
                csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = nameId;
1531
                csvLine[table.getIndex(CdmLightExportTable.TYPE_VERBATIM_CITATION)] = specimenType.getTypeSpecimen().generateTitle();
1532
                //TODO: add link to existing Vorcabulary
1533
                csvLine[table.getIndex(CdmLightExportTable.TYPE_CATEGORY)] = "";
1534
                csvLine[table.getIndex(CdmLightExportTable.TYPE_DESIGNATED_BY_STRING)] = specimenType.getCitation().getTitleCache();
1535
                csvLine[table.getIndex(CdmLightExportTable.TYPE_DESIGNATED_BY_REF_FK)] = getId(state, specimenType.getCitation());
1536
            }
1537
        } catch (Exception e) {
1538
            state.getResult().addException(e, "An unexpected error occurred when handling specimen type designations for " +
1539
                    cdmBaseStr(name) + ": " + e.getMessage());
1540
        }
1541
    }
1542

    
1543
    /**
1544
     * @param state
1545
     * @param specimen
1546
     */
1547
    private void handleSpecimen(CdmLightExportState state, SpecimenOrObservationBase specimen) {
1548
        try {
1549
            state.addSpecimenToStore(specimen);
1550
            CdmLightExportTable table = CdmLightExportTable.SPECIMEN;
1551
            String specimenId = getId(state, specimen);
1552
            String[] csvLine = new String[table.getSize()];
1553

    
1554
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_ID)] = specimenId;
1555
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_CITATION)] = specimen.getTitleCache();
1556
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_IMAGE_URIS)] = extractURIs(state, specimen.getDescriptions(), Feature.IMAGE());
1557
            if (specimen instanceof DerivedUnit){
1558
                    DerivedUnit derivedUnit = (DerivedUnit)specimen;
1559
                    if (derivedUnit.getCollection() != null){ csvLine[table.getIndex(CdmLightExportTable.HERBARIUM_ABBREV)] = derivedUnit.getCollection().getCode();}
1560

    
1561
                if (specimen instanceof MediaSpecimen){
1562
                    MediaSpecimen mediaSpecimen = (MediaSpecimen) specimen;
1563
                    Iterator<MediaRepresentation> it = mediaSpecimen.getMediaSpecimen().getRepresentations().iterator();
1564
                    String mediaUris = extractMediaUris(it);
1565
                    csvLine[table.getIndex(CdmLightExportTable.MEDIA_SPECIMEN_URL)] = mediaUris;
1566

    
1567
                }
1568

    
1569
                if (derivedUnit.getDerivedFrom() != null){
1570
                    for (SpecimenOrObservationBase<?> original: derivedUnit.getDerivedFrom().getOriginals()){
1571
                        //TODO: What to do if there are more then one FieldUnit??
1572
                        if (original instanceof FieldUnit){
1573
                            FieldUnit fieldUnit = (FieldUnit)original;
1574
                            csvLine[table.getIndex(CdmLightExportTable.COLLECTOR_NUMBER)] = fieldUnit.getFieldNumber();
1575

    
1576
                            GatheringEvent gathering = fieldUnit.getGatheringEvent();
1577
                            if (gathering != null){
1578
                                if (gathering.getLocality() != null){ csvLine[table.getIndex(CdmLightExportTable.LOCALITY)] = gathering.getLocality().getText();}
1579
                                if (gathering.getCountry() != null){csvLine[table.getIndex(CdmLightExportTable.COUNTRY)] = gathering.getCountry().getLabel();}
1580
                                csvLine[table.getIndex(CdmLightExportTable.COLLECTOR_STRING)] = createCollectorString(state, gathering, fieldUnit);
1581
                                addCollectingAreas(state, gathering);
1582
                                if (gathering.getGatheringDate() != null){csvLine[table.getIndex(CdmLightExportTable.COLLECTION_DATE)] = gathering.getGatheringDate().toString();}
1583
                                if (!gathering.getCollectingAreas().isEmpty()){
1584
                                    int index = 0;
1585
                                    csvLine[table.getIndex(CdmLightExportTable.FURTHER_AREAS)] = "0";
1586
                                    for (NamedArea area: gathering.getCollectingAreas()){
1587
                                        if (index == 0){
1588
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY1)] = area.getTermType().getKey();
1589
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME1)] = area.getLabel();
1590
                                        }
1591
                                        if (index == 1){
1592
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY2)] = area.getTermType().getKey();
1593
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME2)] = area.getLabel();
1594
                                        }
1595
                                        if (index == 2){
1596
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY3)] = area.getTermType().getKey();
1597
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME3)] = area.getLabel();
1598
                                        }
1599
                                        if (index == 3){
1600
                                            csvLine[table.getIndex(CdmLightExportTable.FURTHER_AREAS)] = "1";
1601
                                            break;
1602
                                        }
1603
                                        index++;
1604
                                    }
1605
                                }
1606
                            }
1607
                        }
1608
                    }
1609
                }
1610
            }
1611

    
1612
            state.getProcessor().put(table, specimen, csvLine);
1613
        } catch (Exception e) {
1614
            state.getResult().addException(e, "An unexpected error occurred when handling specimen " +
1615
                    cdmBaseStr(specimen) + ": " + e.getMessage());
1616
        }
1617
    }
1618

    
1619
    /**
1620
     * @param it
1621
     */
1622
    private String extractMediaUris(Iterator<MediaRepresentation> it) {
1623

    
1624
        String mediaUriString = "";
1625
        boolean first = true;
1626
        while(it.hasNext()){
1627
            MediaRepresentation rep = it.next();
1628
            List<MediaRepresentationPart> parts = rep.getParts();
1629
            for (MediaRepresentationPart part: parts){
1630
                if (first){
1631
                    if (part.getUri() != null){
1632
                        mediaUriString += part.getUri().toString();
1633
                        first = false;
1634
                    }
1635
                }else{
1636
                    if (part.getUri() != null){
1637
                        mediaUriString += ", " +part.getUri().toString();
1638
                    }
1639
                }
1640
            }
1641
        }
1642

    
1643
        return mediaUriString;
1644
    }
1645

    
1646
    /**
1647
     * @param state
1648
     * @param gathering
1649
     */
1650
    private void addCollectingAreas(CdmLightExportState state, GatheringEvent gathering) {
1651
        // TODO implement !!!
1652

    
1653
        if (!gathering.getCollectingAreas().isEmpty()){
1654
            state.getResult().addWarning("Collecting areas not yet implemented but gathering " +
1655
                    cdmBaseStr(gathering) + " has collecting areas.");
1656
        }
1657

    
1658
    }
1659

    
1660
    /**
1661
     * @param gathering
1662
     * @return
1663
     */
1664
    private String createCollectorString(CdmLightExportState state, GatheringEvent gathering, FieldUnit fieldUnit) {
1665
        try {
1666
            String collectorString = "";
1667
            AgentBase<?> collectorA = CdmBase.deproxy(gathering.getCollector());
1668
            if (gathering.getCollector() != null){
1669
               if (collectorA instanceof TeamOrPersonBase
1670
                       && state.getConfig().isHighLightPrimaryCollector()){
1671

    
1672
                   Person primaryCollector = fieldUnit.getPrimaryCollector();
1673
                   if (collectorA instanceof Team){
1674
                       Team collectorTeam = (Team)collectorA;
1675
                       boolean isFirst = true;
1676
                       for (Person member: collectorTeam.getTeamMembers()){
1677
                           if (!isFirst){
1678
                               collectorString += "; ";
1679
                           }
1680
                           if (member.equals(primaryCollector)){
1681
                               //highlight
1682
                               collectorString += "<b>" + member.getTitleCache() + "</b>";
1683
                           }else{
1684
                               collectorString += member.getTitleCache();
1685
                           }
1686
                       }
1687
                   }
1688
               } else{
1689
                   collectorString = collectorA.getTitleCache();
1690
               }
1691
           }
1692
           return collectorString;
1693
        } catch (Exception e) {
1694
            state.getResult().addException(e, "An unexpected error occurred when creating collector string for " +
1695
                    cdmBaseStr(fieldUnit) + ": " + e.getMessage());
1696
            return "";
1697
        }
1698
    }
1699

    
1700

    
1701
    /**
1702
     * Returns a string representation of the {@link CdmBase cdmBase} object
1703
     * for result messages.
1704
     */
1705
    private String cdmBaseStr(CdmBase cdmBase) {
1706
        if (cdmBase == null){
1707
            return "-no object available-";
1708
        }else{
1709
            return cdmBase.getClass().getSimpleName() + ": " + cdmBase.getUuid();
1710
        }
1711
    }
1712

    
1713
    /**
1714
     * {@inheritDoc}
1715
     */
1716
    @Override
1717
    protected boolean doCheck(CdmLightExportState state) {
1718
        return false;
1719
    }
1720

    
1721
    /**
1722
     * {@inheritDoc}
1723
     */
1724
    @Override
1725
    protected boolean isIgnore(CdmLightExportState state) {
1726
        return false;
1727
    }
1728

    
1729
}
(1-1/5)