Project

General

Profile

Download (136 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.Collection;
14
import java.util.Collections;
15
import java.util.Comparator;
16
import java.util.HashMap;
17
import java.util.HashSet;
18
import java.util.Iterator;
19
import java.util.List;
20
import java.util.Map;
21
import java.util.Set;
22
import java.util.UUID;
23

    
24
import org.apache.commons.lang3.StringUtils;
25
import org.springframework.beans.factory.annotation.Autowired;
26
import org.springframework.stereotype.Component;
27

    
28
import eu.etaxonomy.cdm.api.service.dto.CondensedDistribution;
29
import eu.etaxonomy.cdm.api.service.name.TypeDesignationSetFormatter;
30
import eu.etaxonomy.cdm.api.service.name.TypeDesignationSetContainer;
31
import eu.etaxonomy.cdm.common.CdmUtils;
32
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
33
import eu.etaxonomy.cdm.compare.name.TypeComparator;
34
import eu.etaxonomy.cdm.compare.taxon.HomotypicGroupTaxonComparator;
35
import eu.etaxonomy.cdm.ext.geo.IEditGeoService;
36
import eu.etaxonomy.cdm.filter.TaxonNodeFilter;
37
import eu.etaxonomy.cdm.format.reference.OriginalSourceFormatter;
38
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
39
import eu.etaxonomy.cdm.io.common.CdmExportBase;
40
import eu.etaxonomy.cdm.io.common.ExportResult.ExportResultState;
41
import eu.etaxonomy.cdm.io.common.TaxonNodeOutStreamPartitioner;
42
import eu.etaxonomy.cdm.io.common.XmlExportState;
43
import eu.etaxonomy.cdm.io.common.mapping.out.IExportTransformer;
44
import eu.etaxonomy.cdm.model.agent.AgentBase;
45
import eu.etaxonomy.cdm.model.agent.Person;
46
import eu.etaxonomy.cdm.model.agent.Team;
47
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
48
import eu.etaxonomy.cdm.model.common.Annotation;
49
import eu.etaxonomy.cdm.model.common.AnnotationType;
50
import eu.etaxonomy.cdm.model.common.CdmBase;
51
import eu.etaxonomy.cdm.model.common.ICdmBase;
52
import eu.etaxonomy.cdm.model.common.IIdentifiableEntity;
53
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
54
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
55
import eu.etaxonomy.cdm.model.common.Identifier;
56
import eu.etaxonomy.cdm.model.common.Language;
57
import eu.etaxonomy.cdm.model.common.LanguageString;
58
import eu.etaxonomy.cdm.model.description.CommonTaxonName;
59
import eu.etaxonomy.cdm.model.description.DescriptionBase;
60
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
61
import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
62
import eu.etaxonomy.cdm.model.description.Distribution;
63
import eu.etaxonomy.cdm.model.description.Feature;
64
import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
65
import eu.etaxonomy.cdm.model.description.TaxonDescription;
66
import eu.etaxonomy.cdm.model.description.TaxonInteraction;
67
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
68
import eu.etaxonomy.cdm.model.description.TextData;
69
import eu.etaxonomy.cdm.model.location.NamedArea;
70
import eu.etaxonomy.cdm.model.media.ExternalLink;
71
import eu.etaxonomy.cdm.model.media.Media;
72
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
73
import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
74
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
75
import eu.etaxonomy.cdm.model.name.NameRelationship;
76
import eu.etaxonomy.cdm.model.name.NameRelationshipType;
77
import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
78
import eu.etaxonomy.cdm.model.name.NomenclaturalSource;
79
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
80
import eu.etaxonomy.cdm.model.name.Rank;
81
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
82
import eu.etaxonomy.cdm.model.name.TaxonName;
83
import eu.etaxonomy.cdm.model.name.TextualTypeDesignation;
84
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
85
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
86
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
87
import eu.etaxonomy.cdm.model.occurrence.GatheringEvent;
88
import eu.etaxonomy.cdm.model.occurrence.MediaSpecimen;
89
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
90
import eu.etaxonomy.cdm.model.reference.NamedSource;
91
import eu.etaxonomy.cdm.model.reference.OriginalSourceType;
92
import eu.etaxonomy.cdm.model.reference.Reference;
93
import eu.etaxonomy.cdm.model.reference.ReferenceType;
94
import eu.etaxonomy.cdm.model.taxon.Classification;
95
import eu.etaxonomy.cdm.model.taxon.Synonym;
96
import eu.etaxonomy.cdm.model.taxon.Taxon;
97
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
98
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
99
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
100
import eu.etaxonomy.cdm.model.term.DefinedTerm;
101
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
102
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDtoByRankAndNameComparator;
103
import eu.etaxonomy.cdm.strategy.cache.HTMLTagRules;
104
import eu.etaxonomy.cdm.strategy.cache.TagEnum;
105
import eu.etaxonomy.cdm.strategy.cache.TaggedText;
106
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
107

    
108
/**
109
 * @author k.luther
110
 * @since 15.03.2017
111
 */
112
@Component
113
public class CdmLightClassificationExport
114
        extends CdmExportBase<CdmLightExportConfigurator, CdmLightExportState, IExportTransformer, File>{
115

    
116
    private static final long serialVersionUID = 2518643632756927053L;
117

    
118
    @Autowired
119
    private IEditGeoService geoService;
120

    
121
    public CdmLightClassificationExport() {
122
        this.ioName = this.getClass().getSimpleName();
123
    }
124

    
125
    @Override
126
    public long countSteps(CdmLightExportState state) {
127
        TaxonNodeFilter filter = state.getConfig().getTaxonNodeFilter();
128
        return getTaxonNodeService().count(filter);
129
    }
130

    
131
    @Override
132
    protected void doInvoke(CdmLightExportState state) {
133
        try {
134

    
135
            IProgressMonitor monitor = state.getConfig().getProgressMonitor();
136
            CdmLightExportConfigurator config = state.getConfig();
137
            if (config.getTaxonNodeFilter().hasClassificationFilter()) {
138
                Classification classification = getClassificationService()
139
                        .load(config.getTaxonNodeFilter().getClassificationFilter().get(0).getUuid());
140
                state.setRootId(classification.getRootNode().getUuid());
141

    
142
            } else if (config.getTaxonNodeFilter().hasSubtreeFilter()) {
143
                state.setRootId(config.getTaxonNodeFilter().getSubtreeFilter().get(0).getUuid());
144
            }
145
            @SuppressWarnings("unchecked")
146
            TaxonNodeOutStreamPartitioner<XmlExportState> partitioner = TaxonNodeOutStreamPartitioner.NewInstance(this,
147
                    state, state.getConfig().getTaxonNodeFilter(), 100, monitor, null);
148

    
149
            handleMetaData(state);
150
            monitor.subTask("Start partitioning");
151

    
152
            TaxonNode node = partitioner.next();
153
            while (node != null) {
154
                handleTaxonNode(state, node);
155
                node = partitioner.next();
156
            }
157
            // get rootNode and create helperObjects
158
            if (state.getRootId() != null) {
159
                List<TaxonNodeDto> childrenOfRoot = state.getNodeChildrenMap().get(state.getRootId());
160

    
161
                Comparator<TaxonNodeDto> comp = state.getConfig().getComparator();
162
                if (comp == null) {
163
                    comp = new TaxonNodeDtoByRankAndNameComparator();
164
                }
165
                if (childrenOfRoot != null) {
166
                    Collections.sort(childrenOfRoot, comp);
167
                    OrderHelper helper = new OrderHelper(state.getRootId());
168
                    helper.setOrderIndex(state.getActualOrderIndexAndUpdate());
169
                    state.getOrderHelperMap().put(state.getRootId(), helper);
170

    
171
                    for (TaxonNodeDto child : childrenOfRoot) {
172
                        OrderHelper childHelper = new OrderHelper(child.getTaxonUuid());
173
                        helper.addChild(childHelper);
174
                        childHelper.setOrderIndex(state.getActualOrderIndexAndUpdate());
175
                        childHelper.addChildren(
176
                                createOrderHelper(state.getNodeChildrenMap().get(child.getUuid()), state));
177
                    }
178
                }
179

    
180
                state.getNodeChildrenMap().clear();
181
                for (OrderHelper order : state.getOrderHelperMap().values()) {
182
                    setOrderIndex(state, order);
183
                }
184
            }
185

    
186
            state.getProcessor().createFinalResult(state);
187
        } catch (Exception e) {
188
            state.getResult().addException(e,
189
                    "An unexpected error occurred in main method doInvoke() " + e.getMessage());
190
            e.printStackTrace();
191
        }
192
    }
193

    
194
    private void setOrderIndex(CdmLightExportState state, OrderHelper order) {
195

    
196
        if (order.getTaxonUuid() != null
197
                && state.getProcessor().hasRecord(CdmLightExportTable.TAXON, order.getTaxonUuid().toString())) {
198
            String[] csvLine = state.getProcessor().getRecord(CdmLightExportTable.TAXON,
199
                    order.getTaxonUuid().toString());
200
            csvLine[CdmLightExportTable.TAXON.getIndex(CdmLightExportTable.SORT_INDEX)] = String
201
                    .valueOf(order.getOrderIndex());
202
        }
203

    
204
        if (order.getChildren() == null) {
205
            return;
206
        }
207
        for (OrderHelper helper : order.getChildren()) {
208
            setOrderIndex(state, helper);
209
        }
210
    }
211

    
212
    private List<OrderHelper> createOrderHelper(List<TaxonNodeDto> nodes, CdmLightExportState state) {
213
        List<TaxonNodeDto> children = nodes;
214
        // alreadySortedNodes.add(parentUuid);
215
        if (children == null) {
216
            return null;
217
        }
218
        Comparator<TaxonNodeDto> comp = state.getConfig().getComparator();
219
        if (comp == null) {
220
            comp = new TaxonNodeDtoByRankAndNameComparator();
221
        }
222
        Collections.sort(children, comp);
223
        // TODO: nochmal checken!!!
224
        OrderHelper helperChild;
225
        List<OrderHelper> childrenHelper = new ArrayList<>();
226
        for (TaxonNodeDto child : children) {
227
            helperChild = new OrderHelper(child.getTaxonUuid());
228
            helperChild.setOrderIndex(state.getActualOrderIndexAndUpdate());
229

    
230
            if (state.getNodeChildrenMap().get(child.getUuid()) != null) {
231
                children = state.getNodeChildrenMap().get(child.getUuid());
232
                helperChild.addChildren(createOrderHelper(children, state));
233
            }
234
            childrenHelper.add(helperChild);
235
        }
236
        return childrenHelper;
237
    }
238

    
239
    private void handleTaxonNode(CdmLightExportState state, TaxonNode taxonNode) {
240

    
241
        if (taxonNode == null) {
242
            String message = "TaxonNode for given taxon node UUID not found. ";
243
            // TODO
244
            state.getResult().addWarning(message);
245
        } else {
246
            try {
247
                TaxonNode root = taxonNode;
248
                List<TaxonNodeDto> childNodes;
249
                if (root.hasChildNodes()) {
250
                    childNodes = new ArrayList<>();
251
                    for (TaxonNode child : root.getChildNodes()) {
252
                    	if (child != null) {
253
                    		childNodes.add(new TaxonNodeDto(child));
254
                    	}
255
                    }
256
                    state.getNodeChildrenMap().put(root.getUuid(), childNodes);
257

    
258
                    // add root to node map
259
                }
260
                TaxonNodeDto rootDto = new TaxonNodeDto(root);
261
                UUID parentUuid = root.getParent() != null ? root.getParent().getUuid()
262
                        : state.getClassificationUUID(root);
263
                List<TaxonNodeDto> children = state.getNodeChildrenMap().get(parentUuid);
264
                if (children != null && !children.contains(rootDto)) {
265
                    state.getNodeChildrenMap().get(parentUuid).add(rootDto);
266
                } else if (state.getNodeChildrenMap().get(parentUuid) == null) {
267
                    List<TaxonNodeDto> rootList = new ArrayList<>();
268
                    rootList.add(rootDto);
269
                    state.getNodeChildrenMap().put(parentUuid, rootList);
270
                }
271
                if (root.hasTaxon()) {
272
                    handleTaxon(state, root);
273
                }
274
            } catch (Exception e) {
275
                state.getResult().addException(e, "An unexpected error occurred when handling taxonNode "
276
                        + taxonNode.getUuid() + ": " + e.getMessage() + e.getStackTrace());
277
            }
278
        }
279
    }
280

    
281
    private void handleTaxon(CdmLightExportState state, TaxonNode taxonNode) {
282
        try {
283

    
284
            if (taxonNode == null) {
285
                state.getResult().addError("The taxonNode was null.", "handleTaxon");
286
                state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
287
                return;
288
            }
289
            if (taxonNode.getTaxon() == null) {
290
                state.getResult().addError("There was a taxon node without a taxon: " + taxonNode.getUuid(),
291
                        "handleTaxon");
292
                state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
293
            } else {
294
                Taxon taxon = CdmBase.deproxy(taxonNode.getTaxon());
295

    
296
                try {
297
                    //accepted name
298
                    TaxonName name = taxon.getName();
299
                    handleName(state, name, taxon, true);
300

    
301
                    //homotypic group / synonyms
302
                    HomotypicalGroup homotypicGroup = taxon.getHomotypicGroup();
303
                    int index = 0;
304
                    int homotypicGroupIndex = 0;
305
                    handleHomotypicalGroup(state, homotypicGroup, taxon, homotypicGroupIndex);
306
                    homotypicGroupIndex++;
307
                    for (Synonym syn : taxon.getSynonymsInGroup(homotypicGroup)) {
308
                        handleSynonym(state, syn, index);
309
                        index++;
310
                    }
311
                    List<HomotypicalGroup> heterotypicHomotypicGroups = taxon.getHeterotypicSynonymyGroups();
312
                    for (HomotypicalGroup group: heterotypicHomotypicGroups){
313
                        handleHomotypicalGroup(state, group, taxon, homotypicGroupIndex);
314
                        for (Synonym syn : taxon.getSynonymsInGroup(group)) {
315
                            handleSynonym(state, syn, index);
316
                            index++;
317
                        }
318
                        homotypicGroupIndex++;
319
                    }
320

    
321
                    //pro parte synonyms
322
                    index = 0;
323
                    for (Taxon tax : taxon.getAllProParteSynonyms()) {
324
                        handleProPartePartialMisapplied(state, tax, taxon, true, false, index);
325
                        index++;
326
                    }
327

    
328
                    //misapplications
329
                    for (Taxon tax : taxon.getAllMisappliedNames()) {
330
                        handleProPartePartialMisapplied(state, tax, taxon, false, true, index);
331
                        index++;
332
                    }
333

    
334
                    //taxon table
335
                    CdmLightExportTable table = CdmLightExportTable.TAXON;
336
                    String[] csvLine = new String[table.getSize()];
337

    
338
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_ID)] = getId(state, taxon);
339
                    csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
340
                    Taxon parent = (taxonNode.getParent() == null) ? null : taxonNode.getParent().getTaxon();
341
                    csvLine[table.getIndex(CdmLightExportTable.PARENT_FK)] = getId(state, parent);
342

    
343
                    //secundum reference
344
                    csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE_FK)] = getId(state, taxon.getSec());
345
                    if (taxon.getSec() != null && taxon.getSec().getDatePublished() != null
346
                            && taxon.getSec().getDatePublished().getFreeText() != null) {
347
                        String sec_string = taxon.getSec().getTitleCache() + ". "
348
                                + taxon.getSec().getDatePublished().getFreeText();
349
                        sec_string = sec_string.replace("..", ".");
350
                        csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = sec_string;
351
                    } else {
352
                        csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = getTitleCache(taxon.getSec());
353
                    }
354
                    if (taxon.getSec() != null) {
355
                        if (!state.getReferenceStore().contains((taxon.getSec().getUuid()))) {
356
                            handleReference(state, taxon.getSec());
357
                        }
358
                    }
359
                    //secundum subname
360
                    TaxonName subName = taxon.getSecSource() == null? null : taxon.getSecSource().getNameUsedInSource();
361
                    if (subName != null) {
362
                        csvLine[table.getIndex(CdmLightExportTable.SEC_SUBNAME_FK)] = getId(state, subName);
363
                        if (!state.getNameStore().containsKey((subName.getId()))) {
364
                            handleName(state, subName, null);
365
                        }
366
                        csvLine[table.getIndex(CdmLightExportTable.SEC_SUBNAME)] = subName.getNameCache();
367
                        csvLine[table.getIndex(CdmLightExportTable.SEC_SUBNAME_AUTHORS)] = subName.getAuthorshipCache();
368
                    }
369

    
370
                    csvLine[table.getIndex(CdmLightExportTable.APPENDED_PHRASE)] = taxon.getAppendedPhrase();
371
                    csvLine[table.getIndex(CdmLightExportTable.CLASSIFICATION_ID)] = getId(state,
372
                            taxonNode.getClassification());
373
                    csvLine[table.getIndex(CdmLightExportTable.CLASSIFICATION_TITLE)] = taxonNode.getClassification()
374
                            .getTitleCache();
375
                    csvLine[table.getIndex(CdmLightExportTable.PUBLISHED)] = taxon.isPublish() ? "1" : "0";
376

    
377
                    //taxon node
378
                    csvLine[table.getIndex(CdmLightExportTable.EXCLUDED)] = taxonNode.isExcluded() ? "1" : "0";
379
                    csvLine[table.getIndex(CdmLightExportTable.UNPLACED)] = taxonNode.isUnplaced() ? "1" : "0";
380
                    csvLine[table.getIndex(CdmLightExportTable.DOUBTFUL)] = taxonNode.isDoubtful() ? "1" : "0";
381
                    Map<Language, LanguageString> notesMap = taxonNode.getStatusNote();
382
                    String statusNotes = "";
383
                    if (!notesMap.isEmpty() && notesMap.size() == 1) {
384
                        statusNotes = notesMap.values().iterator().next().getText();
385
                    } else if (!notesMap.isEmpty()) {
386
                        statusNotes = notesMap.get(Language.getDefaultLanguage()) != null
387
                                ? notesMap.get(Language.getDefaultLanguage()).getText() : null;
388
                        if (statusNotes == null) {
389
                            statusNotes = notesMap.values().iterator().next().getText();
390
                        }
391
                    }
392
                    csvLine[table.getIndex(CdmLightExportTable.STATUS_NOTES)] = statusNotes;
393

    
394
                    if (taxonNode.getSource() != null) {
395
                        csvLine[table.getIndex(CdmLightExportTable.PLACEMENT_REF_FK)] = getId(state, taxonNode.getSource().getCitation());
396
                        String sourceStr = OriginalSourceFormatter.INSTANCE.format(taxonNode.getSource());
397
                        csvLine[table.getIndex(CdmLightExportTable.PLACEMENT_REFERENCE)] = sourceStr;
398
                    }
399

    
400
                    //process taxon line
401
                    state.getProcessor().put(table, taxon, csvLine);
402

    
403
                    //descriptions
404
                    handleDescriptions(state, taxon);
405
                } catch (Exception e) {
406
                    state.getResult().addException(e,
407
                            "An unexpected problem occurred when trying to export taxon with id " + taxon.getId() + " " + taxon.getTitleCache());
408
                    state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
409
                }
410
            }
