Project

General

Profile

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

    
11
import java.io.File;
12
import java.util.ArrayList;
13
import java.util.Collection;
14
import java.util.Collections;
15
import java.util.Comparator;
16
import java.util.HashMap;
17
import java.util.HashSet;
18
import java.util.Iterator;
19
import java.util.List;
20
import java.util.Map;
21
import java.util.Set;
22
import java.util.UUID;
23

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

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

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

    
116
    private static final long serialVersionUID = 2518643632756927053L;
117

    
118
    private static final String IPNI_NAME_IDENTIFIER = "Ipni Name Identifier";
119
    private static final String TROPICOS_NAME_IDENTIFIER = "Tropicos Name Identifier";
120
    private static final String WFO_NAME_IDENTIFIER = "WFO Name Identifier";
121

    
122
    @Autowired
123
    IEditGeoService geoService;
124

    
125
    public CdmLightClassificationExport() {
126
        super();
127
        this.ioName = this.getClass().getSimpleName();
128
    }
129

    
130
    @Override
131
    public long countSteps(CdmLightExportState state) {
132
        TaxonNodeFilter filter = state.getConfig().getTaxonNodeFilter();
133
        return getTaxonNodeService().count(filter);
134
    }
135

    
136
    @Override
137
    protected void doInvoke(CdmLightExportState state) {
138
        try {
139

    
140
            IProgressMonitor monitor = state.getConfig().getProgressMonitor();
141
            CdmLightExportConfigurator config = state.getConfig();
142
            if (config.getTaxonNodeFilter().hasClassificationFilter()) {
143
                Classification classification = getClassificationService()
144
                        .load(config.getTaxonNodeFilter().getClassificationFilter().get(0).getUuid());
145
                state.setRootId(classification.getRootNode().getUuid());
146

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

    
154
            handleMetaData(state);
155
            monitor.subTask("Start partitioning");
156

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

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

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

    
185
                state.getNodeChildrenMap().clear();
186
                for (OrderHelper order : state.getOrderHelperMap().values()) {
187
                    setOrderIndex(state, order);
188
                }
189
            }
190

    
191
            state.getProcessor().createFinalResult(state);
192
        } catch (Exception e) {
193
            state.getResult().addException(e,
194
                    "An unexpected error occurred in main method doInvoke() " + e.getMessage());
195
            e.printStackTrace();
196
        }
197
    }
198

    
199
    private void setOrderIndex(CdmLightExportState state, OrderHelper order) {
200

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

    
209
        if (order.getChildren() == null) {
210
            return;
211
        }
212
        for (OrderHelper helper : order.getChildren()) {
213
            setOrderIndex(state, helper);
214
        }
215
    }
216

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

    
235
            if (state.getNodeChildrenMap().get(child.getUuid()) != null) {
236
                children = state.getNodeChildrenMap().get(child.getUuid());
237
                helperChild.addChildren(createOrderHelper(children, state));
238
            }
239
            childrenHelper.add(helperChild);
240
        }
241
        return childrenHelper;
242
    }
243

    
244
    private void handleTaxonNode(CdmLightExportState state, TaxonNode taxonNode) {
245

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

    
263
                    // add root to node map
264

    
265
                }
266
                TaxonNodeDto rootDto = new TaxonNodeDto(root);
267
                UUID parentUuid = root.getParent() != null ? root.getParent().getUuid()
268
                        : state.getClassificationUUID(root);
269
                List<TaxonNodeDto> children = state.getNodeChildrenMap().get(parentUuid);
270
                if (children != null && !children.contains(rootDto)) {
271
                    state.getNodeChildrenMap().get(parentUuid).add(rootDto);
272
                } else if (state.getNodeChildrenMap().get(parentUuid) == null) {
273
                    List<TaxonNodeDto> rootList = new ArrayList<>();
274
                    rootList.add(rootDto);
275
                    state.getNodeChildrenMap().put(parentUuid, rootList);
276

    
277
                }
278
                if (root.hasTaxon()) {
279
                    handleTaxon(state, root);
280

    
281
                }
282
            } catch (Exception e) {
283
                state.getResult().addException(e, "An unexpected error occurred when handling taxonNode "
284
                        + taxonNode.getUuid() + ": " + e.getMessage() + e.getStackTrace());
285
            }
286
        }
287
    }
288

    
289
    private void handleTaxon(CdmLightExportState state, TaxonNode taxonNode) {
290
        try {
291

    
292
            if (taxonNode == null) {
293
                state.getResult().addError("The taxonNode was null.", "handleTaxon");
294
                state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
295
                return;
296
            }
297
            if (taxonNode.getTaxon() == null) {
298
                state.getResult().addError("There was a taxon node without a taxon: " + taxonNode.getUuid(),
299
                        "handleTaxon");
300
                state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
301
            } else {
302
                Taxon taxon = CdmBase.deproxy(taxonNode.getTaxon());
303

    
304
                try {
305
                    TaxonName name = taxon.getName();
306
                    handleName(state, name, taxon, true);
307
                    HomotypicalGroup homotypicGroup = taxon.getHomotypicGroup();
308
                    int index = 0;
309
                    int homotypicGroupIndex = 0;
310
                    handleHomotypicalGroup(state, homotypicGroup, taxon, homotypicGroupIndex);
311
                    homotypicGroupIndex++;
312
                    for (Synonym syn : taxon.getSynonymsInGroup(homotypicGroup)) {
313
                        handleSynonym(state, syn, index);
314
                        index++;
315
                    }
316
                    List<HomotypicalGroup> heterotypicHomotypicGroups = taxon.getHeterotypicSynonymyGroups();
317
                    for (HomotypicalGroup group: heterotypicHomotypicGroups){
318
                        handleHomotypicalGroup(state, group, taxon, homotypicGroupIndex);
319
                        for (Synonym syn : taxon.getSynonymsInGroup(group)) {
320
                            handleSynonym(state, syn, index);
321
                            index++;
322
                        }
323
                        homotypicGroupIndex++;
324
                    }
325

    
326
                    index = 0;
327
                    for (Taxon tax : taxon.getAllProParteSynonyms()) {
328
                        handleProPartePartialMisapplied(state, tax, taxon, true, false, index);
329
                        index++;
330
                    }
331

    
332

    
333
                    for (Taxon tax : taxon.getAllMisappliedNames()) {
334
                        handleProPartePartialMisapplied(state, tax, taxon, false, true, index);
335
                        index++;
336
                    }
337

    
338
                    CdmLightExportTable table = CdmLightExportTable.TAXON;
339
                    String[] csvLine = new String[table.getSize()];
340

    
341
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_ID)] = getId(state, taxon);
342
                    csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
343
                    Taxon parent = (taxonNode.getParent() == null) ? null : taxonNode.getParent().getTaxon();
344
                    csvLine[table.getIndex(CdmLightExportTable.PARENT_FK)] = getId(state, parent);
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
                    csvLine[table.getIndex(CdmLightExportTable.APPENDED_PHRASE)] = taxon.getAppendedPhrase();
361
                    csvLine[table.getIndex(CdmLightExportTable.CLASSIFICATION_ID)] = getId(state,
362
                            taxonNode.getClassification());
363
                    csvLine[table.getIndex(CdmLightExportTable.CLASSIFICATION_TITLE)] = taxonNode.getClassification()
364
                            .getTitleCache();
365

    
366
                    csvLine[table.getIndex(CdmLightExportTable.PUBLISHED)] = taxon.isPublish() ? "1" : "0";
367
                    csvLine[table.getIndex(CdmLightExportTable.EXCLUDED)] = taxonNode.isExcluded() ? "1" : "0";
368
                    Map<Language, LanguageString> notesMap = taxonNode.getStatusNote();
369
                    String statusNotes = "";
370
                    if (!notesMap.isEmpty() && notesMap.size() == 1) {
371
                        statusNotes = notesMap.values().iterator().next().getText();
372
                    } else if (!notesMap.isEmpty()) {
373
                        statusNotes = notesMap.get(Language.getDefaultLanguage()) != null
374
                                ? notesMap.get(Language.getDefaultLanguage()).getText() : null;
375
                        if (statusNotes == null) {
376
                            statusNotes = notesMap.values().iterator().next().getText();
377
                        }
378
                    }
379
                    csvLine[table.getIndex(CdmLightExportTable.STATUS_NOTES)] = statusNotes;
380

    
381
                    csvLine[table.getIndex(CdmLightExportTable.UNPLACED)] = taxonNode.isUnplaced() ? "1" : "0";
382
                    csvLine[table.getIndex(CdmLightExportTable.DOUBTFUL)] = taxonNode.isDoubtful() ? "1" : "0";
383
                    state.getProcessor().put(table, taxon, csvLine);
384
                    handleDescriptions(state, taxon);
385
                } catch (Exception e) {
386
                    state.getResult().addException(e,
387
                            "An unexpected problem occurred when trying to export taxon with id " + taxon.getId() + " " + taxon.getTitleCache());
388
                    state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
389
                }
390
            }
391

    
392
        } catch (Exception e) {
393
            state.getResult().addException(e, "An unexpected error occurred when handling the taxon node of "
394
                    + cdmBaseStr(taxonNode.getTaxon()) + ", titleCache:"+ taxonNode.getTaxon().getTitleCache()+": " + e.getMessage());
395
        }
396
    }
397

    
398
    private void handleDescriptions(CdmLightExportState state, CdmBase cdmBase) {
399
        String titleCache = null;
400
        try {
401

    
402
            if (cdmBase instanceof Taxon) {
403
                Taxon taxon = HibernateProxyHelper.deproxy(cdmBase, Taxon.class);
404
                titleCache = taxon.getTitleCache();
405
                Set<TaxonDescription> descriptions = taxon.getDescriptions();
406
                List<DescriptionElementBase> simpleFacts = new ArrayList<>();
407
                List<DescriptionElementBase> specimenFacts = new ArrayList<>();
408
                List<DescriptionElementBase> distributionFacts = new ArrayList<>();
409
                List<DescriptionElementBase> taxonInteractionsFacts = new ArrayList<>();
410
                List<DescriptionElementBase> commonNameFacts = new ArrayList<>();
411
                List<DescriptionElementBase> usageFacts = new ArrayList<>();
412
                for (TaxonDescription description : descriptions) {
413
                    if (description.getElements() != null) {
414
                        for (DescriptionElementBase element : description.getElements()) {
415
                            element = CdmBase.deproxy(element);
416
                            handleAnnotations(element);
417
                            if (element.getFeature().equals(Feature.COMMON_NAME())) {
418
                                commonNameFacts.add(element);
419
                            } else if (element.getFeature().equals(Feature.DISTRIBUTION())) {
420
                                distributionFacts.add(element);
421
                            } else if (element instanceof IndividualsAssociation
422
                                    || isSpecimenFeature(element.getFeature())) {
423
                                specimenFacts.add(element);
424
                            } else if (element.getFeature().isSupportsTaxonInteraction()) {
425
                                taxonInteractionsFacts.add(element);
426
                            } else {
427
                                simpleFacts.add(element);
428
                            }
429
                        }
430
                    }
431
                }
432
                if (!commonNameFacts.isEmpty()) {
433
                    handleCommonNameFacts(state, taxon, commonNameFacts);
434
                }
435
                if (!distributionFacts.isEmpty()) {
436
                    handleDistributionFacts(state, taxon, distributionFacts);
437
                }
438
                if (!specimenFacts.isEmpty()) {
439
                    handleSpecimenFacts(state, taxon, specimenFacts);
440
                }
441
                if (!simpleFacts.isEmpty()) {
442
                    handleSimpleFacts(state, taxon, simpleFacts);
443
                }
444
                if (!taxonInteractionsFacts.isEmpty()) {
445
                    handleTaxonInteractionsFacts(state, taxon, taxonInteractionsFacts);
446
                }
447
            } else if (cdmBase instanceof TaxonName) {
448
                TaxonName name = CdmBase.deproxy(cdmBase, TaxonName.class);
449
                titleCache = name.getTitleCache();
450
                Set<TaxonNameDescription> descriptions = name.getDescriptions();
451
                List<DescriptionElementBase> simpleFacts = new ArrayList<>();
452
                for (TaxonNameDescription description : descriptions) {
453
                    if (description.getElements() != null) {
454
                        for (DescriptionElementBase element : description.getElements()) {
455
                            simpleFacts.add(element);
456
                        }
457
                    }
458
                }
459
                if (!simpleFacts.isEmpty()) {
460
                    handleSimpleFacts(state, name, simpleFacts);
461
                }
462
            }
463
        } catch (Exception e) {
464
            state.getResult().addException(e, "An unexpected error occurred when handling description of "
465
                    + cdmBaseStr(cdmBase) + (titleCache != null? (" " +titleCache) : "")+": " + e.getMessage());
466
        }
467
    }
468

    
469
    private void handleAnnotations(DescriptionElementBase element) {
470
        // TODO Auto-generated method stub
471
    }
472

    
473
    private void handleMetaData(CdmLightExportState state) {
474
        CdmLightExportTable table = CdmLightExportTable.METADATA;
475
        String[] csvLine = new String[table.getSize()];
476
//        csvLine[table.getIndex(CdmLightExportTable.INSTANCE_ID)] = state.getConfig().getInctanceId();
477
//        csvLine[table.getIndex(CdmLightExportTable.INSTANCE_NAME)] = state.getConfig().getInstanceName();
478
        csvLine[table.getIndex(CdmLightExportTable.DATASET_BASE_URL)] = state.getConfig().getBase_url();
479
        csvLine[table.getIndex(CdmLightExportTable.DATASET_CONTRIBUTOR)] = state.getConfig().getContributor();
480
        csvLine[table.getIndex(CdmLightExportTable.DATASET_CREATOR)] = state.getConfig().getCreator();
481
        csvLine[table.getIndex(CdmLightExportTable.DATASET_DESCRIPTION)] = state.getConfig().getDescription();
482
        csvLine[table.getIndex(CdmLightExportTable.DATASET_DOWNLOAD_LINK)] = state.getConfig().getDataset_download_link();
483
        csvLine[table.getIndex(CdmLightExportTable.DATASET_KEYWORDS)] = state.getConfig().getKeywords();
484
        csvLine[table.getIndex(CdmLightExportTable.DATASET_LANDINGPAGE)] = state.getConfig().getDataSet_landing_page();
485

    
486
        csvLine[table.getIndex(CdmLightExportTable.DATASET_LANGUAGE)] = state.getConfig().getLanguage() != null? state.getConfig().getLanguage().getLabel(): null;
487
        csvLine[table.getIndex(CdmLightExportTable.DATASET_LICENCE)] = state.getConfig().getLicence();
488
        csvLine[table.getIndex(CdmLightExportTable.DATASET_LOCATION)] = state.getConfig().getLocation();
489
        csvLine[table.getIndex(CdmLightExportTable.DATASET_RECOMMENDED_CITATTION)] = state.getConfig().getRecommended_citation();
490
        csvLine[table.getIndex(CdmLightExportTable.DATASET_TITLE)] = state.getConfig().getTitle();
491
        state.getProcessor().put(table, "", csvLine);
492
    }
