Project

General

Profile

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

    
11
import java.io.File;
12
import java.util.ArrayList;
13
import java.util.Collections;
14
import java.util.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.model.taxon.TaxonRelationship;
80
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
81
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
82

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

    
92

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

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

    
101
    public CdmLightClassificationExport() {
102
        super();
103
        this.ioName = this.getClass().getSimpleName();
104

    
105
    }
106

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

    
113

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

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

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

    
131

    
132

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

    
147

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

    
154

    
155
                monitor.subTask("Start partitioning");
156

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

    
163

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

    
175
    /**
176
     * @param state
177
     * @param classificationUuid
178
     */
179
    private void handleTaxonNode(CdmLightExportState state, TaxonNode taxonNode) {
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
                try {
187
                    TaxonNode root = taxonNode;
188
                    if (root.hasTaxon()){
189
                        handleTaxon(state, root);
190
                    }else{
191
    //                    for (TaxonNode child : root.getChildNodes()){
192
    //                        handleTaxon(state, child);
193
    //                        //TODO progress monitor
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
    /**
204
     * @param state
205
     * @param taxon
206
     */
207
    private void handleTaxon(CdmLightExportState state, TaxonNode taxonNode) {
208
        try{
209
      //  Taxon taxon = taxonNode.getTaxon();
210
        if (taxonNode == null){
211
            state.getResult().addError ("The taxonNode was null.", "handleTaxon");
212
            state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
213
            return;
214
        }
215
        if (taxonNode.getTaxon() == null){
216
            state.getResult().addError ("There was a taxon node without a taxon: " + taxonNode.getUuid(), "handleTaxon");
217
            state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
218
        }else{
219
            Taxon taxon = HibernateProxyHelper.deproxy(taxonNode.getTaxon(), Taxon.class);
220

    
221
             try{
222
                TaxonName name = taxon.getName();
223
                handleName(state, name);
224
                for (Synonym syn : taxon.getSynonyms()){
225
                    handleSynonym(state, syn);
226
                }
227
                for (TaxonRelationship rel : taxon.getProParteAndPartialSynonymRelations()){
228
                    handleProPartePartialMisapplied(state, rel);
229
                }
230
                for (TaxonRelationship rel : taxon.getMisappliedNameRelations()){
231
                    handleProPartePartialMisapplied(state, rel);
232
                }
233

    
234
                CdmLightExportTable table = CdmLightExportTable.TAXON;
235
                String[] csvLine = new String[table.getSize()];
236

    
237
                csvLine[table.getIndex(CdmLightExportTable.TAXON_ID)] = getId(state, taxon);
238
                csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
239
                Taxon parent = (taxonNode.getParent()==null) ? null : taxonNode.getParent().getTaxon();
240
                csvLine[table.getIndex(CdmLightExportTable.PARENT_FK)] = getId(state, parent);
241
                csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE_FK)] = getId(state, taxon.getSec());
242
                csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = getTitleCache(taxon.getSec());
243
                csvLine[table.getIndex(CdmLightExportTable.CLASSIFICATION_ID)] = getId(state, taxonNode.getClassification());
244
                csvLine[table.getIndex(CdmLightExportTable.CLASSIFICATION_TITLE)] = taxonNode.getClassification().getTitleCache();
245

    
246
                state.getProcessor().put(table, taxon, csvLine);
247
                handleDescriptions(state, taxon);
248
             }catch(Exception e){
249
                 state.getResult().addException (e, "An unexpected problem occurred when trying to export "
250
                         + "taxon with id " + taxon.getId());
251
                 state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
252
             }
253
       }
254

    
255
       taxonNode.removeNullValueFromChildren();
256
//       for (TaxonNode child: taxonNode.getChildNodes()){
257
//           handleTaxon(state, child);
258
//       }
259
        }catch (Exception e){
260
            state.getResult().addException(e, "An unexpected error occurred when handling the taxon node of " +
261
                    cdmBaseStr(taxonNode.getTaxon()) + ": " + e.getMessage());
262
        }
263
    }
264

    
265

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

    
331

    
332
    /**
333
     * @param feature
334
     * @return
335
     */
336
    private boolean isSpecimenFeature(Feature feature) {
337
        //TODO allow user defined specimen features
338
        if (feature == null){
339
            return false;
340
        }else if (feature.isSupportsIndividualAssociation()){
341
            return true;
342
        }else{
343
            return feature.equals(Feature.SPECIMEN()) || feature.equals(Feature.INDIVIDUALS_ASSOCIATION())
344
                    || feature.equals(Feature.MATERIALS_EXAMINED()) || feature.equals(Feature.OBSERVATION())
345
                    || feature.equals(Feature.OCCURRENCE())
346
                     ;
347
        }
348
    }
349

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

    
373
    /**
374
     * @param state
375
     * @param cdmBase
376
     * @param tableMedia
377
     * @param element
378
     */
379
    private void handleSimpleMediaFact(CdmLightExportState state, CdmBase cdmBase, CdmLightExportTable table,
380
            DescriptionElementBase element) {
381
        try {
382
            String[] csvLine;
383
            handleSource(state, element, CdmLightExportTable.MEDIA);
384

    
385
            if (element instanceof TextData){
386
               TextData textData = (TextData)element;
387
               csvLine = new String[table.getSize()];
388
               csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
389
               if (cdmBase instanceof Taxon){
390
                   csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
391
                   csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = "";
392
               }else if (cdmBase instanceof TaxonName){
393
                   csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = "";
394
                   csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, cdmBase);
395
               }
396

    
397

    
398
               String mediaUris = "";
399
               for (Media media: textData.getMedia()){
400
                   String mediaString = extractMediaUris(media.getRepresentations().iterator());
401
                   if (!StringUtils.isBlank(mediaString)){
402
                       mediaUris +=  mediaString + ";";
403
                   }
404
                   else{
405
                       state.getResult().addWarning("Empty Media object for "
406
                               + cdmBase.getUserFriendlyTypeName() + " " + cdmBase.getUuid()
407
                               + " (media: " + media.getUuid() + ")");
408
                   }
409
               }
410
               csvLine[table.getIndex(CdmLightExportTable.MEDIA_URI)] = mediaUris;
411

    
412
            }
413
        } catch (Exception e) {
414
            state.getResult().addException(e, "An unexpected error occurred when handling single simple fact " +
415
                    cdmBaseStr(element) + ": " + e.getMessage());
416
        }
417

    
418
    }
419

    
420
    /**
421
     * @param state
422
     * @param cdmBase
423
     * @param table
424
     * @param element
425
     */
426
    private void handleSingleSimpleFact(CdmLightExportState state, CdmBase cdmBase, CdmLightExportTable table,
427
            DescriptionElementBase element) {
428
        try {
429
            String[] csvLine;
430
            handleSource(state, element, CdmLightExportTable.SIMPLE_FACT);
431

    
432
            if (element instanceof TextData){
433
               TextData textData = (TextData)element;
434
               csvLine = new String[table.getSize()];
435
               csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
436
               if (cdmBase instanceof Taxon){
437
                   csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
438
                   csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = "";
439
               }else if (cdmBase instanceof TaxonName){
440
                   csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = "";
441
                   csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, cdmBase);
442
               }
443
               csvLine[table.getIndex(CdmLightExportTable.FACT_CATEGORY)] = textData.getFeature().getLabel();
444

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

    
465
                       csvLineLanguage[table.getIndex(CdmLightExportTable.FACT_TEXT)] = langString.getText();
466
                       csvLineLanguage[table.getIndex(CdmLightExportTable.LANGUAGE)] = language.getLabel();
467
                       state.getProcessor().put(table, textData, csvLineLanguage);
468
                   }
469
               } else{
470
                   state.getProcessor().put(table, textData, csvLine);
471
               }
472
            }
473
        } catch (Exception e) {
474
            state.getResult().addException(e, "An unexpected error occurred when handling single simple fact " +
475
                    cdmBaseStr(element) + ": " + e.getMessage());
476
        }
477
    }
478

    
479

    
480
    /**
481
     * @param state
482
     * @param specimenFacts
483
     */
