Project

General

Profile

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

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

    
117
    private static final long serialVersionUID = 2518643632756927053L;
118

    
119
    @Autowired
120
    private IEditGeoService geoService;
121

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
564
            try {
565

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

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

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

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

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

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

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

    
620
    }
621

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

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

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

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

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

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

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

    
701
                if (element instanceof IndividualsAssociation) {
702

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

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

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

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

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

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

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

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

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

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

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

    
803
    }
804

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
977
            Reference secRef = ppSyonym.getSec();
978

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

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

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

    
1018
            // pro parte type
1019

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

    
1030
    }
1031

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

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

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

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

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

    
1082

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

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

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

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

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

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

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

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

    
1132
            }
1133

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

    
1136
            Reference nomRef = name.getNomenclaturalReference();
1137

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

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

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

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

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

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

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

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

    
1273

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

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

    
1310

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

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

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

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

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

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

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

    
1343

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

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

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

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

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

    
1400

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

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

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

    
1473

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

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

    
1486

    
1487

    
1488

    
1489

    
1490
    }
1491

    
1492

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

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

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

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

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

    
1527
        rels = name.getRelationsToThisName();
1528

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

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

    
1539

    
1540
        }
1541
    }
1542

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

    
1556
        return collation;
1557
    }
1558

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

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

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

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

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

    
1604

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

    
1639

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1880

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

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

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

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

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

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

    
1923
                });
1924

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

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

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

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

    
1962

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

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

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

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

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

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

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

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

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

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

    
2089

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

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

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

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

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

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

    
2139
                        typeDesStateRefs += "]";
2140
                    }
2141

    
2142
            		typeTextDesignations =  typeTextDesignations + typeDesStateRefs +"; ";
2143

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

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

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

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

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

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

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

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

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

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

    
2231
        return typeDesignations;
2232
    }
2233

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

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

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

    
2276
            String exBasionymAuthorString = "";
2277

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2441
        } else if (authorship instanceof Team) {
2442

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

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

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

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

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

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

    
2503
                }
2504

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

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

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

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

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

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

    
2593
        return mediaUriString;
2594
    }
2595

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

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

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

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

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

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

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

    
2673
}
(1-1/6)