493

    
494
    private boolean isSpecimenFeature(Feature feature) {
495
        // TODO allow user defined specimen features
496
        if (feature == null) {
497
            return false;
498
        } else if (feature.isSupportsIndividualAssociation()) {
499
            return true;
500
        } else {
501
            return feature.equals(Feature.SPECIMEN()) || feature.equals(Feature.INDIVIDUALS_ASSOCIATION())
502
                    || feature.equals(Feature.MATERIALS_EXAMINED()) || feature.equals(Feature.OBSERVATION())
503
                    || feature.equals(Feature.OCCURRENCE());
504
        }
505
    }
506

    
507
    private void handleSimpleFacts(CdmLightExportState state, CdmBase cdmBase,
508
            List<DescriptionElementBase> simpleFacts) {
509
        String titleCache = null;
510
        try {
511
            CdmLightExportTable table;
512
            if (cdmBase instanceof TaxonName) {
513
                titleCache = ((TaxonName)cdmBase).getTitleCache();
514
                table = CdmLightExportTable.NAME_FACT;
515
            } else {
516
                if (cdmBase instanceof Taxon){
517
                    titleCache = ((Taxon)cdmBase).getTitleCache();
518
                }
519
                table = CdmLightExportTable.SIMPLE_FACT;
520
            }
521
            CdmLightExportTable tableMedia = CdmLightExportTable.MEDIA;
522
            for (DescriptionElementBase element : simpleFacts) {
523
                if (element.getModifyingText().isEmpty() && !element.getMedia().isEmpty()) {
524
                    handleSimpleMediaFact(state, cdmBase, tableMedia, element);
525
                } else {
526
                    handleSingleSimpleFact(state, cdmBase, table, element);
527
                }
528
            }
529
        } catch (Exception e) {
530
            state.getResult().addException(e, "An unexpected error occurred when handling simple facts for "
531
                    + cdmBaseStr(cdmBase) + (titleCache != null? (" " +titleCache) : "")+ ": " + e.getMessage());
532
        }
533
    }
534

    
535
    private void handleTaxonInteractionsFacts(CdmLightExportState state, CdmBase cdmBase,
536
            List<DescriptionElementBase> taxonInteractionsFacts) {
537
        CdmLightExportTable table = CdmLightExportTable.TAXON_INTERACTION_FACT;
538
        String titleCache = null;
539
        if (cdmBase instanceof TaxonBase){
540
            titleCache = ((TaxonBase)cdmBase).getTitleCache();
541
        }
542
        for (DescriptionElementBase element : taxonInteractionsFacts) {
543

    
544
            try {
545

    
546
                String[] csvLine = new String[table.getSize()];
547

    
548
                csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
549
                handleSource(state, element, table);
550
                csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
551
                csvLine[table.getIndex(CdmLightExportTable.TAXON2_FK)] = getId(state,
552
                        ((TaxonInteraction) element).getTaxon2());
553
                csvLine[table.getIndex(CdmLightExportTable.DESCRIPTION)] = createMultilanguageString(
554
                        ((TaxonInteraction) element).getDescription());
555
                state.getProcessor().put(table, element, csvLine);
556

    
557
            } catch (Exception e) {
558
                state.getResult().addException(e, "An unexpected error occurred when handling taxon interaction"
559
                        + cdmBaseStr(element) + (titleCache != null? (" " +titleCache) : "")+ ": " + e.getMessage());
560
            }
561
        }
562
    }
563

    
564
    private void handleSimpleMediaFact(CdmLightExportState state, CdmBase cdmBase, CdmLightExportTable table,
565
            DescriptionElementBase element) {
566
        try {
567
            String[] csvLine;
568
            handleSource(state, element, CdmLightExportTable.MEDIA);
569

    
570
            if (element instanceof TextData) {
571
                TextData textData = (TextData) element;
572
                csvLine = new String[table.getSize()];
573
                csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
574
                if (cdmBase instanceof Taxon) {
575
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
576
                    csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = "";
577
                } else if (cdmBase instanceof TaxonName) {
578
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = "";
579
                    csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, cdmBase);
580
                }
581

    
582
                String mediaUris = "";
583
                for (Media media : textData.getMedia()) {
584
                    String mediaString = extractMediaUris(media.getRepresentations().iterator());
585
                    if (!StringUtils.isBlank(mediaString)) {
586
                        mediaUris += mediaString + ";";
587
                    } else {
588
                        state.getResult().addWarning("Empty Media object for " + cdmBase.getUserFriendlyTypeName() + " "
589
                                + cdmBase.getUuid() + " (media: " + media.getUuid() + ")");
590
                    }
591
                }
592
                csvLine[table.getIndex(CdmLightExportTable.MEDIA_URI)] = mediaUris;
593

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

    
600
    }
601

    
602
    private void handleSingleSimpleFact(CdmLightExportState state, CdmBase cdmBase, CdmLightExportTable table,
603
            DescriptionElementBase element) {
604
        try {
605
            String[] csvLine;
606
            handleSource(state, element, CdmLightExportTable.SIMPLE_FACT);
607

    
608
            if (element instanceof TextData) {
609
                TextData textData = (TextData) element;
610
                csvLine = new String[table.getSize()];
611
                csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
612
                if (cdmBase instanceof Taxon) {
613
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
614
                } else if (cdmBase instanceof TaxonName) {
615
                    csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, cdmBase);
616
                }
617
                csvLine[table.getIndex(CdmLightExportTable.FACT_CATEGORY)] = textData.getFeature().getLabel();
618

    
619
                String mediaUris = "";
620
                for (Media media : textData.getMedia()) {
621
                    String mediaString = extractMediaUris(media.getRepresentations().iterator());
622
                    if (!StringUtils.isBlank(mediaString)) {
623
                        mediaUris += mediaString + ";";
624
                    } else {
625
                        state.getResult().addWarning("Empty Media object for uuid: " + cdmBase.getUuid()
626
                                + " uuid of media: " + media.getUuid());
627
                    }
628
                }
629
                csvLine[table.getIndex(CdmLightExportTable.MEDIA_URI)] = mediaUris;
630
                if (textData.getFeature().equals(Feature.CITATION())) {
631
                    state.getProcessor().put(table, textData, csvLine);
632
                } else if (!textData.getMultilanguageText().isEmpty()) {
633
                    for (Language language : textData.getMultilanguageText().keySet()) {
634
                        String[] csvLineLanguage = csvLine.clone();
635
                        LanguageString langString = textData.getLanguageText(language);
636
                        String text = langString.getText();
637
                        if (state.getConfig().isFilterIntextReferences()) {
638
                            text = filterIntextReferences(langString.getText());
639
                        }
640
                        csvLineLanguage[table.getIndex(CdmLightExportTable.FACT_TEXT)] = text;
641
                        csvLineLanguage[table.getIndex(CdmLightExportTable.LANGUAGE)] = language.getLabel();
642
                        state.getProcessor().put(table, textData, csvLineLanguage);
643
                    }
644
                } else {
645
                    state.getProcessor().put(table, textData, csvLine);
646
                }
647
            }
648
        } catch (Exception e) {
649
            state.getResult().addException(e, "An unexpected error occurred when handling single simple fact "
650
                    + cdmBaseStr(element) + ": " + e.getMessage());
651
        }
652
    }
653

    
654
    private String filterIntextReferences(String text) {
655
        /*
656
         * (<cdm:reference cdmId='fbd19251-efee-4ded-b780-915000f66d41'
657
         * intextId='1352d42c-e201-4155-a02a-55360d3b563e'>Ridley in Fl. Malay
658
         * Pen. 3 (1924) 22</cdm:reference>)
659
         */
660
        String newText = text.replaceAll("<cdm:reference cdmId='[a-z0-9\\-]*' intextId='[a-z0-9\\-]*'>", "");
661
        newText = newText.replaceAll("</cdm:reference>", "");
662

    
663
        newText = newText.replaceAll("<cdm:key cdmId='[a-z0-9\\-]*' intextId='[a-z0-9\\-]*'>", "");
664
        newText = newText.replaceAll("</cdm:key>", "");
665
        return newText;
666
    }
667

    
668
    private void handleSpecimenFacts(CdmLightExportState state, Taxon taxon,
669
            List<DescriptionElementBase> specimenFacts) {
670
        CdmLightExportTable table = CdmLightExportTable.SPECIMEN_FACT;
671

    
672
        for (DescriptionElementBase element : specimenFacts) {
673
            try {
674
                String[] csvLine = new String[table.getSize()];
675
                csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
676
                csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, taxon);
677
                handleSource(state, element, table);
678
                csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_NOTES)] = createAnnotationsString(
679
                        element.getAnnotations());
680

    
681
                if (element instanceof IndividualsAssociation) {
682

    
683
                    IndividualsAssociation indAssociation = (IndividualsAssociation) element;
684
                    if (indAssociation.getAssociatedSpecimenOrObservation() == null) {
685
                        state.getResult()
686
                                .addWarning("There is an individual association with no specimen associated (Taxon "
687
                                        + taxon.getTitleCache() + "(" + taxon.getUuid() + "). Could not be exported.");
688
                        continue;
689
                    } else {
690
                        if (!state.getSpecimenStore()
691
                                .contains((indAssociation.getAssociatedSpecimenOrObservation().getUuid()))) {
692
                            SpecimenOrObservationBase<?> specimenBase = HibernateProxyHelper.deproxy(
693
                                    indAssociation.getAssociatedSpecimenOrObservation(),
694
                                    SpecimenOrObservationBase.class);
695

    
696
                            handleSpecimen(state, specimenBase);
697
                            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_FK)] = getId(state,
698
                                    indAssociation.getAssociatedSpecimenOrObservation());
699
                        }
700
                    }
701
                } else if (element instanceof TextData) {
702
                    TextData textData = HibernateProxyHelper.deproxy(element, TextData.class);
703
                    csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_DESCRIPTION)] = createMultilanguageString(
704
                            textData.getMultilanguageText());
705
                }
706
                state.getProcessor().put(table, element, csvLine);
707
            } catch (Exception e) {
708
                state.getResult().addException(e, "An unexpected error occurred when handling single specimen fact "
709
                        + cdmBaseStr(element) + ": " + e.getMessage());
710
            }
711
        }
712
    }
713

    
714
    private String createMultilanguageString(Map<Language, LanguageString> multilanguageText) {
715
        String text = "";
716
        int index = multilanguageText.size();
717
        for (LanguageString langString : multilanguageText.values()) {
718
            text += langString.getText();
719
            if (index > 1) {
720
                text += "; ";
721
            }
722
            index--;
723
        }
724
        return text;
725
    }
726

    
727
    private String createAnnotationsString(Set<Annotation> annotations) {
728
        StringBuffer strBuff = new StringBuffer();
729

    
730
        for (Annotation ann : annotations) {
731
            if (ann.getAnnotationType() == null || !ann.getAnnotationType().equals(AnnotationType.TECHNICAL())) {
732
                strBuff.append(ann.getText());
733
                strBuff.append("; ");
734
            }
735
        }
736

    
737
        if (strBuff.length() > 2) {
738
            return strBuff.substring(0, strBuff.length() - 2);
739
        } else {
740
            return null;
741
        }
742
    }
743

    
744
    private void handleSource(CdmLightExportState state, DescriptionElementBase element,
745
            CdmLightExportTable factsTable) {
746
        CdmLightExportTable table = CdmLightExportTable.FACT_SOURCES;
747
        try {
748
            Set<DescriptionElementSource> sources = element.getSources();
749

    
750
            for (DescriptionElementSource source : sources) {
751
                if (!(source.getType().equals(OriginalSourceType.Import)
752
                        && state.getConfig().isExcludeImportSources())) {
753
                    String[] csvLine = new String[table.getSize()];
754
                    Reference ref = source.getCitation();
755
                    if ((ref == null) && (source.getNameUsedInSource() == null)) {
756
                        continue;
757
                    }
758
                    if (ref != null) {
759
                        if (!state.getReferenceStore().contains(ref.getUuid())) {
760
                            handleReference(state, ref);
761

    
762
                        }
763
                        csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)] = getId(state, ref);
764
                    }
765
                    csvLine[table.getIndex(CdmLightExportTable.FACT_FK)] = getId(state, element);
766

    
767
                    csvLine[table.getIndex(CdmLightExportTable.NAME_IN_SOURCE_FK)] = getId(state,
768
                            source.getNameUsedInSource());
769
                    csvLine[table.getIndex(CdmLightExportTable.FACT_TYPE)] = factsTable.getTableName();
770
                    if (StringUtils.isBlank(csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)])
771
                            && StringUtils.isBlank(csvLine[table.getIndex(CdmLightExportTable.NAME_IN_SOURCE_FK)])) {
772
                        continue;
773
                    }
774
                    state.getProcessor().put(table, source, csvLine);
775
                }
776

    
777
            }
778
        } catch (Exception e) {
779
            state.getResult().addException(e, "An unexpected error occurred when handling single source "
780
                    + cdmBaseStr(element) + ": " + e.getMessage());
781
        }
782

    
783
    }
784

    
785
    private void handleDistributionFacts(CdmLightExportState state, Taxon taxon,
786
            List<DescriptionElementBase> distributionFacts) {
787

    
788
        CdmLightExportTable table = CdmLightExportTable.GEOGRAPHIC_AREA_FACT;
789
        Set<Distribution> distributions = new HashSet<>();
790
        for (DescriptionElementBase element : distributionFacts) {
791
            try {
792
                if (element instanceof Distribution) {
793
                    String[] csvLine = new String[table.getSize()];
794
                    Distribution distribution = (Distribution) element;
795
                    distributions.add(distribution);
796
                    csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
797
                    handleSource(state, element, table);
798
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, taxon);
799
                    if (distribution.getArea() != null) {
800
                        csvLine[table.getIndex(CdmLightExportTable.AREA_LABEL)] = distribution.getArea().getLabel();
801
                    }
802
                    if (distribution.getStatus() != null) {
803
                        csvLine[table.getIndex(CdmLightExportTable.STATUS_LABEL)] = distribution.getStatus().getLabel();
804
                    }
805
                    state.getProcessor().put(table, distribution, csvLine);
806
                } else {
807
                    state.getResult()
808
                            .addError("The distribution description for the taxon " + taxon.getUuid()
809
                                    + " is not of type distribution. Could not be exported. UUID of the description element: "
810
                                    + element.getUuid());
811
                }
812
            } catch (Exception e) {
813
                state.getResult().addException(e, "An unexpected error occurred when handling single distribution "
814
                        + cdmBaseStr(element) + ": " + e.getMessage());
815
            }
816
        }