484
    private void handleSpecimenFacts(CdmLightExportState state, Taxon taxon, List<DescriptionElementBase> specimenFacts) {
485
        CdmLightExportTable table = CdmLightExportTable.SPECIMEN_FACT;
486

    
487
        for (DescriptionElementBase element: specimenFacts){
488
            try {
489
                String[] csvLine = new String[table.getSize()];
490
                csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
491
                csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, taxon);
492
                handleSource(state, element, table);
493
                csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_NOTES)] = createAnnotationsString(element.getAnnotations());
494

    
495
                if (element instanceof IndividualsAssociation){
496

    
497
                    IndividualsAssociation indAssociation = (IndividualsAssociation)element;
498
                    if (indAssociation.getAssociatedSpecimenOrObservation() == null){
499
                        state.getResult().addWarning("There is an individual association with no specimen associated (Taxon "+ taxon.getTitleCache() + "(" + taxon.getUuid() +"). Could not be exported.");
500
                        continue;
501
                    }else{
502
                        if (state.getSpecimenFromStore(indAssociation.getAssociatedSpecimenOrObservation().getId()) == null){
503
                            SpecimenOrObservationBase<?> specimenBase = HibernateProxyHelper.deproxy(indAssociation.getAssociatedSpecimenOrObservation());
504

    
505
                            if (specimenBase instanceof SpecimenOrObservationBase){
506
                                SpecimenOrObservationBase derivedUnit = specimenBase;
507
                                handleSpecimen(state, derivedUnit);
508
                                csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_FK)] = getId(state, indAssociation.getAssociatedSpecimenOrObservation());
509
                            }else{
510
                                //field units are not supported
511
                                state.getResult().addError("The associated Specimen of taxon " + taxon.getUuid() + " is not an DerivedUnit. Could not be exported.");
512

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

    
528
    /**
529
     * @param multilanguageText
530
     * @return
531
     */
532
    private String createMultilanguageString(Map<Language, LanguageString> multilanguageText) {
533
       String text = "";
534
       int index = multilanguageText.size();
535
       for(LanguageString langString: multilanguageText.values()){
536
           text += langString.getText();
537
           if (index > 1){
538
               text += "; ";
539
           }
540
           index --;
541
       }
542

    
543
        return text;
544
    }
545

    
546
    /**
547
     * @param annotations
548
     * @return
549
     */
550
    private String createAnnotationsString(Set<Annotation> annotations) {
551
        StringBuffer strBuff = new StringBuffer();
552

    
553
        for (Annotation ann:annotations){
554
            if (ann.getAnnotationType() == null ||!ann.getAnnotationType().equals(AnnotationType.TECHNICAL())){
555
                strBuff.append(ann.getText());
556
                strBuff.append("; ");
557
            }
558
        }
559

    
560
        if (strBuff.length() > 2){
561
            return strBuff.substring(0, strBuff.length()-2);
562
        }else{
563
            return null;
564
        }
565
    }
566

    
567
    /**
568
     * @param state
569
     * @param taxon
570
     * @param element
571
     */
572
    private void handleSource(CdmLightExportState state, DescriptionElementBase element, CdmLightExportTable factsTable) {
573
        CdmLightExportTable table = CdmLightExportTable.FACT_SOURCES;
574
        try {
575
        Set<DescriptionElementSource> sources = element.getSources();
576

    
577
        for (DescriptionElementSource source: sources){
578

    
579
                String[] csvLine = new  String[table.getSize()];
580
                Reference ref = source.getCitation();
581
                if ((ref == null) && (source.getNameUsedInSource() == null)){
582
                    continue;
583
                }
584
                if (ref != null){
585
                    if (state.getReferenceFromStore(ref.getId()) == null){
586
                        handleReference(state, ref);
587

    
588
                    }
589
                    csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)] = getId(state, ref);
590
                }
591
                csvLine[table.getIndex(CdmLightExportTable.FACT_FK)] = getId(state, element);
592

    
593
                csvLine[table.getIndex(CdmLightExportTable.NAME_IN_SOURCE_FK)] = getId(state, source.getNameUsedInSource());
594
                csvLine[table.getIndex(CdmLightExportTable.FACT_TYPE)] = factsTable.getTableName();
595
                if ( StringUtils.isBlank(csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)])  && StringUtils.isBlank(csvLine[table.getIndex(CdmLightExportTable.NAME_IN_SOURCE_FK)])){
596
                    continue;
597
                }
598
                state.getProcessor().put(table, source, csvLine);
599

    
600
        }
601
        } catch (Exception e) {
602
            state.getResult().addException(e, "An unexpected error occurred when handling single source " +
603
                    cdmBaseStr(element) + ": " + e.getMessage());
604
        }
605

    
606
    }
607

    
608
    /**
609
     * @param state
610
     * @param distributionFacts
611
     */
612
    private void handleDistributionFacts(CdmLightExportState state, Taxon taxon, List<DescriptionElementBase> distributionFacts) {
613
        CdmLightExportTable table = CdmLightExportTable.GEOGRAPHIC_AREA_FACT;
614

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

    
640
    /**
641
     * @param state
642
     * @param commonNameFacts
643
     */
644
    private void handleCommonNameFacts(CdmLightExportState state, Taxon taxon, List<DescriptionElementBase> commonNameFacts) {
645
        CdmLightExportTable table = CdmLightExportTable.COMMON_NAME_FACT;
646

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

    
669
    /**
670
     * @param sec
671
     * @return
672
     */
673
    private String getTitleCache(IIdentifiableEntity identEntity) {
674
        if (identEntity == null){
675
            return "";
676
        }
677
        //TODO refresh?
678
        return identEntity.getTitleCache();
679
    }
680

    
681
    /**
682
     * @param state
683
     * @param taxon
684
     * @return
685
     */
686
    private String getId(CdmLightExportState state, ICdmBase cdmBase) {
687
        if (cdmBase == null){
688
            return "";
689
        }
690
        //TODO make configurable
691
        return cdmBase.getUuid().toString();
692
    }
693

    
694
    /**
695
     * @param state
696
     * @param synonym
697
     */
698
    private void handleSynonym(CdmLightExportState state, Synonym synonym) {
699
       try {
700
           if (isUnpublished(state.getConfig(), synonym)){
701
               return;
702
           }
703
           TaxonName name = synonym.getName();
704
           handleName(state, name);
705

    
706
           CdmLightExportTable table = CdmLightExportTable.SYNONYM;
707
           String[] csvLine = new String[table.getSize()];
708

    
709
           csvLine[table.getIndex(CdmLightExportTable.SYNONYM_ID)] = getId(state, synonym);
710
           csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, synonym.getAcceptedTaxon());
711
           csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
712
           csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE_FK)] = getId(state, synonym.getSec());
713
           csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = getTitleCache(synonym.getSec());
714

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

    
722

    
723
    /**
724
     * Handles Misapplied names (including pro parte and partial as well as
725
     * pro parte and partial synonyms
726
     * @param state
727
     * @param rel
728
     */
729
    private void handleProPartePartialMisapplied(CdmLightExportState state, TaxonRelationship rel) {
730
        try {
731
            Taxon ppSyonym = rel.getFromTaxon();
732
            if (isUnpublished(state.getConfig(), ppSyonym)){
733
                return;
734
            }
735
            TaxonName name = ppSyonym.getName();
736
            handleName(state, name);
737

    
738
            CdmLightExportTable table = CdmLightExportTable.SYNONYM;
739
            String[] csvLine = new String[table.getSize()];
740

    
741
            csvLine[table.getIndex(CdmLightExportTable.SYNONYM_ID)] = getId(state, rel);
742
            csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, rel.getToTaxon());
743
            csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
744

    
745
            //TODO pro parte synonyms have to references, the synonym relationship reference
746
            //and the sec reference of the Taxon representing the synonym.
747
            //As we currently do have only 1 reference column in CDM light the synonym relationship
748
            //reference is used here. This is according to how pro parte synonyms were mapped to
749
            //concept relationships in #7334
750
//            Reference secRef = rel.getCitation();
751
//            csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE_FK)] = getId(state, secRef);
752
//            csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = getTitleCache(secRef);
753

    
754
            Reference secRef = ppSyonym.getSec();
755
            csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE_FK)] = getId(state, secRef);
756
            csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = getTitleCache(secRef);
757
            Reference synSecRef = rel.getCitation();
758
            csvLine[table.getIndex(CdmLightExportTable.SYN_SEC_REFERENCE_FK)] = getId(state, secRef);