411
        } catch (Exception e) {
412
            state.getResult().addException(e, "An unexpected error occurred when handling the taxon node of "
413
                    + cdmBaseStr(taxonNode.getTaxon()) + ", titleCache:"+ taxonNode.getTaxon().getTitleCache()+": " + e.getMessage());
414
        }
415
    }
416

    
417
    private void handleDescriptions(CdmLightExportState state, CdmBase cdmBase) {
418
        String titleCache = null;
419
        try {
420

    
421
            if (cdmBase instanceof Taxon) {
422
                Taxon taxon = HibernateProxyHelper.deproxy(cdmBase, Taxon.class);
423
                titleCache = taxon.getTitleCache();
424
                Set<TaxonDescription> descriptions = taxon.getDescriptions();
425
                List<DescriptionElementBase> simpleFacts = new ArrayList<>();
426
                List<DescriptionElementBase> specimenFacts = new ArrayList<>();
427
                List<DescriptionElementBase> distributionFacts = new ArrayList<>();
428
                List<DescriptionElementBase> taxonInteractionsFacts = new ArrayList<>();
429
                List<DescriptionElementBase> commonNameFacts = new ArrayList<>();
430
                List<DescriptionElementBase> usageFacts = new ArrayList<>();
431
                for (TaxonDescription description : descriptions) {
432
                    if (description.getElements() != null) {
433
                        for (DescriptionElementBase element : description.getElements()) {
434
                            element = CdmBase.deproxy(element);
435
                            handleAnnotations(element);
436
                            if (element.getFeature().equals(Feature.COMMON_NAME())) {
437
                                commonNameFacts.add(element);
438
                            } else if (element.getFeature().equals(Feature.DISTRIBUTION())) {
439
                                distributionFacts.add(element);
440
                            } else if (element instanceof IndividualsAssociation
441
                                    || isSpecimenFeature(element.getFeature())) {
442
                                specimenFacts.add(element);
443
                            } else if (element.getFeature().isSupportsTaxonInteraction()) {
444
                                taxonInteractionsFacts.add(element);
445
                            } else {
446
                                simpleFacts.add(element);
447
                            }
448
                        }
449
                    }
450
                }
451
                if (!commonNameFacts.isEmpty()) {
452
                    handleCommonNameFacts(state, taxon, commonNameFacts);
453
                }
454
                if (!distributionFacts.isEmpty()) {
455
                    handleDistributionFacts(state, taxon, distributionFacts);
456
                }
457
                if (!specimenFacts.isEmpty()) {
458
                    handleSpecimenFacts(state, taxon, specimenFacts);
459
                }
460
                if (!simpleFacts.isEmpty()) {
461
                    handleSimpleFacts(state, taxon, simpleFacts);
462
                }
463
                if (!taxonInteractionsFacts.isEmpty()) {
464
                    handleTaxonInteractionsFacts(state, taxon, taxonInteractionsFacts);
465
                }
466
            } else if (cdmBase instanceof TaxonName) {
467
                TaxonName name = CdmBase.deproxy(cdmBase, TaxonName.class);
468
                titleCache = name.getTitleCache();
469
                Set<TaxonNameDescription> descriptions = name.getDescriptions();
470
                List<DescriptionElementBase> simpleFacts = new ArrayList<>();
471
                for (TaxonNameDescription description : descriptions) {
472
                    if (description.getElements() != null) {
473
                        for (DescriptionElementBase element : description.getElements()) {
474
                            simpleFacts.add(element);
475
                        }
476
                    }
477
                }
478
                if (!simpleFacts.isEmpty()) {
479
                    handleSimpleFacts(state, name, simpleFacts);
480
                }
481
            }
482
        } catch (Exception e) {
483
            state.getResult().addException(e, "An unexpected error occurred when handling description of "
484
                    + cdmBaseStr(cdmBase) + (titleCache != null? (" " +titleCache) : "")+": " + e.getMessage());
485
        }
486
    }
487

    
488
    private void handleAnnotations(DescriptionElementBase element) {
489
        // TODO Auto-generated method stub
490
    }
491

    
492
    private void handleMetaData(CdmLightExportState state) {
493
        CdmLightExportTable table = CdmLightExportTable.METADATA;
494
        String[] csvLine = new String[table.getSize()];
495
//        csvLine[table.getIndex(CdmLightExportTable.INSTANCE_ID)] = state.getConfig().getInctanceId();
496
//        csvLine[table.getIndex(CdmLightExportTable.INSTANCE_NAME)] = state.getConfig().getInstanceName();
497
        csvLine[table.getIndex(CdmLightExportTable.DATASET_BASE_URL)] = state.getConfig().getBase_url();
498
        csvLine[table.getIndex(CdmLightExportTable.DATASET_CONTRIBUTOR)] = state.getConfig().getContributor();
499
        csvLine[table.getIndex(CdmLightExportTable.DATASET_CREATOR)] = state.getConfig().getCreator();
500
        csvLine[table.getIndex(CdmLightExportTable.DATASET_DESCRIPTION)] = state.getConfig().getDescription();
501
        csvLine[table.getIndex(CdmLightExportTable.DATASET_DOWNLOAD_LINK)] = state.getConfig().getDataset_download_link();
502
        csvLine[table.getIndex(CdmLightExportTable.DATASET_KEYWORDS)] = state.getConfig().getKeywords();
503
        csvLine[table.getIndex(CdmLightExportTable.DATASET_LANDINGPAGE)] = state.getConfig().getDataSet_landing_page();
504

    
505
        csvLine[table.getIndex(CdmLightExportTable.DATASET_LANGUAGE)] = state.getConfig().getLanguage() != null? state.getConfig().getLanguage().getLabel(): null;
506
        csvLine[table.getIndex(CdmLightExportTable.DATASET_LICENCE)] = state.getConfig().getLicence();
507
        csvLine[table.getIndex(CdmLightExportTable.DATASET_LOCATION)] = state.getConfig().getLocation();
508
        csvLine[table.getIndex(CdmLightExportTable.DATASET_RECOMMENDED_CITATTION)] = state.getConfig().getRecommended_citation();
509
        csvLine[table.getIndex(CdmLightExportTable.DATASET_TITLE)] = state.getConfig().getTitle();
510
        state.getProcessor().put(table, "", csvLine);
511
    }
512

    
513
    private boolean isSpecimenFeature(Feature feature) {
514
        // TODO allow user defined specimen features
515
        if (feature == null) {
516
            return false;
517
        } else if (feature.isSupportsIndividualAssociation()) {
518
            return true;
519
        } else {
520
            return feature.equals(Feature.SPECIMEN()) || feature.equals(Feature.INDIVIDUALS_ASSOCIATION())
521
                    || feature.equals(Feature.MATERIALS_EXAMINED()) || feature.equals(Feature.OBSERVATION())
522
                    || feature.equals(Feature.OCCURRENCE());
523
        }
524
    }
525

    
526
    private void handleSimpleFacts(CdmLightExportState state, CdmBase cdmBase,
527
            List<DescriptionElementBase> simpleFacts) {
528
        String titleCache = null;
529
        try {
530
            CdmLightExportTable table;
531
            if (cdmBase instanceof TaxonName) {
532
                titleCache = ((TaxonName)cdmBase).getTitleCache();
533
                table = CdmLightExportTable.NAME_FACT;
534
            } else {
535
                if (cdmBase instanceof Taxon){
536
                    titleCache = ((Taxon)cdmBase).getTitleCache();
537
                }
538
                table = CdmLightExportTable.SIMPLE_FACT;
539
            }
540
            CdmLightExportTable tableMedia = CdmLightExportTable.MEDIA;
541
            for (DescriptionElementBase element : simpleFacts) {
542
                if (element.getModifyingText().isEmpty() && !element.getMedia().isEmpty()) {
543
                    handleSimpleMediaFact(state, cdmBase, tableMedia, element);
544
                } else {
545
                    handleSingleSimpleFact(state, cdmBase, table, element);
546
                }
547
            }
548
        } catch (Exception e) {
549
            state.getResult().addException(e, "An unexpected error occurred when handling simple facts for "
550
                    + cdmBaseStr(cdmBase) + (titleCache != null? (" " +titleCache) : "")+ ": " + e.getMessage());
551
        }
552
    }
553

    
554
    private void handleTaxonInteractionsFacts(CdmLightExportState state, CdmBase cdmBase,
555
            List<DescriptionElementBase> taxonInteractionsFacts) {
556
        CdmLightExportTable table = CdmLightExportTable.TAXON_INTERACTION_FACT;
557
        String titleCache = null;
558
        if (cdmBase instanceof TaxonBase){
559
            titleCache = ((TaxonBase)cdmBase).getTitleCache();
560
        }
561
        for (DescriptionElementBase element : taxonInteractionsFacts) {
562

    
563
            try {
564

    
565
                String[] csvLine = new String[table.getSize()];
566

    
567
                csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
568
                handleSource(state, element, table);
569
                csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
570
                csvLine[table.getIndex(CdmLightExportTable.TAXON2_FK)] = getId(state,
571
                        ((TaxonInteraction) element).getTaxon2());
572
                csvLine[table.getIndex(CdmLightExportTable.DESCRIPTION)] = createMultilanguageString(
573
                        ((TaxonInteraction) element).getDescription());
574
                state.getProcessor().put(table, element, csvLine);
575

    
576
            } catch (Exception e) {
577
                state.getResult().addException(e, "An unexpected error occurred when handling taxon interaction"
578
                        + cdmBaseStr(element) + (titleCache != null? (" " +titleCache) : "")+ ": " + e.getMessage());
579
            }
580
        }
581
    }
582

    
583
    private void handleSimpleMediaFact(CdmLightExportState state, CdmBase cdmBase, CdmLightExportTable table,
584
            DescriptionElementBase element) {
585
        try {
586
            String[] csvLine;
587
            handleSource(state, element, CdmLightExportTable.MEDIA);
588

    
589
            if (element instanceof TextData) {
590
                TextData textData = (TextData) element;
591
                csvLine = new String[table.getSize()];
592
                csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
593
                if (cdmBase instanceof Taxon) {
594
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
595
                    csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = "";
596
                } else if (cdmBase instanceof TaxonName) {
597
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = "";
598
                    csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, cdmBase);
599
                }
600

    
601
                String mediaUris = "";
602
                for (Media media : textData.getMedia()) {
603
                    String mediaString = extractMediaUris(media.getRepresentations().iterator());
604
                    if (!StringUtils.isBlank(mediaString)) {
605
                        mediaUris += mediaString + ";";
606
                    } else {
607
                        state.getResult().addWarning("Empty Media object for " + cdmBase.getUserFriendlyTypeName() + " "
608
                                + cdmBase.getUuid() + " (media: " + media.getUuid() + ")");
609
                    }
610
                }
611
                csvLine[table.getIndex(CdmLightExportTable.MEDIA_URI)] = mediaUris;
612

    
613
            }
614
        } catch (Exception e) {
615
            state.getResult().addException(e, "An unexpected error occurred when handling single simple fact "
616
                    + cdmBaseStr(element) + ": " + e.getMessage());
617
        }
618

    
619
    }
620

    
621
    private void handleSingleSimpleFact(CdmLightExportState state, CdmBase cdmBase, CdmLightExportTable table,
622
            DescriptionElementBase element) {
623
        try {
624
            String[] csvLine;
625
            handleSource(state, element, CdmLightExportTable.SIMPLE_FACT);
626

    
627
            if (element instanceof TextData) {
628
                TextData textData = (TextData) element;
629
                csvLine = new String[table.getSize()];
630
                csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
631
                if (cdmBase instanceof Taxon) {
632
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
633
                } else if (cdmBase instanceof TaxonName) {
634
                    csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, cdmBase);
635
                }
636
                csvLine[table.getIndex(CdmLightExportTable.FACT_CATEGORY)] = textData.getFeature().getLabel();
637

    
638
                String mediaUris = "";
639
                for (Media media : textData.getMedia()) {
640
                    String mediaString = extractMediaUris(media.getRepresentations().iterator());
641
                    if (!StringUtils.isBlank(mediaString)) {
642
                        mediaUris += mediaString + ";";
643
                    } else {
644
                        state.getResult().addWarning("Empty Media object for uuid: " + cdmBase.getUuid()
645
                                + " uuid of media: " + media.getUuid());
646
                    }
647
                }
648
                csvLine[table.getIndex(CdmLightExportTable.MEDIA_URI)] = mediaUris;
649
                if (textData.getFeature().equals(Feature.CITATION())) {
650
                    state.getProcessor().put(table, textData, csvLine);
651
                } else if (!textData.getMultilanguageText().isEmpty()) {
652
                    for (Language language : textData.getMultilanguageText().keySet()) {
653
                        String[] csvLineLanguage = csvLine.clone();
654
                        LanguageString langString = textData.getLanguageText(language);
655
                        String text = langString.getText();
656
                        if (state.getConfig().isFilterIntextReferences()) {
657
                            text = filterIntextReferences(langString.getText());
658
                        }
659
                        csvLineLanguage[table.getIndex(CdmLightExportTable.FACT_TEXT)] = text;
660
                        csvLineLanguage[table.getIndex(CdmLightExportTable.LANGUAGE)] = language.getLabel();
661
                        state.getProcessor().put(table, textData, csvLineLanguage);
662
                    }
663
                } else {
664
                    state.getProcessor().put(table, textData, csvLine);
665
                }
666
            }
667
        } catch (Exception e) {
668
            state.getResult().addException(e, "An unexpected error occurred when handling single simple fact "
669
                    + cdmBaseStr(element) + ": " + e.getMessage());
670
        }
671
    }