817
         if(state.getConfig().isCreateCondensedDistributionString()){
818
             List<Language> langs = new ArrayList<>();
819
             langs.add(Language.ENGLISH());
820

    
821
             CondensedDistribution conDis = geoService.getCondensedDistribution(
822
                     //TODO add CondensedDistributionConfiguration to export configuration
823
                     distributions, true, null, state.getConfig().getCondensedDistributionConfiguration(), langs);
824
             CdmLightExportTable tableCondensed =
825
                     CdmLightExportTable.SIMPLE_FACT;
826
             String[] csvLine = new String[tableCondensed.getSize()];
827
             //the computed fact has no uuid, TODO: remember the uuid for later reference assignment
828
             UUID randomUuid = UUID.randomUUID();
829
             csvLine[tableCondensed.getIndex(CdmLightExportTable.FACT_ID)] =
830
                     randomUuid.toString();
831
             csvLine[tableCondensed.getIndex(CdmLightExportTable.TAXON_FK)] =
832
                     getId(state, taxon);
833
             csvLine[tableCondensed.getIndex(CdmLightExportTable.FACT_TEXT)] =
834
                     conDis.toString();
835
             csvLine[tableCondensed.getIndex(CdmLightExportTable.LANGUAGE)] =Language.ENGLISH().toString();
836

    
837
             csvLine[tableCondensed.getIndex(CdmLightExportTable.FACT_CATEGORY)] =
838
                     "CondensedDistribution";
839

    
840
             state.getProcessor().put(tableCondensed, taxon, csvLine);
841
         }
842
    }
843

    
844
    private void handleCommonNameFacts(CdmLightExportState state, Taxon taxon,
845
            List<DescriptionElementBase> commonNameFacts) {
846
        CdmLightExportTable table = CdmLightExportTable.COMMON_NAME_FACT;
847

    
848
        for (DescriptionElementBase element : commonNameFacts) {
849
            try {
850
                if (element instanceof CommonTaxonName) {
851
                    String[] csvLine = new String[table.getSize()];
852
                    CommonTaxonName commonName = (CommonTaxonName) element;
853
                    csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
854
                    handleSource(state, element, table);
855
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, taxon);
856
                    if (commonName.getName() != null) {
857
                        csvLine[table.getIndex(CdmLightExportTable.FACT_TEXT)] = commonName.getName();
858
                    }
859
                    if (commonName.getLanguage() != null) {
860
                        csvLine[table.getIndex(CdmLightExportTable.LANGUAGE)] = commonName.getLanguage().getLabel();
861
                    }
862
                    if (commonName.getArea() != null) {
863
                        csvLine[table.getIndex(CdmLightExportTable.AREA_LABEL)] = commonName.getArea().getLabel();
864
                    }
865
                    state.getProcessor().put(table, commonName, csvLine);
866
                } else if (element instanceof TextData){
867
                    String[] csvLine = new String[table.getSize()];
868
                    TextData commonName = (TextData) element;
869
                    csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
870
                    handleSource(state, element, table);
871
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, taxon);
872
                    if (commonName.getMultilanguageText() != null) {
873
                        csvLine[table.getIndex(CdmLightExportTable.FACT_TEXT)] = createMultilanguageString(commonName.getMultilanguageText());
874
                    }
875
                    state.getProcessor().put(table, commonName, csvLine);
876
                } else {
877
                    state.getResult()
878
                            .addError("The common name description for the taxon " + taxon.getUuid()
879
                                    + " is not of type common name. Could not be exported. UUID of the description element: "
880
                                    + element.getUuid());
881
                }
882
            } catch (Exception e) {
883
                state.getResult().addException(e, "An unexpected error occurred when handling single common name "
884
                        + cdmBaseStr(element) + " - "+taxon.getTitleCache()+ ": " + e.getMessage());
885
            }
886
        }
887
    }
888

    
889
    private String getTitleCache(IIdentifiableEntity identEntity) {
890
        if (identEntity == null) {
891
            return "";
892
        }
893
        // TODO refresh?
894
        return identEntity.getTitleCache();
895
    }
896

    
897
    private String getId(CdmLightExportState state, ICdmBase cdmBase) {
898
        if (cdmBase == null) {
899
            return "";
900
        }
901
        // TODO make configurable
902
        return cdmBase.getUuid().toString();
903
    }
904

    
905
    private void handleSynonym(CdmLightExportState state, Synonym synonym, int index) {
906
        try {
907
            if (isUnpublished(state.getConfig(), synonym)) {
908
                return;
909
            }
910
            TaxonName name = synonym.getName();
911
            handleName(state, name, synonym.getAcceptedTaxon());
912

    
913
            CdmLightExportTable table = CdmLightExportTable.SYNONYM;
914
            String[] csvLine = new String[table.getSize()];
915

    
916
            csvLine[table.getIndex(CdmLightExportTable.SYNONYM_ID)] = getId(state, synonym);
917
            csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, synonym.getAcceptedTaxon());
918
            csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
919
            if (synonym.getSec() != null && !state.getReferenceStore().contains(synonym.getSec().getUuid())) {
920
                handleReference(state, synonym.getSec());
921
            }
922
            csvLine[table.getIndex(CdmLightExportTable.APPENDED_PHRASE)] = synonym.getAppendedPhrase();
923
            csvLine[table.getIndex(CdmLightExportTable.SYN_SEC_REFERENCE_FK)] = getId(state, synonym.getSec());
924
            csvLine[table.getIndex(CdmLightExportTable.SYN_SEC_REFERENCE)] = getTitleCache(synonym.getSec());
925
            csvLine[table.getIndex(CdmLightExportTable.PUBLISHED)] = synonym.isPublish() ? "1" : "0";
926
            csvLine[table.getIndex(CdmLightExportTable.IS_PRO_PARTE)] = "0";
927
            csvLine[table.getIndex(CdmLightExportTable.IS_PARTIAL)] = "0";
928
            csvLine[table.getIndex(CdmLightExportTable.IS_MISAPPLIED)] = "0";
929
            csvLine[table.getIndex(CdmLightExportTable.SORT_INDEX)] = String.valueOf(index);
930
            state.getProcessor().put(table, synonym, csvLine);
931
        } catch (Exception e) {
932
            state.getResult().addException(e, "An unexpected error occurred when handling synonym "
933
                    + cdmBaseStr(synonym) + ": " + e.getMessage());
934
        }
935
    }
936

    
937
    /**
938
     * Handles misapplied names (including pro parte and partial as well as pro
939
     * parte and partial synonyms
940
     */
941
    private void handleProPartePartialMisapplied(CdmLightExportState state, Taxon taxon, Taxon accepted, boolean isProParte, boolean isMisapplied, int index) {
942
        try {
943
            Taxon ppSyonym = taxon;
944
            if (isUnpublished(state.getConfig(), ppSyonym)) {
945
                return;
946
            }
947
            TaxonName name = ppSyonym.getName();
948
            handleName(state, name, accepted);
949

    
950
            CdmLightExportTable table = CdmLightExportTable.SYNONYM;
951
            String[] csvLine = new String[table.getSize()];
952

    
953
            csvLine[table.getIndex(CdmLightExportTable.SYNONYM_ID)] = getId(state, ppSyonym);
954
            csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, accepted);
955
            csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
956

    
957
            Reference secRef = ppSyonym.getSec();
958

    
959
            if (secRef != null && !state.getReferenceStore().contains(secRef.getUuid())) {
960
                handleReference(state, secRef);
961
            }
962
            csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE_FK)] = getId(state, secRef);
963
            csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = getTitleCache(secRef);
964
            Set<TaxonRelationship> rels = accepted.getTaxonRelations(ppSyonym);
965
            TaxonRelationship rel = null;
966
            boolean isPartial = false;
967
            if (rels.size() == 1){
968
                rel = rels.iterator().next();
969

    
970
            }else if (rels.size() > 1){
971
                Iterator<TaxonRelationship> iterator = rels.iterator();
972
                while (iterator.hasNext()){
973
                    rel = iterator.next();
974
                    if (isProParte && rel.getType().isAnySynonym()){
975
                        break;
976
                    } else if (isMisapplied && rel.getType().isAnyMisappliedName()){
977
                        break;
978
                    }else{
979
                        rel = null;
980
                    }
981
                }
982
            }
983
            if (rel != null){
984
                Reference synSecRef = rel.getCitation();
985
                if (synSecRef != null && !state.getReferenceStore().contains(synSecRef.getUuid())) {
986
                    handleReference(state, synSecRef);
987
                }
988
                csvLine[table.getIndex(CdmLightExportTable.SYN_SEC_REFERENCE_FK)] = getId(state, synSecRef);
989
                csvLine[table.getIndex(CdmLightExportTable.SYN_SEC_REFERENCE)] = getTitleCache(synSecRef);
990
                isProParte = rel.getType().isProParte();
991
                isPartial = rel.getType().isPartial();
992

    
993
            }else{
994
                state.getResult().addWarning("An unexpected error occurred when handling "
995
                        + "pro parte/partial synonym or misapplied name  " + cdmBaseStr(taxon) );
996
            }
997

    
998
            // pro parte type
999

    
1000
            csvLine[table.getIndex(CdmLightExportTable.IS_PRO_PARTE)] = isProParte ? "1" : "0";
1001
            csvLine[table.getIndex(CdmLightExportTable.IS_PARTIAL)] = isPartial ? "1" : "0";
1002
            csvLine[table.getIndex(CdmLightExportTable.IS_MISAPPLIED)] = isMisapplied ? "1" : "0";
1003
            csvLine[table.getIndex(CdmLightExportTable.SORT_INDEX)] = String.valueOf(index);
1004
            state.getProcessor().put(table, ppSyonym, csvLine);
1005
        } catch (Exception e) {
1006
            state.getResult().addException(e, "An unexpected error occurred when handling "
1007
                    + "pro parte/partial synonym or misapplied name  " + cdmBaseStr(taxon) + ": " + e.getMessage());
1008
        }
1009

    
1010
    }
1011

    
1012
    private void handleName(CdmLightExportState state, TaxonName name, Taxon acceptedTaxon){
1013
        handleName(state, name, acceptedTaxon, false);
1014
    }
1015

    
1016
    private void handleName(CdmLightExportState state, TaxonName name, Taxon acceptedTaxon, boolean acceptedName) {
1017
        if (name == null || state.getNameStore().containsKey(name.getId())) {
1018
            return;
1019
        }
1020
        try {
1021
            Rank rank = name.getRank();
1022
            CdmLightExportTable table = CdmLightExportTable.SCIENTIFIC_NAME;
1023
            name = HibernateProxyHelper.deproxy(name);
1024
            state.getNameStore().put(name.getId(), name.getUuid());
1025
            String[] csvLine = new String[table.getSize()];
1026

    
1027
            csvLine[table.getIndex(CdmLightExportTable.NAME_ID)] = getId(state, name);
1028
            if (name.getLsid() != null) {
1029
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = name.getLsid().getLsid();
1030
            } else {
1031
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = "";
1032
            }
1033

    
1034
            handleIdentifier(state, name);
1035
            handleDescriptions(state, name);
1036

    
1037
            csvLine[table.getIndex(CdmLightExportTable.RANK)] = getTitleCache(rank);
1038
            if (rank != null) {
1039
                csvLine[table.getIndex(CdmLightExportTable.RANK_SEQUENCE)] = String.valueOf(rank.getOrderIndex());
1040
                if (rank.isInfraGeneric()) {
1041
                    try {
1042
                        csvLine[table.getIndex(CdmLightExportTable.INFRAGENERIC_RANK)] = name.getRank()
1043
                                .getInfraGenericMarker();
1044
                    } catch (UnknownCdmTypeException e) {
1045
                        state.getResult().addError("Infrageneric marker expected but not available for rank "
1046
                                + name.getRank().getTitleCache());
1047
                    }
1048
                }
1049
                if (rank.isInfraSpecific()) {
1050
                    csvLine[table.getIndex(CdmLightExportTable.INFRASPECIFIC_RANK)] = name.getRank().getAbbreviation();
1051
                }
1052
            } else {
1053
                csvLine[table.getIndex(CdmLightExportTable.RANK_SEQUENCE)] = "";
1054
            }
1055
            if (name.isProtectedTitleCache()) {
1056
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_AUTHORS)] = name.getTitleCache();
1057
            } else {
1058
                // TODO: adapt the tropicos titlecache creation
1059
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_AUTHORS)] = name.getTitleCache();
1060
            }
1061

    
1062

    
1063
            if (!state.getConfig().isAddHTML()) {
1064
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_REF)] = name.getFullTitleCache();
1065
            } else {
1066
                List<TaggedText> taggedFullTitleCache = name.getTaggedFullTitle();
1067
                List<TaggedText> taggedName = name.getTaggedName();
1068

    
1069
                String fullTitleWithHtml = createNameWithItalics(taggedFullTitleCache);
1070
                // TODO: adapt the tropicos titlecache creation
1071
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_REF)] = fullTitleWithHtml.trim();
1072
            }
1073

    
1074
            csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_NO_AUTHORS)] = name.getNameCache();
1075
            csvLine[table.getIndex(CdmLightExportTable.GENUS_UNINOMIAL)] = name.getGenusOrUninomial();
1076

    
1077
            csvLine[table.getIndex(CdmLightExportTable.INFRAGENERIC_EPITHET)] = name.getInfraGenericEpithet();
1078
            csvLine[table.getIndex(CdmLightExportTable.SPECIFIC_EPITHET)] = name.getSpecificEpithet();
1079

    
1080
            csvLine[table.getIndex(CdmLightExportTable.INFRASPECIFIC_EPITHET)] = name.getInfraSpecificEpithet();
1081

    
1082
            csvLine[table.getIndex(CdmLightExportTable.APPENDED_PHRASE)] = name.getAppendedPhrase();
1083

    
1084
            csvLine[table.getIndex(CdmLightExportTable.BAS_AUTHORTEAM_FK)] = getId(state, name.getBasionymAuthorship());
1085
            if (name.getBasionymAuthorship() != null) {
1086
                if (state.getAuthorFromStore(name.getBasionymAuthorship().getId()) == null) {
1087
                    handleAuthor(state, name.getBasionymAuthorship());
1088
                }
1089
            }
1090
            csvLine[table.getIndex(CdmLightExportTable.BAS_EX_AUTHORTEAM_FK)] = getId(state,
1091
                    name.getExBasionymAuthorship());
1092
            if (name.getExBasionymAuthorship() != null) {
1093
                if (state.getAuthorFromStore(name.getExBasionymAuthorship().getId()) == null) {
1094
                    handleAuthor(state, name.getExBasionymAuthorship());
1095
                }
1096

    
1097
            }
1098
            csvLine[table.getIndex(CdmLightExportTable.COMB_AUTHORTEAM_FK)] = getId(state,
1099
                    name.getCombinationAuthorship());
1100
            if (name.getCombinationAuthorship() != null) {
1101
                if (state.getAuthorFromStore(name.getCombinationAuthorship().getId()) == null) {
1102
                    handleAuthor(state, name.getCombinationAuthorship());
1103
                }
1104
            }
1105
            csvLine[table.getIndex(CdmLightExportTable.COMB_EX_AUTHORTEAM_FK)] = getId(state,
1106
                    name.getExCombinationAuthorship());
1107
            if (name.getExCombinationAuthorship() != null) {
1108
                if (state.getAuthorFromStore(name.getExCombinationAuthorship().getId()) == null) {
1109
                    handleAuthor(state, name.getExCombinationAuthorship());
1110
                }
1111

    
1112
            }
1113

    
1114
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_TEAM_STRING)] = name.getAuthorshipCache();
1115

    
1116
            Reference nomRef = name.getNomenclaturalReference();
1117

    
1118
            NomenclaturalSource nomenclaturalSource = name.getNomenclaturalSource();