759
            csvLine[table.getIndex(CdmLightExportTable.SYN_SEC_REFERENCE)] = getTitleCache(secRef);
760

    
761
            //pro parte type
762
            TaxonRelationshipType type = rel.getType();
763
            csvLine[table.getIndex(CdmLightExportTable.IS_PRO_PARTE)] = type.isProParte()? "1":"0";
764
            csvLine[table.getIndex(CdmLightExportTable.IS_PARTIAL)] = type.isPartial()? "1":"0";
765
            csvLine[table.getIndex(CdmLightExportTable.IS_MISAPPLIED)] = type.isAnyMisappliedName()? "1":"0";
766
            if (type.isPartial()) {
767
                String message = "Partial synonyms/misapplied names not yet handled by CDM light. Created "
768
                    + "pro parte synonym/misapplied name instead for " +  rel.getId();
769
                state.getResult().addWarning(message, "handleProParteSynonym", ppSyonym.getTitleCache());
770
                csvLine[table.getIndex(CdmLightExportTable.IS_PRO_PARTE)] = "1";
771
            }
772

    
773
            state.getProcessor().put(table, ppSyonym, csvLine);
774
         } catch (Exception e) {
775
             state.getResult().addException(e, "An unexpected error occurred when handling "
776
                     + "pro parte/partial synonym relationship " +
777
                     cdmBaseStr(rel) + ": " + e.getMessage());
778
         }
779

    
780
    }
781

    
782

    
783
    /**
784
     * @param state
785
     * @param name
786
     */
787
    private void handleName(CdmLightExportState state, TaxonName name) {
788
        if (name == null){
789
            return;
790
        }
791
        try {
792
            Rank rank = name.getRank();
793
            CdmLightExportTable table = CdmLightExportTable.SCIENTIFIC_NAME;
794
            name = HibernateProxyHelper.deproxy(name);
795
            String[] csvLine = new String[table.getSize()];
796

    
797
            csvLine[table.getIndex(CdmLightExportTable.NAME_ID)] = getId(state, name);
798
            if (name.getLsid() != null){
799
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = name.getLsid().getLsid();
800
            }else{
801
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = "";
802
            }
803

    
804
            handleIdentifier(state, name);
805
            handleDescriptions(state, name);
806

    
807
            csvLine[table.getIndex(CdmLightExportTable.RANK)] = getTitleCache(rank);
808
            if (rank != null){
809
                csvLine[table.getIndex(CdmLightExportTable.RANK_SEQUENCE)] = String.valueOf(rank.getOrderIndex());
810
                if (rank.isInfraGeneric()){
811
                    try {
812
                        csvLine[table.getIndex(CdmLightExportTable.INFRAGENERIC_RANK)] = name.getRank().getInfraGenericMarker();
813
                    } catch (UnknownCdmTypeException e) {
814
                        state.getResult().addError("Infrageneric marker expected but not available for rank " + name.getRank().getTitleCache());
815
                    }
816
                }
817
                if (rank.isInfraSpecific()){
818
                    csvLine[table.getIndex(CdmLightExportTable.INFRASPECIFIC_RANK)] = name.getRank().getAbbreviation();
819
                }
820
            }else{
821
                csvLine[table.getIndex(CdmLightExportTable.RANK_SEQUENCE)] = "";
822
            }
823
            if (name.isProtectedTitleCache()){
824
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_AUTHORS)] =name.getTitleCache();
825
            }else{
826
                //TODO: adapt the tropicos titlecache creation
827
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_AUTHORS)] = name.getTitleCache();
828
            }
829
            csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_NO_AUTHORS)] = name.getNameCache();
830
            csvLine[table.getIndex(CdmLightExportTable.GENUS_UNINOMIAL)] = name.getGenusOrUninomial();
831

    
832
            csvLine[table.getIndex(CdmLightExportTable.INFRAGENERIC_EPITHET)] = name.getInfraGenericEpithet();
833
            csvLine[table.getIndex(CdmLightExportTable.SPECIFIC_EPITHET)] = name.getSpecificEpithet();
834

    
835
            csvLine[table.getIndex(CdmLightExportTable.INFRASPECIFIC_EPITHET)] = name.getInfraSpecificEpithet();
836
            csvLine[table.getIndex(CdmLightExportTable.BAS_AUTHORTEAM_FK)] = getId(state,name.getBasionymAuthorship());
837
            if (name.getBasionymAuthorship() != null){
838
                if (state.getAuthorFromStore(name.getBasionymAuthorship().getId()) == null) {
839
                    handleAuthor(state, name.getBasionymAuthorship());
840
                }
841
            }
842
            csvLine[table.getIndex(CdmLightExportTable.BAS_EX_AUTHORTEAM_FK)] = getId(state, name.getExBasionymAuthorship());
843
            if (name.getExBasionymAuthorship() != null){
844
                if (state.getAuthorFromStore(name.getExBasionymAuthorship().getId()) == null) {
845
                    handleAuthor(state, name.getExBasionymAuthorship());
846
                }
847

    
848
            }
849
            csvLine[table.getIndex(CdmLightExportTable.COMB_AUTHORTEAM_FK)] = getId(state,name.getCombinationAuthorship());
850
            if (name.getCombinationAuthorship() != null){
851
                if (state.getAuthorFromStore(name.getCombinationAuthorship().getId()) == null) {
852
                    handleAuthor(state, name.getCombinationAuthorship());
853
                }
854
            }
855
            csvLine[table.getIndex(CdmLightExportTable.COMB_EX_AUTHORTEAM_FK)] = getId(state, name.getExCombinationAuthorship());
856
            if (name.getExCombinationAuthorship() != null){
857
                if (state.getAuthorFromStore(name.getExCombinationAuthorship().getId()) == null) {
858
                    handleAuthor(state, name.getExCombinationAuthorship());
859
                }
860

    
861
            }
862

    
863
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_TEAM_STRING)] = name.getAuthorshipCache();
864

    
865
            Reference nomRef = name.getNomenclaturalReference();
866

    
867
            if (nomRef != null){
868
                if (state.getReferenceFromStore(nomRef.getId()) == null){
869
                    handleReference(state, nomRef);
870
                }
871
                csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)] = getId(state, nomRef);
872
                csvLine[table.getIndex(CdmLightExportTable.PUBLICATION_TYPE)] = nomRef.getType().name();
873
                if (nomRef.getVolume() != null){
874
                    csvLine[table.getIndex(CdmLightExportTable.VOLUME_ISSUE)] = nomRef.getVolume();
875
                    csvLine[table.getIndex(CdmLightExportTable.COLLATION)] = createCollatation(name);
876
                }
877
                if (nomRef.getDatePublished() != null){
878
                    csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = nomRef.getTimePeriodPublishedString();
879
                    csvLine[table.getIndex(CdmLightExportTable.YEAR_PUBLISHED)] = nomRef.getDatePublished().getYear();
880
                    csvLine[table.getIndex(CdmLightExportTable.VERBATIM_DATE)] = nomRef.getDatePublished().getVerbatimDate();
881
                }
882
                if (name.getNomenclaturalMicroReference() != null){
883
                    csvLine[table.getIndex(CdmLightExportTable.DETAIL)] = name.getNomenclaturalMicroReference();
884
                }
885
                nomRef = HibernateProxyHelper.deproxy(nomRef);