672

    
673
    private String filterIntextReferences(String text) {
674
        /*
675
         * (<cdm:reference cdmId='fbd19251-efee-4ded-b780-915000f66d41'
676
         * intextId='1352d42c-e201-4155-a02a-55360d3b563e'>Ridley in Fl. Malay
677
         * Pen. 3 (1924) 22</cdm:reference>)
678
         */
679
        String newText = text.replaceAll("<cdm:reference cdmId='[a-z0-9\\-]*' intextId='[a-z0-9\\-]*'>", "");
680
        newText = newText.replaceAll("</cdm:reference>", "");
681

    
682
        newText = newText.replaceAll("<cdm:key cdmId='[a-z0-9\\-]*' intextId='[a-z0-9\\-]*'>", "");
683
        newText = newText.replaceAll("</cdm:key>", "");
684
        return newText;
685
    }
686

    
687
    private void handleSpecimenFacts(CdmLightExportState state, Taxon taxon,
688
            List<DescriptionElementBase> specimenFacts) {
689
        CdmLightExportTable table = CdmLightExportTable.SPECIMEN_FACT;
690

    
691
        for (DescriptionElementBase element : specimenFacts) {
692
            try {
693
                String[] csvLine = new String[table.getSize()];
694
                csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
695
                csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, taxon);
696
                handleSource(state, element, table);
697
                csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_NOTES)] = createAnnotationsString(
698
                        element.getAnnotations());
699

    
700
                if (element instanceof IndividualsAssociation) {
701

    
702
                    IndividualsAssociation indAssociation = (IndividualsAssociation) element;
703
                    if (indAssociation.getAssociatedSpecimenOrObservation() == null) {
704
                        state.getResult()
705
                                .addWarning("There is an individual association with no specimen associated (Taxon "
706
                                        + taxon.getTitleCache() + "(" + taxon.getUuid() + "). Could not be exported.");
707
                        continue;
708
                    } else {
709
                        if (!state.getSpecimenStore()
710
                                .contains((indAssociation.getAssociatedSpecimenOrObservation().getUuid()))) {
711
                            SpecimenOrObservationBase<?> specimenBase = HibernateProxyHelper.deproxy(
712
                                    indAssociation.getAssociatedSpecimenOrObservation(),
713
                                    SpecimenOrObservationBase.class);
714

    
715
                            handleSpecimen(state, specimenBase);
716
                            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_FK)] = getId(state,
717
                                    indAssociation.getAssociatedSpecimenOrObservation());
718
                        }
719
                    }
720
                } else if (element instanceof TextData) {
721
                    TextData textData = HibernateProxyHelper.deproxy(element, TextData.class);
722
                    csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_DESCRIPTION)] = createMultilanguageString(
723
                            textData.getMultilanguageText());
724
                }
725
                state.getProcessor().put(table, element, csvLine);
726
            } catch (Exception e) {
727
                state.getResult().addException(e, "An unexpected error occurred when handling single specimen fact "
728
                        + cdmBaseStr(element) + ": " + e.getMessage());
729
            }
730
        }
731
    }
732

    
733
    private String createMultilanguageString(Map<Language, LanguageString> multilanguageText) {
734
        String text = "";
735
        int index = multilanguageText.size();
736
        for (LanguageString langString : multilanguageText.values()) {
737
            text += langString.getText();
738
            if (index > 1) {
739
                text += "; ";
740
            }
741
            index--;
742
        }
743
        return text;
744
    }
745

    
746
    private String createAnnotationsString(Set<Annotation> annotations) {
747
        StringBuffer strBuff = new StringBuffer();
748

    
749
        for (Annotation ann : annotations) {
750
            if (ann.getAnnotationType() == null || !ann.getAnnotationType().equals(AnnotationType.TECHNICAL())) {
751
                strBuff.append(ann.getText());
752
                strBuff.append("; ");
753
            }
754
        }
755

    
756
        if (strBuff.length() > 2) {
757
            return strBuff.substring(0, strBuff.length() - 2);
758
        } else {
759
            return null;
760
        }
761
    }
762

    
763
    private void handleSource(CdmLightExportState state, DescriptionElementBase element,
764
            CdmLightExportTable factsTable) {
765
        CdmLightExportTable table = CdmLightExportTable.FACT_SOURCES;
766
        try {
767
            Set<DescriptionElementSource> sources = element.getSources();
768

    
769
            for (DescriptionElementSource source : sources) {
770
                if (!(source.getType().equals(OriginalSourceType.Import)
771
                        && state.getConfig().isExcludeImportSources())) {
772
                    String[] csvLine = new String[table.getSize()];
773
                    Reference ref = source.getCitation();
774
                    if ((ref == null) && (source.getNameUsedInSource() == null)) {
775
                        continue;
776
                    }
777
                    if (ref != null) {
778
                        if (!state.getReferenceStore().contains(ref.getUuid())) {
779
                            handleReference(state, ref);
780

    
781
                        }
782
                        csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)] = getId(state, ref);
783
                    }
784
                    csvLine[table.getIndex(CdmLightExportTable.FACT_FK)] = getId(state, element);
785

    
786
                    csvLine[table.getIndex(CdmLightExportTable.NAME_IN_SOURCE_FK)] = getId(state,
787
                            source.getNameUsedInSource());
788
                    csvLine[table.getIndex(CdmLightExportTable.FACT_TYPE)] = factsTable.getTableName();
789
                    if (StringUtils.isBlank(csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)])
790
                            && StringUtils.isBlank(csvLine[table.getIndex(CdmLightExportTable.NAME_IN_SOURCE_FK)])) {
791
                        continue;
792
                    }
793
                    state.getProcessor().put(table, source, csvLine);
794
                }
795

    
796
            }
797
        } catch (Exception e) {
798
            state.getResult().addException(e, "An unexpected error occurred when handling single source "
799
                    + cdmBaseStr(element) + ": " + e.getMessage());
800
        }
801

    
802
    }
803

    
804
    private void handleDistributionFacts(CdmLightExportState state, Taxon taxon,
805
            List<DescriptionElementBase> distributionFacts) {
806

    
807
        CdmLightExportTable table = CdmLightExportTable.GEOGRAPHIC_AREA_FACT;
808
        Set<Distribution> distributions = new HashSet<>();
809
        for (DescriptionElementBase element : distributionFacts) {
810
            try {
811
                if (element instanceof Distribution) {
812
                    String[] csvLine = new String[table.getSize()];
813
                    Distribution distribution = (Distribution) element;
814
                    distributions.add(distribution);
815
                    csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
816
                    handleSource(state, element, table);
817
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, taxon);
818
                    if (distribution.getArea() != null) {
819
                        csvLine[table.getIndex(CdmLightExportTable.AREA_LABEL)] = distribution.getArea().getLabel();
820
                    }
821
                    if (distribution.getStatus() != null) {
822
                        csvLine[table.getIndex(CdmLightExportTable.STATUS_LABEL)] = distribution.getStatus().getLabel();
823
                    }
824
                    state.getProcessor().put(table, distribution, csvLine);
825
                } else {
826
                    state.getResult()
827
                            .addError("The distribution description for the taxon " + taxon.getUuid()
828
                                    + " is not of type distribution. Could not be exported. UUID of the description element: "
829
                                    + element.getUuid());
830
                }
831
            } catch (Exception e) {
832
                state.getResult().addException(e, "An unexpected error occurred when handling single distribution "
833
                        + cdmBaseStr(element) + ": " + e.getMessage());
834
            }
835
        }
836
         if(state.getConfig().isCreateCondensedDistributionString()){
837
             List<Language> langs = new ArrayList<>();
838
             langs.add(Language.ENGLISH());
839

    
840
             CondensedDistribution conDis = geoService.getCondensedDistribution(
841
                     //TODO add CondensedDistributionConfiguration to export configuration
842
                     distributions, true, null, state.getConfig().getCondensedDistributionConfiguration(), langs);
843
             CdmLightExportTable tableCondensed =
844
                     CdmLightExportTable.SIMPLE_FACT;
845
             String[] csvLine = new String[tableCondensed.getSize()];
846
             //the computed fact has no uuid, TODO: remember the uuid for later reference assignment
847
             UUID randomUuid = UUID.randomUUID();
848
             csvLine[tableCondensed.getIndex(CdmLightExportTable.FACT_ID)] =
849
                     randomUuid.toString();
850
             csvLine[tableCondensed.getIndex(CdmLightExportTable.TAXON_FK)] =
851
                     getId(state, taxon);
852
             csvLine[tableCondensed.getIndex(CdmLightExportTable.FACT_TEXT)] =
853
                     conDis.toString();
854
             csvLine[tableCondensed.getIndex(CdmLightExportTable.LANGUAGE)] =Language.ENGLISH().toString();
855

    
856
             csvLine[tableCondensed.getIndex(CdmLightExportTable.FACT_CATEGORY)] =
857
                     "CondensedDistribution";
858

    
859
             state.getProcessor().put(tableCondensed, taxon, csvLine);
860
         }
861
    }
862

    
863
    private void handleCommonNameFacts(CdmLightExportState state, Taxon taxon,
864
            List<DescriptionElementBase> commonNameFacts) {
865
        CdmLightExportTable table = CdmLightExportTable.COMMON_NAME_FACT;
866

    
867
        for (DescriptionElementBase element : commonNameFacts) {
868
            try {
869
                if (element instanceof CommonTaxonName) {
870
                    String[] csvLine = new String[table.getSize()];
871
                    CommonTaxonName commonName = (CommonTaxonName) element;
872
                    csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
873
                    handleSource(state, element, table);
874
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, taxon);
875
                    if (commonName.getName() != null) {
876
                        csvLine[table.getIndex(CdmLightExportTable.FACT_TEXT)] = commonName.getName();
877
                    }
878
                    if (commonName.getLanguage() != null) {
879
                        csvLine[table.getIndex(CdmLightExportTable.LANGUAGE)] = commonName.getLanguage().getLabel();
880
                    }
881
                    if (commonName.getArea() != null) {
882
                        csvLine[table.getIndex(CdmLightExportTable.AREA_LABEL)] = commonName.getArea().getLabel();
883
                    }
884
                    state.getProcessor().put(table, commonName, csvLine);
885
                } else if (element instanceof TextData){
886
                    String[] csvLine = new String[table.getSize()];
887
                    TextData commonName = (TextData) element;
888
                    csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
889
                    handleSource(state, element, table);
890
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, taxon);
891
                    if (commonName.getMultilanguageText() != null) {
892
                        csvLine[table.getIndex(CdmLightExportTable.FACT_TEXT)] = createMultilanguageString(commonName.getMultilanguageText());
893
                    }
894
                    state.getProcessor().put(table, commonName, csvLine);
895
                } else {
896
                    state.getResult()
897
                            .addError("The common name description for the taxon " + taxon.getUuid()
898
                                    + " is not of type common name. Could not be exported. UUID of the description element: "
899
                                    + element.getUuid());
900
                }
901
            } catch (Exception e) {
902
                state.getResult().addException(e, "An unexpected error occurred when handling single common name "
903
                        + cdmBaseStr(element) + " - "+taxon.getTitleCache()+ ": " + e.getMessage());
904
            }
905
        }
906
    }
907

    
908
    private String getTitleCache(IIdentifiableEntity identEntity) {
909
        if (identEntity == null) {
910
            return "";
911
        }
912
        // TODO refresh?
913
        return identEntity.getTitleCache();
914
    }
915

    
916
    private String getId(CdmLightExportState state, ICdmBase cdmBase) {
917
        if (cdmBase == null) {
918
            return "";
919
        }
920
        // TODO make configurable
921
        return cdmBase.getUuid().toString();
922
    }
923

    
924
    private void handleSynonym(CdmLightExportState state, Synonym synonym, int index) {
925
        try {
926
            if (isUnpublished(state.getConfig(), synonym)) {
927
                return;
928
            }
929
            TaxonName name = synonym.getName();
930
            handleName(state, name, synonym.getAcceptedTaxon());
931

    
932
            CdmLightExportTable table = CdmLightExportTable.SYNONYM;
933
            String[] csvLine = new String[table.getSize()];
934

    
935
            csvLine[table.getIndex(CdmLightExportTable.SYNONYM_ID)] = getId(state, synonym);
936
            csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, synonym.getAcceptedTaxon());
937
            csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
938
            if (synonym.getSec() != null && !state.getReferenceStore().contains(synonym.getSec().getUuid())) {
939
                handleReference(state, synonym.getSec());
940
            }
941
            csvLine[table.getIndex(CdmLightExportTable.APPENDED_PHRASE)] = synonym.getAppendedPhrase();
942
            csvLine[table.getIndex(CdmLightExportTable.SYN_SEC_REFERENCE_FK)] = getId(state, synonym.getSec());
943
            csvLine[table.getIndex(CdmLightExportTable.SYN_SEC_REFERENCE)] = getTitleCache(synonym.getSec());
944
            csvLine[table.getIndex(CdmLightExportTable.PUBLISHED)] = synonym.isPublish() ? "1" : "0";
945
            csvLine[table.getIndex(CdmLightExportTable.IS_PRO_PARTE)] = "0";
946
            csvLine[table.getIndex(CdmLightExportTable.IS_PARTIAL)] = "0";
947
            csvLine[table.getIndex(CdmLightExportTable.IS_MISAPPLIED)] = "0";
948
            csvLine[table.getIndex(CdmLightExportTable.SORT_INDEX)] = String.valueOf(index);
949
            state.getProcessor().put(table, synonym, csvLine);
950
        } catch (Exception e) {
951
            state.getResult().addException(e, "An unexpected error occurred when handling synonym "
952
                    + cdmBaseStr(synonym) + ": " + e.getMessage());
953
        }
954
    }
955

    
956
    /**
957
     * Handles misapplied names (including pro parte and partial as well as pro
958
     * parte and partial synonyms
959
     */
960
    private void handleProPartePartialMisapplied(CdmLightExportState state, Taxon taxon, Taxon accepted, boolean isProParte, boolean isMisapplied, int index) {
961
        try {
962
            Taxon ppSyonym = taxon;
963
            if (isUnpublished(state.getConfig(), ppSyonym)) {
964
                return;
965
            }
966
            TaxonName name = ppSyonym.getName();
967
            handleName(state, name, accepted);
968

    
969
            CdmLightExportTable table = CdmLightExportTable.SYNONYM;
970
            String[] csvLine = new String[table.getSize()];
971

    
972
            csvLine[table.getIndex(CdmLightExportTable.SYNONYM_ID)] = getId(state, ppSyonym);
973
            csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, accepted);
974
            csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
975

    
976
            Reference secRef = ppSyonym.getSec();
977

    
978
            if (secRef != null && !state.getReferenceStore().contains(secRef.getUuid())) {
979
                handleReference(state, secRef);
980
            }
981
            csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE_FK)] = getId(state, secRef);
982
            csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = getTitleCache(secRef);
983
            Set<TaxonRelationship> rels = accepted.getTaxonRelations(ppSyonym);
984
            TaxonRelationship rel = null;
985
            boolean isPartial = false;
986
            if (rels.size() == 1){
987
                rel = rels.iterator().next();
988

    
989
            }else if (rels.size() > 1){
990
                Iterator<TaxonRelationship> iterator = rels.iterator();
991
                while (iterator.hasNext()){
992
                    rel = iterator.next();
993
                    if (isProParte && rel.getType().isAnySynonym()){
994
                        break;
995
                    } else if (isMisapplied && rel.getType().isAnyMisappliedName()){
996
                        break;
997
                    }else{
998
                        rel = null;
999
                    }
1000
                }
1001
            }
1002
            if (rel != null){
1003
                Reference synSecRef = rel.getCitation();
1004
                if (synSecRef != null && !state.getReferenceStore().contains(synSecRef.getUuid())) {
1005
                    handleReference(state, synSecRef);
1006
                }
1007
                csvLine[table.getIndex(CdmLightExportTable.SYN_SEC_REFERENCE_FK)] = getId(state, synSecRef);
1008
                csvLine[table.getIndex(CdmLightExportTable.SYN_SEC_REFERENCE)] = getTitleCache(synSecRef);
1009
                isProParte = rel.getType().isProParte();
1010
                isPartial = rel.getType().isPartial();
1011

    
1012
            }else{
1013
                state.getResult().addWarning("An unexpected error occurred when handling "
1014
                        + "pro parte/partial synonym or misapplied name  " + cdmBaseStr(taxon) );
1015
            }
1016

    
1017
            // pro parte type
1018

    
1019
            csvLine[table.getIndex(CdmLightExportTable.IS_PRO_PARTE)] = isProParte ? "1" : "0";
1020
            csvLine[table.getIndex(CdmLightExportTable.IS_PARTIAL)] = isPartial ? "1" : "0";