1119
            if (nomenclaturalSource != null &&nomenclaturalSource.getNameUsedInSource() != null){
1120
                handleName(state, nomenclaturalSource.getNameUsedInSource(), null);
1121
                csvLine[table.getIndex(CdmLightExportTable.NAME_USED_IN_SOURCE)] = getId(state, nomenclaturalSource.getNameUsedInSource());
1122
            }
1123

    
1124
            if (nomRef != null) {
1125
                if (!state.getReferenceStore().contains(nomRef.getUuid())) {
1126
                    handleReference(state, nomRef);
1127
                }
1128
                csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)] = getId(state, nomRef);
1129
                csvLine[table.getIndex(CdmLightExportTable.PUBLICATION_TYPE)] = nomRef.getType().name();
1130
                if (nomRef.getVolume() != null) {
1131
                    csvLine[table.getIndex(CdmLightExportTable.VOLUME_ISSUE)] = nomRef.getVolume();
1132
                    csvLine[table.getIndex(CdmLightExportTable.COLLATION)] = createCollatation(name);
1133
                }
1134
                if (nomRef.getDatePublished() != null) {
1135
                    csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = nomRef.getTimePeriodPublishedString();
1136
                    csvLine[table.getIndex(CdmLightExportTable.YEAR_PUBLISHED)] = nomRef.getDatePublished().getYear();
1137
                    csvLine[table.getIndex(CdmLightExportTable.VERBATIM_DATE)] = nomRef.getDatePublished()
1138
                            .getVerbatimDate();
1139
                }
1140
                if (name.getNomenclaturalMicroReference() != null) {
1141
                    csvLine[table.getIndex(CdmLightExportTable.DETAIL)] = name.getNomenclaturalMicroReference();
1142
                }
1143
                nomRef = HibernateProxyHelper.deproxy(nomRef);
1144
                if (nomRef.getInReference() != null) {
1145
                    Reference inReference = nomRef.getInReference();
1146
                    if (inReference.getDatePublished() != null && nomRef.getDatePublished() == null) {
1147
                        csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = inReference
1148
                                .getDatePublishedString();
1149
                        csvLine[table.getIndex(CdmLightExportTable.YEAR_PUBLISHED)] = inReference.getDatePublished()
1150
                                .getYear();
1151
                    }
1152
                    if (nomRef.getVolume() == null && inReference.getVolume() != null) {
1153
                        csvLine[table.getIndex(CdmLightExportTable.VOLUME_ISSUE)] = inReference.getVolume();
1154
                        csvLine[table.getIndex(CdmLightExportTable.COLLATION)] = createCollatation(name);
1155
                    }
1156
                    if (inReference.getInReference() != null) {
1157
                        inReference = inReference.getInReference();
1158
                    }
1159
                    if (inReference.getAbbrevTitle() == null) {
1160
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils
1161
                                .Nz(inReference.getTitle());
1162
                    } else {
1163
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils
1164
                                .Nz(inReference.getAbbrevTitle());
1165
                    }
1166
                    if (inReference.getTitle() == null) {
1167
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils
1168
                                .Nz(inReference.getAbbrevTitle()!= null? inReference.getAbbrevTitle(): inReference.getTitleCache());
1169
                    } else {
1170
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(inReference.getTitle());
1171
                    }
1172

    
1173
                    TeamOrPersonBase<?> author = inReference.getAuthorship();
1174
                    if (author != null
1175
                            && (nomRef.isOfType(ReferenceType.BookSection) || nomRef.isOfType(ReferenceType.Section))) {
1176
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = author.isProtectedTitleCache()
1177
                                ? author.getTitleCache() : CdmUtils.Nz(author.getNomenclaturalTitleCache());
1178
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = CdmUtils
1179
                                .Nz(author.getTitleCache());
1180
                    } else {
1181
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = "";
1182
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = "";
1183
                    }
1184
                } else {
1185
                    if (nomRef.getAbbrevTitle() == null) {
1186
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils
1187
                                .Nz(nomRef.getTitle()!= null? nomRef.getTitle():nomRef.getAbbrevTitleCache());
1188
                    } else {
1189
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_TITLE)] = CdmUtils
1190
                                .Nz(nomRef.getAbbrevTitle());
1191
                    }
1192
                    if (nomRef.getTitle() == null) {
1193
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] =  CdmUtils
1194
                                .Nz(nomRef.getAbbrevTitle()!= null? nomRef.getAbbrevTitle(): nomRef.getTitleCache());
1195
                    } else {
1196
                        csvLine[table.getIndex(CdmLightExportTable.FULL_TITLE)] = CdmUtils.Nz(nomRef.getTitle());
1197
                    }
1198
                    TeamOrPersonBase<?> author = nomRef.getAuthorship();
1199
                    if (author != null) {
1200
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = author.isProtectedTitleCache()
1201
                                ? author.getTitleCache() : CdmUtils.Nz(author.getNomenclaturalTitleCache());
1202
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = CdmUtils
1203
                                .Nz(author.getTitleCache());
1204
                    } else {
1205
                        csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_AUTHOR)] = "";
1206
                        csvLine[table.getIndex(CdmLightExportTable.FULL_REF_AUTHOR)] = "";
1207
                    }
1208

    
1209
                }
1210
            } else {
1211
                csvLine[table.getIndex(CdmLightExportTable.PUBLICATION_TYPE)] = "";
1212
            }
1213

    
1214
            /*
1215
             * Collation
1216
             *
1217
             * Detail
1218
             *
1219
             * TitlePageYear
1220
             */
1221
            String protologueUriString = extractProtologueURIs(state, name);
1222

    
1223
            csvLine[table.getIndex(CdmLightExportTable.PROTOLOGUE_URI)] = protologueUriString;
1224
            Collection<TypeDesignationBase> specimenTypeDesignations = new ArrayList<>();
1225
            List<TextualTypeDesignation> textualTypeDesignations = new ArrayList<>();
1226
            for (TypeDesignationBase<?> typeDesignation : name.getTypeDesignations()) {
1227
                if (typeDesignation.isInstanceOf(TextualTypeDesignation.class)) {
1228

    
1229
                    if (((TextualTypeDesignation) typeDesignation).isVerbatim() ){
1230
                        Set<IdentifiableSource> sources =  typeDesignation.getSources();
1231
                        boolean isProtologue = false;
1232
                        if (sources != null && !sources.isEmpty()){
1233
                            IdentifiableSource source = sources.iterator().next();
1234
                            if (name.getNomenclaturalReference() != null){
1235
                                isProtologue = source.getCitation() != null? source.getCitation().getUuid().equals(name.getNomenclaturalReference().getUuid()): false;
1236
                            }
1237
                        }
1238
                        if (isProtologue){
1239
                            csvLine[table.getIndex(CdmLightExportTable.PROTOLOGUE_TYPE_STATEMENT)] = ((TextualTypeDesignation) typeDesignation)
1240
                                    .getPreferredText(Language.DEFAULT());
1241
                        }else{
1242
                            textualTypeDesignations.add((TextualTypeDesignation) typeDesignation);
1243
                        }
1244

    
1245
                    } else {
1246
                        textualTypeDesignations.add((TextualTypeDesignation) typeDesignation);
1247
                    }
1248
                } else if (typeDesignation.isInstanceOf(SpecimenTypeDesignation.class)) {
1249
                    SpecimenTypeDesignation specimenType = HibernateProxyHelper.deproxy(typeDesignation, SpecimenTypeDesignation.class);
1250
                    specimenTypeDesignations.add(specimenType);
1251
                    handleSpecimenType(state, specimenType);
1252

    
1253

    
1254
                }else if (typeDesignation instanceof NameTypeDesignation){
1255
                    specimenTypeDesignations.add(HibernateProxyHelper.deproxy(typeDesignation, NameTypeDesignation.class));
1256
                }
1257
            }
1258
            TypeDesignationSetManager manager = new TypeDesignationSetManager(specimenTypeDesignations, name);
1259
            HTMLTagRules rules = new HTMLTagRules();
1260
            rules.addRule(TagEnum.name, "i");
1261
            String test = manager.print(false, false, false, rules);;
1262
            csvLine[table.getIndex(CdmLightExportTable.TYPE_SPECIMEN)] = manager.print(false, false, false, rules);
1263

    
1264
            StringBuilder stringbuilder = new StringBuilder();
1265
            int i = 1;
1266
            for (TextualTypeDesignation typeDesignation : textualTypeDesignations) {
1267
                stringbuilder.append(typeDesignation.getPreferredText(Language.DEFAULT()));
1268
                if (typeDesignation.getSources() != null && !typeDesignation.getSources().isEmpty() ){
1269
                    stringbuilder.append( " [");
1270
                    int index = 1;
1271
                    for (IdentifiableSource source: typeDesignation.getSources()){
1272
                        if (source.getCitation() != null){
1273
                            stringbuilder.append(OriginalSourceFormatter.INSTANCE.format(source));
1274
                        }
1275
                        if (index < typeDesignation.getSources().size()) {
1276
                            stringbuilder.append( ", ");
1277
                        }
1278
                        index++;
1279
                    }
1280
                    stringbuilder.append( "]");
1281
                }
1282
                if (i < textualTypeDesignations.size()) {
1283
                    stringbuilder.append( "; ");
1284
                } else {
1285
                    stringbuilder.append(".");
1286
                }
1287
                i++;
1288
            }
1289
            csvLine[table.getIndex(CdmLightExportTable.TYPE_STATEMENT)] = stringbuilder.toString();
1290

    
1291

    
1292
            if (name.getStatus() == null || name.getStatus().isEmpty()) {
1293
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS)] = "";
1294
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS_ABBREV)] = "";
1295
            } else {
1296

    
1297
                String statusStringAbbrev = extractStatusString(state, name, true);
1298
                String statusString = extractStatusString(state, name, false);
1299

    
1300
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS)] = statusString.trim();
1301
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS_ABBREV)] = statusStringAbbrev.trim();
1302
            }
1303

    
1304
            HomotypicalGroup group = HibernateProxyHelper.deproxy(name.getHomotypicalGroup(), HomotypicalGroup.class);
1305

    
1306
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_FK)] = getId(state, group);
1307
            List<TaxonName> typifiedNames = new ArrayList<>();
1308
            if (acceptedTaxon != null){
1309
                HomotypicGroupTaxonComparator comparator = new HomotypicGroupTaxonComparator(acceptedTaxon);
1310
                List<Synonym> synonymsInGroup = null;
1311
                if (group.equals(acceptedTaxon.getHomotypicGroup())){
1312
                    synonymsInGroup = acceptedTaxon.getHomotypicSynonymsByHomotypicGroup(comparator);
1313
                    typifiedNames.add(name);
1314
                }else{
1315
                    synonymsInGroup = acceptedTaxon.getSynonymsInGroup(group, comparator);
1316
                }
1317

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

    
1320
            }else{
1321
                typifiedNames.addAll(group.getTypifiedNames());
1322
            }
1323

    
1324

    
1325
            Integer seqNumber = typifiedNames.indexOf(name);
1326
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_SEQ)] = String.valueOf(seqNumber);
1327
            state.getProcessor().put(table, name, csvLine);
1328
            handleNameRelationships(state, name);
1329

    
1330
        } catch (Exception e) {
1331
            state.getResult().addException(e,
1332
                    "An unexpected error occurred when handling the name " + cdmBaseStr(name) + ": " + name.getTitleCache() + ": " + e.getMessage());
1333

    
1334
            e.printStackTrace();
1335
        }
1336
    }
1337

    
1338
    /**
1339
     * @param specimenType
1340
     */
1341
    private void handleSpecimenType_(CdmLightExportState state, SpecimenTypeDesignation specimenType) {
1342
        if (specimenType.getTypeSpecimen() != null){
1343
            DerivedUnit specimen =  specimenType.getTypeSpecimen();
1344
            if(specimen != null && !state.getSpecimenStore().contains( specimen.getUuid())){
1345
               handleSpecimen(state, specimen);
1346
            }
1347
        }
1348
        CdmLightExportTable table = CdmLightExportTable.TYPE_DESIGNATION;
1349
        String[] csvLine = new String[table.getSize()];
1350
        //TYPE_ID, SPECIMEN_FK, TYPE_VERBATIM_CITATION, TYPE_STATUS, TYPE_DESIGNATED_BY_STRING, TYPE_DESIGNATED_BY_REF_FK};
1351
        //Specimen_Fk und den Typusangaben (Art des Typus [holo, lecto, etc.], Quelle, Designation-Quelle, +
1352
        Set<TaxonName> typifiedNames = specimenType.getTypifiedNames();
1353
        for (TaxonName name: typifiedNames){
1354
            csvLine[table.getIndex(CdmLightExportTable.TYPE_STATUS)] = specimenType.getTypeStatus() != null? specimenType.getTypeStatus().getDescription(): "";
1355
            csvLine[table.getIndex(CdmLightExportTable.TYPE_ID)] = getId(state, specimenType);
1356
            csvLine[table.getIndex(CdmLightExportTable.TYPIFIED_NAME_FK)] = getId(state, name);
1357
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_FK)] = getId(state, specimenType.getTypeSpecimen());
1358
            if (specimenType.getSources() != null && !specimenType.getSources().isEmpty()){
1359
                String sourceString = "";
1360
                int index = 0;
1361
                for (IdentifiableSource source: specimenType.getSources()){
1362
                    if (source.getCitation()!= null){
1363
                        sourceString = sourceString.concat(source.getCitation().getCitation());
1364
                    }
1365
                    index++;
1366
                    if (index != specimenType.getSources().size()){
1367
                        sourceString.concat(", ");
1368
                    }
1369
                }
1370
                csvLine[table.getIndex(CdmLightExportTable.TYPE_INFORMATION_REF_STRING)] = sourceString;
1371
            }
1372
            if (specimenType.getDesignationSource() != null && specimenType.getDesignationSource().getCitation() != null && !state.getReferenceStore().contains(specimenType.getDesignationSource().getCitation().getUuid())){
1373
                handleReference(state, specimenType.getDesignationSource().getCitation());
1374
                csvLine[table.getIndex(CdmLightExportTable.TYPE_DESIGNATED_BY_REF_FK)] = specimenType.getDesignationSource() != null ? getId(state, specimenType.getDesignationSource().getCitation()): "";
1375
            }
1376

    
1377
            state.getProcessor().put(table, specimenType, csvLine);
1378
        }
1379
    }
1380

    
1381

    
1382
    /**
1383
     * @param specimenType
1384
     */
1385
    private void handleSpecimenType(CdmLightExportState state, SpecimenTypeDesignation specimenType) {
1386
        if (specimenType.getTypeSpecimen() != null){
1387
            DerivedUnit specimen =  specimenType.getTypeSpecimen();
1388
            if(specimen != null && !state.getSpecimenStore().contains( specimen.getUuid())){
1389
               handleSpecimen(state, specimen);
1390
            }
1391
        }
1392
        CdmLightExportTable table = CdmLightExportTable.TYPE_DESIGNATION;
1393
        String[] csvLine = new String[table.getSize()];
1394

    
1395
        csvLine[table.getIndex(CdmLightExportTable.TYPE_STATUS)] = specimenType.getTypeStatus() != null? specimenType.getTypeStatus().getDescription(): "";
1396
        csvLine[table.getIndex(CdmLightExportTable.TYPE_ID)] = getId(state, specimenType);
1397
        csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_FK)] = getId(state, specimenType.getTypeSpecimen());