886
                if (nomRef.getInReference() != null){
887
                    Reference inReference = nomRef.getInReference();
888
                    if (inReference.getDatePublished() != null && nomRef.getDatePublished() == null){
889
                        csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = inReference.getDatePublishedString();
890
                        csvLine[table.getIndex(CdmLightExportTable.YEAR_PUBLISHED)] = inReference.getDatePublished().getYear();
891
                    }
892
                    if (nomRef.getVolume() == null && inReference.getVolume() != null){
893
                        csvLine[table.getIndex(CdmLightExportTable.VOLUME_ISSUE)] = inReference.getVolume();
894
                        csvLine[table.getIndex(CdmLightExportTable.COLLATION)] = createCollatation(name);
895
                    }
896
                    if (inReference.getInReference() != null){
897
                        inReference = inReference.getInReference();
898
                    }
899
                    if (inReference.getAbbrevTitle() == null){
900
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils.Nz(inReference.getAbbrevTitleCache());
901
                    }else{
902
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils.Nz(inReference.getAbbrevTitle());
903
                    }
904
                    if (inReference.getTitle() == null){
905
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(inReference.getTitleCache());
906
                    }else{
907
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(inReference.getTitle());
908
                    }
909

    
910

    
911
                    TeamOrPersonBase<?> author = inReference.getAuthorship();
912
                    if (author != null && (nomRef.isOfType(ReferenceType.BookSection) || nomRef.isOfType(ReferenceType.Section))){
913
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = CdmUtils.Nz(author.getNomenclaturalTitle());
914
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = CdmUtils.Nz(author.getTitleCache());
915
                    }else{
916
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = "";
917
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = "";
918
                    }
919
                }else{
920
                    if (nomRef.getAbbrevTitle() == null){
921
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils.Nz(nomRef.getAbbrevTitleCache());
922
                    }else{
923
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils.Nz(nomRef.getAbbrevTitle());
924
                    }
925
                    if (nomRef.getTitle() == null){
926
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(nomRef.getTitleCache());
927
                    }else{
928
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(nomRef.getTitle());
929
                    }
930
                    TeamOrPersonBase<?> author = nomRef.getAuthorship();
931
                    if (author != null ){
932
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = CdmUtils.Nz(author.getNomenclaturalTitle());
933
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = CdmUtils.Nz(author.getTitleCache());
934
                    }else{
935
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = "";
936
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = "";
937
                    }
938

    
939
                }
940
            }else{
941
                csvLine[table.getIndex(CdmLightExportTable.PUBLICATION_TYPE)] = "";
942
            }
943

    
944

    
945

    
946
            /*
947
            * Collation
948

    
949
            Detail
950

    
951

    
952
            TitlePageYear
953
            */
954
            Set<TaxonNameDescription> descriptions = name.getDescriptions();
955
            String protologueUriString = extractURIs(state, descriptions, Feature.PROTOLOGUE());
956

    
957
            csvLine[table.getIndex(CdmLightExportTable.PROTOLOGUE_URI)] = protologueUriString;
958

    
959
            if (name.getStatus() == null || name.getStatus().isEmpty()){
960
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS)] = "";
961
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS_ABBREV)] = "";
962
            }else{
963

    
964
                String statusStringAbbrev = extractStatusString(state, name, true);
965
                String statusString = extractStatusString(state, name, false);
966

    
967
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS)] = statusString.trim();
968
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS_ABBREV)] = statusStringAbbrev.trim();
969
            }
970

    
971
            HomotypicalGroup group =name.getHomotypicalGroup();
972

    
973
            if (state.getHomotypicalGroupFromStore(group.getId()) == null){
974
                handleHomotypicalGroup(state, group);
975
            }
976
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_FK)] = getId(state, group);
977
            List<TaxonName> typifiedNames = new ArrayList<>();
978
            typifiedNames.addAll(group.getTypifiedNames());
979
            Collections.sort(typifiedNames, new HomotypicalGroupNameComparator(null, true));
980
            Integer  seqNumber= typifiedNames.indexOf(name);
981
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_SEQ)] = String.valueOf(seqNumber);
982
            state.getProcessor().put(table, name, csvLine);
983

    
984
            /*
985
             *
986
            Tropicos_ID
987
            IPNI_ID
988

    
989

    
990
            InfragenericRank
991

    
992

    
993
            InfraspecificRank
994
            Collation
995
            Volume (Issue)
996
            Detail
997
            DatePublished
998
            YearPublished
999
            TitlePageYear
1000

    
1001

    
1002

    
1003
            HomotypicGroupSequenceNumber
1004

    
1005

    
1006
             *
1007
             */
1008
        } catch (Exception e) {
1009
            state.getResult().addException(e, "An unexpected error occurred when handling synonym " +
1010
                    cdmBaseStr(name) + ": " + e.getMessage());
1011
        }
1012
    }
1013

    
1014
    /**
1015
     * @return
1016
     */
1017
    private String createCollatation(TaxonName name) {
1018
        String collation = "";
1019
        if (name.getNomenclaturalReference() != null){
1020
            Reference ref = name.getNomenclaturalReference();
1021
            collation = getVolume(ref);
1022
        }
1023
        if (name.getNomenclaturalMicroReference() != null){
1024
            if (!StringUtils.isBlank(collation)){
1025
                collation += ":";
1026
            }
1027
            collation +=name.getNomenclaturalMicroReference();
1028
        }
1029

    
1030
        return collation;
1031
    }
1032

    
1033
    /**
1034
     * @param nomenclaturalReference
1035
     * @return
1036
     */
1037
    private String getVolume(Reference reference) {
1038
        if (reference.getVolume() != null){
1039
            return reference.getVolume();
1040
        }else if (reference.getInReference() != null){
1041
            if (reference.getInReference().getVolume() != null){
1042
                return reference.getInReference().getVolume();
1043
            }
1044
        }
1045
        return null;
1046
    }
1047

    
1048
    /**
1049
     * @param state
1050
     * @param name
1051
     */
1052
    private void handleIdentifier(CdmLightExportState state, TaxonName name) {
1053
        CdmLightExportTable table = CdmLightExportTable.IDENTIFIER;
1054
        String[] csvLine;
1055
        try {
1056
            Set<String>  IPNIidentifiers = name.getIdentifiers(DefinedTerm.IDENTIFIER_NAME_IPNI());
1057
            Set<String>  tropicosIdentifiers = name.getIdentifiers(DefinedTerm.IDENTIFIER_NAME_TROPICOS());
1058
            Set<String>  WFOIdentifiers = name.getIdentifiers(DefinedTerm.uuidWfoNameIdentifier);
1059
            if (!IPNIidentifiers.isEmpty()){
1060
                csvLine = new String[table.getSize()];
1061
                csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId( state, name);
1062
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = IPNI_NAME_IDENTIFIER;
1063
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_IDS)] = extractIdentifier(IPNIidentifiers);
1064
                state.getProcessor().put(table, name, csvLine);
1065
            }
1066
            if (!tropicosIdentifiers.isEmpty()){
1067
                csvLine = new String[table.getSize()];
1068
                csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId( state, name);
1069
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = TROPICOS_NAME_IDENTIFIER;
1070
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_IDS)] = extractIdentifier(tropicosIdentifiers);
1071
                state.getProcessor().put(table, name, csvLine);
1072
            }
1073
            if (!WFOIdentifiers.isEmpty()){
1074
                csvLine = new String[table.getSize()];
1075
                csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId( state, name);
1076
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = WFO_NAME_IDENTIFIER;
1077
                csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_IDS)] = extractIdentifier(WFOIdentifiers);
1078
                state.getProcessor().put(table, name, csvLine);
1079
            }
1080
        } catch (Exception e) {
1081
            state.getResult().addException(e, "An unexpected error occurred when handling identifiers for " +
1082
                    cdmBaseStr(name) + ": " + e.getMessage());
1083

    
1084
        }
1085
    }
1086

    
1087
    /**
1088
     * @param tropicosIdentifiers
1089
     */
1090
    private String extractIdentifier(Set<String> identifierSet) {
1091

    
1092
        String identifierString = "";
1093
        for (String identifier: identifierSet){
1094
            if (!StringUtils.isBlank(identifierString)){
1095
                identifierString += ", ";
1096
            }
1097
            identifierString += identifier;
1098
        }
1099

    
1100
        return identifierString;
1101
    }
1102

    
1103
    /**
1104
     * @param state
1105
     * @param descriptions
1106
     * @return
1107
     */