1021
            csvLine[table.getIndex(CdmLightExportTable.IS_MISAPPLIED)] = isMisapplied ? "1" : "0";
1022
            csvLine[table.getIndex(CdmLightExportTable.SORT_INDEX)] = String.valueOf(index);
1023
            state.getProcessor().put(table, ppSyonym, csvLine);
1024
        } catch (Exception e) {
1025
            state.getResult().addException(e, "An unexpected error occurred when handling "
1026
                    + "pro parte/partial synonym or misapplied name  " + cdmBaseStr(taxon) + ": " + e.getMessage());
1027
        }
1028

    
1029
    }
1030

    
1031
    private void handleName(CdmLightExportState state, TaxonName name, Taxon acceptedTaxon){
1032
        handleName(state, name, acceptedTaxon, false);
1033
    }
1034

    
1035
    private void handleName(CdmLightExportState state, TaxonName name, Taxon acceptedTaxon, boolean acceptedName) {
1036
        if (name == null || state.getNameStore().containsKey(name.getId())) {
1037
            return;
1038
        }
1039
        try {
1040
            Rank rank = name.getRank();
1041
            CdmLightExportTable table = CdmLightExportTable.SCIENTIFIC_NAME;
1042
            name = HibernateProxyHelper.deproxy(name);
1043
            state.getNameStore().put(name.getId(), name.getUuid());
1044
            String[] csvLine = new String[table.getSize()];
1045

    
1046
            csvLine[table.getIndex(CdmLightExportTable.NAME_ID)] = getId(state, name);
1047
            if (name.getLsid() != null) {
1048
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = name.getLsid().getLsid();
1049
            } else {
1050
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = "";
1051
            }
1052

    
1053
            handleIdentifier(state, name);
1054
            handleDescriptions(state, name);
1055

    
1056
            csvLine[table.getIndex(CdmLightExportTable.RANK)] = getTitleCache(rank);
1057
            if (rank != null) {
1058
                csvLine[table.getIndex(CdmLightExportTable.RANK_SEQUENCE)] = String.valueOf(rank.getOrderIndex());
1059
                if (rank.isInfraGeneric()) {
1060
                    try {
1061
                        csvLine[table.getIndex(CdmLightExportTable.INFRAGENERIC_RANK)] = name.getRank()
1062
                                .getInfraGenericMarker();
1063
                    } catch (UnknownCdmTypeException e) {
1064
                        state.getResult().addError("Infrageneric marker expected but not available for rank "
1065
                                + name.getRank().getTitleCache());
1066
                    }
1067
                }
1068
                if (rank.isInfraSpecific()) {
1069
                    csvLine[table.getIndex(CdmLightExportTable.INFRASPECIFIC_RANK)] = name.getRank().getAbbreviation();
1070
                }
1071
            } else {
1072
                csvLine[table.getIndex(CdmLightExportTable.RANK_SEQUENCE)] = "";
1073
            }
1074
            if (name.isProtectedTitleCache()) {
1075
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_AUTHORS)] = name.getTitleCache();
1076
            } else {
1077
                // TODO: adapt the tropicos titlecache creation
1078
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_AUTHORS)] = name.getTitleCache();
1079
            }
1080

    
1081

    
1082
            if (!state.getConfig().isAddHTML()) {
1083
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_REF)] = name.getFullTitleCache();
1084
            } else {
1085
                List<TaggedText> taggedFullTitleCache = name.getTaggedFullTitle();
1086
                List<TaggedText> taggedName = name.getTaggedName();
1087

    
1088
                String fullTitleWithHtml = createNameWithItalics(taggedFullTitleCache);
1089
                // TODO: adapt the tropicos titlecache creation
1090
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_REF)] = fullTitleWithHtml.trim();
1091
            }
1092

    
1093
            csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_NO_AUTHORS)] = name.getNameCache();
1094
            csvLine[table.getIndex(CdmLightExportTable.GENUS_UNINOMIAL)] = name.getGenusOrUninomial();
1095

    
1096
            csvLine[table.getIndex(CdmLightExportTable.INFRAGENERIC_EPITHET)] = name.getInfraGenericEpithet();
1097
            csvLine[table.getIndex(CdmLightExportTable.SPECIFIC_EPITHET)] = name.getSpecificEpithet();
1098

    
1099
            csvLine[table.getIndex(CdmLightExportTable.INFRASPECIFIC_EPITHET)] = name.getInfraSpecificEpithet();
1100

    
1101
            csvLine[table.getIndex(CdmLightExportTable.APPENDED_PHRASE)] = name.getAppendedPhrase();
1102

    
1103
            csvLine[table.getIndex(CdmLightExportTable.BAS_AUTHORTEAM_FK)] = getId(state, name.getBasionymAuthorship());
1104
            if (name.getBasionymAuthorship() != null) {
1105
                if (state.getAuthorFromStore(name.getBasionymAuthorship().getId()) == null) {
1106
                    handleAuthor(state, name.getBasionymAuthorship());
1107
                }
1108
            }
1109
            csvLine[table.getIndex(CdmLightExportTable.BAS_EX_AUTHORTEAM_FK)] = getId(state,
1110
                    name.getExBasionymAuthorship());
1111
            if (name.getExBasionymAuthorship() != null) {
1112
                if (state.getAuthorFromStore(name.getExBasionymAuthorship().getId()) == null) {
1113
                    handleAuthor(state, name.getExBasionymAuthorship());
1114
                }
1115

    
1116
            }
1117
            csvLine[table.getIndex(CdmLightExportTable.COMB_AUTHORTEAM_FK)] = getId(state,
1118
                    name.getCombinationAuthorship());
1119
            if (name.getCombinationAuthorship() != null) {
1120
                if (state.getAuthorFromStore(name.getCombinationAuthorship().getId()) == null) {
1121
                    handleAuthor(state, name.getCombinationAuthorship());
1122
                }
1123
            }
1124
            csvLine[table.getIndex(CdmLightExportTable.COMB_EX_AUTHORTEAM_FK)] = getId(state,
1125
                    name.getExCombinationAuthorship());
1126
            if (name.getExCombinationAuthorship() != null) {
1127
                if (state.getAuthorFromStore(name.getExCombinationAuthorship().getId()) == null) {
1128
                    handleAuthor(state, name.getExCombinationAuthorship());
1129
                }
1130

    
1131
            }
1132

    
1133
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_TEAM_STRING)] = name.getAuthorshipCache();
1134

    
1135
            Reference nomRef = name.getNomenclaturalReference();
1136

    
1137
            NomenclaturalSource nomenclaturalSource = name.getNomenclaturalSource();
1138
            if (nomenclaturalSource != null &&nomenclaturalSource.getNameUsedInSource() != null){
1139
                handleName(state, nomenclaturalSource.getNameUsedInSource(), null);
1140
                csvLine[table.getIndex(CdmLightExportTable.NAME_USED_IN_SOURCE_FK)] = getId(state, nomenclaturalSource.getNameUsedInSource());
1141
            }
1142

    
1143
            if (nomRef != null) {
1144
                if (!state.getReferenceStore().contains(nomRef.getUuid())) {
1145
                    handleReference(state, nomRef);
1146
                }
1147
                csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)] = getId(state, nomRef);
1148
                csvLine[table.getIndex(CdmLightExportTable.PUBLICATION_TYPE)] = nomRef.getType().name();
1149
                if (nomRef.getVolume() != null) {
1150
                    csvLine[table.getIndex(CdmLightExportTable.VOLUME_ISSUE)] = nomRef.getVolume();
1151
                    csvLine[table.getIndex(CdmLightExportTable.COLLATION)] = createCollatation(name);
1152
                }
1153
                if (nomRef.getDatePublished() != null) {
1154
                    csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = nomRef.getTimePeriodPublishedString();
1155
                    csvLine[table.getIndex(CdmLightExportTable.YEAR_PUBLISHED)] = nomRef.getDatePublished().getYear();
1156
                    csvLine[table.getIndex(CdmLightExportTable.VERBATIM_DATE)] = nomRef.getDatePublished()
1157
                            .getVerbatimDate();
1158
                }
1159
                if (name.getNomenclaturalMicroReference() != null) {
1160
                    csvLine[table.getIndex(CdmLightExportTable.DETAIL)] = name.getNomenclaturalMicroReference();
1161
                }
1162
                nomRef = HibernateProxyHelper.deproxy(nomRef);
1163
                if (nomRef.getInReference() != null) {
1164
                    Reference inReference = nomRef.getInReference();
1165
                    if (inReference.getDatePublished() != null && nomRef.getDatePublished() == null) {
1166
                        csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = inReference
1167
                                .getDatePublishedString();
1168
                        csvLine[table.getIndex(CdmLightExportTable.YEAR_PUBLISHED)] = inReference.getDatePublished()
1169
                                .getYear();
1170
                    }
1171
                    if (nomRef.getVolume() == null && inReference.getVolume() != null) {
1172
                        csvLine[table.getIndex(CdmLightExportTable.VOLUME_ISSUE)] = inReference.getVolume();
1173
                        csvLine[table.getIndex(CdmLightExportTable.COLLATION)] = createCollatation(name);
1174
                    }
1175
                    if (inReference.getInReference() != null) {
1176
                        inReference = inReference.getInReference();
1177
                    }
1178
                    if (inReference.getAbbrevTitle() == null) {
1179
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils
1180
                                .Nz(inReference.getTitle());
1181
                    } else {
1182
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils
1183
                                .Nz(inReference.getAbbrevTitle());
1184
                    }
1185
                    if (inReference.getTitle() == null) {
1186
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils
1187
                                .Nz(inReference.getAbbrevTitle()!= null? inReference.getAbbrevTitle(): inReference.getTitleCache());
1188
                    } else {
1189
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(inReference.getTitle());
1190
                    }
1191

    
1192
                    TeamOrPersonBase<?> author = inReference.getAuthorship();
1193
                    if (author != null
1194
                            && (nomRef.isOfType(ReferenceType.BookSection) || nomRef.isOfType(ReferenceType.Section))) {
1195
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = author.isProtectedTitleCache()
1196
                                ? author.getTitleCache() : CdmUtils.Nz(author.getNomenclaturalTitleCache());
1197
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = CdmUtils
1198
                                .Nz(author.getTitleCache());
1199
                    } else {
1200
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = "";
1201
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = "";
1202
                    }
1203
                } else {
1204
                    if (nomRef.getAbbrevTitle() == null) {
1205
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils
1206
                                .Nz(nomRef.getTitle()!= null? nomRef.getTitle():nomRef.getAbbrevTitleCache());
1207
                    } else {
1208
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils
1209
                                .Nz(nomRef.getAbbrevTitle());
1210
                    }
1211
                    if (nomRef.getTitle() == null) {
1212
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] =  CdmUtils
1213
                                .Nz(nomRef.getAbbrevTitle()!= null? nomRef.getAbbrevTitle(): nomRef.getTitleCache());
1214
                    } else {
1215
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(nomRef.getTitle());
1216
                    }
1217
                    TeamOrPersonBase<?> author = nomRef.getAuthorship();
1218
                    if (author != null) {
1219
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = author.isProtectedTitleCache()
1220
                                ? author.getTitleCache() : CdmUtils.Nz(author.getNomenclaturalTitleCache());
1221
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = CdmUtils
1222
                                .Nz(author.getTitleCache());
1223
                    } else {
1224
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = "";
1225
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = "";
1226
                    }
1227

    
1228
                }
1229
            } else {
1230
                csvLine[table.getIndex(CdmLightExportTable.PUBLICATION_TYPE)] = "";
1231
            }
1232

    
1233
            /*
1234
             * Collation
1235
             *
1236
             * Detail
1237
             *
1238
             * TitlePageYear
1239
             */
1240
            String protologueUriString = extractProtologueURIs(state, name);
1241

    
1242
            csvLine[table.getIndex(CdmLightExportTable.PROTOLOGUE_URI)] = protologueUriString;
1243
            Collection<TypeDesignationBase> specimenTypeDesignations = new ArrayList<>();
1244
            List<TextualTypeDesignation> textualTypeDesignations = new ArrayList<>();
1245
            for (TypeDesignationBase<?> typeDesignation : name.getTypeDesignations()) {
1246
                if (typeDesignation.isInstanceOf(TextualTypeDesignation.class)) {
1247

    
1248
                    if (((TextualTypeDesignation) typeDesignation).isVerbatim() ){
1249
                        Set<IdentifiableSource> sources =  typeDesignation.getSources();
1250
                        boolean isProtologue = false;
1251
                        if (sources != null && !sources.isEmpty()){
1252
                            IdentifiableSource source = sources.iterator().next();
1253
                            if (name.getNomenclaturalReference() != null){
1254
                                isProtologue = source.getCitation() != null? source.getCitation().getUuid().equals(name.getNomenclaturalReference().getUuid()): false;
1255
                            }
1256
                        }
1257
                        if (isProtologue){
1258
                            csvLine[table.getIndex(CdmLightExportTable.PROTOLOGUE_TYPE_STATEMENT)] = ((TextualTypeDesignation) typeDesignation)
1259
                                    .getPreferredText(Language.DEFAULT());
1260
                        }else{
1261
                            textualTypeDesignations.add((TextualTypeDesignation) typeDesignation);
1262
                        }
1263

    
1264
                    } else {
1265
                        textualTypeDesignations.add((TextualTypeDesignation) typeDesignation);
1266
                    }
1267
                } else if (typeDesignation.isInstanceOf(SpecimenTypeDesignation.class)) {
1268
                    SpecimenTypeDesignation specimenType = HibernateProxyHelper.deproxy(typeDesignation, SpecimenTypeDesignation.class);
1269
                    specimenTypeDesignations.add(specimenType);
1270
                    handleSpecimenType(state, specimenType);
1271

    
1272

    
1273
                }else if (typeDesignation instanceof NameTypeDesignation){
1274
                    specimenTypeDesignations.add(HibernateProxyHelper.deproxy(typeDesignation, NameTypeDesignation.class));
1275
                }
1276
            }
1277
            TypeDesignationSetContainer manager = new TypeDesignationSetContainer(specimenTypeDesignations, name);
1278
            HTMLTagRules rules = new HTMLTagRules();
1279
            rules.addRule(TagEnum.name, "i");
1280
            csvLine[table.getIndex(CdmLightExportTable.TYPE_SPECIMEN)] = manager.print(false, false, false, rules);
1281

    
1282
            StringBuilder stringbuilder = new StringBuilder();
1283
            int i = 1;
1284
            for (TextualTypeDesignation typeDesignation : textualTypeDesignations) {
1285
                stringbuilder.append(typeDesignation.getPreferredText(Language.DEFAULT()));
1286
                if (typeDesignation.getSources() != null && !typeDesignation.getSources().isEmpty() ){
1287
                    stringbuilder.append( " [");
1288
                    int index = 1;
1289
                    for (IdentifiableSource source: typeDesignation.getSources()){
1290
                        if (source.getCitation() != null){
1291
                            stringbuilder.append(OriginalSourceFormatter.INSTANCE.format(source));
1292
                        }
1293
                        if (index < typeDesignation.getSources().size()) {
1294
                            stringbuilder.append( ", ");
1295
                        }
1296
                        index++;
1297
                    }
1298
                    stringbuilder.append( "]");
1299
                }
1300
                if (i < textualTypeDesignations.size()) {
1301
                    stringbuilder.append( "; ");
1302
                } else {
1303
                    stringbuilder.append(".");
1304
                }
1305
                i++;
1306
            }
1307
            csvLine[table.getIndex(CdmLightExportTable.TYPE_STATEMENT)] = stringbuilder.toString();
1308

    
1309

    
1310
            if (name.getStatus() == null || name.getStatus().isEmpty()) {
1311
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS)] = "";
1312
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS_ABBREV)] = "";
1313
            } else {
1314

    
1315
                String statusStringAbbrev = extractStatusString(state, name, true);
1316
                String statusString = extractStatusString(state, name, false);
1317

    
1318
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS)] = statusString.trim();
1319
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS_ABBREV)] = statusStringAbbrev.trim();
1320
            }
1321

    
1322
            HomotypicalGroup group = HibernateProxyHelper.deproxy(name.getHomotypicalGroup(), HomotypicalGroup.class);
1323

    
1324
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_FK)] = getId(state, group);
1325
            List<TaxonName> typifiedNames = new ArrayList<>();