1398
        if (specimenType.getSources() != null && !specimenType.getSources().isEmpty()){
1399
            String sourceString = "";
1400
            int index = 0;
1401
            List<IdentifiableSource> sources = new ArrayList<>(specimenType.getSources());
1402
            Comparator<IdentifiableSource> compareByYear = new Comparator<IdentifiableSource>() {
1403
                @Override
1404
                public int compare(IdentifiableSource o1, IdentifiableSource o2) {
1405
                    if (o1 == o2){
1406
                        return 0;
1407
                    }
1408
                    if (o1.getCitation() == null && o2.getCitation() != null){
1409
                        return -1;
1410
                    }
1411
                    if (o2.getCitation() == null && o1.getCitation() != null){
1412
                        return 1;
1413
                    }
1414
                    if (o1.getCitation().equals(o2.getCitation())){
1415
                        return 0;
1416
                    }
1417
                    if (o1.getCitation().getDatePublished() == null && o2.getCitation().getDatePublished() != null){
1418
                        return -1;
1419
                    }
1420
                    if (o1.getCitation().getDatePublished() != null && o2.getCitation().getDatePublished() == null){
1421
                        return 1;
1422
                    }
1423
                    if (o1.getCitation().getDatePublished().getYear() == null && o2.getCitation().getDatePublished().getYear() != null){
1424
                        return -1;
1425
                    }
1426
                    if (o1.getCitation().getDatePublished().getYear() != null && o2.getCitation().getDatePublished().getYear() == null){
1427
                        return 1;
1428
                    }
1429
                    return o1.getCitation().getDatePublished().getYear().compareTo(o2.getCitation().getDatePublished().getYear());
1430
                }
1431
            };
1432
            Collections.sort(sources, compareByYear);
1433
            for (IdentifiableSource source: sources){
1434
                if (source.getCitation()!= null){
1435
                    sourceString = sourceString.concat(source.getCitation().getCitation());
1436
                    handleReference(state, source.getCitation());
1437
                }
1438
                index++;
1439
                if (index <= specimenType.getSources().size()){
1440
                    sourceString = sourceString.concat("; ");
1441
                }
1442
            }
1443

    
1444
            csvLine[table.getIndex(CdmLightExportTable.TYPE_INFORMATION_REF_STRING)] = sourceString;
1445
            if (sources.get(0).getCitation() != null ){
1446
                csvLine[table.getIndex(CdmLightExportTable.TYPE_INFORMATION_REF_FK)] = getId(state, sources.get(0).getCitation());
1447
            }
1448
        }
1449
        if (specimenType.getDesignationSource() != null && specimenType.getDesignationSource().getCitation() != null && !state.getReferenceStore().contains(specimenType.getDesignationSource().getCitation().getUuid())){
1450
            handleReference(state, specimenType.getDesignationSource().getCitation());
1451
            csvLine[table.getIndex(CdmLightExportTable.TYPE_DESIGNATED_BY_REF_FK)] = specimenType.getDesignationSource() != null ? getId(state, specimenType.getDesignationSource().getCitation()): "";
1452
        }
1453

    
1454

    
1455
        Set<TaxonName> typifiedNames = specimenType.getTypifiedNames();
1456

    
1457
        if (typifiedNames.size() > 1){
1458
            state.getResult().addWarning("Please check the specimen type  "
1459
                    + cdmBaseStr(specimenType) + " there are more then one typified name.");
1460
        }
1461
        if (typifiedNames.iterator().hasNext()){
1462
            TaxonName name = typifiedNames.iterator().next();
1463
            csvLine[table.getIndex(CdmLightExportTable.TYPIFIED_NAME_FK)] = getId(state, name);
1464
        }
1465
        state.getProcessor().put(table, specimenType, csvLine);
1466

    
1467

    
1468

    
1469

    
1470

    
1471
    }
1472

    
1473

    
1474
    private String createNameWithItalics(List<TaggedText> taggedName) {
1475

    
1476
        String fullTitleWithHtml = "";
1477
        for (TaggedText taggedText: taggedName){
1478
            if (taggedText.getType().equals(TagEnum.name)){
1479
                fullTitleWithHtml += "<i>" + taggedText.getText() + "</i> ";
1480
            }else if (taggedText.getType().equals(TagEnum.separator)){
1481
                fullTitleWithHtml = fullTitleWithHtml.trim() + taggedText.getText() ;
1482
            }else{
1483
                fullTitleWithHtml += taggedText.getText() + " ";
1484
            }
1485
        }
1486
        return fullTitleWithHtml;
1487
    }
1488

    
1489
    private void handleNameRelationships(CdmLightExportState state, TaxonName name) {
1490
        Set<NameRelationship> rels = name.getRelationsFromThisName();
1491
        CdmLightExportTable table = CdmLightExportTable.NAME_RELATIONSHIP;
1492
        String[] csvLine = new String[table.getSize()];
1493

    
1494
        for (NameRelationship rel : rels) {
1495
            NameRelationshipType type = rel.getType();
1496
            TaxonName name2 = rel.getToName();
1497
            name2 = HibernateProxyHelper.deproxy(name2, TaxonName.class);
1498
            if (!state.getNameStore().containsKey(name2.getId())) {
1499
                handleName(state, name2, null);
1500
            }
1501

    
1502
            csvLine[table.getIndex(CdmLightExportTable.NAME_REL_TYPE)] = type.getLabel();
1503
            csvLine[table.getIndex(CdmLightExportTable.NAME1_FK)] = getId(state, name);
1504
            csvLine[table.getIndex(CdmLightExportTable.NAME2_FK)] = getId(state, name2);
1505
            state.getProcessor().put(table, name, csvLine);
1506
        }
1507

    
1508
        rels = name.getRelationsToThisName();
1509

    
1510
        csvLine = new String[table.getSize()];
1511

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

    
1520

    
1521
        }
1522
    }
1523

    
1524
    private String createCollatation(TaxonName name) {
1525
        String collation = "";
1526
        if (name.getNomenclaturalReference() != null) {
1527
            Reference ref = name.getNomenclaturalReference();
1528
            collation = getVolume(ref);
1529
        }
1530
        if (name.getNomenclaturalMicroReference() != null) {
1531
            if (!StringUtils.isBlank(collation)) {
1532
                collation += ":";
1533
            }
1534
            collation += name.getNomenclaturalMicroReference();
1535
        }
1536

    
1537
        return collation;
1538
    }
1539

    
1540
    private String getVolume(Reference reference) {
1541
        if (reference.getVolume() != null) {
1542
            return reference.getVolume();
1543
        } else if (reference.getInReference() != null) {
1544
            if (reference.getInReference().getVolume() != null) {
1545
                return reference.getInReference().getVolume();
1546
            }
1547
        }
1548
        return null;
1549
    }
1550

    
1551
    private void handleIdentifier(CdmLightExportState state, CdmBase cdmBase) {
1552
        CdmLightExportTable table = CdmLightExportTable.IDENTIFIER;
1553
        String[] csvLine;
1554
        try {
1555
            if (cdmBase instanceof TaxonName){
1556
                TaxonName name = (TaxonName)cdmBase;
1557

    
1558
                try{
1559
                    List<Identifier> identifiers = name.getIdentifiers();
1560

    
1561
                    //first check which kind of identifiers are available and then sort and create table entries
1562
                    Map<DefinedTerm, Set<Identifier>> identifierTypes = new HashMap<>();
1563
                    for (Identifier identifier: identifiers){
1564
                        DefinedTerm type = identifier.getType();
1565
                        if (identifierTypes.containsKey(type)){
1566
                            identifierTypes.get(type).add(identifier);
1567
                        }else{
1568
                            Set<Identifier> tempList = new HashSet<>();
1569
                            tempList.add(identifier);
1570
                            identifierTypes.put(type, tempList);
1571
                        }
1572
                    }
1573

    
1574
                    for (DefinedTerm type:identifierTypes.keySet()){
1575
                        Set<Identifier> identifiersByType = identifierTypes.get(type);
1576
                        csvLine = new String[table.getSize()];
1577
                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, name);
1578
                        csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = "ScientificName";
1579
                        csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = type.getLabel();
1580
                        csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = extractIdentifier(
1581
                                identifiersByType);
1582
                        state.getProcessor().put(table, name.getUuid() + ", " + type.getLabel(), csvLine);
1583
                    }
1584

    
1585

    
1586
//                    Set<String> IPNIidentifiers = name.getIdentifiers(DefinedTerm.IDENTIFIER_NAME_IPNI());
1587
//                    Set<String> tropicosIdentifiers = name.getIdentifiers(DefinedTerm.IDENTIFIER_NAME_TROPICOS());
1588
//                    Set<String> WFOIdentifiers = name.getIdentifiers(DefinedTerm.uuidWfoNameIdentifier);
1589
//                    if (!IPNIidentifiers.isEmpty()) {
1590
//                        csvLine = new String[table.getSize()];
1591
//                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, name);
1592
//                        csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = "ScientificName";
1593
//                        csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = IPNI_NAME_IDENTIFIER;
1594
//                        csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = extractIdentifier(
1595
//                                IPNIidentifiers);
1596
//                        state.getProcessor().put(table, name.getUuid() + ", " + IPNI_NAME_IDENTIFIER, csvLine);
1597
//                    }
1598
//                    if (!tropicosIdentifiers.isEmpty()) {
1599
//                        csvLine = new String[table.getSize()];
1600
//                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, name);
1601
//                        csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = "ScientificName";
1602
//                        csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = TROPICOS_NAME_IDENTIFIER;
1603
//                        csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = extractIdentifier(
1604
//                                tropicosIdentifiers);
1605
//                        state.getProcessor().put(table, name.getUuid() + ", " + IPNI_NAME_IDENTIFIER, csvLine);
1606
//                    }
1607
//                    if (!WFOIdentifiers.isEmpty()) {
1608
//                        csvLine = new String[table.getSize()];
1609
//                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, name);
1610
//                        csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = "ScientificName";
1611
//                        csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = WFO_NAME_IDENTIFIER;
1612
//                        csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = extractIdentifier(
1613
//                                WFOIdentifiers);
1614
//                        state.getProcessor().put(table, name.getUuid() + ", " + WFO_NAME_IDENTIFIER, csvLine);
1615
//                    }
1616
                }catch(Exception e){
1617
                    state.getResult().addWarning("Please check the identifiers for "
1618
                            + cdmBaseStr(cdmBase) + " maybe there is an empty identifier");
1619

    
1620

    
1621
                }
1622
            }else{
1623
                if (cdmBase instanceof IdentifiableEntity){
1624
                    IdentifiableEntity<?> identifiableEntity = (IdentifiableEntity<?>) cdmBase;
1625
                    List<Identifier> identifiers = identifiableEntity.getIdentifiers();
1626
                    String tableName = null;
1627
                    if (cdmBase instanceof Reference){
1628
                        tableName = "Reference";
1629
                    }else if (cdmBase instanceof SpecimenOrObservationBase){
1630
                        tableName = "Specimen";
1631
                    }else if (cdmBase instanceof Taxon){
1632
                        tableName = "Taxon";
1633
                    }else if (cdmBase instanceof Synonym){
1634
                        tableName = "Synonym";
1635
                    }else if (cdmBase instanceof TeamOrPersonBase){
1636
                        tableName = "PersonOrTeam";
1637
                    }
1638

    
1639
                    for (Identifier identifier: identifiers){
1640
                        if (identifier.getType() == null && identifier.getIdentifier() == null){
1641
                            state.getResult().addWarning("Please check the identifiers for "
1642
                                    + cdmBaseStr(cdmBase) + " there is an empty identifier");
1643
                            continue;
1644
                        }
1645

    
1646
                        csvLine = new String[table.getSize()];
1647
                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, cdmBase);
1648

    
1649
                        if (tableName != null){
1650
                            csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = tableName;
1651
                            csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = identifier.getType() != null? identifier.getType().getLabel():null;
1652
                            csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = identifier.getIdentifier();
1653
                            state.getProcessor().put(table, cdmBase.getUuid() + (identifier.getType() != null? identifier.getType().getLabel():null), csvLine);
1654
                        }
1655
                    }
1656
                    if (cdmBase instanceof Reference ){
1657
                        Reference ref = (Reference)cdmBase;
1658
                        if (ref.getDoi() != null){
1659
                            csvLine = new String[table.getSize()];
1660
                            csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, cdmBase);
1661
                            csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = tableName;
1662
                            csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = "DOI";
1663
                            csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = ref.getDoiString();
1664
                            state.getProcessor().put(table, cdmBase.getUuid() + "DOI", csvLine);
1665
                        }
1666
                    }
1667

    
1668
                    if (cdmBase instanceof TeamOrPersonBase){
1669
                        TeamOrPersonBase<?> person= HibernateProxyHelper.deproxy(cdmBase, TeamOrPersonBase.class);
1670
                        if (person instanceof Person &&  ((Person)person).getOrcid() != null){
1671
                            csvLine = new String[table.getSize()];
1672
                            csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, cdmBase);
1673
                            csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = tableName;
1674
                            csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = "ORCID";
1675
                            csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)]=  ((Person)person).getOrcid().asURI();
1676
                            state.getProcessor().put(table, cdmBase.getUuid() + "ORCID", csvLine);
1677
                        }
1678
                    }
1679
                }
1680
            }
1681
        } catch (Exception e) {
1682
            state.getResult().addException(e, "An unexpected error occurred when handling identifiers for "
1683
                    + cdmBaseStr(cdmBase) + ": " + e.getMessage());
1684
            e.printStackTrace();
1685
        }
1686
    }
1687

    
1688
    private String extractIdentifier(Set<Identifier> identifierSet) {
1689

    
1690
        String identifierString = "";
1691
        for (Identifier identifier : identifierSet) {
1692
            if (!StringUtils.isBlank(identifierString)) {
1693
                identifierString += ", ";
1694
            }
1695
            identifierString += identifier.getIdentifier();
1696
        }
1697
        return identifierString;
1698
    }
1699

    
1700
    private String extractProtologueURIs(CdmLightExportState state, TaxonName name) {
1701
        if (name.getNomenclaturalSource() != null){
1702
            Set<ExternalLink> links = name.getNomenclaturalSource().getLinks();
1703
            return extractLinkUris(links.iterator());
1704
        }else{
1705
            return null;
1706
        }
1707
    }
1708

    
1709
    private String extractMediaURIs(CdmLightExportState state, Set<? extends DescriptionBase<?>> descriptionsSet,
1710
            Feature feature) {
1711

    
1712
        String mediaUriString = "";
1713
        Set<DescriptionElementBase> elements = new HashSet<>();
1714
        for (DescriptionBase<?> description : descriptionsSet) {
1715
            try {
1716
                if (!description.getElements().isEmpty()) {
1717
                    elements = description.getElements();
1718

    
1719
                    for (DescriptionElementBase element : elements) {
1720
                        Feature entityFeature = HibernateProxyHelper.deproxy(element.getFeature());
1721
                        if (entityFeature.equals(feature)) {
1722
                            if (!element.getMedia().isEmpty()) {
1723
                                List<Media> media = element.getMedia();
1724
                                for (Media mediaElement : media) {
1725
                                    Iterator<MediaRepresentation> it = mediaElement.getRepresentations().iterator();
1726
                                    mediaUriString = extractMediaUris(it);
1727
                                }
1728
                            }
1729
                        }
1730
                    }
1731
                }
1732
            } catch (Exception e) {
1733
                state.getResult().addException(e, "An unexpected error occurred when extracting media URIs for "
1734
                        + cdmBaseStr(description) + ": " + e.getMessage());
1735
            }
1736
        }
1737
        return mediaUriString;
1738
    }