1108
    private String extractURIs(CdmLightExportState state,
1109
            Set<? extends DescriptionBase<?>> descriptionsSet, Feature feature) {
1110
        String mediaUriString = "";
1111
        SpecimenDescription specimenDescription;
1112
        TaxonDescription taxonDescription;
1113
        TaxonNameDescription nameDescription;
1114
        Set<DescriptionElementBase> elements = new HashSet<>();
1115
        for (DescriptionBase<?> description : descriptionsSet){
1116
            try {
1117
                if (!description.getElements().isEmpty()){
1118
                    if (description instanceof SpecimenDescription){
1119
                        specimenDescription = (SpecimenDescription)description;
1120
                        elements = specimenDescription.getElements();
1121
                    }else if (description instanceof TaxonDescription){
1122
                        taxonDescription = (TaxonDescription) description;
1123
                        elements = taxonDescription.getElements();
1124
                    } else if (description instanceof TaxonNameDescription){
1125
                        nameDescription = (TaxonNameDescription) description;
1126
                        elements = nameDescription.getElements();
1127
                    }
1128

    
1129
                    for (DescriptionElementBase element : elements){
1130
                        Feature entityFeature = HibernateProxyHelper.deproxy(element.getFeature());
1131
                        if (entityFeature.equals(feature)){
1132
                            if (!element.getMedia().isEmpty()){
1133
                                List<Media> media = element.getMedia();
1134
                                for (Media mediaElement: media){
1135
                                    Iterator<MediaRepresentation> it =  mediaElement.getRepresentations().iterator();
1136
                                    mediaUriString = extractMediaUris(it);
1137
                                }
1138
                            }
1139
                        }
1140
                    }
1141
                }
1142
            } catch (Exception e) {
1143
                state.getResult().addException(e, "An unexpected error occurred when extracting media URIs for " +
1144
                        cdmBaseStr(description) + ": " + e.getMessage());
1145
            }
1146
        }
1147
        return mediaUriString;
1148
    }
1149

    
1150
    /**
1151
     * @param state
1152
     * @param basionymAuthorship
1153
     */
1154
    private void handleAuthor(CdmLightExportState state, TeamOrPersonBase<?> author) {
1155
        try {
1156
            if (state.getAuthorFromStore(author.getId()) != null){
1157
                return;
1158
            }
1159
            state.addAuthorToStore(author);
1160
            CdmLightExportTable table = CdmLightExportTable.NOMENCLATURAL_AUTHOR;
1161
            String[] csvLine = new String[table.getSize()];
1162
            CdmLightExportTable tableAuthorRel = CdmLightExportTable.NOMENCLATURAL_AUTHOR_TEAM_RELATION;
1163
            String[] csvLineRel = new String[tableAuthorRel.getSize()];
1164
            String[] csvLineMember = new String[table.getSize()];
1165
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_ID)] = getId(state, author);
1166
            csvLine[table.getIndex(CdmLightExportTable.ABBREV_AUTHOR)] = author.getNomenclaturalTitle();
1167
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_TITLE)] = author.getTitleCache();
1168
            author = HibernateProxyHelper.deproxy(author);
1169
            if (author instanceof Person){
1170
                Person authorPerson = (Person)author;
1171
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_GIVEN_NAME)] = authorPerson.getGivenName();
1172
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_FAMILY_NAME)] = authorPerson.getFamilyName();
1173
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_PREFIX)] = authorPerson.getPrefix();
1174
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_SUFFIX)] = authorPerson.getSuffix();
1175
            } else{
1176
                // create an entry in rel table and all members in author table, check whether the team members already in author table
1177

    
1178
                Team authorTeam = (Team)author;
1179
                int index = 0;
1180
                for (Person member: authorTeam.getTeamMembers()){
1181
                    csvLineRel = new String[tableAuthorRel.getSize()];
1182
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_TEAM_FK)] = getId(state, authorTeam);
1183
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_FK)] = getId(state, member);
1184
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_TEAM_SEQ_NUMBER)] = String.valueOf(index);
1185
                    state.getProcessor().put(tableAuthorRel, authorTeam.getId() +":" +member.getId(), csvLineRel);
1186

    
1187
                    if (state.getAuthorFromStore(member.getId()) == null){
1188
                        state.addAuthorToStore(member);
1189
                        csvLineMember = new String[table.getSize()];
1190
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_ID)] = getId(state, member);
1191
                        csvLineMember[table.getIndex(CdmLightExportTable.ABBREV_AUTHOR)] = member.getNomenclaturalTitle();
1192
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_TITLE)] = member.getTitleCache();
1193
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_GIVEN_NAME)] = member.getGivenName();
1194
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_FAMILY_NAME)] = member.getFamilyName();
1195
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_PREFIX)] = member.getPrefix();
1196
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_SUFFIX)] = member.getSuffix();
1197
                        state.getProcessor().put(table, member, csvLineMember);
1198
                    }
1199
                    index++;
1200

    
1201
                }
1202
            }
1203
            state.getProcessor().put(table, author, csvLine);
1204
        } catch (Exception e) {
1205
            state.getResult().addException(e, "An unexpected error occurred when handling author " +
1206
                    cdmBaseStr(author) + ": " + e.getMessage());
1207
        }
1208
    }
1209

    
1210
    /**
1211
     * @param state
1212
     * @param name
1213
     * @param statusString
1214
     * @return
1215
     */
1216
    private String extractStatusString(CdmLightExportState state, TaxonName name, boolean abbrev) {
1217
        try {
1218
            Set<NomenclaturalStatus> status = name.getStatus();
1219
            if (status.isEmpty()){
1220
                return "";
1221
            }
1222
            String statusString = "";
1223
            for (NomenclaturalStatus nameStatus: status){
1224
                if (nameStatus != null){
1225
                    if (abbrev){
1226
                        if (nameStatus.getType() != null){
1227
                            statusString += nameStatus.getType().getIdInVocabulary();
1228
                        }
1229
                    }else{
1230
                        if (nameStatus.getType() != null){
1231
                            statusString += nameStatus.getType().getTitleCache();
1232
                        }
1233
                    }
1234
                    if (!abbrev){
1235

    
1236
                        if (nameStatus.getRuleConsidered() != null && !StringUtils.isBlank(nameStatus.getRuleConsidered())){
1237
                            statusString += " " + nameStatus.getRuleConsidered();
1238
                        }
1239
                        if (nameStatus.getCitation() != null){
1240
                            statusString += " " + nameStatus.getCitation().getTitleCache();
1241
                        }
1242
                        if (nameStatus.getCitationMicroReference() != null && !StringUtils.isBlank(nameStatus.getCitationMicroReference())){
1243
                            statusString += " " + nameStatus.getCitationMicroReference();
1244
                        }
1245
                    }
1246
                    statusString += " ";
1247
                }
1248
            }
1249
            return statusString;
1250
        } catch (Exception e) {
1251
            state.getResult().addException(e, "An unexpected error occurred when extracting status string for " +
1252
                    cdmBaseStr(name) + ": " + e.getMessage());
1253
            return "";
1254
        }
1255
    }
1256

    
1257
    /**
1258
     * @param group
1259
     */
1260
    private void handleHomotypicalGroup(CdmLightExportState state, HomotypicalGroup group) {
1261
        try {
1262
            state.addHomotypicalGroupToStore(group);
1263
            CdmLightExportTable table = CdmLightExportTable.HOMOTYPIC_GROUP;
1264
            String[] csvLine = new String[table.getSize()];
1265

    
1266
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_ID)] = getId(state, group);
1267
            List<TaxonName> typifiedNames = new ArrayList<>();
1268
            typifiedNames.addAll(group.getTypifiedNames());
1269
            Collections.sort(typifiedNames, new HomotypicalGroupNameComparator(null, true));
1270
            String typifiedNamesString = "";
1271
            for (TaxonName name: typifiedNames){
1272
                //Concatenated output string for homotypic group (names and citations) + status + some name relations (e.g. “non”)
1273
                //TODO: nameRelations, which and how to display
1274

    
1275

    
1276
                typifiedNamesString += name.getTitleCache()+ extractStatusString(state, name, true) + "; ";
1277
            }
1278
            typifiedNamesString = typifiedNamesString.substring(0, typifiedNamesString.length()-2);
1279
            if (typifiedNamesString != null){
1280
                csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_STRING)] = typifiedNamesString.trim();
1281
            }else{
1282
                csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_STRING)] = "";
1283
            }
1284
            Set<TypeDesignationBase> typeDesigantions = group.getTypeDesignations();
1285
            List<TypeDesignationBase> designationList = new ArrayList<>();
1286
            designationList.addAll(typeDesigantions);
1287
            Collections.sort(designationList, new TypeComparator());
1288
            StringBuffer typeDesignationString = new StringBuffer();