1326
            if (acceptedTaxon != null){
1327
                HomotypicGroupTaxonComparator comparator = new HomotypicGroupTaxonComparator(acceptedTaxon);
1328
                List<Synonym> synonymsInGroup = null;
1329
                if (group.equals(acceptedTaxon.getHomotypicGroup())){
1330
                    synonymsInGroup = acceptedTaxon.getHomotypicSynonymsByHomotypicGroup(comparator);
1331
                    typifiedNames.add(name);
1332
                }else{
1333
                    synonymsInGroup = acceptedTaxon.getSynonymsInGroup(group, comparator);
1334
                }
1335

    
1336
                synonymsInGroup.stream().forEach(synonym -> typifiedNames.add(HibernateProxyHelper.deproxy(synonym.getName(), TaxonName.class)));
1337

    
1338
            }else{
1339
                typifiedNames.addAll(group.getTypifiedNames());
1340
            }
1341

    
1342

    
1343
            Integer seqNumber = typifiedNames.indexOf(name);
1344
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_SEQ)] = String.valueOf(seqNumber);
1345
            state.getProcessor().put(table, name, csvLine);
1346
            handleNameRelationships(state, name);
1347

    
1348
        } catch (Exception e) {
1349
            state.getResult().addException(e,
1350
                    "An unexpected error occurred when handling the name " + cdmBaseStr(name) + ": " + name.getTitleCache() + ": " + e.getMessage());
1351

    
1352
            e.printStackTrace();
1353
        }
1354
    }
1355

    
1356
    /**
1357
     * @param specimenType
1358
     */
1359
    private void handleSpecimenType_(CdmLightExportState state, SpecimenTypeDesignation specimenType) {
1360
        if (specimenType.getTypeSpecimen() != null){
1361
            DerivedUnit specimen =  specimenType.getTypeSpecimen();
1362
            if(specimen != null && !state.getSpecimenStore().contains( specimen.getUuid())){
1363
               handleSpecimen(state, specimen);
1364
            }
1365
        }
1366
        CdmLightExportTable table = CdmLightExportTable.TYPE_DESIGNATION;
1367
        String[] csvLine = new String[table.getSize()];
1368
        //TYPE_ID, SPECIMEN_FK, TYPE_VERBATIM_CITATION, TYPE_STATUS, TYPE_DESIGNATED_BY_STRING, TYPE_DESIGNATED_BY_REF_FK};
1369
        //Specimen_Fk und den Typusangaben (Art des Typus [holo, lecto, etc.], Quelle, Designation-Quelle, +
1370
        Set<TaxonName> typifiedNames = specimenType.getTypifiedNames();
1371
        for (TaxonName name: typifiedNames){
1372
            csvLine[table.getIndex(CdmLightExportTable.TYPE_STATUS)] = specimenType.getTypeStatus() != null? specimenType.getTypeStatus().getDescription(): "";
1373
            csvLine[table.getIndex(CdmLightExportTable.TYPE_ID)] = getId(state, specimenType);
1374
            csvLine[table.getIndex(CdmLightExportTable.TYPIFIED_NAME_FK)] = getId(state, name);
1375
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_FK)] = getId(state, specimenType.getTypeSpecimen());
1376
            if (specimenType.getSources() != null && !specimenType.getSources().isEmpty()){
1377
                String sourceString = "";
1378
                int index = 0;
1379
                for (IdentifiableSource source: specimenType.getSources()){
1380
                    if (source.getCitation()!= null){
1381
                        sourceString = sourceString.concat(source.getCitation().getCitation());
1382
                    }
1383
                    index++;
1384
                    if (index != specimenType.getSources().size()){
1385
                        sourceString.concat(", ");
1386
                    }
1387
                }
1388
                csvLine[table.getIndex(CdmLightExportTable.TYPE_INFORMATION_REF_STRING)] = sourceString;
1389
            }
1390
            if (specimenType.getDesignationSource() != null && specimenType.getDesignationSource().getCitation() != null && !state.getReferenceStore().contains(specimenType.getDesignationSource().getCitation().getUuid())){
1391
                handleReference(state, specimenType.getDesignationSource().getCitation());
1392
                csvLine[table.getIndex(CdmLightExportTable.TYPE_DESIGNATED_BY_REF_FK)] = specimenType.getDesignationSource() != null ? getId(state, specimenType.getDesignationSource().getCitation()): "";
1393
            }
1394

    
1395
            state.getProcessor().put(table, specimenType, csvLine);
1396
        }
1397
    }
1398

    
1399

    
1400
    /**
1401
     * @param specimenType
1402
     */
1403
    private void handleSpecimenType(CdmLightExportState state, SpecimenTypeDesignation specimenType) {
1404
        if (specimenType.getTypeSpecimen() != null){
1405
            DerivedUnit specimen =  specimenType.getTypeSpecimen();
1406
            if(specimen != null && !state.getSpecimenStore().contains( specimen.getUuid())){
1407
               handleSpecimen(state, specimen);
1408
            }
1409
        }
1410
        CdmLightExportTable table = CdmLightExportTable.TYPE_DESIGNATION;
1411
        String[] csvLine = new String[table.getSize()];
1412

    
1413
        csvLine[table.getIndex(CdmLightExportTable.TYPE_STATUS)] = specimenType.getTypeStatus() != null? specimenType.getTypeStatus().getDescription(): "";
1414
        csvLine[table.getIndex(CdmLightExportTable.TYPE_ID)] = getId(state, specimenType);
1415
        csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_FK)] = getId(state, specimenType.getTypeSpecimen());
1416
        if (specimenType.getSources() != null && !specimenType.getSources().isEmpty()){
1417
            String sourceString = "";
1418
            int index = 0;
1419
            List<IdentifiableSource> sources = new ArrayList<>(specimenType.getSources());
1420
            Comparator<IdentifiableSource> compareByYear = new Comparator<IdentifiableSource>() {
1421
                @Override
1422
                public int compare(IdentifiableSource o1, IdentifiableSource o2) {
1423
                    if (o1 == o2){
1424
                        return 0;
1425
                    }
1426
                    if (o1.getCitation() == null && o2.getCitation() != null){
1427
                        return -1;
1428
                    }
1429
                    if (o2.getCitation() == null && o1.getCitation() != null){
1430
                        return 1;
1431
                    }
1432
                    if (o1.getCitation().equals(o2.getCitation())){
1433
                        return 0;
1434
                    }
1435
                    if (o1.getCitation().getDatePublished() == null && o2.getCitation().getDatePublished() != null){
1436
                        return -1;
1437
                    }
1438
                    if (o1.getCitation().getDatePublished() != null && o2.getCitation().getDatePublished() == null){
1439
                        return 1;
1440
                    }
1441
                    if (o1.getCitation().getDatePublished().getYear() == null && o2.getCitation().getDatePublished().getYear() != null){
1442
                        return -1;
1443
                    }
1444
                    if (o1.getCitation().getDatePublished().getYear() != null && o2.getCitation().getDatePublished().getYear() == null){
1445
                        return 1;
1446
                    }
1447
                    return o1.getCitation().getDatePublished().getYear().compareTo(o2.getCitation().getDatePublished().getYear());
1448
                }
1449
            };
1450
            Collections.sort(sources, compareByYear);
1451
            for (IdentifiableSource source: sources){
1452
                if (source.getCitation()!= null){
1453
                    sourceString = sourceString.concat(source.getCitation().getCitation());
1454
                    handleReference(state, source.getCitation());
1455
                }
1456
                index++;
1457
                if (index <= specimenType.getSources().size()){
1458
                    sourceString = sourceString.concat("; ");
1459
                }
1460
            }
1461

    
1462
            csvLine[table.getIndex(CdmLightExportTable.TYPE_INFORMATION_REF_STRING)] = sourceString;
1463
            if (sources.get(0).getCitation() != null ){
1464
                csvLine[table.getIndex(CdmLightExportTable.TYPE_INFORMATION_REF_FK)] = getId(state, sources.get(0).getCitation());
1465
            }
1466
        }
1467
        if (specimenType.getDesignationSource() != null && specimenType.getDesignationSource().getCitation() != null && !state.getReferenceStore().contains(specimenType.getDesignationSource().getCitation().getUuid())){
1468
            handleReference(state, specimenType.getDesignationSource().getCitation());
1469
            csvLine[table.getIndex(CdmLightExportTable.TYPE_DESIGNATED_BY_REF_FK)] = specimenType.getDesignationSource() != null ? getId(state, specimenType.getDesignationSource().getCitation()): "";
1470
        }
1471

    
1472

    
1473
        Set<TaxonName> typifiedNames = specimenType.getTypifiedNames();
1474

    
1475
        if (typifiedNames.size() > 1){
1476
            state.getResult().addWarning("Please check the specimen type  "
1477
                    + cdmBaseStr(specimenType) + " there are more then one typified name.");
1478
        }
1479
        if (typifiedNames.iterator().hasNext()){
1480
            TaxonName name = typifiedNames.iterator().next();
1481
            csvLine[table.getIndex(CdmLightExportTable.TYPIFIED_NAME_FK)] = getId(state, name);
1482
        }
1483
        state.getProcessor().put(table, specimenType, csvLine);
1484

    
1485

    
1486

    
1487

    
1488

    
1489
    }
1490

    
1491

    
1492
    private String createNameWithItalics(List<TaggedText> taggedName) {
1493

    
1494
        String fullTitleWithHtml = "";
1495
        for (TaggedText taggedText: taggedName){
1496
            if (taggedText.getType().equals(TagEnum.name)){
1497
                fullTitleWithHtml += "<i>" + taggedText.getText() + "</i> ";
1498
            }else if (taggedText.getType().equals(TagEnum.separator)){
1499
                fullTitleWithHtml = fullTitleWithHtml.trim() + taggedText.getText() ;
1500
            }else{
1501
                fullTitleWithHtml += taggedText.getText() + " ";
1502
            }
1503
        }
1504
        return fullTitleWithHtml;
1505
    }
1506

    
1507
    private void handleNameRelationships(CdmLightExportState state, TaxonName name) {
1508
        Set<NameRelationship> rels = name.getRelationsFromThisName();
1509
        CdmLightExportTable table = CdmLightExportTable.NAME_RELATIONSHIP;
1510
        String[] csvLine = new String[table.getSize()];
1511

    
1512
        for (NameRelationship rel : rels) {
1513
            NameRelationshipType type = rel.getType();
1514
            TaxonName name2 = rel.getToName();
1515
            name2 = HibernateProxyHelper.deproxy(name2, TaxonName.class);
1516
            if (!state.getNameStore().containsKey(name2.getId())) {
1517
                handleName(state, name2, null);
1518
            }
1519

    
1520
            csvLine[table.getIndex(CdmLightExportTable.NAME_REL_TYPE)] = type.getLabel();
1521
            csvLine[table.getIndex(CdmLightExportTable.NAME1_FK)] = getId(state, name);
1522
            csvLine[table.getIndex(CdmLightExportTable.NAME2_FK)] = getId(state, name2);
1523
            state.getProcessor().put(table, name, csvLine);
1524
        }
1525

    
1526
        rels = name.getRelationsToThisName();
1527

    
1528
        csvLine = new String[table.getSize()];
1529

    
1530
        for (NameRelationship rel : rels) {
1531
            NameRelationshipType type = rel.getType();
1532
            TaxonName name2 = rel.getFromName();
1533
            name2 = HibernateProxyHelper.deproxy(name2, TaxonName.class);
1534
            if (!state.getNameStore().containsKey(name2.getId())) {
1535
                handleName(state, name2, null);
1536
            }
1537

    
1538

    
1539
        }
1540
    }
1541

    
1542
    private String createCollatation(TaxonName name) {
1543
        String collation = "";
1544
        if (name.getNomenclaturalReference() != null) {
1545
            Reference ref = name.getNomenclaturalReference();
1546
            collation = getVolume(ref);
1547
        }
1548
        if (name.getNomenclaturalMicroReference() != null) {
1549
            if (!StringUtils.isBlank(collation)) {
1550
                collation += ":";
1551
            }
1552
            collation += name.getNomenclaturalMicroReference();
1553
        }
1554

    
1555
        return collation;
1556
    }
1557

    
1558
    private String getVolume(Reference reference) {
1559
        if (reference.getVolume() != null) {
1560
            return reference.getVolume();
1561
        } else if (reference.getInReference() != null) {
1562
            if (reference.getInReference().getVolume() != null) {
1563
                return reference.getInReference().getVolume();
1564
            }
1565
        }
1566
        return null;
1567
    }
1568

    
1569
    private void handleIdentifier(CdmLightExportState state, CdmBase cdmBase) {
1570
        CdmLightExportTable table = CdmLightExportTable.IDENTIFIER;
1571
        String[] csvLine;
1572
        try {
1573
            if (cdmBase instanceof TaxonName){
1574
                TaxonName name = (TaxonName)cdmBase;
1575

    
1576
                try{
1577
                    List<Identifier> identifiers = name.getIdentifiers();
1578

    
1579
                    //first check which kind of identifiers are available and then sort and create table entries
1580
                    Map<DefinedTerm, Set<Identifier>> identifierTypes = new HashMap<>();
1581
                    for (Identifier identifier: identifiers){
1582
                        DefinedTerm type = identifier.getType();
1583
                        if (identifierTypes.containsKey(type)){
1584
                            identifierTypes.get(type).add(identifier);
1585
                        }else{
1586
                            Set<Identifier> tempList = new HashSet<>();
1587
                            tempList.add(identifier);
1588
                            identifierTypes.put(type, tempList);
1589
                        }
1590
                    }
1591

    
1592
                    for (DefinedTerm type:identifierTypes.keySet()){
1593
                        Set<Identifier> identifiersByType = identifierTypes.get(type);
1594
                        csvLine = new String[table.getSize()];
1595
                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, name);
1596
                        csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = "ScientificName";
1597
                        csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = type.getLabel();
1598
                        csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = extractIdentifier(
1599
                                identifiersByType);
1600
                        state.getProcessor().put(table, name.getUuid() + ", " + type.getLabel(), csvLine);
1601
                    }
1602

    
1603

    
1604
//                    Set<String> IPNIidentifiers = name.getIdentifiers(DefinedTerm.IDENTIFIER_NAME_IPNI());
1605
//                    Set<String> tropicosIdentifiers = name.getIdentifiers(DefinedTerm.IDENTIFIER_NAME_TROPICOS());
1606
//                    Set<String> WFOIdentifiers = name.getIdentifiers(DefinedTerm.uuidWfoNameIdentifier);
1607
//                    if (!IPNIidentifiers.isEmpty()) {
1608
//                        csvLine = new String[table.getSize()];
1609
//                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, name);
1610
//                        csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = "ScientificName";
1611
//                        csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = IPNI_NAME_IDENTIFIER;
1612
//                        csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = extractIdentifier(
1613
//                                IPNIidentifiers);
1614
//                        state.getProcessor().put(table, name.getUuid() + ", " + IPNI_NAME_IDENTIFIER, csvLine);
1615
//                    }
1616
//                    if (!tropicosIdentifiers.isEmpty()) {
1617
//                        csvLine = new String[table.getSize()];
1618
//                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, name);
1619
//                        csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = "ScientificName";
1620
//                        csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = TROPICOS_NAME_IDENTIFIER;
1621
//                        csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = extractIdentifier(
1622
//                                tropicosIdentifiers);
1623
//                        state.getProcessor().put(table, name.getUuid() + ", " + IPNI_NAME_IDENTIFIER, csvLine);
1624
//                    }
1625
//                    if (!WFOIdentifiers.isEmpty()) {
1626
//                        csvLine = new String[table.getSize()];
1627
//                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, name);
1628
//                        csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = "ScientificName";
1629
//                        csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = WFO_NAME_IDENTIFIER;
1630
//                        csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = extractIdentifier(
1631
//                                WFOIdentifiers);
1632
//                        state.getProcessor().put(table, name.getUuid() + ", " + WFO_NAME_IDENTIFIER, csvLine);
1633
//                    }
1634
                }catch(Exception e){
1635
                    state.getResult().addWarning("Please check the identifiers for "
1636
                            + cdmBaseStr(cdmBase) + " maybe there is an empty identifier");
1637

    
1638

    
1639
                }
1640
            }else{
1641
                if (cdmBase instanceof IdentifiableEntity){
1642
                    IdentifiableEntity<?> identifiableEntity = (IdentifiableEntity<?>) cdmBase;
1643
                    List<Identifier> identifiers = identifiableEntity.getIdentifiers();
1644
                    String tableName = null;
1645
                    if (cdmBase instanceof Reference){
1646
                        tableName = "Reference";
1647
                    }else if (cdmBase instanceof SpecimenOrObservationBase){
1648
                        tableName = "Specimen";
1649
                    }else if (cdmBase instanceof Taxon){
1650
                        tableName = "Taxon";
1651
                    }else if (cdmBase instanceof Synonym){
1652
                        tableName = "Synonym";
1653
                    }else if (cdmBase instanceof TeamOrPersonBase){
1654
                        tableName = "PersonOrTeam";
1655
                    }
1656

    
1657
                    for (Identifier identifier: identifiers){
1658
                        if (identifier.getType() == null && identifier.getIdentifier() == null){
1659
                            state.getResult().addWarning("Please check the identifiers for "
1660
                                    + cdmBaseStr(cdmBase) + " there is an empty identifier");
1661
                            continue;
1662
                        }
1663

    
1664
                        csvLine = new String[table.getSize()];
1665
                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, cdmBase);
1666

    
1667
                        if (tableName != null){
1668
                            csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = tableName;
1669
                            csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = identifier.getType() != null? identifier.getType().getLabel():null;
1670
                            csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = identifier.getIdentifier();
1671
                            state.getProcessor().put(table, cdmBase.getUuid() + (identifier.getType() != null? identifier.getType().getLabel():null), csvLine);
1672
                        }
1673
                    }
1674
                    if (cdmBase instanceof Reference ){
1675
                        Reference ref = (Reference)cdmBase;
1676
                        if (ref.getDoi() != null){
1677
                            csvLine = new String[table.getSize()];
1678
                            csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, cdmBase);
1679
                            csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = tableName;
1680
                            csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = "DOI";
1681
                            csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = ref.getDoiString();
1682
                            state.getProcessor().put(table, cdmBase.getUuid() + "DOI", csvLine);
1683
                        }
1684
                    }
1685

    
1686
                    if (cdmBase instanceof TeamOrPersonBase){
1687
                        TeamOrPersonBase<?> person= HibernateProxyHelper.deproxy(cdmBase, TeamOrPersonBase.class);
1688
                        if (person instanceof Person &&  ((Person)person).getOrcid() != null){
1689
                            csvLine = new String[table.getSize()];
1690
                            csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, cdmBase);
1691
                            csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = tableName;
1692
                            csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = "ORCID";
1693
                            csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)]=  ((Person)person).getOrcid().asURI();