1739

    
1740
    private void handleAuthor(CdmLightExportState state, TeamOrPersonBase<?> author) {
1741
        try {
1742
            if (state.getAuthorFromStore(author.getId()) != null) {
1743
                return;
1744
            }
1745
            state.addAuthorToStore(author);
1746
            handleIdentifier(state, author);
1747
            CdmLightExportTable table = CdmLightExportTable.NOMENCLATURAL_AUTHOR;
1748
            String[] csvLine = new String[table.getSize()];
1749
            CdmLightExportTable tableAuthorRel = CdmLightExportTable.NOMENCLATURAL_AUTHOR_TEAM_RELATION;
1750
            String[] csvLineRel = new String[tableAuthorRel.getSize()];
1751
            String[] csvLineMember = new String[table.getSize()];
1752
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_ID)] = getId(state, author);
1753
            csvLine[table.getIndex(CdmLightExportTable.ABBREV_AUTHOR)] = author.isProtectedTitleCache()
1754
                    ? author.getTitleCache() : author.getNomenclaturalTitleCache();
1755
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_TITLE)] = author.getTitleCache();
1756
            author = HibernateProxyHelper.deproxy(author);
1757
            if (author instanceof Person) {
1758
                Person authorPerson = (Person) author;
1759
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_GIVEN_NAME)] = authorPerson.getGivenName();
1760
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_FAMILY_NAME)] = authorPerson.getFamilyName();
1761
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_PREFIX)] = authorPerson.getPrefix();
1762
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_SUFFIX)] = authorPerson.getSuffix();
1763
            } else {
1764
                // create an entry in rel table and all members in author table,
1765
                // check whether the team members already in author table
1766

    
1767
                Team authorTeam = (Team) author;
1768
                int index = 0;
1769
                for (Person member : authorTeam.getTeamMembers()) {
1770
                    csvLineRel = new String[tableAuthorRel.getSize()];
1771
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_TEAM_FK)] = getId(state, authorTeam);
1772
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_FK)] = getId(state, member);
1773
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_TEAM_SEQ_NUMBER)] = String
1774
                            .valueOf(index);
1775
                    state.getProcessor().put(tableAuthorRel, authorTeam.getId() + ":" + member.getId(), csvLineRel);
1776

    
1777
                    if (state.getAuthorFromStore(member.getId()) == null) {
1778
                        state.addAuthorToStore(member);
1779
                        csvLineMember = new String[table.getSize()];
1780
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_ID)] = getId(state, member);
1781
                        csvLineMember[table.getIndex(CdmLightExportTable.ABBREV_AUTHOR)] = member
1782
                                .isProtectedTitleCache() ? member.getTitleCache() : member.getNomenclaturalTitleCache();
1783
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_TITLE)] = member.getTitleCache();
1784
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_GIVEN_NAME)] = member.getGivenName();
1785
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_FAMILY_NAME)] = member.getFamilyName();
1786
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_PREFIX)] = member.getPrefix();
1787
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_SUFFIX)] = member.getSuffix();
1788
                        state.getProcessor().put(table, member, csvLineMember);
1789
                    }
1790
                    index++;
1791
                }
1792
            }
1793
            state.getProcessor().put(table, author, csvLine);
1794
        } catch (Exception e) {
1795
            state.getResult().addException(e,
1796
                    "An unexpected error occurred when handling author " + cdmBaseStr(author) + ": " + e.getMessage());
1797
        }
1798
    }
1799

    
1800
    private String extractStatusString(CdmLightExportState state, TaxonName name, boolean abbrev) {
1801
        try {
1802
            Set<NomenclaturalStatus> status = name.getStatus();
1803
            if (status.isEmpty()) {
1804
                return "";
1805
            }
1806
            String statusString = "";
1807
            for (NomenclaturalStatus nameStatus : status) {
1808
                if (nameStatus != null) {
1809
                    if (abbrev) {
1810
                        if (nameStatus.getType() != null) {
1811
                            statusString += nameStatus.getType().getIdInVocabulary();
1812
                        }
1813
                    } else {
1814
                        if (nameStatus.getType() != null) {
1815
                            statusString += nameStatus.getType().getTitleCache();
1816
                        }
1817
                    }
1818
                    if (!abbrev) {
1819

    
1820
                        if (nameStatus.getRuleConsidered() != null
1821
                                && !StringUtils.isBlank(nameStatus.getRuleConsidered())) {
1822
                            statusString += ": " + nameStatus.getRuleConsidered();
1823
                        }
1824
                        if (nameStatus.getCitation() != null) {
1825
                            String shortCitation = OriginalSourceFormatter.INSTANCE.format(nameStatus.getCitation(), null);
1826
                            statusString += " (" + shortCitation + ")";
1827
                        }
1828
//                        if (nameStatus.getCitationMicroReference() != null
1829
//                                && !StringUtils.isBlank(nameStatus.getCitationMicroReference())) {
1830
//                            statusString += " " + nameStatus.getCitationMicroReference();
1831
//                        }
1832
                    }
1833
                    statusString += " ";
1834
                }
1835
            }
1836
            return statusString;
1837
        } catch (Exception e) {
1838
            state.getResult().addException(e, "An unexpected error occurred when extracting status string for "
1839
                    + cdmBaseStr(name) + ": " + e.getMessage());
1840
            return "";
1841
        }
1842
    }
1843

    
1844
    private void handleHomotypicalGroup(CdmLightExportState state, HomotypicalGroup group, Taxon acceptedTaxon, int sortIndex) {
1845
        try {
1846
            state.addHomotypicalGroupToStore(group);
1847
            CdmLightExportTable table = CdmLightExportTable.HOMOTYPIC_GROUP;
1848
            String[] csvLine = new String[table.getSize()];
1849
            csvLine[table.getIndex(CdmLightExportTable.SORT_INDEX)] = String.valueOf(sortIndex);
1850
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_ID)] = getId(state, group);
1851

    
1852
            List<TaxonName> typifiedNames = new ArrayList<>();
1853
            if (acceptedTaxon != null){
1854
                List<Synonym> synonymsInGroup = acceptedTaxon.getSynonymsInGroup(group);
1855
                if (group.equals(acceptedTaxon.getHomotypicGroup())){
1856
                    typifiedNames.add(acceptedTaxon.getName());
1857
                }
1858
                synonymsInGroup.stream().forEach(synonym -> typifiedNames.add(CdmBase.deproxy(synonym.getName())));
1859
            }
1860

    
1861

    
1862
            TaxonName firstname = null;
1863
            for (TaxonName name: typifiedNames){
1864
                Iterator<Taxon> taxa = name.getTaxa().iterator();
1865
                while(taxa.hasNext()){
1866
                    Taxon taxon = taxa.next();
1867
                    if(!(taxon.isMisapplication() || taxon.isProparteSynonym())){
1868
                        firstname = name;
1869
                        break;
1870
                    }
1871
                }
1872
            }
1873

    
1874
//            Collections.sort(typifiedNames, new HomotypicalGroupNameComparator(firstname, true));
1875
            String typifiedNamesString = "";
1876
            String typifiedNamesWithSecString = "";
1877
            String typifiedNamesWithoutAccepted = "";
1878
            String typifiedNamesWithoutAcceptedWithSec = "";
1879
            int index = 0;
1880
            for (TaxonName name : typifiedNames) {
1881
                // Concatenated output string for homotypic group (names and
1882
                // citations) + status + some name relations (e.g. “non”)
1883
                // TODO: nameRelations, which and how to display
1884
                Set<TaxonBase> taxonBases = name.getTaxonBases();
1885
                TaxonBase<?> taxonBase;
1886

    
1887
                String sec = "";
1888
                String nameString = name.getFullTitleCache();
1889
                String doubtful = "";
1890

    
1891
                if (state.getConfig().isAddHTML()){
1892
                    nameString = createNameWithItalics(name.getTaggedFullTitle()) ;
1893
                }
1894

    
1895
                Set<NameRelationship> related = name.getNameRelations();
1896
                List<NameRelationship> relatedList = new ArrayList<>(related);
1897

    
1898
                Collections.sort(relatedList, new Comparator<NameRelationship>() {
1899
                    @Override
1900
                    public int compare(NameRelationship nr1, NameRelationship nr2) {
1901
                        return nr1.getType().compareTo(nr2.getType());
1902
                    }
1903

    
1904
                });
1905

    
1906
                List<NameRelationship> nonNames = new ArrayList<>();
1907
                List<NameRelationship> otherRelationships = new ArrayList<>();
1908

    
1909
                for (NameRelationship rel: relatedList){
1910
                    //no inverse relations
1911
                    if (rel.getFromName().equals(name)){
1912
                     // alle Homonyme und inverse blocking names
1913
                        if (rel.getType().equals(NameRelationshipType.LATER_HOMONYM())
1914
                                || rel.getType().equals(NameRelationshipType.TREATED_AS_LATER_HOMONYM())
1915
                                || (rel.getType().equals(NameRelationshipType.BLOCKING_NAME_FOR()))
1916
                                || (rel.getType().equals(NameRelationshipType.UNSPECIFIC_NON()))){
1917
                            nonNames.add(rel);
1918
                        }else if (!rel.getType().isBasionymRelation()){
1919
                            otherRelationships.add(rel);
1920
                        }
1921
                    }
1922
                }
1923

    
1924
                String nonRelNames = "";
1925
                String relNames = "";
1926

    
1927
                if (nonNames.size() > 0){
1928
                    nonRelNames += " [";
1929
                }
1930
                for (NameRelationship relName: nonNames){
1931
                    String label = "non ";
1932
                    TaxonName relatedName = null;
1933
                    if (relName.getFromName().equals(name)){
1934
                        relatedName = relName.getToName();
1935
                        nonRelNames += label + relatedName.getTitleCache() + " ";
1936
                    }
1937
//                    else{
1938
//                        label = relName.getType().getInverseLabel() + " ";
1939
//                        relatedName = relName.getFromName();
1940
//                        nonRelNames += label + relatedName.getTitleCache() + " ";
1941
//                    }
1942

    
1943

    
1944
                }
1945
                relNames.trim();
1946
                if (nonNames.size() > 0){
1947
                    nonRelNames = StringUtils.strip(nonRelNames, null);
1948
                    nonRelNames += "] ";
1949
                }
1950

    
1951
                if (otherRelationships.size() > 0){
1952
                    relNames += " [";
1953
                }
1954
                for (NameRelationship rel: otherRelationships){
1955
                    String label = "";
1956
                    TaxonName relatedName = null;
1957
                    if (rel.getFromName().equals(name)){
1958
                        label = rel.getType().getLabel() + " ";
1959
                        relatedName = rel.getToName();
1960
                        if (state.getConfig().isAddHTML()){
1961
                            relNames += label + createNameWithItalics(relatedName.getTaggedName())+ " ";
1962
                        }else{
1963
                            relNames += label + relatedName.getTitleCache();
1964
                        }
1965
                    }
1966
//                    else {
1967
//                        label = rel.getType().getInverseLabel() + " ";
1968
//                        relatedName = rel.getFromName();
1969
//                    }
1970

    
1971
                }
1972
                relNames.trim();
1973
                if (otherRelationships.size() > 0){
1974
                    relNames = StringUtils.stripEnd(relNames, null);
1975
                    relNames += "] ";
1976
                }
1977

    
1978
                String synonymSign = "";
1979
                if (index > 0){
1980
                    if (name.isInvalid()){
1981
                        synonymSign = "\u2212 ";
1982
                    }else{
1983
                        synonymSign = "\u2261 ";
1984
                    }
1985
                }else{
1986
                    if (name.isInvalid() ){
1987
                        synonymSign = "\u2212 ";
1988
                    }else{
1989
                        synonymSign = "\u003D ";
1990
                    }
1991
                }
1992
                boolean isAccepted = false;
1993

    
1994
                if (taxonBases.size() == 1){
1995
                     taxonBase = HibernateProxyHelper.deproxy(taxonBases.iterator().next());
1996

    
1997
                     if (taxonBase.getSec() != null){
1998
                         sec = OriginalSourceFormatter.INSTANCE_WITH_YEAR_BRACKETS.format(taxonBase.getSecSource());
1999
                     }
2000
                     if (taxonBase.isDoubtful()){
2001
                         doubtful = "?";
2002
                     }else{
2003
                         doubtful = "";
2004
                     }
2005
                     if (taxonBase instanceof Synonym){
2006
                         if (isNotBlank(sec)){
2007
                             sec = " syn. sec. " + sec + " ";
2008
                         }else {
2009
                             sec = "";
2010
                         }
2011

    
2012
                         typifiedNamesWithoutAccepted += synonymSign + doubtful + nameString + nonRelNames + relNames;
2013
                         typifiedNamesWithoutAcceptedWithSec += synonymSign + doubtful + nameString + sec + nonRelNames + relNames;
2014
                     }else{
2015
//                         sec = "";
2016
                         if (!(((Taxon)taxonBase).isProparteSynonym() || ((Taxon)taxonBase).isMisapplication())){
2017
                             isAccepted = true;
2018
                         }else {
2019
                             synonymSign = "\u003D ";
2020
                         }
2021

    
2022
                     }
2023
                     if (taxonBase.getAppendedPhrase() != null){
2024
                         if (state.getConfig().isAddHTML()){
2025
                             String taxonString = createNameWithItalics(taxonBase.getTaggedTitle()) ;
2026
                             taxonString = taxonString.replace("sec "+sec, "");
2027
                             String nameCacheWithItalics = createNameWithItalics(name.getTaggedName());
2028
                             nameString = nameString.replace(nameCacheWithItalics, taxonString);
2029
                         }
2030
                     }
2031
                }else{
2032
                    //there are names used more than once?
2033
                    for (TaxonBase<?> tb: taxonBases){
2034
                        if (tb.getSec() != null){
2035
                            sec = OriginalSourceFormatter.INSTANCE_WITH_YEAR_BRACKETS.format(tb.getSecSource());
2036
                        }
2037
                        if (tb.isDoubtful()){
2038
                            doubtful = "?";
2039
                        }else{
2040
                            doubtful = "";
2041
                        }
2042
                        if (tb instanceof Synonym){
2043
                            if (StringUtils.isNotBlank(sec)){
2044
                                sec = " syn. sec. " + sec + " ";
2045
                            }else {
2046
                                sec = "";
2047
                            }
2048

    
2049
                            break;
2050
                        }else{
2051
                            sec = "";
2052
                            if (!(((Taxon)tb).isProparteSynonym() || ((Taxon)tb).isMisapplication())){
2053
                                isAccepted = true;
2054
                                break;
2055
                            }else {
2056
                                synonymSign = "\u003D ";
2057
                            }
2058

    
2059
                        }
2060
                    }
2061
                    if (!isAccepted){
2062
                        typifiedNamesWithoutAccepted += synonymSign + doubtful + nameString + "; ";
2063
                        typifiedNamesWithoutAcceptedWithSec += synonymSign + doubtful + nameString + sec;
2064
                        typifiedNamesWithoutAcceptedWithSec = typifiedNamesWithoutAcceptedWithSec.trim() + "; ";
2065
                    }
2066
                }
2067
                typifiedNamesString += synonymSign + doubtful + nameString + nonRelNames + relNames;
2068
                typifiedNamesWithSecString += synonymSign + doubtful + nameString + sec + nonRelNames + relNames;
2069

    
2070

    
2071
                csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_STRING)] = typifiedNamesString.trim();