1289
            for (TypeDesignationBase typeDesignation: typeDesigantions){
1290
                if (typeDesignation != null && typeDesignation.getTypeStatus() != null){
1291
                    typeDesignationString.append(typeDesignation.getTypeStatus().getTitleCache() + ": ");
1292
                }
1293
                if (typeDesignation instanceof SpecimenTypeDesignation){
1294
                    if (((SpecimenTypeDesignation)typeDesignation).getTypeSpecimen() != null){
1295
                        typeDesignationString.append(((SpecimenTypeDesignation)typeDesignation).getTypeSpecimen().getTitleCache());
1296
                        handleSpecimen(state, ((SpecimenTypeDesignation)typeDesignation).getTypeSpecimen());
1297
                    }
1298
                }else{
1299
                    if (((NameTypeDesignation)typeDesignation).getTypeName() != null){
1300
                        typeDesignationString.append(((NameTypeDesignation)typeDesignation).getTypeName().getTitleCache());
1301
                    }
1302
                }
1303
                if(typeDesignation.getCitation() != null ){
1304
                    typeDesignationString.append(", "+typeDesignation.getCitation().getTitleCache());
1305
                }
1306
                //TODO...
1307
                /*
1308
                 * Sortierung:
1309
                1.  Status der Typen: a) holo, lecto, neo, syn, b) epi, paralecto, c) para (wenn überhaupt) – die jeweiligen iso immer direct mit dazu
1310
                2.  Land
1311
                3.  Sammler
1312
                4.  Nummer
1313

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

    
1317
                 */
1318
            }
1319
            String typeDesignations = typeDesignationString.toString();
1320
            if (typeDesignations != null){
1321
                csvLine[table.getIndex(CdmLightExportTable.TYPE_STRING)] = typeDesignations;
1322
            }else{
1323
                csvLine[table.getIndex(CdmLightExportTable.TYPE_STRING)] = "";
1324
            }
1325
            state.getProcessor().put(table, String.valueOf(group.getId()), csvLine);
1326
        } catch (Exception e) {
1327
            state.getResult().addException(e, "An unexpected error occurred when handling homotypic group " +
1328
                    cdmBaseStr(group) + ": " + e.getMessage());
1329
        }
1330
    }
1331

    
1332
    /**
1333
     * @param name
1334
     * @return
1335
     */
1336
    private String getTropicosTitleCache(CdmLightExportState state, TaxonName name) {
1337
        try {
1338
            String basionymStart = "(";
1339
            String basionymEnd = ") ";
1340
            String exAuthorSeperator = " ex ";
1341
            TeamOrPersonBase<?> combinationAuthor = name.getCombinationAuthorship();
1342
            TeamOrPersonBase<?> exCombinationAuthor = name.getExCombinationAuthorship();
1343
            TeamOrPersonBase<?> basionymAuthor = name.getBasionymAuthorship();
1344
            TeamOrPersonBase<?> exBasionymAuthor = name.getExBasionymAuthorship();
1345

    
1346
            String combinationAuthorString = "";
1347
            if (combinationAuthor != null){
1348
                combinationAuthor = HibernateProxyHelper.deproxy(combinationAuthor);
1349
                if (combinationAuthor instanceof Team){
1350
                    combinationAuthorString = createTropicosTeamTitle(combinationAuthor);
1351
                }else{
1352
                    Person person = HibernateProxyHelper.deproxy(combinationAuthor, Person.class);
1353
                    combinationAuthorString = createTropicosAuthorString(person);
1354
                }
1355
            }
1356
            String exCombinationAuthorString = "";
1357
            if (exCombinationAuthor != null){
1358
                exCombinationAuthor = HibernateProxyHelper.deproxy(exCombinationAuthor);
1359
                if (exCombinationAuthor instanceof Team){
1360
                   exCombinationAuthorString = createTropicosTeamTitle(exCombinationAuthor);
1361
                }else{
1362
                    Person person = HibernateProxyHelper.deproxy(exCombinationAuthor, Person.class);
1363
                    exCombinationAuthorString = createTropicosAuthorString(person);
1364
                }
1365
            }
1366

    
1367
            String basionymAuthorString = "";
1368
            if (basionymAuthor != null){
1369
                basionymAuthor = HibernateProxyHelper.deproxy(basionymAuthor);
1370
                if (basionymAuthor instanceof Team){
1371
                    basionymAuthorString =  createTropicosTeamTitle(basionymAuthor);
1372
                }else{
1373
                    Person person = HibernateProxyHelper.deproxy(basionymAuthor, Person.class);
1374
                    basionymAuthorString = createTropicosAuthorString(person);
1375
                }
1376
            }
1377

    
1378
            String exBasionymAuthorString = "";
1379

    
1380
            if (exBasionymAuthor != null){
1381
                exBasionymAuthor = HibernateProxyHelper.deproxy(exBasionymAuthor);
1382
                if (exBasionymAuthor instanceof Team){
1383
                    exBasionymAuthorString = createTropicosTeamTitle(exBasionymAuthor);
1384

    
1385
                }else{
1386
                    Person person = HibernateProxyHelper.deproxy(exBasionymAuthor, Person.class);
1387
                    exBasionymAuthorString = createTropicosAuthorString(person);
1388
                }
1389
            }
1390
            String completeAuthorString =  name.getNameCache() + " ";
1391

    
1392
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString) || !CdmUtils.isBlank(basionymAuthorString)) ? basionymStart: "";
1393
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString)) ? (CdmUtils.Nz(exBasionymAuthorString) + exAuthorSeperator): "" ;
1394
            completeAuthorString += (!CdmUtils.isBlank(basionymAuthorString))? CdmUtils.Nz(basionymAuthorString):"";
1395
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString) || !CdmUtils.isBlank(basionymAuthorString)) ?  basionymEnd:"";
1396
            completeAuthorString += (!CdmUtils.isBlank(exCombinationAuthorString)) ? (CdmUtils.Nz(exCombinationAuthorString) + exAuthorSeperator): "" ;
1397
            completeAuthorString += (!CdmUtils.isBlank(combinationAuthorString))? CdmUtils.Nz(combinationAuthorString):"";
1398

    
1399

    
1400
            return completeAuthorString;
1401
        } catch (Exception e) {
1402
            state.getResult().addException(e, "An unexpected error occurred when handling tropicos title cache for " +
1403
                    cdmBaseStr(name) + ": " + e.getMessage());
1404
            return null;
1405
        }
1406
    }
1407

    
1408
    /**
1409
     * @param combinationAuthor
1410
     * @return
1411
     */
1412
    private String createTropicosTeamTitle(TeamOrPersonBase<?> combinationAuthor) {
1413
        String combinationAuthorString;
1414
        Team team = HibernateProxyHelper.deproxy(combinationAuthor, Team.class);
1415
        Team tempTeam = Team.NewInstance();
1416
        for (Person teamMember:team.getTeamMembers()){
1417
            combinationAuthorString = createTropicosAuthorString(teamMember);
1418
            Person tempPerson = Person.NewTitledInstance(combinationAuthorString);
1419
            tempTeam.addTeamMember(tempPerson);
1420
        }
1421
        combinationAuthorString = tempTeam.generateTitle();
1422
        return combinationAuthorString;
1423
    }
1424

    
1425
    /**
1426
     * @param teamMember
1427
     */
1428
    private String createTropicosAuthorString(Person teamMember) {
1429
        String nomAuthorString = "";
1430
        String[] splittedAuthorString = null;
1431
        if (teamMember == null){
1432
            return nomAuthorString;
1433
        }
1434

    
1435
        if (teamMember.getGivenName() != null){
1436
            String givenNameString = teamMember.getGivenName().replaceAll("\\.", "\\. ");
1437
            splittedAuthorString = givenNameString.split("\\s");
1438
            for (String split: splittedAuthorString){
1439
                if (!StringUtils.isBlank(split)){
1440
                    nomAuthorString += split.substring(0, 1);
1441
                    nomAuthorString += ".";
1442
                }
1443
            }
1444
        }
1445
        if (teamMember.getFamilyName() != null){
1446
            String familyNameString = teamMember.getFamilyName().replaceAll("\\.", "\\. ");
1447
            splittedAuthorString = familyNameString.split("\\s");
1448
            for (String split: splittedAuthorString){
1449
                nomAuthorString += " " +split;
1450
            }
1451
        }
1452
        if (StringUtils.isBlank(nomAuthorString.trim())){
1453
            if (teamMember.getTitleCache() != null) {
1454
                String titleCacheString = teamMember.getTitleCache().replaceAll("\\.", "\\. ");
1455
                splittedAuthorString = titleCacheString.split("\\s");
1456
            }
1457

    
1458

    
1459
            int index = 0;
1460
            for (String split: splittedAuthorString){
1461
                if ( index < splittedAuthorString.length-1 && (split.length()==1 || split.endsWith("."))){
1462
                    nomAuthorString += split;
1463
                }else{
1464
                    nomAuthorString = nomAuthorString +" "+ split;
1465
                }
1466
                index++;
1467
            }
1468
        }
1469
        return nomAuthorString.trim();
1470
    }