1694
                            state.getProcessor().put(table, cdmBase.getUuid() + "ORCID", csvLine);
1695
                        }
1696
                    }
1697
                }
1698
            }
1699
        } catch (Exception e) {
1700
            state.getResult().addException(e, "An unexpected error occurred when handling identifiers for "
1701
                    + cdmBaseStr(cdmBase) + ": " + e.getMessage());
1702
            e.printStackTrace();
1703
        }
1704
    }
1705

    
1706
    private String extractIdentifier(Set<Identifier> identifierSet) {
1707

    
1708
        String identifierString = "";
1709
        for (Identifier identifier : identifierSet) {
1710
            if (!StringUtils.isBlank(identifierString)) {
1711
                identifierString += ", ";
1712
            }
1713
            identifierString += identifier.getIdentifier();
1714
        }
1715
        return identifierString;
1716
    }
1717

    
1718
    private String extractProtologueURIs(CdmLightExportState state, TaxonName name) {
1719
        if (name.getNomenclaturalSource() != null){
1720
            Set<ExternalLink> links = name.getNomenclaturalSource().getLinks();
1721
            return extractLinkUris(links.iterator());
1722
        }else{
1723
            return null;
1724
        }
1725
    }
1726

    
1727
    private String extractMediaURIs(CdmLightExportState state, Set<? extends DescriptionBase<?>> descriptionsSet,
1728
            Feature feature) {
1729

    
1730
        String mediaUriString = "";
1731
        Set<DescriptionElementBase> elements = new HashSet<>();
1732
        for (DescriptionBase<?> description : descriptionsSet) {
1733
            try {
1734
                if (!description.getElements().isEmpty()) {
1735
                    elements = description.getElements();
1736

    
1737
                    for (DescriptionElementBase element : elements) {
1738
                        Feature entityFeature = HibernateProxyHelper.deproxy(element.getFeature());
1739
                        if (entityFeature.equals(feature)) {
1740
                            if (!element.getMedia().isEmpty()) {
1741
                                List<Media> media = element.getMedia();
1742
                                for (Media mediaElement : media) {
1743
                                    Iterator<MediaRepresentation> it = mediaElement.getRepresentations().iterator();
1744
                                    mediaUriString = extractMediaUris(it);
1745
                                }
1746
                            }
1747
                        }
1748
                    }
1749
                }
1750
            } catch (Exception e) {
1751
                state.getResult().addException(e, "An unexpected error occurred when extracting media URIs for "
1752
                        + cdmBaseStr(description) + ": " + e.getMessage());
1753
            }
1754
        }
1755
        return mediaUriString;
1756
    }
1757

    
1758
    private void handleAuthor(CdmLightExportState state, TeamOrPersonBase<?> author) {
1759
        try {
1760
            if (state.getAuthorFromStore(author.getId()) != null) {
1761
                return;
1762
            }
1763
            state.addAuthorToStore(author);
1764
            handleIdentifier(state, author);
1765
            CdmLightExportTable table = CdmLightExportTable.NOMENCLATURAL_AUTHOR;
1766
            String[] csvLine = new String[table.getSize()];
1767
            CdmLightExportTable tableAuthorRel = CdmLightExportTable.NOMENCLATURAL_AUTHOR_TEAM_RELATION;
1768
            String[] csvLineRel = new String[tableAuthorRel.getSize()];
1769
            String[] csvLineMember = new String[table.getSize()];
1770
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_ID)] = getId(state, author);
1771
            csvLine[table.getIndex(CdmLightExportTable.ABBREV_AUTHOR)] = author.isProtectedTitleCache()
1772
                    ? author.getTitleCache() : author.getNomenclaturalTitleCache();
1773
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_TITLE)] = author.getTitleCache();
1774
            author = HibernateProxyHelper.deproxy(author);
1775
            if (author instanceof Person) {
1776
                Person authorPerson = (Person) author;
1777
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_GIVEN_NAME)] = authorPerson.getGivenName();
1778
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_FAMILY_NAME)] = authorPerson.getFamilyName();
1779
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_PREFIX)] = authorPerson.getPrefix();
1780
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_SUFFIX)] = authorPerson.getSuffix();
1781
            } else {
1782
                // create an entry in rel table and all members in author table,
1783
                // check whether the team members already in author table
1784

    
1785
                Team authorTeam = (Team) author;
1786
                int index = 0;
1787
                for (Person member : authorTeam.getTeamMembers()) {
1788
                    csvLineRel = new String[tableAuthorRel.getSize()];
1789
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_TEAM_FK)] = getId(state, authorTeam);
1790
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_FK)] = getId(state, member);
1791
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_TEAM_SEQ_NUMBER)] = String
1792
                            .valueOf(index);
1793
                    state.getProcessor().put(tableAuthorRel, authorTeam.getId() + ":" + member.getId(), csvLineRel);
1794

    
1795
                    if (state.getAuthorFromStore(member.getId()) == null) {
1796
                        state.addAuthorToStore(member);
1797
                        csvLineMember = new String[table.getSize()];
1798
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_ID)] = getId(state, member);
1799
                        csvLineMember[table.getIndex(CdmLightExportTable.ABBREV_AUTHOR)] = member
1800
                                .isProtectedTitleCache() ? member.getTitleCache() : member.getNomenclaturalTitleCache();
1801
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_TITLE)] = member.getTitleCache();
1802
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_GIVEN_NAME)] = member.getGivenName();
1803
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_FAMILY_NAME)] = member.getFamilyName();
1804
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_PREFIX)] = member.getPrefix();
1805
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_SUFFIX)] = member.getSuffix();
1806
                        state.getProcessor().put(table, member, csvLineMember);
1807
                    }
1808
                    index++;
1809
                }
1810
            }
1811
            state.getProcessor().put(table, author, csvLine);
1812
        } catch (Exception e) {
1813
            state.getResult().addException(e,
1814
                    "An unexpected error occurred when handling author " + cdmBaseStr(author) + ": " + e.getMessage());
1815
        }
1816
    }
1817

    
1818
    private String extractStatusString(CdmLightExportState state, TaxonName name, boolean abbrev) {
1819
        try {
1820
            Set<NomenclaturalStatus> status = name.getStatus();
1821
            if (status.isEmpty()) {
1822
                return "";
1823
            }
1824
            String statusString = "";
1825
            for (NomenclaturalStatus nameStatus : status) {
1826
                if (nameStatus != null) {
1827
                    if (abbrev) {
1828
                        if (nameStatus.getType() != null) {
1829
                            statusString += nameStatus.getType().getIdInVocabulary();
1830
                        }
1831
                    } else {
1832
                        if (nameStatus.getType() != null) {
1833
                            statusString += nameStatus.getType().getTitleCache();
1834
                        }
1835
                    }
1836
                    if (!abbrev) {
1837

    
1838
                        if (nameStatus.getRuleConsidered() != null
1839
                                && !StringUtils.isBlank(nameStatus.getRuleConsidered())) {
1840
                            statusString += ": " + nameStatus.getRuleConsidered();
1841
                        }
1842
                        if (nameStatus.getCitation() != null) {
1843
                            String shortCitation = OriginalSourceFormatter.INSTANCE.format(nameStatus.getCitation(), null);
1844
                            statusString += " (" + shortCitation + ")";
1845
                        }
1846
//                        if (nameStatus.getCitationMicroReference() != null
1847
//                                && !StringUtils.isBlank(nameStatus.getCitationMicroReference())) {
1848
//                            statusString += " " + nameStatus.getCitationMicroReference();
1849
//                        }
1850
                    }
1851
                    statusString += " ";
1852
                }
1853
            }
1854
            return statusString;
1855
        } catch (Exception e) {
1856
            state.getResult().addException(e, "An unexpected error occurred when extracting status string for "
1857
                    + cdmBaseStr(name) + ": " + e.getMessage());
1858
            return "";
1859
        }
1860
    }
1861

    
1862
    private void handleHomotypicalGroup(CdmLightExportState state, HomotypicalGroup group, Taxon acceptedTaxon, int sortIndex) {
1863
        try {
1864
            state.addHomotypicalGroupToStore(group);
1865
            CdmLightExportTable table = CdmLightExportTable.HOMOTYPIC_GROUP;
1866
            String[] csvLine = new String[table.getSize()];
1867
            csvLine[table.getIndex(CdmLightExportTable.SORT_INDEX)] = String.valueOf(sortIndex);
1868
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_ID)] = getId(state, group);
1869

    
1870
            List<TaxonName> typifiedNames = new ArrayList<>();
1871
            if (acceptedTaxon != null){
1872
                List<Synonym> synonymsInGroup = acceptedTaxon.getSynonymsInGroup(group);
1873
                if (group.equals(acceptedTaxon.getHomotypicGroup())){
1874
                    typifiedNames.add(acceptedTaxon.getName());
1875
                }
1876
                synonymsInGroup.stream().forEach(synonym -> typifiedNames.add(CdmBase.deproxy(synonym.getName())));
1877
            }
1878

    
1879

    
1880
            TaxonName firstname = null;
1881
            for (TaxonName name: typifiedNames){
1882
                Iterator<Taxon> taxa = name.getTaxa().iterator();
1883
                while(taxa.hasNext()){
1884
                    Taxon taxon = taxa.next();
1885
                    if(!(taxon.isMisapplication() || taxon.isProparteSynonym())){
1886
                        firstname = name;
1887
                        break;
1888
                    }
1889
                }
1890
            }
1891

    
1892
//            Collections.sort(typifiedNames, new HomotypicalGroupNameComparator(firstname, true));
1893
            String typifiedNamesString = "";
1894
            String typifiedNamesWithSecString = "";
1895
            String typifiedNamesWithoutAccepted = "";
1896
            String typifiedNamesWithoutAcceptedWithSec = "";
1897
            int index = 0;
1898
            for (TaxonName name : typifiedNames) {
1899
                // Concatenated output string for homotypic group (names and
1900
                // citations) + status + some name relations (e.g. “non”)
1901
                // TODO: nameRelations, which and how to display
1902
                Set<TaxonBase> taxonBases = name.getTaxonBases();
1903
                TaxonBase<?> taxonBase;
1904

    
1905
                String sec = "";
1906
                String nameString = name.getFullTitleCache();
1907
                String doubtful = "";
1908

    
1909
                if (state.getConfig().isAddHTML()){
1910
                    nameString = createNameWithItalics(name.getTaggedFullTitle()) ;
1911
                }
1912

    
1913
                Set<NameRelationship> related = name.getNameRelations();
1914
                List<NameRelationship> relatedList = new ArrayList<>(related);
1915

    
1916
                Collections.sort(relatedList, new Comparator<NameRelationship>() {
1917
                    @Override
1918
                    public int compare(NameRelationship nr1, NameRelationship nr2) {
1919
                        return nr1.getType().compareTo(nr2.getType());
1920
                    }
1921

    
1922
                });
1923

    
1924
                List<NameRelationship> nonNames = new ArrayList<>();
1925
                List<NameRelationship> otherRelationships = new ArrayList<>();
1926

    
1927
                for (NameRelationship rel: relatedList){
1928
                    //no inverse relations
1929
                    if (rel.getFromName().equals(name)){
1930
                     // alle Homonyme und inverse blocking names
1931
                        if (rel.getType().equals(NameRelationshipType.LATER_HOMONYM())
1932
                                || rel.getType().equals(NameRelationshipType.TREATED_AS_LATER_HOMONYM())
1933
                                || (rel.getType().equals(NameRelationshipType.BLOCKING_NAME_FOR()))
1934
                                || (rel.getType().equals(NameRelationshipType.UNSPECIFIC_NON()))){
1935
                            nonNames.add(rel);
1936
                        }else if (!rel.getType().isBasionymRelation()){
1937
                            otherRelationships.add(rel);
1938
                        }
1939
                    }
1940
                }
1941

    
1942
                String nonRelNames = "";
1943
                String relNames = "";
1944

    
1945
                if (nonNames.size() > 0){
1946
                    nonRelNames += " [";
1947
                }
1948
                for (NameRelationship relName: nonNames){
1949
                    String label = "non ";
1950
                    TaxonName relatedName = null;
1951
                    if (relName.getFromName().equals(name)){
1952
                        relatedName = relName.getToName();
1953
                        nonRelNames += label + relatedName.getTitleCache() + " ";
1954
                    }
1955
//                    else{
1956
//                        label = relName.getType().getInverseLabel() + " ";
1957
//                        relatedName = relName.getFromName();
1958
//                        nonRelNames += label + relatedName.getTitleCache() + " ";
1959
//                    }
1960

    
1961

    
1962
                }
1963
                relNames.trim();
1964
                if (nonNames.size() > 0){
1965
                    nonRelNames = StringUtils.strip(nonRelNames, null);
1966
                    nonRelNames += "] ";
1967
                }
1968

    
1969
                if (otherRelationships.size() > 0){
1970
                    relNames += " [";
1971
                }
1972
                for (NameRelationship rel: otherRelationships){
1973
                    String label = "";
1974
                    TaxonName relatedName = null;
1975
                    if (rel.getFromName().equals(name)){
1976
                        label = rel.getType().getLabel() + " ";
1977
                        relatedName = rel.getToName();
1978
                        if (state.getConfig().isAddHTML()){
1979
                            relNames += label + createNameWithItalics(relatedName.getTaggedName())+ " ";
1980
                        }else{
1981
                            relNames += label + relatedName.getTitleCache();
1982
                        }
1983
                    }
1984
//                    else {
1985
//                        label = rel.getType().getInverseLabel() + " ";
1986
//                        relatedName = rel.getFromName();
1987
//                    }
1988

    
1989
                }
1990
                relNames.trim();
1991
                if (otherRelationships.size() > 0){
1992
                    relNames = StringUtils.stripEnd(relNames, null);
1993
                    relNames += "] ";
1994
                }
1995

    
1996
                String synonymSign = "";
1997
                if (index > 0){
1998
                    if (name.isInvalid()){
1999
                        synonymSign = "\u2212 ";
2000
                    }else{
2001
                        synonymSign = "\u2261 ";
2002
                    }
2003
                }else{
2004
                    if (name.isInvalid() ){
2005
                        synonymSign = "\u2212 ";
2006
                    }else{
2007
                        synonymSign = "\u003D ";
2008
                    }
2009
                }
2010
                boolean isAccepted = false;
2011

    
2012
                if (taxonBases.size() == 1){
2013
                     taxonBase = HibernateProxyHelper.deproxy(taxonBases.iterator().next());
2014

    
2015
                     if (taxonBase.getSec() != null){
2016
                         sec = OriginalSourceFormatter.INSTANCE_WITH_YEAR_BRACKETS.format(taxonBase.getSecSource());
2017
                     }
2018
                     if (taxonBase.isDoubtful()){
2019
                         doubtful = "?";
2020
                     }else{
2021
                         doubtful = "";
2022
                     }
2023
                     if (taxonBase instanceof Synonym){
2024
                         if (isNotBlank(sec)){
2025
                             sec = " syn. sec. " + sec + " ";
2026
                         }else {
2027
                             sec = "";
2028
                         }
2029

    
2030
                         typifiedNamesWithoutAccepted += synonymSign + doubtful + nameString + nonRelNames + relNames;
2031
                         typifiedNamesWithoutAcceptedWithSec += synonymSign + doubtful + nameString + sec + nonRelNames + relNames;
2032
                     }else{
2033
//                         sec = "";
2034
                         if (!(((Taxon)taxonBase).isProparteSynonym() || ((Taxon)taxonBase).isMisapplication())){
2035
                             isAccepted = true;
2036
                         }else {
2037
                             synonymSign = "\u003D ";
2038
                         }
2039

    
2040
                     }
2041
                     if (taxonBase.getAppendedPhrase() != null){
2042
                         if (state.getConfig().isAddHTML()){
2043
                             String taxonString = createNameWithItalics(taxonBase.getTaggedTitle()) ;
2044
                             taxonString = taxonString.replace("sec "+sec, "");
2045
                             String nameCacheWithItalics = createNameWithItalics(name.getTaggedName());
2046
                             nameString = nameString.replace(nameCacheWithItalics, taxonString);
2047
                         }
2048
                     }
2049
                }else{
2050
                    //there are names used more than once?
2051
                    for (TaxonBase<?> tb: taxonBases){
2052
                        if (tb.getSec() != null){
2053
                            sec = OriginalSourceFormatter.INSTANCE_WITH_YEAR_BRACKETS.format(tb.getSecSource());
2054
                        }
2055
                        if (tb.isDoubtful()){
2056
                            doubtful = "?";
2057
                        }else{
2058
                            doubtful = "";
2059
                        }
2060
                        if (tb instanceof Synonym){
2061
                            if (StringUtils.isNotBlank(sec)){
2062
                                sec = " syn. sec. " + sec + " ";
2063
                            }else {
2064
                                sec = "";
2065
                            }
2066

    
2067
                            break;
2068
                        }else{
2069
                            sec = "";
2070
                            if (!(((Taxon)tb).isProparteSynonym() || ((Taxon)tb).isMisapplication())){
2071
                                isAccepted = true;
2072
                                break;
2073
                            }else {
2074
                                synonymSign = "\u003D ";
2075
                            }
2076

    
2077
                        }
2078
                    }
2079
                    if (!isAccepted){
2080
                        typifiedNamesWithoutAccepted += synonymSign + doubtful + nameString + "; ";
2081
                        typifiedNamesWithoutAcceptedWithSec += synonymSign + doubtful + nameString + sec;
2082
                        typifiedNamesWithoutAcceptedWithSec = typifiedNamesWithoutAcceptedWithSec.trim() + "; ";
2083
                    }
2084
                }
2085
                typifiedNamesString += synonymSign + doubtful + nameString + nonRelNames + relNames;
2086
                typifiedNamesWithSecString += synonymSign + doubtful + nameString + sec + nonRelNames + relNames;
2087

    
2088

    
2089
                csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_STRING)] = typifiedNamesString.trim();