2072

    
2073
                csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITH_SEC_STRING)] = typifiedNamesWithSecString.trim();
2074

    
2075
                if (typifiedNamesWithoutAccepted != null && firstname != null) {
2076
                    csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTED)] = typifiedNamesWithoutAccepted.trim();
2077
                } else {
2078
                    csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTED)] = "";
2079
                }
2080

    
2081
                if (typifiedNamesWithoutAcceptedWithSec != null && firstname != null) {
2082
                    csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTEDWITHSEC)] = typifiedNamesWithoutAcceptedWithSec.trim();
2083
                } else {
2084
                    csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTEDWITHSEC)] = "";
2085
                }
2086
                index++;
2087
            }
2088

    
2089
            Set<TypeDesignationBase<?>> typeDesigantionSet = group.getTypeDesignations();
2090
            List<TypeDesignationBase<?>> designationList = new ArrayList<>();
2091
            designationList.addAll(typeDesigantionSet);
2092
            Collections.sort(designationList, new TypeComparator());
2093

    
2094
            List<TaggedText> list = new ArrayList<>();
2095
            if (!designationList.isEmpty()) {
2096
                TypeDesignationSetManager manager = new TypeDesignationSetManager(group);
2097
                list.addAll(new TypeDesignationSetFormatter(true, false, false).toTaggedText(manager));
2098
            }
2099
            String typeTextDesignations = "";
2100
            //The typeDesignationManager does not handle the textual typeDesignations
2101
            for (TypeDesignationBase<?> typeDes: designationList) {
2102
            	if (typeDes instanceof TextualTypeDesignation) {
2103
            		typeTextDesignations = typeTextDesignations + ((TextualTypeDesignation)typeDes).getText(Language.getDefaultLanguage());
2104
            		String typeDesStateRefs = "";
2105
                    if (typeDes.getDesignationSource() != null ){
2106
                        typeDesStateRefs = "[";
2107
                        NamedSource source = typeDes.getDesignationSource();
2108
                        if (source.getCitation() != null){
2109
                            typeDesStateRefs += "fide " + OriginalSourceFormatter.INSTANCE.format(source.getCitation(), null);
2110
                        }
2111
                        typeDesStateRefs += "]";
2112
                    }else if (typeDes.getSources() != null && !typeDes.getSources().isEmpty()){
2113
                        typeDesStateRefs = "[";
2114
                        for (IdentifiableSource source: typeDes.getSources()) {
2115
                            if (source.getCitation() != null){
2116
                                typeDesStateRefs += "fide " +OriginalSourceFormatter.INSTANCE.format(source.getCitation(), null);
2117
                            }
2118
                        }
2119

    
2120
                        typeDesStateRefs += "]";
2121
                    }
2122

    
2123
            		typeTextDesignations =  typeTextDesignations + typeDesStateRefs +"; ";
2124

    
2125
            	}else if (typeDes instanceof SpecimenTypeDesignation){
2126
            	    DerivedUnit specimen =  ((SpecimenTypeDesignation)typeDes).getTypeSpecimen();
2127
            	    if(specimen != null && !state.getSpecimenStore().contains( specimen.getUuid())){
2128
            	        handleSpecimen(state, specimen);
2129
            	    }
2130
            	}
2131
            }
2132
            if (typeTextDesignations.equals("; ")) {
2133
            	typeTextDesignations = "";
2134
            }
2135
            if (StringUtils.isNotBlank(typeTextDesignations)) {
2136
            	typeTextDesignations = typeTextDesignations.substring(0, typeTextDesignations.length()-2);
2137
            }
2138
            String specimenTypeString = !list.isEmpty()? createTypeDesignationString(list, true, typifiedNames.get(0).isSpecies() || typifiedNames.get(0).isInfraSpecific()):"";
2139

    
2140
            if (StringUtils.isNotBlank(specimenTypeString)) {
2141
                if (!specimenTypeString.endsWith(".")) {
2142
                	specimenTypeString = specimenTypeString + ".";
2143
                }
2144
                csvLine[table.getIndex(CdmLightExportTable.TYPE_STRING)] = specimenTypeString;
2145

    
2146
            } else {
2147
                csvLine[table.getIndex(CdmLightExportTable.TYPE_STRING)] = "";
2148
            }
2149
            if (StringUtils.isNotBlank(typeTextDesignations)) {
2150
                if (!typeTextDesignations.endsWith(".")) {
2151
                	typeTextDesignations = typeTextDesignations + ".";
2152
                }
2153
                csvLine[table.getIndex(CdmLightExportTable.TYPE_CACHE)] = typeTextDesignations;
2154

    
2155
            } else {
2156
                csvLine[table.getIndex(CdmLightExportTable.TYPE_CACHE)] = "";
2157
            }
2158
            state.getProcessor().put(table, String.valueOf(group.getId()), csvLine);
2159
        } catch (Exception e) {
2160
            state.getResult().addException(e, "An unexpected error occurred when handling homotypic group "
2161
                    + cdmBaseStr(group) + ": " + e.getMessage());
2162
        }
2163
    }
2164

    
2165
    private String createTypeDesignationString(List<TaggedText> list, boolean isHomotypicGroup, boolean isSpecimenTypeDesignation) {
2166
        StringBuffer homotypicalGroupTypeDesignationString = new StringBuffer();
2167

    
2168
        for (TaggedText text : list) {
2169
            if (text == null || text.getText() == null){
2170
                continue;  //just in case
2171
            }
2172
            if ((text.getText().equalsIgnoreCase("Type:")  //should not happen anymore
2173
                    || text.getText().equalsIgnoreCase("Nametype:")  //should not happen anymore
2174
                    || (text.getType().equals(TagEnum.name) && !isHomotypicGroup))) {
2175
                // do nothing
2176
            }else if (text.getType().equals(TagEnum.reference)) {
2177
                homotypicalGroupTypeDesignationString.append(text.getText());
2178
            }else if (text.getType().equals(TagEnum.name)){
2179
                if (!isSpecimenTypeDesignation){
2180
                    homotypicalGroupTypeDesignationString
2181
                        .append("<i>"+text.getText()+"</i> ");
2182
                }
2183
            }else if (text.getType().equals(TagEnum.typeDesignation) ) {
2184
                if(isSpecimenTypeDesignation){
2185
                    homotypicalGroupTypeDesignationString
2186
                        .append(text.getText().replace(").", "").replace("(", "").replace(")", ""));
2187
                }else{
2188
                    homotypicalGroupTypeDesignationString
2189
                        .append(text.getText());
2190
                }
2191

    
2192
            } else {
2193
                homotypicalGroupTypeDesignationString.append(text.getText());
2194
            }
2195
        }
2196

    
2197
        String typeDesignations = homotypicalGroupTypeDesignationString.toString();
2198
        typeDesignations = typeDesignations.trim();
2199

    
2200
        if (typeDesignations.endsWith(";")){
2201
            typeDesignations = typeDesignations.substring(0, typeDesignations.length()-1);
2202
        }
2203
        typeDesignations += ".";
2204
        typeDesignations = typeDesignations.replace("..", ".");
2205
        typeDesignations = typeDesignations.replace(". .", ".");
2206
        typeDesignations = typeDesignations.replace("; \u2261", " \u2261 ");
2207

    
2208
        if (typeDesignations.trim().equals(".")) {
2209
            typeDesignations = null;
2210
        }
2211

    
2212
        return typeDesignations;
2213
    }
2214

    
2215
    private String getTropicosTitleCache(CdmLightExportState state, TaxonName name) {
2216
        try {
2217
            String basionymStart = "(";
2218
            String basionymEnd = ") ";
2219
            String exAuthorSeperator = " ex ";
2220
            TeamOrPersonBase<?> combinationAuthor = name.getCombinationAuthorship();
2221
            TeamOrPersonBase<?> exCombinationAuthor = name.getExCombinationAuthorship();
2222
            TeamOrPersonBase<?> basionymAuthor = name.getBasionymAuthorship();
2223
            TeamOrPersonBase<?> exBasionymAuthor = name.getExBasionymAuthorship();
2224

    
2225
            String combinationAuthorString = "";
2226
            if (combinationAuthor != null) {
2227
                combinationAuthor = HibernateProxyHelper.deproxy(combinationAuthor);
2228
                if (combinationAuthor instanceof Team) {
2229
                    combinationAuthorString = createTropicosTeamTitle(combinationAuthor);
2230
                } else {
2231
                    Person person = HibernateProxyHelper.deproxy(combinationAuthor, Person.class);
2232
                    combinationAuthorString = createTropicosAuthorString(person);
2233
                }
2234
            }
2235
            String exCombinationAuthorString = "";
2236
            if (exCombinationAuthor != null) {
2237
                exCombinationAuthor = HibernateProxyHelper.deproxy(exCombinationAuthor);
2238
                if (exCombinationAuthor instanceof Team) {
2239
                    exCombinationAuthorString = createTropicosTeamTitle(exCombinationAuthor);
2240
                } else {
2241
                    Person person = HibernateProxyHelper.deproxy(exCombinationAuthor, Person.class);
2242
                    exCombinationAuthorString = createTropicosAuthorString(person);
2243
                }
2244
            }
2245

    
2246
            String basionymAuthorString = "";
2247
            if (basionymAuthor != null) {
2248
                basionymAuthor = HibernateProxyHelper.deproxy(basionymAuthor);
2249
                if (basionymAuthor instanceof Team) {
2250
                    basionymAuthorString = createTropicosTeamTitle(basionymAuthor);
2251
                } else {
2252
                    Person person = HibernateProxyHelper.deproxy(basionymAuthor, Person.class);
2253
                    basionymAuthorString = createTropicosAuthorString(person);
2254
                }
2255
            }
2256

    
2257
            String exBasionymAuthorString = "";
2258

    
2259
            if (exBasionymAuthor != null) {
2260
                exBasionymAuthor = HibernateProxyHelper.deproxy(exBasionymAuthor);
2261
                if (exBasionymAuthor instanceof Team) {
2262
                    exBasionymAuthorString = createTropicosTeamTitle(exBasionymAuthor);
2263

    
2264
                } else {
2265
                    Person person = HibernateProxyHelper.deproxy(exBasionymAuthor, Person.class);
2266
                    exBasionymAuthorString = createTropicosAuthorString(person);
2267
                }
2268
            }
2269
            String completeAuthorString = name.getNameCache() + " ";
2270

    
2271
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString)
2272
                    || !CdmUtils.isBlank(basionymAuthorString)) ? basionymStart : "";
2273
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString))
2274
                    ? (CdmUtils.Nz(exBasionymAuthorString) + exAuthorSeperator) : "";
2275
            completeAuthorString += (!CdmUtils.isBlank(basionymAuthorString)) ? CdmUtils.Nz(basionymAuthorString) : "";
2276
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString)
2277
                    || !CdmUtils.isBlank(basionymAuthorString)) ? basionymEnd : "";
2278
            completeAuthorString += (!CdmUtils.isBlank(exCombinationAuthorString))
2279
                    ? (CdmUtils.Nz(exCombinationAuthorString) + exAuthorSeperator) : "";
2280
            completeAuthorString += (!CdmUtils.isBlank(combinationAuthorString)) ? CdmUtils.Nz(combinationAuthorString)
2281
                    : "";
2282

    
2283
            return completeAuthorString;
2284
        } catch (Exception e) {
2285
            state.getResult().addException(e, "An unexpected error occurred when handling tropicos title cache for "
2286
                    + cdmBaseStr(name) + ": " + e.getMessage());
2287
            return null;
2288
        }
2289
    }
2290

    
2291
    private String createTropicosTeamTitle(TeamOrPersonBase<?> combinationAuthor) {
2292
        String combinationAuthorString;
2293
        Team team = HibernateProxyHelper.deproxy(combinationAuthor, Team.class);
2294
        Team tempTeam = Team.NewInstance();
2295
        for (Person teamMember : team.getTeamMembers()) {
2296
            combinationAuthorString = createTropicosAuthorString(teamMember);
2297
            Person tempPerson = Person.NewTitledInstance(combinationAuthorString);
2298
            tempTeam.addTeamMember(tempPerson);
2299
        }
2300
        combinationAuthorString = tempTeam.generateTitle();
2301
        return combinationAuthorString;
2302
    }
2303

    
2304
    private String createTropicosAuthorString(Person teamMember) {
2305
        String nomAuthorString = "";
2306
        String[] splittedAuthorString = null;
2307
        if (teamMember == null) {
2308
            return nomAuthorString;
2309
        }
2310

    
2311
        if (teamMember.getGivenName() != null) {
2312
            String givenNameString = teamMember.getGivenName().replaceAll("\\.", "\\. ");
2313
            splittedAuthorString = givenNameString.split("\\s");
2314
            for (String split : splittedAuthorString) {
2315
                if (!StringUtils.isBlank(split)) {
2316
                    nomAuthorString += split.substring(0, 1);
2317
                    nomAuthorString += ".";
2318
                }
2319
            }
2320
        }
2321
        if (teamMember.getFamilyName() != null) {
2322
            String familyNameString = teamMember.getFamilyName().replaceAll("\\.", "\\. ");
2323
            splittedAuthorString = familyNameString.split("\\s");
2324
            for (String split : splittedAuthorString) {
2325
                nomAuthorString += " " + split;
2326
            }
2327
        }
2328
        if (isBlank(nomAuthorString.trim())) {
2329
            if (teamMember.getTitleCache() != null) {
2330
                String titleCacheString = teamMember.getTitleCache().replaceAll("\\.", "\\. ");
2331
                splittedAuthorString = titleCacheString.split("\\s");
2332
            } else {
2333
                splittedAuthorString = new String[0];
2334
            }
2335

    
2336
            int index = 0;
2337
            for (String split : splittedAuthorString) {
2338
                if (index < splittedAuthorString.length - 1 && (split.length() == 1 || split.endsWith("."))) {
2339
                    nomAuthorString += split;
2340
                } else {
2341
                    nomAuthorString = nomAuthorString + " " + split;
2342
                }
2343
                index++;
2344
            }
2345
        }
2346
        return nomAuthorString.trim();
2347
    }