1471

    
1472
    /**
1473
     * @param state
1474
     * @param name
1475
     */
1476
    private void handleReference(CdmLightExportState state, Reference reference) {
1477
        try {
1478
            state.addReferenceToStore(reference);
1479
            CdmLightExportTable table = CdmLightExportTable.REFERENCE;
1480

    
1481
            String[] csvLine = new String[table.getSize()];
1482
            csvLine[table.getIndex(CdmLightExportTable.REFERENCE_ID)] = getId(state, reference);
1483
            //TODO short citations correctly
1484
            String shortCitation = createShortCitation(reference);  //Should be Author(year) like in Taxon.sec
1485
            csvLine[table.getIndex(CdmLightExportTable.BIBLIO_SHORT_CITATION)] = shortCitation;
1486
            //TODO get preferred title
1487
            csvLine[table.getIndex(CdmLightExportTable.REF_TITLE)] = reference.getTitle();
1488
            csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_TITLE)] = reference.getAbbrevTitle();
1489
            csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = reference.getDatePublishedString();
1490
            //TBC
1491
            csvLine[table.getIndex(CdmLightExportTable.EDITION)] = reference.getEdition();
1492
            csvLine[table.getIndex(CdmLightExportTable.EDITOR)] = reference.getEditor();
1493
            csvLine[table.getIndex(CdmLightExportTable.ISBN)] = reference.getIsbn();
1494
            csvLine[table.getIndex(CdmLightExportTable.ISSN)] = reference.getIssn();
1495
            csvLine[table.getIndex(CdmLightExportTable.ORGANISATION)] = reference.getOrganization();
1496
            csvLine[table.getIndex(CdmLightExportTable.PAGES)] = reference.getPages();
1497
            csvLine[table.getIndex(CdmLightExportTable.PLACE_PUBLISHED)] = reference.getPlacePublished();
1498
            csvLine[table.getIndex(CdmLightExportTable.PUBLISHER)] = reference.getPublisher();
1499
            csvLine[table.getIndex(CdmLightExportTable.REF_ABSTRACT)] = reference.getReferenceAbstract();
1500
            csvLine[table.getIndex(CdmLightExportTable.SERIES_PART)] = reference.getSeriesPart();
1501
            csvLine[table.getIndex(CdmLightExportTable.VOLUME)] = reference.getVolume();
1502
            csvLine[table.getIndex(CdmLightExportTable.YEAR)] = reference.getYear();
1503
            if ( reference.getAuthorship() != null){
1504
                csvLine[table.getIndex(CdmLightExportTable.AUTHORSHIP_TITLE)] = reference.getAuthorship().getTitleCache();
1505
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_FK)] = getId(state,reference.getAuthorship());
1506
            }
1507

    
1508
            csvLine[table.getIndex(CdmLightExportTable.IN_REFERENCE)] = getId(state, reference.getInReference());
1509
            if (reference.getInReference() != null && state.getReferenceFromStore(reference.getInReference().getId()) == null){
1510
                handleReference(state, reference.getInReference());
1511
            }
1512
            if ( reference.getInstitution() != null){ csvLine[table.getIndex(CdmLightExportTable.INSTITUTION)] = reference.getInstitution().getTitleCache();}
1513
            if ( reference.getLsid() != null){ csvLine[table.getIndex(CdmLightExportTable.LSID)] = reference.getLsid().getLsid();}
1514
            if ( reference.getSchool() != null){ csvLine[table.getIndex(CdmLightExportTable.SCHOOL)] = reference.getSchool().getTitleCache();}
1515
            if ( reference.getUri() != null){ csvLine[table.getIndex(CdmLightExportTable.URI)] = reference.getUri().toString();}
1516
            csvLine[table.getIndex(CdmLightExportTable.REF_TYPE)] = reference.getType().getKey();
1517

    
1518
            state.getProcessor().put(table, reference, csvLine);
1519
        } catch (Exception e) {
1520
            state.getResult().addException(e, "An unexpected error occurred when handling reference " +
1521
                    cdmBaseStr(reference) + ": " + e.getMessage());
1522
        }
1523

    
1524
    }
1525

    
1526

    
1527
    /**
1528
     * @param reference
1529
     * @return
1530
     */
1531
    private String createShortCitation(Reference reference) {
1532
        TeamOrPersonBase<?> authorship = reference.getAuthorship();
1533
        String shortCitation = "";
1534
        if (authorship == null) {
1535
            return null;
1536
        }
1537
        authorship = HibernateProxyHelper.deproxy(authorship);
1538
        if (authorship instanceof Person){ shortCitation = ((Person)authorship).getFamilyName();}
1539
        else if (authorship instanceof Team){
1540

    
1541
            Team authorTeam = HibernateProxyHelper.deproxy(authorship, Team.class);
1542
            int index = 0;
1543

    
1544
            for (Person teamMember : authorTeam.getTeamMembers()){
1545
                index++;
1546
                String concat = concatString(authorTeam, authorTeam.getTeamMembers(), index);
1547
                shortCitation += concat + teamMember.getFamilyName();
1548
            }
1549

    
1550
        }
1551
        if (reference.getYear() != null){
1552
            shortCitation = shortCitation + " (" + reference.getYear() + ")";
1553
        }
1554
        return shortCitation;
1555
    }
1556

    
1557
    private static String concatString(Team team, List<Person> teamMembers, int i) {
1558
        String concat;
1559
        if (i <= 1){
1560
            concat = "";
1561
        }else if (i < teamMembers.size() || ( team.isHasMoreMembers() && i == teamMembers.size())){
1562
            concat = STD_TEAM_CONCATINATION;
1563
        }else{
1564
            concat = FINAL_TEAM_CONCATINATION;
1565
        }
1566
        return concat;
1567
    }
1568

    
1569
    /*
1570
     * TypeDesignation table
1571
     * Specimen_Fk
1572
     *  EditName_Fk
1573
     *   TypeVerbatimCitation
1574
     *   TypeCategory
1575
     *   TypeDesignatedByString
1576
     *   TypeDesignatedByRef_Fk
1577
     */
1578

    
1579
    private void handleSpecimenTypeDesignations(CdmLightExportState state, TaxonName name){
1580
       try {
1581
           Set<SpecimenTypeDesignation> typeDesignations = name.getSpecimenTypeDesignations();
1582
           CdmLightExportTable table = CdmLightExportTable.TYPE_DESIGNATION;
1583
           String nameId = getId(state, name);
1584
           String[] csvLine = new String[table.getSize()];
1585
            for (SpecimenTypeDesignation specimenType: typeDesignations){
1586
                csvLine = new String[table.getSize()];
1587
                DerivedUnit specimen = specimenType.getTypeSpecimen();
1588
                if (state.getSpecimenFromStore(specimen.getId()) == null){
1589
                    handleSpecimen(state, specimen);
1590
                }
1591
                csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_FK)] = getId(state, specimenType.getTypeSpecimen());
1592
                csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = nameId;
1593
                csvLine[table.getIndex(CdmLightExportTable.TYPE_VERBATIM_CITATION)] = specimenType.getTypeSpecimen().generateTitle();
1594
                //TODO: add link to existing Vorcabulary
1595
                csvLine[table.getIndex(CdmLightExportTable.TYPE_CATEGORY)] = "";
1596
                csvLine[table.getIndex(CdmLightExportTable.TYPE_DESIGNATED_BY_STRING)] = specimenType.getCitation().getTitleCache();
1597
                csvLine[table.getIndex(CdmLightExportTable.TYPE_DESIGNATED_BY_REF_FK)] = getId(state, specimenType.getCitation());
1598
            }