2090

    
2091
                csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITH_SEC_STRING)] = typifiedNamesWithSecString.trim();
2092

    
2093
                if (typifiedNamesWithoutAccepted != null && firstname != null) {
2094
                    csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTED)] = typifiedNamesWithoutAccepted.trim();
2095
                } else {
2096
                    csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTED)] = "";
2097
                }
2098

    
2099
                if (typifiedNamesWithoutAcceptedWithSec != null && firstname != null) {
2100
                    csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTEDWITHSEC)] = typifiedNamesWithoutAcceptedWithSec.trim();
2101
                } else {
2102
                    csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTEDWITHSEC)] = "";
2103
                }
2104
                index++;
2105
            }
2106

    
2107
            Set<TypeDesignationBase<?>> typeDesigantionSet = group.getTypeDesignations();
2108
            List<TypeDesignationBase<?>> designationList = new ArrayList<>();
2109
            designationList.addAll(typeDesigantionSet);
2110
            Collections.sort(designationList, new TypeComparator());
2111

    
2112
            List<TaggedText> list = new ArrayList<>();
2113
            if (!designationList.isEmpty()) {
2114
                TypeDesignationSetContainer manager = new TypeDesignationSetContainer(group);
2115
                list.addAll(new TypeDesignationSetFormatter(true, false, false).toTaggedText(manager));
2116
            }
2117
            String typeTextDesignations = "";
2118
            //The typeDesignationManager does not handle the textual typeDesignations
2119
            for (TypeDesignationBase<?> typeDes: designationList) {
2120
            	if (typeDes instanceof TextualTypeDesignation) {
2121
            		typeTextDesignations = typeTextDesignations + ((TextualTypeDesignation)typeDes).getText(Language.getDefaultLanguage());
2122
            		String typeDesStateRefs = "";
2123
                    if (typeDes.getDesignationSource() != null ){
2124
                        typeDesStateRefs = "[";
2125
                        NamedSource source = typeDes.getDesignationSource();
2126
                        if (source.getCitation() != null){
2127
                            typeDesStateRefs += "fide " + OriginalSourceFormatter.INSTANCE.format(source.getCitation(), null);
2128
                        }
2129
                        typeDesStateRefs += "]";
2130
                    }else if (typeDes.getSources() != null && !typeDes.getSources().isEmpty()){
2131
                        typeDesStateRefs = "[";
2132
                        for (IdentifiableSource source: typeDes.getSources()) {
2133
                            if (source.getCitation() != null){
2134
                                typeDesStateRefs += "fide " +OriginalSourceFormatter.INSTANCE.format(source.getCitation(), null);
2135
                            }
2136
                        }
2137

    
2138
                        typeDesStateRefs += "]";
2139
                    }
2140

    
2141
            		typeTextDesignations =  typeTextDesignations + typeDesStateRefs +"; ";
2142

    
2143
            	}else if (typeDes instanceof SpecimenTypeDesignation){
2144
            	    DerivedUnit specimen =  ((SpecimenTypeDesignation)typeDes).getTypeSpecimen();
2145
            	    if(specimen != null && !state.getSpecimenStore().contains( specimen.getUuid())){
2146
            	        handleSpecimen(state, specimen);
2147
            	    }
2148
            	}
2149
            }
2150
            if (typeTextDesignations.equals("; ")) {
2151
            	typeTextDesignations = "";
2152
            }
2153
            if (StringUtils.isNotBlank(typeTextDesignations)) {
2154
            	typeTextDesignations = typeTextDesignations.substring(0, typeTextDesignations.length()-2);
2155
            }
2156
            String specimenTypeString = !list.isEmpty()? createTypeDesignationString(list, true, typifiedNames.get(0).isSpecies() || typifiedNames.get(0).isInfraSpecific()):"";
2157

    
2158
            if (StringUtils.isNotBlank(specimenTypeString)) {
2159
                if (!specimenTypeString.endsWith(".")) {
2160
                	specimenTypeString = specimenTypeString + ".";
2161
                }
2162
                csvLine[table.getIndex(CdmLightExportTable.TYPE_STRING)] = specimenTypeString;
2163

    
2164
            } else {
2165
                csvLine[table.getIndex(CdmLightExportTable.TYPE_STRING)] = "";
2166
            }
2167
            if (StringUtils.isNotBlank(typeTextDesignations)) {
2168
                if (!typeTextDesignations.endsWith(".")) {
2169
                	typeTextDesignations = typeTextDesignations + ".";
2170
                }
2171
                csvLine[table.getIndex(CdmLightExportTable.TYPE_CACHE)] = typeTextDesignations;
2172

    
2173
            } else {
2174
                csvLine[table.getIndex(CdmLightExportTable.TYPE_CACHE)] = "";
2175
            }
2176
            state.getProcessor().put(table, String.valueOf(group.getId()), csvLine);
2177
        } catch (Exception e) {
2178
            state.getResult().addException(e, "An unexpected error occurred when handling homotypic group "
2179
                    + cdmBaseStr(group) + ": " + e.getMessage());
2180
        }
2181
    }
2182

    
2183
    private String createTypeDesignationString(List<TaggedText> list, boolean isHomotypicGroup, boolean isSpecimenTypeDesignation) {
2184
        StringBuffer homotypicalGroupTypeDesignationString = new StringBuffer();
2185

    
2186
        for (TaggedText text : list) {
2187
            if (text == null || text.getText() == null){
2188
                continue;  //just in case
2189
            }
2190
            if ((text.getText().equalsIgnoreCase("Type:")  //should not happen anymore
2191
                    || text.getText().equalsIgnoreCase("Nametype:")  //should not happen anymore
2192
                    || (text.getType().equals(TagEnum.name) && !isHomotypicGroup))) {
2193
                // do nothing
2194
            }else if (text.getType().equals(TagEnum.reference)) {
2195
                homotypicalGroupTypeDesignationString.append(text.getText());
2196
            }else if (text.getType().equals(TagEnum.name)){
2197
                if (!isSpecimenTypeDesignation){
2198
                    homotypicalGroupTypeDesignationString
2199
                        .append("<i>"+text.getText()+"</i> ");
2200
                }
2201
            }else if (text.getType().equals(TagEnum.typeDesignation) ) {
2202
                if(isSpecimenTypeDesignation){
2203
                    homotypicalGroupTypeDesignationString
2204
                        .append(text.getText().replace(").", "").replace("(", "").replace(")", ""));
2205
                }else{
2206
                    homotypicalGroupTypeDesignationString
2207
                        .append(text.getText());
2208
                }
2209

    
2210
            } else {
2211
                homotypicalGroupTypeDesignationString.append(text.getText());
2212
            }
2213
        }
2214

    
2215
        String typeDesignations = homotypicalGroupTypeDesignationString.toString();
2216
        typeDesignations = typeDesignations.trim();
2217

    
2218
        if (typeDesignations.endsWith(";")){
2219
            typeDesignations = typeDesignations.substring(0, typeDesignations.length()-1);
2220
        }
2221
        typeDesignations += ".";
2222
        typeDesignations = typeDesignations.replace("..", ".");
2223
        typeDesignations = typeDesignations.replace(". .", ".");
2224
        typeDesignations = typeDesignations.replace("; \u2261", " \u2261 ");
2225

    
2226
        if (typeDesignations.trim().equals(".")) {
2227
            typeDesignations = null;
2228
        }
2229

    
2230
        return typeDesignations;
2231
    }
2232

    
2233
    private String getTropicosTitleCache(CdmLightExportState state, TaxonName name) {
2234
        try {
2235
            String basionymStart = "(";
2236
            String basionymEnd = ") ";
2237
            String exAuthorSeperator = " ex ";
2238
            TeamOrPersonBase<?> combinationAuthor = name.getCombinationAuthorship();
2239
            TeamOrPersonBase<?> exCombinationAuthor = name.getExCombinationAuthorship();
2240
            TeamOrPersonBase<?> basionymAuthor = name.getBasionymAuthorship();
2241
            TeamOrPersonBase<?> exBasionymAuthor = name.getExBasionymAuthorship();
2242

    
2243
            String combinationAuthorString = "";
2244
            if (combinationAuthor != null) {
2245
                combinationAuthor = HibernateProxyHelper.deproxy(combinationAuthor);
2246
                if (combinationAuthor instanceof Team) {
2247
                    combinationAuthorString = createTropicosTeamTitle(combinationAuthor);
2248
                } else {
2249
                    Person person = HibernateProxyHelper.deproxy(combinationAuthor, Person.class);
2250
                    combinationAuthorString = createTropicosAuthorString(person);
2251
                }
2252
            }
2253
            String exCombinationAuthorString = "";
2254
            if (exCombinationAuthor != null) {
2255
                exCombinationAuthor = HibernateProxyHelper.deproxy(exCombinationAuthor);
2256
                if (exCombinationAuthor instanceof Team) {
2257
                    exCombinationAuthorString = createTropicosTeamTitle(exCombinationAuthor);
2258
                } else {
2259
                    Person person = HibernateProxyHelper.deproxy(exCombinationAuthor, Person.class);
2260
                    exCombinationAuthorString = createTropicosAuthorString(person);
2261
                }
2262
            }
2263

    
2264
            String basionymAuthorString = "";
2265
            if (basionymAuthor != null) {
2266
                basionymAuthor = HibernateProxyHelper.deproxy(basionymAuthor);
2267
                if (basionymAuthor instanceof Team) {
2268
                    basionymAuthorString = createTropicosTeamTitle(basionymAuthor);
2269
                } else {
2270
                    Person person = HibernateProxyHelper.deproxy(basionymAuthor, Person.class);
2271
                    basionymAuthorString = createTropicosAuthorString(person);
2272
                }
2273
            }
2274

    
2275
            String exBasionymAuthorString = "";
2276

    
2277
            if (exBasionymAuthor != null) {
2278
                exBasionymAuthor = HibernateProxyHelper.deproxy(exBasionymAuthor);
2279
                if (exBasionymAuthor instanceof Team) {
2280
                    exBasionymAuthorString = createTropicosTeamTitle(exBasionymAuthor);
2281

    
2282
                } else {
2283
                    Person person = HibernateProxyHelper.deproxy(exBasionymAuthor, Person.class);
2284
                    exBasionymAuthorString = createTropicosAuthorString(person);
2285
                }
2286
            }
2287
            String completeAuthorString = name.getNameCache() + " ";
2288

    
2289
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString)
2290
                    || !CdmUtils.isBlank(basionymAuthorString)) ? basionymStart : "";
2291
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString))
2292
                    ? (CdmUtils.Nz(exBasionymAuthorString) + exAuthorSeperator) : "";
2293
            completeAuthorString += (!CdmUtils.isBlank(basionymAuthorString)) ? CdmUtils.Nz(basionymAuthorString) : "";
2294
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString)
2295
                    || !CdmUtils.isBlank(basionymAuthorString)) ? basionymEnd : "";
2296
            completeAuthorString += (!CdmUtils.isBlank(exCombinationAuthorString))
2297
                    ? (CdmUtils.Nz(exCombinationAuthorString) + exAuthorSeperator) : "";
2298
            completeAuthorString += (!CdmUtils.isBlank(combinationAuthorString)) ? CdmUtils.Nz(combinationAuthorString)
2299
                    : "";
2300

    
2301
            return completeAuthorString;
2302
        } catch (Exception e) {
2303
            state.getResult().addException(e, "An unexpected error occurred when handling tropicos title cache for "
2304
                    + cdmBaseStr(name) + ": " + e.getMessage());
2305
            return null;
2306
        }
2307
    }
2308

    
2309
    private String createTropicosTeamTitle(TeamOrPersonBase<?> combinationAuthor) {
2310
        String combinationAuthorString;
2311
        Team team = HibernateProxyHelper.deproxy(combinationAuthor, Team.class);
2312
        Team tempTeam = Team.NewInstance();
2313
        for (Person teamMember : team.getTeamMembers()) {
2314
            combinationAuthorString = createTropicosAuthorString(teamMember);
2315
            Person tempPerson = Person.NewTitledInstance(combinationAuthorString);
2316
            tempTeam.addTeamMember(tempPerson);
2317
        }
2318
        combinationAuthorString = tempTeam.generateTitle();
2319
        return combinationAuthorString;
2320
    }