2348

    
2349
    private void handleReference(CdmLightExportState state, Reference reference) {
2350
        try {
2351
            state.addReferenceToStore(reference);
2352
            CdmLightExportTable table = CdmLightExportTable.REFERENCE;
2353
            reference = HibernateProxyHelper.deproxy(reference);
2354

    
2355
            handleIdentifier(state, reference);
2356
            String[] csvLine = new String[table.getSize()];
2357
            csvLine[table.getIndex(CdmLightExportTable.REFERENCE_ID)] = getId(state, reference);
2358
            // TODO short citations correctly
2359
            String shortCitation = OriginalSourceFormatter.INSTANCE_WITH_YEAR_BRACKETS.format(reference, null); // Should be Author(year) like in Taxon.sec
2360
            csvLine[table.getIndex(CdmLightExportTable.BIBLIO_SHORT_CITATION)] = shortCitation;
2361
            // TODO get preferred title
2362
            csvLine[table.getIndex(CdmLightExportTable.REF_TITLE)] = reference.isProtectedTitleCache()
2363
                    ? reference.getTitleCache() : reference.getTitle();
2364
            csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_TITLE)] = reference.isProtectedAbbrevTitleCache()
2365
                    ? reference.getAbbrevTitleCache() : reference.getAbbrevTitle();
2366
            csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = reference.getDatePublishedString();
2367
            // TBC
2368
            csvLine[table.getIndex(CdmLightExportTable.EDITION)] = reference.getEdition();
2369
            csvLine[table.getIndex(CdmLightExportTable.EDITOR)] = reference.getEditor();
2370
            csvLine[table.getIndex(CdmLightExportTable.ISBN)] = reference.getIsbn();
2371
            csvLine[table.getIndex(CdmLightExportTable.ISSN)] = reference.getIssn();
2372
            csvLine[table.getIndex(CdmLightExportTable.ORGANISATION)] = reference.getOrganization();
2373
            csvLine[table.getIndex(CdmLightExportTable.PAGES)] = reference.getPages();
2374
            csvLine[table.getIndex(CdmLightExportTable.PLACE_PUBLISHED)] = reference.getPlacePublished();
2375
            csvLine[table.getIndex(CdmLightExportTable.PUBLISHER)] = reference.getPublisher();
2376
            csvLine[table.getIndex(CdmLightExportTable.REF_ABSTRACT)] = reference.getReferenceAbstract();
2377
            csvLine[table.getIndex(CdmLightExportTable.SERIES_PART)] = reference.getSeriesPart();
2378
            csvLine[table.getIndex(CdmLightExportTable.VOLUME)] = reference.getVolume();
2379
            csvLine[table.getIndex(CdmLightExportTable.YEAR)] = reference.getYear();
2380

    
2381
            if (reference.getAuthorship() != null) {
2382
                csvLine[table.getIndex(CdmLightExportTable.AUTHORSHIP_TITLE)] = createFullAuthorship(reference);
2383
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_FK)] = getId(state, reference.getAuthorship());
2384
            }
2385

    
2386
            csvLine[table.getIndex(CdmLightExportTable.IN_REFERENCE)] = getId(state, reference.getInReference());
2387
            if (reference.getInReference() != null
2388
                    && !state.getReferenceStore().contains(reference.getInReference().getUuid())) {
2389
                handleReference(state, reference.getInReference());
2390
            }
2391
            if (reference.getInstitution() != null) {
2392
                csvLine[table.getIndex(CdmLightExportTable.INSTITUTION)] = reference.getInstitution().getTitleCache();
2393
            }
2394
            if (reference.getLsid() != null) {
2395
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = reference.getLsid().getLsid();
2396
            }
2397
            if (reference.getSchool() != null) {
2398
                csvLine[table.getIndex(CdmLightExportTable.SCHOOL)] = reference.getSchool().getTitleCache();
2399
            }
2400
            if (reference.getUri() != null) {
2401
                csvLine[table.getIndex(CdmLightExportTable.URI)] = reference.getUri().toString();
2402
            }
2403
            csvLine[table.getIndex(CdmLightExportTable.REF_TYPE)] = reference.getType().getKey();
2404

    
2405
            state.getProcessor().put(table, reference, csvLine);
2406
        } catch (Exception e) {
2407
            state.getResult().addException(e, "An unexpected error occurred when handling reference "
2408
                    + cdmBaseStr(reference) + ": " + e.getMessage());
2409
        }
2410
    }
2411

    
2412
    private String createFullAuthorship(Reference reference) {
2413
        TeamOrPersonBase<?> authorship = reference.getAuthorship();
2414
        String fullAuthorship = "";
2415
        if (authorship == null) {
2416
            return null;
2417
        }
2418
        authorship = HibernateProxyHelper.deproxy(authorship);
2419
        if (authorship instanceof Person) {
2420
            fullAuthorship = ((Person) authorship).getTitleCache();
2421

    
2422
        } else if (authorship instanceof Team) {
2423

    
2424
            Team authorTeam = (Team)authorship;
2425
            fullAuthorship = authorTeam.cacheStrategy().getTitleCache(authorTeam);
2426
        }
2427
        return fullAuthorship;
2428
    }
2429

    
2430
    private void handleSpecimen(CdmLightExportState state, SpecimenOrObservationBase<?> specimen) {
2431
        try {
2432
            state.addSpecimenToStore(specimen);
2433
            CdmLightExportTable table = CdmLightExportTable.SPECIMEN;
2434
            String specimenId = getId(state, specimen);
2435
            String[] csvLine = new String[table.getSize()];
2436

    
2437
            /*
2438
             * SpecimenCitation = “El Salvador, Municipio La Libertad, San
2439
             * Diego, El Amatal, 14.4.1993, González 159” [Auch ohne Punkt] ->
2440
             * FieldUnit TitleCache HerbariumAbbrev = “B” [wie gehabt]
2441
             * HerbariumCode
2442
             *
2443
             */
2444

    
2445
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_ID)] = specimenId;
2446
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_CITATION)] = specimen.getTitleCache();
2447
            Collection<FieldUnit> fieldUnits = this.getOccurrenceService().findFieldUnits(specimen.getUuid(), null);
2448
            if (fieldUnits.size() == 1) {
2449
                Iterator<FieldUnit> iterator = fieldUnits.iterator();
2450
                if (iterator.hasNext()){
2451
                    FieldUnit fieldUnit = iterator.next();
2452
                    csvLine[table.getIndex(CdmLightExportTable.FIELDUNIT_CITATION)] = fieldUnit.getTitleCache();
2453
                }
2454
            }
2455
            if (specimen.isInstanceOf(DerivedUnit.class)){
2456
                DerivedUnit derivedUnit = (DerivedUnit) specimen;
2457
                if (!StringUtils.isBlank(derivedUnit.getBarcode())){
2458
                    csvLine[table.getIndex(CdmLightExportTable.BARCODE)] = derivedUnit.getBarcode();
2459
                }
2460
                if (!StringUtils.isBlank(derivedUnit.getAccessionNumber())){
2461
                    csvLine[table.getIndex(CdmLightExportTable.ACCESSION_NUMBER)] = derivedUnit.getAccessionNumber();
2462
                }
2463
                if (!StringUtils.isBlank(derivedUnit.getCatalogNumber())){
2464
                    csvLine[table.getIndex(CdmLightExportTable.CATALOGUE_NUMBER)] = derivedUnit.getCatalogNumber();
2465
                }
2466
            }
2467

    
2468
            csvLine[table.getIndex(CdmLightExportTable.PREFERREDSTABLE_ID)] = specimen.getPreferredStableUri() != null? specimen.getPreferredStableUri().toString(): null;
2469
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_IMAGE_URIS)] = extractMediaURIs(state,
2470
                    specimen.getDescriptions(), Feature.IMAGE());
2471
            if (specimen instanceof DerivedUnit) {
2472
                DerivedUnit derivedUnit = HibernateProxyHelper.deproxy(specimen, DerivedUnit.class);
2473
                if (derivedUnit.getCollection() != null) {
2474
                    csvLine[table.getIndex(CdmLightExportTable.HERBARIUM_ABBREV)] = derivedUnit.getCollection()
2475
                            .getCode();
2476
                }
2477

    
2478
                if (specimen instanceof MediaSpecimen) {
2479
                    MediaSpecimen mediaSpecimen = (MediaSpecimen) specimen;
2480
                    Iterator<MediaRepresentation> it = mediaSpecimen.getMediaSpecimen().getRepresentations().iterator();
2481
                    String mediaUris = extractMediaUris(it);
2482
                    csvLine[table.getIndex(CdmLightExportTable.MEDIA_SPECIMEN_URL)] = mediaUris;
2483

    
2484
                }
2485

    
2486
                if (derivedUnit.getDerivedFrom() != null) {
2487
                    for (SpecimenOrObservationBase<?> original : derivedUnit.getDerivedFrom().getOriginals()) {
2488
                        // TODO: What to do if there are more then one
2489
                        // FieldUnit??
2490
                        if (original instanceof FieldUnit) {
2491
                            FieldUnit fieldUnit = (FieldUnit) original;
2492
                            csvLine[table.getIndex(CdmLightExportTable.COLLECTOR_NUMBER)] = fieldUnit.getFieldNumber();
2493

    
2494
                            GatheringEvent gathering = fieldUnit.getGatheringEvent();
2495
                            if (gathering != null) {
2496
                                if (gathering.getLocality() != null) {
2497
                                    csvLine[table.getIndex(CdmLightExportTable.LOCALITY)] = gathering.getLocality()
2498
                                            .getText();
2499
                                }
2500
                                if (gathering.getCountry() != null) {
2501
                                    csvLine[table.getIndex(CdmLightExportTable.COUNTRY)] = gathering.getCountry()
2502
                                            .getLabel();
2503
                                }
2504
                                csvLine[table.getIndex(CdmLightExportTable.COLLECTOR_STRING)] = createCollectorString(
2505
                                        state, gathering, fieldUnit);
2506

    
2507
                                if (gathering.getGatheringDate() != null) {
2508
                                    csvLine[table.getIndex(CdmLightExportTable.COLLECTION_DATE)] = gathering
2509
                                            .getGatheringDate().toString();
2510
                                }
2511
                                if (!gathering.getCollectingAreas().isEmpty()) {
2512
                                    int index = 0;
2513
                                    csvLine[table.getIndex(CdmLightExportTable.FURTHER_AREAS)] = "0";
2514
                                    for (NamedArea area : gathering.getCollectingAreas()) {
2515
                                        if (index == 0) {
2516
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY1)] = area.getLevel() != null?area
2517
                                                    .getLevel().getLabel():"";
2518
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME1)] = area.getLabel();
2519
                                        }
2520
                                        if (index == 1) {
2521
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY2)] = area.getLevel() != null?area
2522
                                                    .getLevel().getLabel():"";
2523
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME2)] = area.getLabel();
2524
                                        }
2525
                                        if (index == 2) {
2526
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY3)] = area.getLevel() != null?area
2527
                                                    .getLevel().getLabel():"";
2528
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME3)] = area.getLabel();
2529
                                        }
2530
                                        if (index == 3) {
2531
                                            csvLine[table.getIndex(CdmLightExportTable.FURTHER_AREAS)] = "1";
2532
                                            break;
2533
                                        }
2534
                                        index++;
2535
                                    }
2536
                                }
2537
                            }
2538
                        }
2539
                    }
2540
                } else {
2541
                    state.getResult().addWarning("The specimen with uuid " + specimen.getUuid()
2542
                            + " is not an DerivedUnit.");
2543
                }
2544
            }
2545

    
2546
            state.getProcessor().put(table, specimen, csvLine);
2547
        } catch (Exception e) {
2548
            state.getResult().addException(e, "An unexpected error occurred when handling specimen "
2549
                    + cdmBaseStr(specimen) + ": " + e.getMessage());
2550
        }
2551
    }
2552

    
2553
    private String extractMediaUris(Iterator<MediaRepresentation> it) {
2554

    
2555
        String mediaUriString = "";
2556
        boolean first = true;
2557
        while (it.hasNext()) {
2558
            MediaRepresentation rep = it.next();
2559
            List<MediaRepresentationPart> parts = rep.getParts();
2560
            for (MediaRepresentationPart part : parts) {
2561
                if (first) {
2562
                    if (part.getUri() != null) {
2563
                        mediaUriString += part.getUri().toString();
2564
                        first = false;
2565
                    }
2566
                } else {
2567
                    if (part.getUri() != null) {
2568
                        mediaUriString += ", " + part.getUri().toString();
2569
                    }
2570
                }
2571
            }
2572
        }
2573

    
2574
        return mediaUriString;
2575
    }
2576

    
2577
    private String extractLinkUris(Iterator<ExternalLink> it) {
2578

    
2579
        String linkUriString = "";
2580
        boolean first = true;
2581
        while (it.hasNext()) {
2582
            ExternalLink link = it.next();
2583
            if (first) {
2584
                if (link.getUri() != null) {
2585
                    linkUriString += link.getUri().toString();
2586
                    first = false;
2587
                }
2588
            } else {
2589
                if (link.getUri() != null) {
2590
                    linkUriString += ", " + link.getUri().toString();
2591
                }
2592
            }
2593
        }
2594
        return linkUriString;
2595
    }
2596

    
2597
    private String createCollectorString(CdmLightExportState state, GatheringEvent gathering, FieldUnit fieldUnit) {
2598
        try {
2599
            String collectorString = "";
2600
            AgentBase<?> collectorA = CdmBase.deproxy(gathering.getCollector());
2601
            if (gathering.getCollector() != null) {
2602
                if (collectorA instanceof TeamOrPersonBase && state.getConfig().isHighLightPrimaryCollector()) {
2603

    
2604
                    Person primaryCollector = fieldUnit.getPrimaryCollector();
2605
                    if (collectorA instanceof Team) {
2606
                        Team collectorTeam = (Team) collectorA;
2607
                        boolean isFirst = true;
2608
                        for (Person member : collectorTeam.getTeamMembers()) {
2609
                            if (!isFirst) {
2610
                                collectorString += "; ";
2611
                            }
2612
                            if (member.equals(primaryCollector)) {
2613
                                // highlight
2614
                                collectorString += "<b>" + member.getTitleCache() + "</b>";
2615
                            } else {
2616
                                collectorString += member.getTitleCache();
2617
                            }
2618
                        }
2619
                    }
2620
                } else {
2621
                    collectorString = collectorA.getTitleCache();
2622
                }
2623
            }
2624
            return collectorString;
2625
        } catch (Exception e) {
2626
            state.getResult().addException(e, "An unexpected error occurred when creating collector string for "
2627
                    + cdmBaseStr(fieldUnit) + ": " + e.getMessage());
2628
            return "";
2629
        }
2630
    }
2631

    
2632
    /**
2633
     * Returns a string representation of the {@link CdmBase cdmBase} object for
2634
     * result messages.
2635
     */
2636
    private String cdmBaseStr(CdmBase cdmBase) {
2637
        if (cdmBase == null) {
2638
            return "-no object available-";
2639
        } else {
2640
            return cdmBase.getClass().getSimpleName() + ": " + cdmBase.getUuid();
2641
        }
2642
    }
2643

    
2644
    @Override
2645
    protected boolean doCheck(CdmLightExportState state) {
2646
        return false;
2647
    }
2648

    
2649
    @Override
2650
    protected boolean isIgnore(CdmLightExportState state) {
2651
        return false;
2652
    }
2653

    
2654
}
(1-1/6)