1599
        } catch (Exception e) {
1600
            state.getResult().addException(e, "An unexpected error occurred when handling specimen type designations for " +
1601
                    cdmBaseStr(name) + ": " + e.getMessage());
1602
        }
1603
    }
1604

    
1605
    /**
1606
     * @param state
1607
     * @param specimen
1608
     */
1609
    private void handleSpecimen(CdmLightExportState state, SpecimenOrObservationBase specimen) {
1610
        try {
1611
            state.addSpecimenToStore(specimen);
1612
            CdmLightExportTable table = CdmLightExportTable.SPECIMEN;
1613
            String specimenId = getId(state, specimen);
1614
            String[] csvLine = new String[table.getSize()];
1615

    
1616
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_ID)] = specimenId;
1617
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_CITATION)] = specimen.getTitleCache();
1618
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_IMAGE_URIS)] = extractURIs(state, specimen.getDescriptions(), Feature.IMAGE());
1619
            if (specimen instanceof DerivedUnit){
1620
                    DerivedUnit derivedUnit = (DerivedUnit)specimen;
1621
                    if (derivedUnit.getCollection() != null){ csvLine[table.getIndex(CdmLightExportTable.HERBARIUM_ABBREV)] = derivedUnit.getCollection().getCode();}
1622

    
1623
                if (specimen instanceof MediaSpecimen){
1624
                    MediaSpecimen mediaSpecimen = (MediaSpecimen) specimen;
1625
                    Iterator<MediaRepresentation> it = mediaSpecimen.getMediaSpecimen().getRepresentations().iterator();
1626
                    String mediaUris = extractMediaUris(it);
1627
                    csvLine[table.getIndex(CdmLightExportTable.MEDIA_SPECIMEN_URL)] = mediaUris;
1628

    
1629
                }
1630

    
1631
                if (derivedUnit.getDerivedFrom() != null){
1632
                    for (SpecimenOrObservationBase<?> original: derivedUnit.getDerivedFrom().getOriginals()){
1633
                        //TODO: What to do if there are more then one FieldUnit??
1634
                        if (original instanceof FieldUnit){
1635
                            FieldUnit fieldUnit = (FieldUnit)original;
1636
                            csvLine[table.getIndex(CdmLightExportTable.COLLECTOR_NUMBER)] = fieldUnit.getFieldNumber();
1637

    
1638
                            GatheringEvent gathering = fieldUnit.getGatheringEvent();
1639
                            if (gathering != null){
1640
                                if (gathering.getLocality() != null){ csvLine[table.getIndex(CdmLightExportTable.LOCALITY)] = gathering.getLocality().getText();}
1641
                                if (gathering.getCountry() != null){csvLine[table.getIndex(CdmLightExportTable.COUNTRY)] = gathering.getCountry().getLabel();}
1642
                                csvLine[table.getIndex(CdmLightExportTable.COLLECTOR_STRING)] = createCollectorString(state, gathering, fieldUnit);
1643
                                addCollectingAreas(state, gathering);
1644
                                if (gathering.getGatheringDate() != null){csvLine[table.getIndex(CdmLightExportTable.COLLECTION_DATE)] = gathering.getGatheringDate().toString();}
1645
                                if (!gathering.getCollectingAreas().isEmpty()){
1646
                                    int index = 0;
1647
                                    csvLine[table.getIndex(CdmLightExportTable.FURTHER_AREAS)] = "0";
1648
                                    for (NamedArea area: gathering.getCollectingAreas()){
1649
                                        if (index == 0){
1650
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY1)] = area.getTermType().getKey();
1651
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME1)] = area.getLabel();
1652
                                        }
1653
                                        if (index == 1){
1654
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY2)] = area.getTermType().getKey();
1655
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME2)] = area.getLabel();
1656
                                        }
1657
                                        if (index == 2){
1658
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY3)] = area.getTermType().getKey();
1659
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME3)] = area.getLabel();
1660
                                        }
1661
                                        if (index == 3){
1662
                                            csvLine[table.getIndex(CdmLightExportTable.FURTHER_AREAS)] = "1";
1663
                                            break;
1664
                                        }
1665
                                        index++;
1666
                                    }
1667
                                }
1668
                            }
1669
                        }
1670
                    }
1671
                }
1672
            }
1673

    
1674
            state.getProcessor().put(table, specimen, csvLine);
1675
        } catch (Exception e) {
1676
            state.getResult().addException(e, "An unexpected error occurred when handling specimen " +
1677
                    cdmBaseStr(specimen) + ": " + e.getMessage());
1678
        }
1679
    }
1680

    
1681
    /**
1682
     * @param it
1683
     */
1684
    private String extractMediaUris(Iterator<MediaRepresentation> it) {
1685

    
1686
        String mediaUriString = "";
1687
        boolean first = true;
1688
        while(it.hasNext()){
1689
            MediaRepresentation rep = it.next();
1690
            List<MediaRepresentationPart> parts = rep.getParts();
1691
            for (MediaRepresentationPart part: parts){
1692
                if (first){
1693
                    if (part.getUri() != null){
1694
                        mediaUriString += part.getUri().toString();
1695
                        first = false;
1696
                    }
1697
                }else{
1698
                    if (part.getUri() != null){
1699
                        mediaUriString += ", " +part.getUri().toString();
1700
                    }
1701
                }
1702
            }
1703
        }
1704

    
1705
        return mediaUriString;
1706
    }
1707

    
1708
    /**
1709
     * @param state
1710
     * @param gathering
1711
     */
1712
    private void addCollectingAreas(CdmLightExportState state, GatheringEvent gathering) {
1713
        // TODO implement !!!
1714

    
1715
        if (!gathering.getCollectingAreas().isEmpty()){
1716
            state.getResult().addWarning("Collecting areas not yet implemented but gathering " +
1717
                    cdmBaseStr(gathering) + " has collecting areas.");
1718
        }
1719

    
1720
    }
1721

    
1722
    /**
1723
     * @param gathering
1724
     * @return
1725
     */
1726
    private String createCollectorString(CdmLightExportState state, GatheringEvent gathering, FieldUnit fieldUnit) {
1727
        try {
1728
            String collectorString = "";
1729
            AgentBase<?> collectorA = CdmBase.deproxy(gathering.getCollector());
1730
            if (gathering.getCollector() != null){
1731
               if (collectorA instanceof TeamOrPersonBase
1732
                       && state.getConfig().isHighLightPrimaryCollector()){
1733

    
1734
                   Person primaryCollector = fieldUnit.getPrimaryCollector();
1735
                   if (collectorA instanceof Team){
1736
                       Team collectorTeam = (Team)collectorA;
1737
                       boolean isFirst = true;
1738
                       for (Person member: collectorTeam.getTeamMembers()){
1739
                           if (!isFirst){
1740
                               collectorString += "; ";
1741
                           }
1742
                           if (member.equals(primaryCollector)){
1743
                               //highlight
1744
                               collectorString += "<b>" + member.getTitleCache() + "</b>";
1745
                           }else{
1746
                               collectorString += member.getTitleCache();
1747
                           }
1748
                       }
1749
                   }
1750
               } else{
1751
                   collectorString = collectorA.getTitleCache();
1752
               }
1753
           }
1754
           return collectorString;
1755
        } catch (Exception e) {
1756
            state.getResult().addException(e, "An unexpected error occurred when creating collector string for " +
1757
                    cdmBaseStr(fieldUnit) + ": " + e.getMessage());
1758
            return "";
1759
        }
1760
    }
1761

    
1762

    
1763
    /**
1764
     * Returns a string representation of the {@link CdmBase cdmBase} object
1765
     * for result messages.
1766
     */
1767
    private String cdmBaseStr(CdmBase cdmBase) {
1768
        if (cdmBase == null){
1769
            return "-no object available-";
1770
        }else{
1771
            return cdmBase.getClass().getSimpleName() + ": " + cdmBase.getUuid();
1772
        }
1773
    }
1774

    
1775
    /**
1776
     * {@inheritDoc}
1777
     */
1778
    @Override
1779
    protected boolean doCheck(CdmLightExportState state) {
1780
        return false;
1781
    }
1782

    
1783
    /**
1784
     * {@inheritDoc}
1785
     */
1786
    @Override
1787
    protected boolean isIgnore(CdmLightExportState state) {
1788
        return false;
1789
    }
1790

    
1791
}
(1-1/5)