2321

    
2322
    private String createTropicosAuthorString(Person teamMember) {
2323
        String nomAuthorString = "";
2324
        String[] splittedAuthorString = null;
2325
        if (teamMember == null) {
2326
            return nomAuthorString;
2327
        }
2328

    
2329
        if (teamMember.getGivenName() != null) {
2330
            String givenNameString = teamMember.getGivenName().replaceAll("\\.", "\\. ");
2331
            splittedAuthorString = givenNameString.split("\\s");
2332
            for (String split : splittedAuthorString) {
2333
                if (!StringUtils.isBlank(split)) {
2334
                    nomAuthorString += split.substring(0, 1);
2335
                    nomAuthorString += ".";
2336
                }
2337
            }
2338
        }
2339
        if (teamMember.getFamilyName() != null) {
2340
            String familyNameString = teamMember.getFamilyName().replaceAll("\\.", "\\. ");
2341
            splittedAuthorString = familyNameString.split("\\s");
2342
            for (String split : splittedAuthorString) {
2343
                nomAuthorString += " " + split;
2344
            }
2345
        }
2346
        if (isBlank(nomAuthorString.trim())) {
2347
            if (teamMember.getTitleCache() != null) {
2348
                String titleCacheString = teamMember.getTitleCache().replaceAll("\\.", "\\. ");
2349
                splittedAuthorString = titleCacheString.split("\\s");
2350
            } else {
2351
                splittedAuthorString = new String[0];
2352
            }
2353

    
2354
            int index = 0;
2355
            for (String split : splittedAuthorString) {
2356
                if (index < splittedAuthorString.length - 1 && (split.length() == 1 || split.endsWith("."))) {
2357
                    nomAuthorString += split;
2358
                } else {
2359
                    nomAuthorString = nomAuthorString + " " + split;
2360
                }
2361
                index++;
2362
            }
2363
        }
2364
        return nomAuthorString.trim();
2365
    }
2366

    
2367
    private void handleReference(CdmLightExportState state, Reference reference) {
2368
        try {
2369
            state.addReferenceToStore(reference);
2370
            CdmLightExportTable table = CdmLightExportTable.REFERENCE;
2371
            reference = HibernateProxyHelper.deproxy(reference);
2372

    
2373
            handleIdentifier(state, reference);
2374
            String[] csvLine = new String[table.getSize()];
2375
            csvLine[table.getIndex(CdmLightExportTable.REFERENCE_ID)] = getId(state, reference);
2376
            // TODO short citations correctly
2377
            String shortCitation = OriginalSourceFormatter.INSTANCE_WITH_YEAR_BRACKETS.format(reference, null); // Should be Author(year) like in Taxon.sec
2378
            csvLine[table.getIndex(CdmLightExportTable.BIBLIO_SHORT_CITATION)] = shortCitation;
2379
            // TODO get preferred title
2380
            csvLine[table.getIndex(CdmLightExportTable.REF_TITLE)] = reference.isProtectedTitleCache()
2381
                    ? reference.getTitleCache() : reference.getTitle();
2382
            csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_TITLE)] = reference.isProtectedAbbrevTitleCache()
2383
                    ? reference.getAbbrevTitleCache() : reference.getAbbrevTitle();
2384
            csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = reference.getDatePublishedString();
2385
            // TBC
2386
            csvLine[table.getIndex(CdmLightExportTable.EDITION)] = reference.getEdition();
2387
            csvLine[table.getIndex(CdmLightExportTable.EDITOR)] = reference.getEditor();
2388
            csvLine[table.getIndex(CdmLightExportTable.ISBN)] = reference.getIsbn();
2389
            csvLine[table.getIndex(CdmLightExportTable.ISSN)] = reference.getIssn();
2390
            csvLine[table.getIndex(CdmLightExportTable.ORGANISATION)] = reference.getOrganization();
2391
            csvLine[table.getIndex(CdmLightExportTable.PAGES)] = reference.getPages();
2392
            csvLine[table.getIndex(CdmLightExportTable.PLACE_PUBLISHED)] = reference.getPlacePublished();
2393
            csvLine[table.getIndex(CdmLightExportTable.PUBLISHER)] = reference.getPublisher();
2394
            csvLine[table.getIndex(CdmLightExportTable.REF_ABSTRACT)] = reference.getReferenceAbstract();
2395
            csvLine[table.getIndex(CdmLightExportTable.SERIES_PART)] = reference.getSeriesPart();
2396
            csvLine[table.getIndex(CdmLightExportTable.VOLUME)] = reference.getVolume();
2397
            csvLine[table.getIndex(CdmLightExportTable.YEAR)] = reference.getYear();
2398

    
2399
            if (reference.getAuthorship() != null) {
2400
                csvLine[table.getIndex(CdmLightExportTable.AUTHORSHIP_TITLE)] = createFullAuthorship(reference);
2401
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_FK)] = getId(state, reference.getAuthorship());
2402
            }
2403

    
2404
            csvLine[table.getIndex(CdmLightExportTable.IN_REFERENCE)] = getId(state, reference.getInReference());
2405
            if (reference.getInReference() != null
2406
                    && !state.getReferenceStore().contains(reference.getInReference().getUuid())) {
2407
                handleReference(state, reference.getInReference());
2408
            }
2409
            if (reference.getInstitution() != null) {
2410
                csvLine[table.getIndex(CdmLightExportTable.INSTITUTION)] = reference.getInstitution().getTitleCache();
2411
            }
2412
            if (reference.getLsid() != null) {
2413
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = reference.getLsid().getLsid();
2414
            }
2415
            if (reference.getSchool() != null) {
2416
                csvLine[table.getIndex(CdmLightExportTable.SCHOOL)] = reference.getSchool().getTitleCache();
2417
            }
2418
            if (reference.getUri() != null) {
2419
                csvLine[table.getIndex(CdmLightExportTable.URI)] = reference.getUri().toString();
2420
            }
2421
            csvLine[table.getIndex(CdmLightExportTable.REF_TYPE)] = reference.getType().getKey();
2422

    
2423
            state.getProcessor().put(table, reference, csvLine);
2424
        } catch (Exception e) {
2425
            state.getResult().addException(e, "An unexpected error occurred when handling reference "
2426
                    + cdmBaseStr(reference) + ": " + e.getMessage());
2427
        }
2428
    }
2429

    
2430
    private String createFullAuthorship(Reference reference) {
2431
        TeamOrPersonBase<?> authorship = reference.getAuthorship();
2432
        String fullAuthorship = "";
2433
        if (authorship == null) {
2434
            return null;
2435
        }
2436
        authorship = HibernateProxyHelper.deproxy(authorship);
2437
        if (authorship instanceof Person) {
2438
            fullAuthorship = ((Person) authorship).getTitleCache();
2439

    
2440
        } else if (authorship instanceof Team) {
2441

    
2442
            Team authorTeam = (Team)authorship;
2443
            fullAuthorship = authorTeam.cacheStrategy().getTitleCache(authorTeam);
2444
        }
2445
        return fullAuthorship;
2446
    }
2447

    
2448
    private void handleSpecimen(CdmLightExportState state, SpecimenOrObservationBase<?> specimen) {
2449
        try {
2450
            state.addSpecimenToStore(specimen);
2451
            CdmLightExportTable table = CdmLightExportTable.SPECIMEN;
2452
            String specimenId = getId(state, specimen);
2453
            String[] csvLine = new String[table.getSize()];
2454

    
2455
            /*
2456
             * SpecimenCitation = “El Salvador, Municipio La Libertad, San
2457
             * Diego, El Amatal, 14.4.1993, González 159” [Auch ohne Punkt] ->
2458
             * FieldUnit TitleCache HerbariumAbbrev = “B” [wie gehabt]
2459
             * HerbariumCode
2460
             *
2461
             */
2462

    
2463
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_ID)] = specimenId;
2464
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_CITATION)] = specimen.getTitleCache();
2465
            Collection<FieldUnit> fieldUnits = this.getOccurrenceService().findFieldUnits(specimen.getUuid(), null);
2466
            if (fieldUnits.size() == 1) {
2467
                Iterator<FieldUnit> iterator = fieldUnits.iterator();
2468
                if (iterator.hasNext()){
2469
                    FieldUnit fieldUnit = iterator.next();
2470
                    csvLine[table.getIndex(CdmLightExportTable.FIELDUNIT_CITATION)] = fieldUnit.getTitleCache();
2471
                }
2472
            }
2473
            if (specimen.isInstanceOf(DerivedUnit.class)){
2474
                DerivedUnit derivedUnit = (DerivedUnit) specimen;
2475
                if (!StringUtils.isBlank(derivedUnit.getBarcode())){
2476
                    csvLine[table.getIndex(CdmLightExportTable.BARCODE)] = derivedUnit.getBarcode();
2477
                }
2478
                if (!StringUtils.isBlank(derivedUnit.getAccessionNumber())){
2479
                    csvLine[table.getIndex(CdmLightExportTable.ACCESSION_NUMBER)] = derivedUnit.getAccessionNumber();
2480
                }
2481
                if (!StringUtils.isBlank(derivedUnit.getCatalogNumber())){
2482
                    csvLine[table.getIndex(CdmLightExportTable.CATALOGUE_NUMBER)] = derivedUnit.getCatalogNumber();
2483
                }
2484
            }
2485

    
2486
            csvLine[table.getIndex(CdmLightExportTable.PREFERREDSTABLE_ID)] = specimen.getPreferredStableUri() != null? specimen.getPreferredStableUri().toString(): null;
2487
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_IMAGE_URIS)] = extractMediaURIs(state,
2488
                    specimen.getDescriptions(), Feature.IMAGE());
2489
            if (specimen instanceof DerivedUnit) {
2490
                DerivedUnit derivedUnit = HibernateProxyHelper.deproxy(specimen, DerivedUnit.class);
2491
                if (derivedUnit.getCollection() != null) {
2492
                    csvLine[table.getIndex(CdmLightExportTable.HERBARIUM_ABBREV)] = derivedUnit.getCollection()
2493
                            .getCode();
2494
                }
2495

    
2496
                if (specimen instanceof MediaSpecimen) {
2497
                    MediaSpecimen mediaSpecimen = (MediaSpecimen) specimen;
2498
                    Iterator<MediaRepresentation> it = mediaSpecimen.getMediaSpecimen().getRepresentations().iterator();
2499
                    String mediaUris = extractMediaUris(it);
2500
                    csvLine[table.getIndex(CdmLightExportTable.MEDIA_SPECIMEN_URL)] = mediaUris;
2501

    
2502
                }
2503

    
2504
                if (derivedUnit.getDerivedFrom() != null) {
2505
                    for (SpecimenOrObservationBase<?> original : derivedUnit.getDerivedFrom().getOriginals()) {
2506
                        // TODO: What to do if there are more then one
2507
                        // FieldUnit??
2508
                        if (original instanceof FieldUnit) {
2509
                            FieldUnit fieldUnit = (FieldUnit) original;
2510
                            csvLine[table.getIndex(CdmLightExportTable.COLLECTOR_NUMBER)] = fieldUnit.getFieldNumber();
2511

    
2512
                            GatheringEvent gathering = fieldUnit.getGatheringEvent();
2513
                            if (gathering != null) {
2514
                                if (gathering.getLocality() != null) {
2515
                                    csvLine[table.getIndex(CdmLightExportTable.LOCALITY)] = gathering.getLocality()
2516
                                            .getText();
2517
                                }
2518
                                if (gathering.getCountry() != null) {
2519
                                    csvLine[table.getIndex(CdmLightExportTable.COUNTRY)] = gathering.getCountry()
2520
                                            .getLabel();
2521
                                }
2522
                                csvLine[table.getIndex(CdmLightExportTable.COLLECTOR_STRING)] = createCollectorString(
2523
                                        state, gathering, fieldUnit);
2524

    
2525
                                if (gathering.getGatheringDate() != null) {
2526
                                    csvLine[table.getIndex(CdmLightExportTable.COLLECTION_DATE)] = gathering
2527
                                            .getGatheringDate().toString();
2528
                                }
2529
                                if (!gathering.getCollectingAreas().isEmpty()) {
2530
                                    int index = 0;
2531
                                    csvLine[table.getIndex(CdmLightExportTable.FURTHER_AREAS)] = "0";
2532
                                    for (NamedArea area : gathering.getCollectingAreas()) {
2533
                                        if (index == 0) {
2534
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY1)] = area.getLevel() != null?area
2535
                                                    .getLevel().getLabel():"";
2536
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME1)] = area.getLabel();
2537
                                        }
2538
                                        if (index == 1) {
2539
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY2)] = area.getLevel() != null?area
2540
                                                    .getLevel().getLabel():"";
2541
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME2)] = area.getLabel();
2542
                                        }
2543
                                        if (index == 2) {
2544
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY3)] = area.getLevel() != null?area
2545
                                                    .getLevel().getLabel():"";
2546
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME3)] = area.getLabel();
2547
                                        }
2548
                                        if (index == 3) {
2549
                                            csvLine[table.getIndex(CdmLightExportTable.FURTHER_AREAS)] = "1";
2550
                                            break;
2551
                                        }
2552
                                        index++;
2553
                                    }
2554
                                }
2555
                            }
2556
                        }
2557
                    }
2558
                } else {
2559
                    state.getResult().addWarning("The specimen with uuid " + specimen.getUuid()
2560
                            + " is not an DerivedUnit.");
2561
                }
2562
            }
2563

    
2564
            state.getProcessor().put(table, specimen, csvLine);
2565
        } catch (Exception e) {
2566
            state.getResult().addException(e, "An unexpected error occurred when handling specimen "
2567
                    + cdmBaseStr(specimen) + ": " + e.getMessage());
2568
        }
2569
    }
2570

    
2571
    private String extractMediaUris(Iterator<MediaRepresentation> it) {
2572

    
2573
        String mediaUriString = "";
2574
        boolean first = true;
2575
        while (it.hasNext()) {
2576
            MediaRepresentation rep = it.next();
2577
            List<MediaRepresentationPart> parts = rep.getParts();
2578
            for (MediaRepresentationPart part : parts) {
2579
                if (first) {
2580
                    if (part.getUri() != null) {
2581
                        mediaUriString += part.getUri().toString();
2582
                        first = false;
2583
                    }
2584
                } else {
2585
                    if (part.getUri() != null) {
2586
                        mediaUriString += ", " + part.getUri().toString();
2587
                    }
2588
                }
2589
            }
2590
        }
2591

    
2592
        return mediaUriString;
2593
    }
2594

    
2595
    private String extractLinkUris(Iterator<ExternalLink> it) {
2596

    
2597
        String linkUriString = "";
2598
        boolean first = true;
2599
        while (it.hasNext()) {
2600
            ExternalLink link = it.next();
2601
            if (first) {
2602
                if (link.getUri() != null) {
2603
                    linkUriString += link.getUri().toString();
2604
                    first = false;
2605
                }
2606
            } else {
2607
                if (link.getUri() != null) {
2608
                    linkUriString += ", " + link.getUri().toString();
2609
                }
2610
            }
2611
        }
2612
        return linkUriString;
2613
    }
2614

    
2615
    private String createCollectorString(CdmLightExportState state, GatheringEvent gathering, FieldUnit fieldUnit) {
2616
        try {
2617
            String collectorString = "";
2618
            AgentBase<?> collectorA = CdmBase.deproxy(gathering.getCollector());
2619
            if (gathering.getCollector() != null) {
2620
                if (collectorA instanceof TeamOrPersonBase && state.getConfig().isHighLightPrimaryCollector()) {
2621

    
2622
                    Person primaryCollector = fieldUnit.getPrimaryCollector();
2623
                    if (collectorA instanceof Team) {
2624
                        Team collectorTeam = (Team) collectorA;
2625
                        boolean isFirst = true;
2626
                        for (Person member : collectorTeam.getTeamMembers()) {
2627
                            if (!isFirst) {
2628
                                collectorString += "; ";
2629
                            }
2630
                            if (member.equals(primaryCollector)) {
2631
                                // highlight
2632
                                collectorString += "<b>" + member.getTitleCache() + "</b>";
2633
                            } else {
2634
                                collectorString += member.getTitleCache();
2635
                            }
2636
                        }
2637
                    }
2638
                } else {
2639
                    collectorString = collectorA.getTitleCache();
2640
                }
2641
            }
2642
            return collectorString;
2643
        } catch (Exception e) {
2644
            state.getResult().addException(e, "An unexpected error occurred when creating collector string for "
2645
                    + cdmBaseStr(fieldUnit) + ": " + e.getMessage());
2646
            return "";
2647
        }
2648
    }
2649

    
2650
    /**
2651
     * Returns a string representation of the {@link CdmBase cdmBase} object for
2652
     * result messages.
2653
     */
2654
    private String cdmBaseStr(CdmBase cdmBase) {
2655
        if (cdmBase == null) {
2656
            return "-no object available-";
2657
        } else {
2658
            return cdmBase.getClass().getSimpleName() + ": " + cdmBase.getUuid();
2659
        }
2660
    }
2661

    
2662
    @Override
2663
    protected boolean doCheck(CdmLightExportState state) {
2664
        return false;
2665
    }
2666

    
2667
    @Override
2668
    protected boolean isIgnore(CdmLightExportState state) {
2669
        return false;
2670
    }
2671

    
2672
}
(1-1/6)