Project

General

Profile

Download (120 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.HashSet;
17
import java.util.Iterator;
18
import java.util.List;
19
import java.util.Map;
20
import java.util.Set;
21
import java.util.UUID;
22

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

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

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

    
114
    private static final long serialVersionUID = 2518643632756927053L;
115
    private static final String STD_TEAM_CONCATINATION = ", ";
116
    private static final String FINAL_TEAM_CONCATINATION = " & ";
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
        // String sortIndex = StringUtils.isBlank(sort_index)?
202
        // String.valueOf(order.getOrderIndex()): sort_index+ "_"
203
        // +String.valueOf(order.getOrderIndex());
204

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

    
213
        if (order.getChildren() == null) {
214
            return;
215
        }
216
        for (OrderHelper helper : order.getChildren()) {
217
            setOrderIndex(state, helper);
218
        }
219
    }
220

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

    
239
            if (state.getNodeChildrenMap().get(child.getUuid()) != null) {
240
                children = state.getNodeChildrenMap().get(child.getUuid());
241
                helperChild.addChildren(createOrderHelper(children, state));
242
            }
243
            childrenHelper.add(helperChild);
244
        }
245
        return childrenHelper;
246
    }
247

    
248
    private void handleTaxonNode(CdmLightExportState state, TaxonNode taxonNode) {
249

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

    
267
                    // add root to node map
268

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

    
281
                }
282
                if (root.hasTaxon()) {
283
                    handleTaxon(state, root);
284

    
285
                }
286
            } catch (Exception e) {
287
                state.getResult().addException(e, "An unexpected error occurred when handling taxonNode "
288
                        + taxonNode.getUuid() + ": " + e.getMessage() + e.getStackTrace());
289
            }
290
        }
291
    }
292

    
293
    private void handleTaxon(CdmLightExportState state, TaxonNode taxonNode) {
294
        try {
295

    
296
            if (taxonNode == null) {
297
                state.getResult().addError("The taxonNode was null.", "handleTaxon");
298
                state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
299
                return;
300
            }
301
            if (taxonNode.getTaxon() == null) {
302
                state.getResult().addError("There was a taxon node without a taxon: " + taxonNode.getUuid(),
303
                        "handleTaxon");
304
                state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
305
            } else {
306
                Taxon taxon = HibernateProxyHelper.deproxy(taxonNode.getTaxon(), Taxon.class);
307

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

    
330
                    index = 0;
331
                    for (Taxon tax : taxon.getAllProParteSynonyms()) {
332
                        handleProPartePartialMisapplied(state, tax, taxon, true, false, index);
333
                        index++;
334
                    }
335

    
336

    
337
                    for (Taxon tax : taxon.getAllMisappliedNames()) {
338
                        handleProPartePartialMisapplied(state, tax, taxon, false, true, index);
339
                        index++;
340
                    }
341

    
342
                    CdmLightExportTable table = CdmLightExportTable.TAXON;
343
                    String[] csvLine = new String[table.getSize()];
344

    
345
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_ID)] = getId(state, taxon);
346
                    csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
347
                    Taxon parent = (taxonNode.getParent() == null) ? null : taxonNode.getParent().getTaxon();
348
                    csvLine[table.getIndex(CdmLightExportTable.PARENT_FK)] = getId(state, parent);
349
                    csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE_FK)] = getId(state, taxon.getSec());
350
                    if (taxon.getSec() != null && taxon.getSec().getDatePublished() != null
351
                            && taxon.getSec().getDatePublished().getFreeText() != null) {
352
                        String sec_string = taxon.getSec().getTitleCache() + ". "
353
                                + taxon.getSec().getDatePublished().getFreeText();
354
                        sec_string = sec_string.replace("..", ".");
355
                        csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = sec_string;
356
                    } else {
357
                        csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = getTitleCache(taxon.getSec());
358
                    }
359
                    if (taxon.getSec() != null) {
360
                        if (!state.getReferenceStore().contains((taxon.getSec().getUuid()))) {
361
                            handleReference(state, taxon.getSec());
362
                        }
363
                    }
364
                    csvLine[table.getIndex(CdmLightExportTable.APPENDED_PHRASE)] = taxon.getAppendedPhrase();
365
                    csvLine[table.getIndex(CdmLightExportTable.CLASSIFICATION_ID)] = getId(state,
366
                            taxonNode.getClassification());
367
                    csvLine[table.getIndex(CdmLightExportTable.CLASSIFICATION_TITLE)] = taxonNode.getClassification()
368
                            .getTitleCache();
369

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

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

    
396
            taxonNode.removeNullValueFromChildren();
397

    
398
        } catch (Exception e) {
399
            state.getResult().addException(e, "An unexpected error occurred when handling the taxon node of "
400
                    + cdmBaseStr(taxonNode.getTaxon()) + ", titleCache:"+ taxonNode.getTaxon().getTitleCache()+": " + e.getMessage());
401
        }
402
    }
403

    
404
    private void handleDescriptions(CdmLightExportState state, CdmBase cdmBase) {
405
        String titleCache = null;
406
        try {
407

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

    
475
    private void handleAnnotations(DescriptionElementBase element) {
476
        // TODO Auto-generated method stub
477
    }
478

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

    
492
        csvLine[table.getIndex(CdmLightExportTable.DATASET_LANGUAGE)] = state.getConfig().getLanguage() != null? state.getConfig().getLanguage().getLabel(): null;
493
        csvLine[table.getIndex(CdmLightExportTable.DATASET_LICENCE)] = state.getConfig().getLicence();
494
        csvLine[table.getIndex(CdmLightExportTable.DATASET_LOCATION)] = state.getConfig().getLocation();
495
        csvLine[table.getIndex(CdmLightExportTable.DATASET_RECOMMENDED_CITATTION)] = state.getConfig().getRecommended_citation();
496
        csvLine[table.getIndex(CdmLightExportTable.DATASET_TITLE)] = state.getConfig().getTitle();
497
        state.getProcessor().put(table, "", csvLine);
498
    }
499

    
500
    private boolean isSpecimenFeature(Feature feature) {
501
        // TODO allow user defined specimen features
502
        if (feature == null) {
503
            return false;
504
        } else if (feature.isSupportsIndividualAssociation()) {
505
            return true;
506
        } else {
507
            return feature.equals(Feature.SPECIMEN()) || feature.equals(Feature.INDIVIDUALS_ASSOCIATION())
508
                    || feature.equals(Feature.MATERIALS_EXAMINED()) || feature.equals(Feature.OBSERVATION())
509
                    || feature.equals(Feature.OCCURRENCE());
510
        }
511
    }
512

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

    
541
    private void handleTaxonInteractionsFacts(CdmLightExportState state, CdmBase cdmBase,
542
            List<DescriptionElementBase> taxonInteractionsFacts) {
543
        CdmLightExportTable table = CdmLightExportTable.TAXON_INTERACTION_FACT;
544
        String titleCache = null;
545
        if (cdmBase instanceof TaxonBase){
546
            titleCache = ((TaxonBase)cdmBase).getTitleCache();
547
        }
548
        for (DescriptionElementBase element : taxonInteractionsFacts) {
549

    
550
            try {
551

    
552
                String[] csvLine = new String[table.getSize()];
553

    
554
                csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
555
                handleSource(state, element, table);
556
                csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
557
                csvLine[table.getIndex(CdmLightExportTable.TAXON2_FK)] = getId(state,
558
                        ((TaxonInteraction) element).getTaxon2());
559
                csvLine[table.getIndex(CdmLightExportTable.DESCRIPTION)] = createMultilanguageString(
560
                        ((TaxonInteraction) element).getDescription());
561
                state.getProcessor().put(table, element, csvLine);
562

    
563
            } catch (Exception e) {
564
                state.getResult().addException(e, "An unexpected error occurred when handling taxon interaction"
565
                        + cdmBaseStr(element) + (titleCache != null? (" " +titleCache) : "")+ ": " + e.getMessage());
566
            }
567
        }
568
    }
569

    
570
    private void handleSimpleMediaFact(CdmLightExportState state, CdmBase cdmBase, CdmLightExportTable table,
571
            DescriptionElementBase element) {
572
        try {
573
            String[] csvLine;
574
            handleSource(state, element, CdmLightExportTable.MEDIA);
575

    
576
            if (element instanceof TextData) {
577
                TextData textData = (TextData) element;
578
                csvLine = new String[table.getSize()];
579
                csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
580
                if (cdmBase instanceof Taxon) {
581
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
582
                    csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = "";
583
                } else if (cdmBase instanceof TaxonName) {
584
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = "";
585
                    csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, cdmBase);
586
                }
587

    
588
                String mediaUris = "";
589
                for (Media media : textData.getMedia()) {
590
                    String mediaString = extractMediaUris(media.getRepresentations().iterator());
591
                    if (!StringUtils.isBlank(mediaString)) {
592
                        mediaUris += mediaString + ";";
593
                    } else {
594
                        state.getResult().addWarning("Empty Media object for " + cdmBase.getUserFriendlyTypeName() + " "
595
                                + cdmBase.getUuid() + " (media: " + media.getUuid() + ")");
596
                    }
597
                }
598
                csvLine[table.getIndex(CdmLightExportTable.MEDIA_URI)] = mediaUris;
599

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

    
606
    }
607

    
608
    private void handleSingleSimpleFact(CdmLightExportState state, CdmBase cdmBase, CdmLightExportTable table,
609
            DescriptionElementBase element) {
610
        try {
611
            String[] csvLine;
612
            handleSource(state, element, CdmLightExportTable.SIMPLE_FACT);
613

    
614
            if (element instanceof TextData) {
615
                TextData textData = (TextData) element;
616
                csvLine = new String[table.getSize()];
617
                csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
618
                if (cdmBase instanceof Taxon) {
619
                    csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, cdmBase);
620
                } else if (cdmBase instanceof TaxonName) {
621
                    csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, cdmBase);
622
                }
623
                csvLine[table.getIndex(CdmLightExportTable.FACT_CATEGORY)] = textData.getFeature().getLabel();
624

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

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

    
669
        newText = newText.replaceAll("<cdm:key cdmId='[a-z0-9\\-]*' intextId='[a-z0-9\\-]*'>", "");
670
        newText = newText.replaceAll("</cdm:key>", "");
671
        return newText;
672
    }
673

    
674
    private void handleSpecimenFacts(CdmLightExportState state, Taxon taxon,
675
            List<DescriptionElementBase> specimenFacts) {
676
        CdmLightExportTable table = CdmLightExportTable.SPECIMEN_FACT;
677

    
678
        for (DescriptionElementBase element : specimenFacts) {
679
            try {
680
                String[] csvLine = new String[table.getSize()];
681
                csvLine[table.getIndex(CdmLightExportTable.FACT_ID)] = getId(state, element);
682
                csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, taxon);
683
                handleSource(state, element, table);
684
                csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_NOTES)] = createAnnotationsString(
685
                        element.getAnnotations());
686

    
687
                if (element instanceof IndividualsAssociation) {
688

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

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

    
720
    private String createMultilanguageString(Map<Language, LanguageString> multilanguageText) {
721
        String text = "";
722
        int index = multilanguageText.size();
723
        for (LanguageString langString : multilanguageText.values()) {
724
            text += langString.getText();
725
            if (index > 1) {
726
                text += "; ";
727
            }
728
            index--;
729
        }
730
        return text;
731
    }
732

    
733
    private String createAnnotationsString(Set<Annotation> annotations) {
734
        StringBuffer strBuff = new StringBuffer();
735

    
736
        for (Annotation ann : annotations) {
737
            if (ann.getAnnotationType() == null || !ann.getAnnotationType().equals(AnnotationType.TECHNICAL())) {
738
                strBuff.append(ann.getText());
739
                strBuff.append("; ");
740
            }
741
        }
742

    
743
        if (strBuff.length() > 2) {
744
            return strBuff.substring(0, strBuff.length() - 2);
745
        } else {
746
            return null;
747
        }
748
    }
749

    
750
    private void handleSource(CdmLightExportState state, DescriptionElementBase element,
751
            CdmLightExportTable factsTable) {
752
        CdmLightExportTable table = CdmLightExportTable.FACT_SOURCES;
753
        try {
754
            Set<DescriptionElementSource> sources = element.getSources();
755

    
756
            for (DescriptionElementSource source : sources) {
757
                if (!(source.getType().equals(OriginalSourceType.Import)
758
                        && state.getConfig().isFilterImportSources())) {
759
                    String[] csvLine = new String[table.getSize()];
760
                    Reference ref = source.getCitation();
761
                    if ((ref == null) && (source.getNameUsedInSource() == null)) {
762
                        continue;
763
                    }
764
                    if (ref != null) {
765
                        if (!state.getReferenceStore().contains(ref.getUuid())) {
766
                            handleReference(state, ref);
767

    
768
                        }
769
                        csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)] = getId(state, ref);
770
                    }
771
                    csvLine[table.getIndex(CdmLightExportTable.FACT_FK)] = getId(state, element);
772

    
773
                    csvLine[table.getIndex(CdmLightExportTable.NAME_IN_SOURCE_FK)] = getId(state,
774
                            source.getNameUsedInSource());
775
                    csvLine[table.getIndex(CdmLightExportTable.FACT_TYPE)] = factsTable.getTableName();
776
                    if (StringUtils.isBlank(csvLine[table.getIndex(CdmLightExportTable.REFERENCE_FK)])
777
                            && StringUtils.isBlank(csvLine[table.getIndex(CdmLightExportTable.NAME_IN_SOURCE_FK)])) {
778
                        continue;
779
                    }
780
                    state.getProcessor().put(table, source, csvLine);
781
                }
782

    
783
            }
784
        } catch (Exception e) {
785
            state.getResult().addException(e, "An unexpected error occurred when handling single source "
786
                    + cdmBaseStr(element) + ": " + e.getMessage());
787
        }
788

    
789
    }
790

    
791
    private void handleDistributionFacts(CdmLightExportState state, Taxon taxon,
792
            List<DescriptionElementBase> distributionFacts) {
793

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

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

    
843
             csvLine[tableCondensed.getIndex(CdmLightExportTable.FACT_CATEGORY)] =
844
                     "CondensedDistribution";
845

    
846
             state.getProcessor().put(tableCondensed, taxon, csvLine);
847
         }
848
    }
849

    
850
    private void handleCommonNameFacts(CdmLightExportState state, Taxon taxon,
851
            List<DescriptionElementBase> commonNameFacts) {
852
        CdmLightExportTable table = CdmLightExportTable.COMMON_NAME_FACT;
853

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

    
895
    private String getTitleCache(IIdentifiableEntity identEntity) {
896
        if (identEntity == null) {
897
            return "";
898
        }
899
        // TODO refresh?
900
        return identEntity.getTitleCache();
901
    }
902

    
903
    private String getId(CdmLightExportState state, ICdmBase cdmBase) {
904
        if (cdmBase == null) {
905
            return "";
906
        }
907
        // TODO make configurable
908
        return cdmBase.getUuid().toString();
909
    }
910

    
911
    private void handleSynonym(CdmLightExportState state, Synonym synonym, int index) {
912
        try {
913
            if (isUnpublished(state.getConfig(), synonym)) {
914
                return;
915
            }
916
            TaxonName name = synonym.getName();
917
            handleName(state, name, synonym.getAcceptedTaxon());
918

    
919
            CdmLightExportTable table = CdmLightExportTable.SYNONYM;
920
            String[] csvLine = new String[table.getSize()];
921

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

    
943
    /**
944
     * Handles Misapplied names (including pro parte and partial as well as pro
945
     * parte and partial synonyms
946
     *
947
     * @param state
948
     * @param rel
949
     */
950
    private void handleProPartePartialMisapplied(CdmLightExportState state, Taxon taxon, Taxon accepted, boolean isProParte, boolean isMisapplied, int index) {
951
        try {
952
            Taxon ppSyonym = taxon;
953
            if (isUnpublished(state.getConfig(), ppSyonym)) {
954
                return;
955
            }
956
            TaxonName name = ppSyonym.getName();
957
            handleName(state, name, accepted);
958

    
959
            CdmLightExportTable table = CdmLightExportTable.SYNONYM;
960
            String[] csvLine = new String[table.getSize()];
961

    
962
            csvLine[table.getIndex(CdmLightExportTable.SYNONYM_ID)] = getId(state, ppSyonym);
963
            csvLine[table.getIndex(CdmLightExportTable.TAXON_FK)] = getId(state, accepted);
964
            csvLine[table.getIndex(CdmLightExportTable.NAME_FK)] = getId(state, name);
965

    
966
            Reference secRef = ppSyonym.getSec();
967

    
968
            if (secRef != null && !state.getReferenceStore().contains(secRef.getUuid())) {
969
                handleReference(state, secRef);
970
            }
971
            csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE_FK)] = getId(state, secRef);
972
            csvLine[table.getIndex(CdmLightExportTable.SEC_REFERENCE)] = getTitleCache(secRef);
973
            Set<TaxonRelationship> rels = accepted.getTaxonRelations(ppSyonym);
974
            TaxonRelationship rel = null;
975
            boolean isPartial = false;
976
            if (rels.size() == 1){
977
                rel = rels.iterator().next();
978

    
979
            }else if (rels.size() > 1){
980
                Iterator<TaxonRelationship> iterator = rels.iterator();
981
                while (iterator.hasNext()){
982
                    rel = iterator.next();
983
                    if (isProParte && rel.getType().isAnySynonym()){
984
                        break;
985
                    } else if (isMisapplied && rel.getType().isAnyMisappliedName()){
986
                        break;
987
                    }else{
988
                        rel = null;
989
                    }
990
                }
991
            }
992
            if (rel != null){
993
                Reference synSecRef = rel.getCitation();
994
                if (synSecRef != null && !state.getReferenceStore().contains(synSecRef.getUuid())) {
995
                    handleReference(state, synSecRef);
996
                }
997
                csvLine[table.getIndex(CdmLightExportTable.SYN_SEC_REFERENCE_FK)] = getId(state, synSecRef);
998
                csvLine[table.getIndex(CdmLightExportTable.SYN_SEC_REFERENCE)] = getTitleCache(synSecRef);
999
                isProParte = rel.getType().isProParte();
1000
                isPartial = rel.getType().isPartial();
1001

    
1002
            }else{
1003
                state.getResult().addWarning("An unexpected error occurred when handling "
1004
                        + "pro parte/partial synonym or misapplied name  " + cdmBaseStr(taxon) );
1005
            }
1006

    
1007
            // pro parte type
1008

    
1009
            csvLine[table.getIndex(CdmLightExportTable.IS_PRO_PARTE)] = isProParte ? "1" : "0";
1010
            csvLine[table.getIndex(CdmLightExportTable.IS_PARTIAL)] = isPartial ? "1" : "0";
1011
            csvLine[table.getIndex(CdmLightExportTable.IS_MISAPPLIED)] = isMisapplied ? "1" : "0";
1012
            csvLine[table.getIndex(CdmLightExportTable.SORT_INDEX)] = String.valueOf(index);
1013
            state.getProcessor().put(table, ppSyonym, csvLine);
1014
        } catch (Exception e) {
1015
            state.getResult().addException(e, "An unexpected error occurred when handling "
1016
                    + "pro parte/partial synonym or misapplied name  " + cdmBaseStr(taxon) + ": " + e.getMessage());
1017
        }
1018

    
1019
    }
1020

    
1021
    private void handleName(CdmLightExportState state, TaxonName name, Taxon acceptedTaxon){
1022
        handleName(state, name, acceptedTaxon, false);
1023
    }
1024

    
1025
    private void handleName(CdmLightExportState state, TaxonName name, Taxon acceptedTaxon, boolean acceptedName) {
1026
        if (name == null || state.getNameStore().containsKey(name.getId())) {
1027
            return;
1028
        }
1029
        try {
1030
            Rank rank = name.getRank();
1031
            CdmLightExportTable table = CdmLightExportTable.SCIENTIFIC_NAME;
1032
            name = HibernateProxyHelper.deproxy(name);
1033
            state.getNameStore().put(name.getId(), name.getUuid());
1034
            String[] csvLine = new String[table.getSize()];
1035

    
1036
            csvLine[table.getIndex(CdmLightExportTable.NAME_ID)] = getId(state, name);
1037
            if (name.getLsid() != null) {
1038
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = name.getLsid().getLsid();
1039
            } else {
1040
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = "";
1041
            }
1042

    
1043
            handleIdentifier(state, name);
1044
            handleDescriptions(state, name);
1045

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

    
1071

    
1072
            if (!state.getConfig().isAddHTML()) {
1073
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_REF)] = name.getFullTitleCache();
1074
            } else {
1075
                List<TaggedText> taggedFullTitleCache = name.getTaggedFullTitle();
1076
                String fullTitleWithHtml = createNameWithItalics(taggedFullTitleCache);
1077
                // TODO: adapt the tropicos titlecache creation
1078
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_REF)] = fullTitleWithHtml.trim();
1079
            }
1080

    
1081
            csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_NO_AUTHORS)] = name.getNameCache();
1082
            csvLine[table.getIndex(CdmLightExportTable.GENUS_UNINOMIAL)] = name.getGenusOrUninomial();
1083

    
1084
            csvLine[table.getIndex(CdmLightExportTable.INFRAGENERIC_EPITHET)] = name.getInfraGenericEpithet();
1085
            csvLine[table.getIndex(CdmLightExportTable.SPECIFIC_EPITHET)] = name.getSpecificEpithet();
1086

    
1087
            csvLine[table.getIndex(CdmLightExportTable.INFRASPECIFIC_EPITHET)] = name.getInfraSpecificEpithet();
1088

    
1089
            csvLine[table.getIndex(CdmLightExportTable.APPENDED_PHRASE)] = name.getAppendedPhrase();
1090

    
1091
            csvLine[table.getIndex(CdmLightExportTable.BAS_AUTHORTEAM_FK)] = getId(state, name.getBasionymAuthorship());
1092
            if (name.getBasionymAuthorship() != null) {
1093
                if (state.getAuthorFromStore(name.getBasionymAuthorship().getId()) == null) {
1094
                    handleAuthor(state, name.getBasionymAuthorship());
1095
                }
1096
            }
1097
            csvLine[table.getIndex(CdmLightExportTable.BAS_EX_AUTHORTEAM_FK)] = getId(state,
1098
                    name.getExBasionymAuthorship());
1099
            if (name.getExBasionymAuthorship() != null) {
1100
                if (state.getAuthorFromStore(name.getExBasionymAuthorship().getId()) == null) {
1101
                    handleAuthor(state, name.getExBasionymAuthorship());
1102
                }
1103

    
1104
            }
1105
            csvLine[table.getIndex(CdmLightExportTable.COMB_AUTHORTEAM_FK)] = getId(state,
1106
                    name.getCombinationAuthorship());
1107
            if (name.getCombinationAuthorship() != null) {
1108
                if (state.getAuthorFromStore(name.getCombinationAuthorship().getId()) == null) {
1109
                    handleAuthor(state, name.getCombinationAuthorship());
1110
                }
1111
            }
1112
            csvLine[table.getIndex(CdmLightExportTable.COMB_EX_AUTHORTEAM_FK)] = getId(state,
1113
                    name.getExCombinationAuthorship());
1114
            if (name.getExCombinationAuthorship() != null) {
1115
                if (state.getAuthorFromStore(name.getExCombinationAuthorship().getId()) == null) {
1116
                    handleAuthor(state, name.getExCombinationAuthorship());
1117
                }
1118

    
1119
            }
1120

    
1121
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_TEAM_STRING)] = name.getAuthorshipCache();
1122

    
1123
            Reference nomRef = name.getNomenclaturalReference();
1124

    
1125
            NomenclaturalSource nomenclaturalSource = name.getNomenclaturalSource();
1126
            if (nomenclaturalSource != null &&nomenclaturalSource.getNameUsedInSource() != null){
1127
                handleName(state, nomenclaturalSource.getNameUsedInSource(), null);
1128
                csvLine[table.getIndex(CdmLightExportTable.NAME_USED_IN_SOURCE)] = getId(state, nomenclaturalSource.getNameUsedInSource());
1129
            }
1130

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

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

    
1216
                }
1217
            } else {
1218
                csvLine[table.getIndex(CdmLightExportTable.PUBLICATION_TYPE)] = "";
1219
            }
1220

    
1221
            /*
1222
             * Collation
1223
             *
1224
             * Detail
1225
             *
1226
             * TitlePageYear
1227
             */
1228
            String protologueUriString = extractProtologueURIs(state, name);
1229

    
1230
            csvLine[table.getIndex(CdmLightExportTable.PROTOLOGUE_URI)] = protologueUriString;
1231
            Collection<TypeDesignationBase> specimenTypeDesignations = new ArrayList<>();
1232
            List<TextualTypeDesignation> textualTypeDesignations = new ArrayList<>();
1233
            for (TypeDesignationBase<?> typeDesignation : name.getTypeDesignations()) {
1234
                if (typeDesignation.isInstanceOf(TextualTypeDesignation.class)) {
1235

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

    
1252
                    } else {
1253
                        textualTypeDesignations.add((TextualTypeDesignation) typeDesignation);
1254
                    }
1255
                } else if (typeDesignation.isInstanceOf(SpecimenTypeDesignation.class)) {
1256

    
1257
                    specimenTypeDesignations.add(HibernateProxyHelper.deproxy(typeDesignation, SpecimenTypeDesignation.class));
1258

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

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

    
1296

    
1297
            if (name.getStatus() == null || name.getStatus().isEmpty()) {
1298
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS)] = "";
1299
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS_ABBREV)] = "";
1300
            } else {
1301

    
1302
                String statusStringAbbrev = extractStatusString(state, name, true);
1303
                String statusString = extractStatusString(state, name, false);
1304

    
1305
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS)] = statusString.trim();
1306
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS_ABBREV)] = statusStringAbbrev.trim();
1307
            }
1308

    
1309
            HomotypicalGroup group = HibernateProxyHelper.deproxy(name.getHomotypicalGroup(), HomotypicalGroup.class);
1310

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

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

    
1325
            }else{
1326
                typifiedNames.addAll(group.getTypifiedNames());
1327
            }
1328

    
1329

    
1330
            Integer seqNumber = typifiedNames.indexOf(name);
1331
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_SEQ)] = String.valueOf(seqNumber);
1332
            state.getProcessor().put(table, name, csvLine);
1333
            handleNameRelationships(state, name);
1334

    
1335
        } catch (Exception e) {
1336
            state.getResult().addException(e,
1337
                    "An unexpected error occurred when handling the name " + cdmBaseStr(name) + ": " + name.getTitleCache() + ": " + e.getMessage());
1338

    
1339
            e.printStackTrace();
1340
        }
1341
    }
1342

    
1343
    private String createNameWithItalics(List<TaggedText> taggedName) {
1344

    
1345
        String fullTitleWithHtml = "";
1346
        for (TaggedText taggedText: taggedName){
1347
            if (taggedText.getType().equals(TagEnum.name)){
1348
                fullTitleWithHtml += "<i>" + taggedText.getText() + "</i> ";
1349
            }else if (taggedText.getType().equals(TagEnum.separator)){
1350
                fullTitleWithHtml = fullTitleWithHtml.trim() + taggedText.getText() ;
1351
            }else{
1352
                fullTitleWithHtml += taggedText.getText() + " ";
1353
            }
1354
        }
1355
        return fullTitleWithHtml;
1356
    }
1357

    
1358
    private void handleNameRelationships(CdmLightExportState state, TaxonName name) {
1359
        Set<NameRelationship> rels = name.getRelationsFromThisName();
1360
        CdmLightExportTable table = CdmLightExportTable.NAME_RELATIONSHIP;
1361
        String[] csvLine = new String[table.getSize()];
1362

    
1363
        for (NameRelationship rel : rels) {
1364
            NameRelationshipType type = rel.getType();
1365
            TaxonName name2 = rel.getToName();
1366
            name2 = HibernateProxyHelper.deproxy(name2, TaxonName.class);
1367
            if (!state.getNameStore().containsKey(name2.getId())) {
1368
                handleName(state, name2, null);
1369
            }
1370

    
1371
            csvLine[table.getIndex(CdmLightExportTable.NAME_REL_TYPE)] = type.getLabel();
1372
            csvLine[table.getIndex(CdmLightExportTable.NAME1_FK)] = getId(state, name);
1373
            csvLine[table.getIndex(CdmLightExportTable.NAME2_FK)] = getId(state, name2);
1374
            state.getProcessor().put(table, name, csvLine);
1375
        }
1376

    
1377
        rels = name.getRelationsToThisName();
1378

    
1379
        csvLine = new String[table.getSize()];
1380

    
1381
        for (NameRelationship rel : rels) {
1382
            NameRelationshipType type = rel.getType();
1383
            TaxonName name2 = rel.getFromName();
1384
            name2 = HibernateProxyHelper.deproxy(name2, TaxonName.class);
1385
            if (!state.getNameStore().containsKey(name2.getId())) {
1386
                handleName(state, name2, null);
1387
            }
1388

    
1389

    
1390
        }
1391
    }
1392

    
1393
    private String createCollatation(TaxonName name) {
1394
        String collation = "";
1395
        if (name.getNomenclaturalReference() != null) {
1396
            Reference ref = name.getNomenclaturalReference();
1397
            collation = getVolume(ref);
1398
        }
1399
        if (name.getNomenclaturalMicroReference() != null) {
1400
            if (!StringUtils.isBlank(collation)) {
1401
                collation += ":";
1402
            }
1403
            collation += name.getNomenclaturalMicroReference();
1404
        }
1405

    
1406
        return collation;
1407
    }
1408

    
1409
    private String getVolume(Reference reference) {
1410
        if (reference.getVolume() != null) {
1411
            return reference.getVolume();
1412
        } else if (reference.getInReference() != null) {
1413
            if (reference.getInReference().getVolume() != null) {
1414
                return reference.getInReference().getVolume();
1415
            }
1416
        }
1417
        return null;
1418
    }
1419

    
1420
    private void handleIdentifier(CdmLightExportState state, CdmBase cdmBase) {
1421
        CdmLightExportTable table = CdmLightExportTable.IDENTIFIER;
1422
        String[] csvLine;
1423
        try {
1424
            if (cdmBase instanceof TaxonName){
1425
                TaxonName name = (TaxonName)cdmBase;
1426

    
1427
                try{
1428
                    Set<String> IPNIidentifiers = name.getIdentifiers(DefinedTerm.IDENTIFIER_NAME_IPNI());
1429
                    Set<String> tropicosIdentifiers = name.getIdentifiers(DefinedTerm.IDENTIFIER_NAME_TROPICOS());
1430
                    Set<String> WFOIdentifiers = name.getIdentifiers(DefinedTerm.uuidWfoNameIdentifier);
1431
                    if (!IPNIidentifiers.isEmpty()) {
1432
                        csvLine = new String[table.getSize()];
1433
                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, name);
1434
                        csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = "ScientificName";
1435
                        csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = IPNI_NAME_IDENTIFIER;
1436
                        csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = extractIdentifier(
1437
                                IPNIidentifiers);
1438
                        state.getProcessor().put(table, name.getUuid() + ", " + IPNI_NAME_IDENTIFIER, csvLine);
1439
                    }
1440
                    if (!tropicosIdentifiers.isEmpty()) {
1441
                        csvLine = new String[table.getSize()];
1442
                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, name);
1443
                        csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = "ScientificName";
1444
                        csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = name.getUuid() + ", " + IPNI_NAME_IDENTIFIER;
1445
                        csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = extractIdentifier(
1446
                                tropicosIdentifiers);
1447
                        state.getProcessor().put(table, name.getUuid() + ", " + IPNI_NAME_IDENTIFIER, csvLine);
1448
                    }
1449
                    if (!WFOIdentifiers.isEmpty()) {
1450
                        csvLine = new String[table.getSize()];
1451
                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, name);
1452
                        csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = "ScientificName";
1453
                        csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = WFO_NAME_IDENTIFIER;
1454
                        csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = extractIdentifier(
1455
                                WFOIdentifiers);
1456
                        state.getProcessor().put(table, name.getUuid() + ", " + WFO_NAME_IDENTIFIER, csvLine);
1457
                    }
1458
                }catch(Exception e){
1459
                    state.getResult().addWarning("Please check the identifiers for "
1460
                            + cdmBaseStr(cdmBase) + " maybe there is an empty identifier");
1461

    
1462

    
1463
                }
1464
            }else{
1465
                if (cdmBase instanceof IdentifiableEntity){
1466
                    IdentifiableEntity<?> identifiableEntity = (IdentifiableEntity<?>) cdmBase;
1467
                    List<Identifier> identifiers = identifiableEntity.getIdentifiers();
1468
                    String tableName = null;
1469
                    if (cdmBase instanceof Reference){
1470
                        tableName = "Reference";
1471
                    }else if (cdmBase instanceof SpecimenOrObservationBase){
1472
                        tableName = "Specimen";
1473
                    }else if (cdmBase instanceof Taxon){
1474
                        tableName = "Taxon";
1475
                    }else if (cdmBase instanceof Synonym){
1476
                        tableName = "Synonym";
1477
                    }else if (cdmBase instanceof TeamOrPersonBase){
1478
                        tableName = "PersonOrTeam";
1479
                    }
1480

    
1481
                    for (Identifier identifier: identifiers){
1482
                        if (identifier.getType() == null && identifier.getIdentifier() == null){
1483
                            state.getResult().addWarning("Please check the identifiers for "
1484
                                    + cdmBaseStr(cdmBase) + " there is an empty identifier");
1485
                            continue;
1486
                        }
1487

    
1488
                        csvLine = new String[table.getSize()];
1489
                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, cdmBase);
1490

    
1491
                        if (tableName != null){
1492
                            csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = tableName;
1493
                            csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = identifier.getType() != null? identifier.getType().getLabel():null;
1494
                            csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = identifier.getIdentifier();
1495
                            state.getProcessor().put(table, cdmBase.getUuid() + (identifier.getType() != null? identifier.getType().getLabel():null), csvLine);
1496
                        }
1497
                    }
1498
                    if (cdmBase instanceof Reference ){
1499
                        Reference ref = (Reference)cdmBase;
1500
                        if (ref.getDoi() != null){
1501
                            csvLine = new String[table.getSize()];
1502
                            csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, cdmBase);
1503
                            csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = tableName;
1504
                            csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = "DOI";
1505
                            csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = ref.getDoiString();
1506
                            state.getProcessor().put(table, cdmBase.getUuid() + "DOI", csvLine);
1507
                        }
1508
                    }
1509

    
1510
                    if (cdmBase instanceof TeamOrPersonBase){
1511
                        TeamOrPersonBase<?> person= HibernateProxyHelper.deproxy(cdmBase, TeamOrPersonBase.class);
1512
                        if (person instanceof Person &&  ((Person)person).getOrcid() != null){
1513
                            csvLine = new String[table.getSize()];
1514
                            csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, cdmBase);
1515
                            csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = tableName;
1516
                            csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = "ORCID";
1517
                            csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)]=  ((Person)person).getOrcid().asURI();
1518
                            state.getProcessor().put(table, cdmBase.getUuid() + "ORCID", csvLine);
1519
                        }
1520
                    }
1521
                }
1522
            }
1523
        } catch (Exception e) {
1524
            state.getResult().addException(e, "An unexpected error occurred when handling identifiers for "
1525
                    + cdmBaseStr(cdmBase) + ": " + e.getMessage());
1526
            e.printStackTrace();
1527
        }
1528
    }
1529

    
1530
    private String extractIdentifier(Set<String> identifierSet) {
1531

    
1532
        String identifierString = "";
1533
        for (String identifier : identifierSet) {
1534
            if (!StringUtils.isBlank(identifierString)) {
1535
                identifierString += ", ";
1536
            }
1537
            identifierString += identifier;
1538
        }
1539
        return identifierString;
1540
    }
1541

    
1542
    private String extractProtologueURIs(CdmLightExportState state, TaxonName name) {
1543
        if (name.getNomenclaturalSource() != null){
1544
            Set<ExternalLink> links = name.getNomenclaturalSource().getLinks();
1545
            return extractLinkUris(links.iterator());
1546
        }else{
1547
            return null;
1548
        }
1549
    }
1550

    
1551
    private String extractMediaURIs(CdmLightExportState state, Set<? extends DescriptionBase<?>> descriptionsSet,
1552
            Feature feature) {
1553

    
1554
        String mediaUriString = "";
1555
        Set<DescriptionElementBase> elements = new HashSet<>();
1556
        for (DescriptionBase<?> description : descriptionsSet) {
1557
            try {
1558
                if (!description.getElements().isEmpty()) {
1559
                    elements = description.getElements();
1560

    
1561
                    for (DescriptionElementBase element : elements) {
1562
                        Feature entityFeature = HibernateProxyHelper.deproxy(element.getFeature());
1563
                        if (entityFeature.equals(feature)) {
1564
                            if (!element.getMedia().isEmpty()) {
1565
                                List<Media> media = element.getMedia();
1566
                                for (Media mediaElement : media) {
1567
                                    Iterator<MediaRepresentation> it = mediaElement.getRepresentations().iterator();
1568
                                    mediaUriString = extractMediaUris(it);
1569
                                }
1570
                            }
1571
                        }
1572
                    }
1573
                }
1574
            } catch (Exception e) {
1575
                state.getResult().addException(e, "An unexpected error occurred when extracting media URIs for "
1576
                        + cdmBaseStr(description) + ": " + e.getMessage());
1577
            }
1578
        }
1579
        return mediaUriString;
1580
    }
1581

    
1582
    private void handleAuthor(CdmLightExportState state, TeamOrPersonBase<?> author) {
1583
        try {
1584
            if (state.getAuthorFromStore(author.getId()) != null) {
1585
                return;
1586
            }
1587
            state.addAuthorToStore(author);
1588
            handleIdentifier(state, author);
1589
            CdmLightExportTable table = CdmLightExportTable.NOMENCLATURAL_AUTHOR;
1590
            String[] csvLine = new String[table.getSize()];
1591
            CdmLightExportTable tableAuthorRel = CdmLightExportTable.NOMENCLATURAL_AUTHOR_TEAM_RELATION;
1592
            String[] csvLineRel = new String[tableAuthorRel.getSize()];
1593
            String[] csvLineMember = new String[table.getSize()];
1594
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_ID)] = getId(state, author);
1595
            csvLine[table.getIndex(CdmLightExportTable.ABBREV_AUTHOR)] = author.isProtectedTitleCache()
1596
                    ? author.getTitleCache() : author.getNomenclaturalTitle();
1597
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_TITLE)] = author.getTitleCache();
1598
            author = HibernateProxyHelper.deproxy(author);
1599
            if (author instanceof Person) {
1600
                Person authorPerson = (Person) author;
1601
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_GIVEN_NAME)] = authorPerson.getGivenName();
1602
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_FAMILY_NAME)] = authorPerson.getFamilyName();
1603
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_PREFIX)] = authorPerson.getPrefix();
1604
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_SUFFIX)] = authorPerson.getSuffix();
1605
            } else {
1606
                // create an entry in rel table and all members in author table,
1607
                // check whether the team members already in author table
1608

    
1609
                Team authorTeam = (Team) author;
1610
                int index = 0;
1611
                for (Person member : authorTeam.getTeamMembers()) {
1612
                    csvLineRel = new String[tableAuthorRel.getSize()];
1613
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_TEAM_FK)] = getId(state, authorTeam);
1614
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_FK)] = getId(state, member);
1615
                    csvLineRel[tableAuthorRel.getIndex(CdmLightExportTable.AUTHOR_TEAM_SEQ_NUMBER)] = String
1616
                            .valueOf(index);
1617
                    state.getProcessor().put(tableAuthorRel, authorTeam.getId() + ":" + member.getId(), csvLineRel);
1618

    
1619
                    if (state.getAuthorFromStore(member.getId()) == null) {
1620
                        state.addAuthorToStore(member);
1621
                        csvLineMember = new String[table.getSize()];
1622
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_ID)] = getId(state, member);
1623
                        csvLineMember[table.getIndex(CdmLightExportTable.ABBREV_AUTHOR)] = member
1624
                                .isProtectedTitleCache() ? member.getTitleCache() : member.getNomenclaturalTitle();
1625
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_TITLE)] = member.getTitleCache();
1626
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_GIVEN_NAME)] = member.getGivenName();
1627
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_FAMILY_NAME)] = member.getFamilyName();
1628
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_PREFIX)] = member.getPrefix();
1629
                        csvLineMember[table.getIndex(CdmLightExportTable.AUTHOR_SUFFIX)] = member.getSuffix();
1630
                        state.getProcessor().put(table, member, csvLineMember);
1631
                    }
1632
                    index++;
1633
                }
1634
            }
1635
            state.getProcessor().put(table, author, csvLine);
1636
        } catch (Exception e) {
1637
            state.getResult().addException(e,
1638
                    "An unexpected error occurred when handling author " + cdmBaseStr(author) + ": " + e.getMessage());
1639
        }
1640
    }
1641

    
1642
    private String extractStatusString(CdmLightExportState state, TaxonName name, boolean abbrev) {
1643
        try {
1644
            Set<NomenclaturalStatus> status = name.getStatus();
1645
            if (status.isEmpty()) {
1646
                return "";
1647
            }
1648
            String statusString = "";
1649
            for (NomenclaturalStatus nameStatus : status) {
1650
                if (nameStatus != null) {
1651
                    if (abbrev) {
1652
                        if (nameStatus.getType() != null) {
1653
                            statusString += nameStatus.getType().getIdInVocabulary();
1654
                        }
1655
                    } else {
1656
                        if (nameStatus.getType() != null) {
1657
                            statusString += nameStatus.getType().getTitleCache();
1658
                        }
1659
                    }
1660
                    if (!abbrev) {
1661

    
1662
                        if (nameStatus.getRuleConsidered() != null
1663
                                && !StringUtils.isBlank(nameStatus.getRuleConsidered())) {
1664
                            statusString += ": " + nameStatus.getRuleConsidered();
1665
                        }
1666
                        if (nameStatus.getCitation() != null) {
1667
                            String shortCitation = OriginalSourceFormatter.INSTANCE.format(nameStatus.getCitation(), null);
1668
                            statusString += " (" + shortCitation + ")";
1669
                        }
1670
//                        if (nameStatus.getCitationMicroReference() != null
1671
//                                && !StringUtils.isBlank(nameStatus.getCitationMicroReference())) {
1672
//                            statusString += " " + nameStatus.getCitationMicroReference();
1673
//                        }
1674
                    }
1675
                    statusString += " ";
1676
                }
1677
            }
1678
            return statusString;
1679
        } catch (Exception e) {
1680
            state.getResult().addException(e, "An unexpected error occurred when extracting status string for "
1681
                    + cdmBaseStr(name) + ": " + e.getMessage());
1682
            return "";
1683
        }
1684
    }
1685

    
1686
    private void handleHomotypicalGroup(CdmLightExportState state, HomotypicalGroup group, Taxon acceptedTaxon, int sortIndex) {
1687
        try {
1688
            state.addHomotypicalGroupToStore(group);
1689
            CdmLightExportTable table = CdmLightExportTable.HOMOTYPIC_GROUP;
1690
            String[] csvLine = new String[table.getSize()];
1691
            csvLine[table.getIndex(CdmLightExportTable.SORT_INDEX)] = String.valueOf(sortIndex);
1692
            csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_ID)] = getId(state, group);
1693

    
1694
            List<TaxonName> typifiedNames = new ArrayList<>();
1695
            if (acceptedTaxon != null){
1696
                List<Synonym> synonymsInGroup = acceptedTaxon.getSynonymsInGroup(group);
1697
                if (group.equals(acceptedTaxon.getHomotypicGroup())){
1698
                    typifiedNames.add(acceptedTaxon.getName());
1699
                }
1700
                synonymsInGroup.stream().forEach(synonym -> typifiedNames.add(HibernateProxyHelper.deproxy(synonym.getName(), TaxonName.class)));
1701
            }
1702

    
1703
//            group.getTypifiedNames().stream().forEach(name -> typifiedNames.add(HibernateProxyHelper.deproxy(name, TaxonName.class)));
1704
            TaxonName firstname = null;
1705
            for (TaxonName name: typifiedNames){
1706
                Iterator<Taxon> taxa = name.getTaxa().iterator();
1707
                while(taxa.hasNext()){
1708
                    Taxon taxon = taxa.next();
1709
                    if(!(taxon.isMisapplication() || taxon.isProparteSynonym())){
1710
                        firstname = name;
1711
                        break;
1712
                    }
1713
                }
1714
            }
1715

    
1716
//            Collections.sort(typifiedNames, new HomotypicalGroupNameComparator(firstname, true));
1717
            String typifiedNamesString = "";
1718
            String typifiedNamesWithSecString = "";
1719
            String typifiedNamesWithoutAccepted = "";
1720
            String typifiedNamesWithoutAcceptedWithSec = "";
1721
            int index = 0;
1722
            for (TaxonName name : typifiedNames) {
1723
                // Concatenated output string for homotypic group (names and
1724
                // citations) + status + some name relations (e.g. “non”)
1725
                // TODO: nameRelations, which and how to display
1726
                Set<TaxonBase> taxonBases = name.getTaxonBases();
1727
                TaxonBase<?> taxonBase;
1728

    
1729
                String sec = "";
1730
                String nameString = name.getFullTitleCache();
1731
                String doubtful = "";
1732

    
1733
                if (state.getConfig().isAddHTML()){
1734
                    nameString = createNameWithItalics(name.getTaggedFullTitle()) ;
1735
                }
1736

    
1737
                String synonymSign = "";
1738
                if (index > 0){
1739
                    if (name.isInvalid()){
1740
                        synonymSign = "\u2212 ";
1741
                    }else{
1742
                        synonymSign = "\u2261 ";
1743
                    }
1744
                }
1745
                boolean isAccepted = false;
1746

    
1747
                if (taxonBases.size() == 1){
1748
                     taxonBase = HibernateProxyHelper.deproxy(taxonBases.iterator().next());
1749
                     if (taxonBase.getSec() != null){
1750
                         sec = OriginalSourceFormatter.INSTANCE_WITH_YEAR_BRACKETS.format(taxonBase.getSecSource());
1751
                     }
1752
                     if (taxonBase.isDoubtful()){
1753
                         doubtful = "?";
1754
                     }else{
1755
                         doubtful = "";
1756
                     }
1757
                     if (taxonBase instanceof Synonym){
1758
                         if (isNotBlank(sec)){
1759
                             sec = " syn. sec. " + sec + " ";
1760
                         }else {
1761
                             sec = "";
1762
                         }
1763

    
1764
                         typifiedNamesWithoutAccepted += synonymSign + doubtful + nameString ;
1765
                         typifiedNamesWithoutAcceptedWithSec += synonymSign + doubtful + nameString + sec ;
1766
                     }else{
1767
                         sec = "";
1768
                         if (!(((Taxon)taxonBase).isProparteSynonym() || ((Taxon)taxonBase).isMisapplication())){
1769
                             isAccepted = true;
1770
                         }
1771
                     }
1772
                }else{
1773
                    //there are names used more than once?
1774
                    for (TaxonBase<?> tb: taxonBases){
1775
                        if (tb.getSec() != null){
1776
                            sec = OriginalSourceFormatter.INSTANCE_WITH_YEAR_BRACKETS.format(tb.getSecSource());
1777
                        }
1778
                        if (tb.isDoubtful()){
1779
                            doubtful = "?";
1780
                        }else{
1781
                            doubtful = "";
1782
                        }
1783
                        if (tb instanceof Synonym){
1784
                            if (StringUtils.isNotBlank(sec)){
1785
                                sec = " syn. sec. " + sec + " ";
1786
                            }else {
1787
                                sec = "";
1788
                            }
1789

    
1790
                            break;
1791
                        }else{
1792
                            sec = "";
1793
                            if (!(((Taxon)tb).isProparteSynonym() || ((Taxon)tb).isMisapplication())){
1794
                                isAccepted = true;
1795
                                break;
1796
                            }
1797

    
1798
                        }
1799
                    }
1800
                    if (!isAccepted){
1801
                        typifiedNamesWithoutAccepted += synonymSign + doubtful + nameString + "; ";
1802
                        typifiedNamesWithoutAcceptedWithSec += synonymSign + doubtful + nameString + sec;
1803
                        typifiedNamesWithoutAcceptedWithSec = typifiedNamesWithoutAcceptedWithSec.trim() + "; ";
1804
                    }
1805
                }
1806
                typifiedNamesString += synonymSign + doubtful + nameString ;
1807
                typifiedNamesWithSecString += synonymSign + doubtful + nameString + sec;
1808

    
1809

    
1810
                csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_STRING)] = typifiedNamesString.trim();
1811

    
1812
                csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITH_SEC_STRING)] = typifiedNamesWithSecString.trim();
1813

    
1814
                if (typifiedNamesWithoutAccepted != null && firstname != null) {
1815
                    csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTED)] = typifiedNamesWithoutAccepted.trim();
1816
                } else {
1817
                    csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTED)] = "";
1818
                }
1819

    
1820
                if (typifiedNamesWithoutAcceptedWithSec != null && firstname != null) {
1821
                    csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTEDWITHSEC)] = typifiedNamesWithoutAcceptedWithSec.trim();
1822
                } else {
1823
                    csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTEDWITHSEC)] = "";
1824
                }
1825
                index++;
1826
            }
1827

    
1828
            Set<TypeDesignationBase<?>> typeDesigantionSet = group.getTypeDesignations();
1829
            List<TypeDesignationBase<?>> designationList = new ArrayList<>();
1830
            designationList.addAll(typeDesigantionSet);
1831
            Collections.sort(designationList, new TypeComparator());
1832

    
1833
            List<TaggedText> list = new ArrayList<>();
1834
            if (!designationList.isEmpty()) {
1835
                TypeDesignationSetManager manager = new TypeDesignationSetManager(group);
1836
                list.addAll(new TypeDesignationSetFormatter(false, false, false).toTaggedText(manager));
1837
            }
1838
            String typeTextDesignations = "";
1839
            //The typeDesignationManager does not handle the textual typeDesignations
1840
            for (TypeDesignationBase<?> typeDes: designationList) {
1841
            	if (typeDes instanceof TextualTypeDesignation) {
1842
            		typeTextDesignations = typeTextDesignations + ((TextualTypeDesignation)typeDes).getText(Language.getDefaultLanguage());
1843
            		typeTextDesignations =  typeTextDesignations + "; ";
1844
            	}
1845
            }
1846
            if (typeTextDesignations.equals("; ")) {
1847
            	typeTextDesignations = "";
1848
            }
1849
            if (StringUtils.isNotBlank(typeTextDesignations)) {
1850
            	typeTextDesignations = typeTextDesignations.substring(0, typeTextDesignations.length()-2);
1851
            }
1852
            String specimenTypeString = !list.isEmpty()? createTypeDesignationString(list, true, typifiedNames.get(0).isSpecies() || typifiedNames.get(0).isInfraSpecific()):"";
1853

    
1854
            if (StringUtils.isNotBlank(specimenTypeString)) {
1855
                if (!specimenTypeString.endsWith(".")) {
1856
                	specimenTypeString = specimenTypeString + ".";
1857
                }
1858
                csvLine[table.getIndex(CdmLightExportTable.TYPE_STRING)] = specimenTypeString;
1859

    
1860
            } else {
1861
                csvLine[table.getIndex(CdmLightExportTable.TYPE_STRING)] = "";
1862
            }
1863
            if (StringUtils.isNotBlank(typeTextDesignations)) {
1864
                if (!typeTextDesignations.endsWith(".")) {
1865
                	typeTextDesignations = typeTextDesignations + ".";
1866
                }
1867
                csvLine[table.getIndex(CdmLightExportTable.TYPE_CACHE)] = typeTextDesignations;
1868

    
1869
            } else {
1870
                csvLine[table.getIndex(CdmLightExportTable.TYPE_CACHE)] = "";
1871
            }
1872
            state.getProcessor().put(table, String.valueOf(group.getId()), csvLine);
1873
        } catch (Exception e) {
1874
            state.getResult().addException(e, "An unexpected error occurred when handling homotypic group "
1875
                    + cdmBaseStr(group) + ": " + e.getMessage());
1876
        }
1877
    }
1878

    
1879
    private String createTypeDesignationString(List<TaggedText> list, boolean isHomotypicGroup, boolean isSpecimenTypeDesignation) {
1880
        StringBuffer homotypicalGroupTypeDesignationString = new StringBuffer();
1881

    
1882
        for (TaggedText text : list) {
1883
            if (text != null && text.getText() != null
1884
                    && (text.getText().equals("Type:") || text.getText().equals("NameType:") || (text.getType().equals(TagEnum.name) && !isHomotypicGroup))) {
1885
                // do nothing
1886
            } else if (text.getType().equals(TagEnum.reference)) {
1887
                homotypicalGroupTypeDesignationString.append(text.getText());
1888
            }else if (text.getType().equals(TagEnum.name)){
1889
                if (!isSpecimenTypeDesignation){
1890
                    homotypicalGroupTypeDesignationString
1891
                    .append("<i>"+text.getText()+"</i> ");
1892
                }
1893
            }else if (text.getType().equals(TagEnum.typeDesignation) ) {
1894
                if(isSpecimenTypeDesignation){
1895
                    homotypicalGroupTypeDesignationString
1896
                        .append(text.getText().replace(").", "").replace("(", "").replace(")", ""));
1897
                }else{
1898
                    homotypicalGroupTypeDesignationString
1899
                        .append(text.getText());
1900
                }
1901

    
1902
            } else {
1903
                homotypicalGroupTypeDesignationString.append(text.getText());
1904
            }
1905
        }
1906

    
1907
        String typeDesignations = homotypicalGroupTypeDesignationString.toString();
1908
        typeDesignations = typeDesignations.trim();
1909

    
1910
        if (typeDesignations.endsWith(";")){
1911
            typeDesignations = typeDesignations.substring(0, typeDesignations.length()-1);
1912
        }
1913
        typeDesignations += ".";
1914
        typeDesignations = typeDesignations.replace("..", ".");
1915
        typeDesignations = typeDesignations.replace(". .", ".");
1916

    
1917
        if (typeDesignations.trim().equals(".")) {
1918
            typeDesignations = null;
1919
        }
1920

    
1921
        return typeDesignations;
1922
    }
1923

    
1924
    private String getTropicosTitleCache(CdmLightExportState state, TaxonName name) {
1925
        try {
1926
            String basionymStart = "(";
1927
            String basionymEnd = ") ";
1928
            String exAuthorSeperator = " ex ";
1929
            TeamOrPersonBase<?> combinationAuthor = name.getCombinationAuthorship();
1930
            TeamOrPersonBase<?> exCombinationAuthor = name.getExCombinationAuthorship();
1931
            TeamOrPersonBase<?> basionymAuthor = name.getBasionymAuthorship();
1932
            TeamOrPersonBase<?> exBasionymAuthor = name.getExBasionymAuthorship();
1933

    
1934
            String combinationAuthorString = "";
1935
            if (combinationAuthor != null) {
1936
                combinationAuthor = HibernateProxyHelper.deproxy(combinationAuthor);
1937
                if (combinationAuthor instanceof Team) {
1938
                    combinationAuthorString = createTropicosTeamTitle(combinationAuthor);
1939
                } else {
1940
                    Person person = HibernateProxyHelper.deproxy(combinationAuthor, Person.class);
1941
                    combinationAuthorString = createTropicosAuthorString(person);
1942
                }
1943
            }
1944
            String exCombinationAuthorString = "";
1945
            if (exCombinationAuthor != null) {
1946
                exCombinationAuthor = HibernateProxyHelper.deproxy(exCombinationAuthor);
1947
                if (exCombinationAuthor instanceof Team) {
1948
                    exCombinationAuthorString = createTropicosTeamTitle(exCombinationAuthor);
1949
                } else {
1950
                    Person person = HibernateProxyHelper.deproxy(exCombinationAuthor, Person.class);
1951
                    exCombinationAuthorString = createTropicosAuthorString(person);
1952
                }
1953
            }
1954

    
1955
            String basionymAuthorString = "";
1956
            if (basionymAuthor != null) {
1957
                basionymAuthor = HibernateProxyHelper.deproxy(basionymAuthor);
1958
                if (basionymAuthor instanceof Team) {
1959
                    basionymAuthorString = createTropicosTeamTitle(basionymAuthor);
1960
                } else {
1961
                    Person person = HibernateProxyHelper.deproxy(basionymAuthor, Person.class);
1962
                    basionymAuthorString = createTropicosAuthorString(person);
1963
                }
1964
            }
1965

    
1966
            String exBasionymAuthorString = "";
1967

    
1968
            if (exBasionymAuthor != null) {
1969
                exBasionymAuthor = HibernateProxyHelper.deproxy(exBasionymAuthor);
1970
                if (exBasionymAuthor instanceof Team) {
1971
                    exBasionymAuthorString = createTropicosTeamTitle(exBasionymAuthor);
1972

    
1973
                } else {
1974
                    Person person = HibernateProxyHelper.deproxy(exBasionymAuthor, Person.class);
1975
                    exBasionymAuthorString = createTropicosAuthorString(person);
1976
                }
1977
            }
1978
            String completeAuthorString = name.getNameCache() + " ";
1979

    
1980
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString)
1981
                    || !CdmUtils.isBlank(basionymAuthorString)) ? basionymStart : "";
1982
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString))
1983
                    ? (CdmUtils.Nz(exBasionymAuthorString) + exAuthorSeperator) : "";
1984
            completeAuthorString += (!CdmUtils.isBlank(basionymAuthorString)) ? CdmUtils.Nz(basionymAuthorString) : "";
1985
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString)
1986
                    || !CdmUtils.isBlank(basionymAuthorString)) ? basionymEnd : "";
1987
            completeAuthorString += (!CdmUtils.isBlank(exCombinationAuthorString))
1988
                    ? (CdmUtils.Nz(exCombinationAuthorString) + exAuthorSeperator) : "";
1989
            completeAuthorString += (!CdmUtils.isBlank(combinationAuthorString)) ? CdmUtils.Nz(combinationAuthorString)
1990
                    : "";
1991

    
1992
            return completeAuthorString;
1993
        } catch (Exception e) {
1994
            state.getResult().addException(e, "An unexpected error occurred when handling tropicos title cache for "
1995
                    + cdmBaseStr(name) + ": " + e.getMessage());
1996
            return null;
1997
        }
1998
    }
1999

    
2000
    private String createTropicosTeamTitle(TeamOrPersonBase<?> combinationAuthor) {
2001
        String combinationAuthorString;
2002
        Team team = HibernateProxyHelper.deproxy(combinationAuthor, Team.class);
2003
        Team tempTeam = Team.NewInstance();
2004
        for (Person teamMember : team.getTeamMembers()) {
2005
            combinationAuthorString = createTropicosAuthorString(teamMember);
2006
            Person tempPerson = Person.NewTitledInstance(combinationAuthorString);
2007
            tempTeam.addTeamMember(tempPerson);
2008
        }
2009
        combinationAuthorString = tempTeam.generateTitle();
2010
        return combinationAuthorString;
2011
    }
2012

    
2013
    private String createTropicosAuthorString(Person teamMember) {
2014
        String nomAuthorString = "";
2015
        String[] splittedAuthorString = null;
2016
        if (teamMember == null) {
2017
            return nomAuthorString;
2018
        }
2019

    
2020
        if (teamMember.getGivenName() != null) {
2021
            String givenNameString = teamMember.getGivenName().replaceAll("\\.", "\\. ");
2022
            splittedAuthorString = givenNameString.split("\\s");
2023
            for (String split : splittedAuthorString) {
2024
                if (!StringUtils.isBlank(split)) {
2025
                    nomAuthorString += split.substring(0, 1);
2026
                    nomAuthorString += ".";
2027
                }
2028
            }
2029
        }
2030
        if (teamMember.getFamilyName() != null) {
2031
            String familyNameString = teamMember.getFamilyName().replaceAll("\\.", "\\. ");
2032
            splittedAuthorString = familyNameString.split("\\s");
2033
            for (String split : splittedAuthorString) {
2034
                nomAuthorString += " " + split;
2035
            }
2036
        }
2037
        if (isBlank(nomAuthorString.trim())) {
2038
            if (teamMember.getTitleCache() != null) {
2039
                String titleCacheString = teamMember.getTitleCache().replaceAll("\\.", "\\. ");
2040
                splittedAuthorString = titleCacheString.split("\\s");
2041
            } else {
2042
                splittedAuthorString = new String[0];
2043
            }
2044

    
2045
            int index = 0;
2046
            for (String split : splittedAuthorString) {
2047
                if (index < splittedAuthorString.length - 1 && (split.length() == 1 || split.endsWith("."))) {
2048
                    nomAuthorString += split;
2049
                } else {
2050
                    nomAuthorString = nomAuthorString + " " + split;
2051
                }
2052
                index++;
2053
            }
2054
        }
2055
        return nomAuthorString.trim();
2056
    }
2057

    
2058
    private void handleReference(CdmLightExportState state, Reference reference) {
2059
        try {
2060
            state.addReferenceToStore(reference);
2061
            CdmLightExportTable table = CdmLightExportTable.REFERENCE;
2062
            reference = HibernateProxyHelper.deproxy(reference);
2063

    
2064
            handleIdentifier(state, reference);
2065
            String[] csvLine = new String[table.getSize()];
2066
            csvLine[table.getIndex(CdmLightExportTable.REFERENCE_ID)] = getId(state, reference);
2067
            // TODO short citations correctly
2068
            String shortCitation = OriginalSourceFormatter.INSTANCE.format(reference, null); // Should be Author(year) like in Taxon.sec
2069
            csvLine[table.getIndex(CdmLightExportTable.BIBLIO_SHORT_CITATION)] = shortCitation;
2070
            // TODO get preferred title
2071
            csvLine[table.getIndex(CdmLightExportTable.REF_TITLE)] = reference.isProtectedTitleCache()
2072
                    ? reference.getTitleCache() : reference.getTitle();
2073
            csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_TITLE)] = reference.isProtectedAbbrevTitleCache()
2074
                    ? reference.getAbbrevTitleCache() : reference.getAbbrevTitle();
2075
            csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = reference.getDatePublishedString();
2076
            // TBC
2077
            csvLine[table.getIndex(CdmLightExportTable.EDITION)] = reference.getEdition();
2078
            csvLine[table.getIndex(CdmLightExportTable.EDITOR)] = reference.getEditor();
2079
            csvLine[table.getIndex(CdmLightExportTable.ISBN)] = reference.getIsbn();
2080
            csvLine[table.getIndex(CdmLightExportTable.ISSN)] = reference.getIssn();
2081
            csvLine[table.getIndex(CdmLightExportTable.ORGANISATION)] = reference.getOrganization();
2082
            csvLine[table.getIndex(CdmLightExportTable.PAGES)] = reference.getPages();
2083
            csvLine[table.getIndex(CdmLightExportTable.PLACE_PUBLISHED)] = reference.getPlacePublished();
2084
            csvLine[table.getIndex(CdmLightExportTable.PUBLISHER)] = reference.getPublisher();
2085
            csvLine[table.getIndex(CdmLightExportTable.REF_ABSTRACT)] = reference.getReferenceAbstract();
2086
            csvLine[table.getIndex(CdmLightExportTable.SERIES_PART)] = reference.getSeriesPart();
2087
            csvLine[table.getIndex(CdmLightExportTable.VOLUME)] = reference.getVolume();
2088
            csvLine[table.getIndex(CdmLightExportTable.YEAR)] = reference.getYear();
2089

    
2090
            if (reference.getAuthorship() != null) {
2091
                csvLine[table.getIndex(CdmLightExportTable.AUTHORSHIP_TITLE)] = createFullAuthorship(reference);
2092
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_FK)] = getId(state, reference.getAuthorship());
2093
            }
2094

    
2095
            csvLine[table.getIndex(CdmLightExportTable.IN_REFERENCE)] = getId(state, reference.getInReference());
2096
            if (reference.getInReference() != null
2097
                    && !state.getReferenceStore().contains(reference.getInReference().getUuid())) {
2098
                handleReference(state, reference.getInReference());
2099
            }
2100
            if (reference.getInstitution() != null) {
2101
                csvLine[table.getIndex(CdmLightExportTable.INSTITUTION)] = reference.getInstitution().getTitleCache();
2102
            }
2103
            if (reference.getLsid() != null) {
2104
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = reference.getLsid().getLsid();
2105
            }
2106
            if (reference.getSchool() != null) {
2107
                csvLine[table.getIndex(CdmLightExportTable.SCHOOL)] = reference.getSchool().getTitleCache();
2108
            }
2109
            if (reference.getUri() != null) {
2110
                csvLine[table.getIndex(CdmLightExportTable.URI)] = reference.getUri().toString();
2111
            }
2112
            csvLine[table.getIndex(CdmLightExportTable.REF_TYPE)] = reference.getType().getKey();
2113

    
2114
            state.getProcessor().put(table, reference, csvLine);
2115
        } catch (Exception e) {
2116
            state.getResult().addException(e, "An unexpected error occurred when handling reference "
2117
                    + cdmBaseStr(reference) + ": " + e.getMessage());
2118
        }
2119
    }
2120

    
2121
    private String createFullAuthorship(Reference reference) {
2122
        TeamOrPersonBase<?> authorship = reference.getAuthorship();
2123
        String fullAuthorship = "";
2124
        if (authorship == null) {
2125
            return null;
2126
        }
2127
        authorship = HibernateProxyHelper.deproxy(authorship);
2128
        if (authorship instanceof Person) {
2129
            fullAuthorship = ((Person) authorship).getTitleCache();
2130

    
2131
        } else if (authorship instanceof Team) {
2132

    
2133
            Team authorTeam = (Team)authorship;
2134
            fullAuthorship = authorTeam.getCacheStrategy().getTitleCache(authorTeam);
2135
        }
2136
        return fullAuthorship;
2137
    }
2138

    
2139
    private void handleSpecimen(CdmLightExportState state, SpecimenOrObservationBase<?> specimen) {
2140
        try {
2141
            state.addSpecimenToStore(specimen);
2142
            CdmLightExportTable table = CdmLightExportTable.SPECIMEN;
2143
            String specimenId = getId(state, specimen);
2144
            String[] csvLine = new String[table.getSize()];
2145

    
2146
            /*
2147
             * SpecimenCitation = “El Salvador, Municipio La Libertad, San
2148
             * Diego, El Amatal, 14.4.1993, González 159” [Auch ohne Punkt] ->
2149
             * FieldUnit TitleCache HerbariumAbbrev = “B” [wie gehabt]
2150
             * HerbariumCode
2151
             *
2152
             */
2153

    
2154
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_ID)] = specimenId;
2155
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_CITATION)] = specimen.getTitleCache();
2156
            Collection<FieldUnit> fieldUnits = this.getOccurrenceService().findFieldUnits(specimen.getUuid(), null);
2157
            if (fieldUnits.size() == 1) {
2158
                Iterator<FieldUnit> iterator = fieldUnits.iterator();
2159
                if (iterator.hasNext()){
2160
                    FieldUnit fieldUnit = iterator.next();
2161
                    csvLine[table.getIndex(CdmLightExportTable.FIELDUNIT_CITATION)] = fieldUnit.getTitleCache();
2162
                }
2163
            }
2164
            if (specimen.isInstanceOf(DerivedUnit.class)){
2165
                DerivedUnit derivedUnit = (DerivedUnit) specimen;
2166
                if (!StringUtils.isBlank(derivedUnit.getBarcode())){
2167
                    csvLine[table.getIndex(CdmLightExportTable.BARCODE)] = derivedUnit.getBarcode();
2168
                }
2169
                if (!StringUtils.isBlank(derivedUnit.getAccessionNumber())){
2170
                    csvLine[table.getIndex(CdmLightExportTable.ACCESSION_NUMBER)] = derivedUnit.getAccessionNumber();
2171
                }
2172
                if (!StringUtils.isBlank(derivedUnit.getCatalogNumber())){
2173
                    csvLine[table.getIndex(CdmLightExportTable.CATALOGUE_NUMBER)] = derivedUnit.getCatalogNumber();
2174
                }
2175
            }
2176

    
2177
            csvLine[table.getIndex(CdmLightExportTable.PREFERREDSTABLE_ID)] = specimen.getPreferredStableUri() != null? specimen.getPreferredStableUri().toString(): null;
2178
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_IMAGE_URIS)] = extractMediaURIs(state,
2179
                    specimen.getDescriptions(), Feature.IMAGE());
2180
            if (specimen instanceof DerivedUnit) {
2181
                DerivedUnit derivedUnit = (DerivedUnit) specimen;
2182
                if (derivedUnit.getCollection() != null) {
2183
                    csvLine[table.getIndex(CdmLightExportTable.HERBARIUM_ABBREV)] = derivedUnit.getCollection()
2184
                            .getCode();
2185
                }
2186

    
2187
                if (specimen instanceof MediaSpecimen) {
2188
                    MediaSpecimen mediaSpecimen = (MediaSpecimen) specimen;
2189
                    Iterator<MediaRepresentation> it = mediaSpecimen.getMediaSpecimen().getRepresentations().iterator();
2190
                    String mediaUris = extractMediaUris(it);
2191
                    csvLine[table.getIndex(CdmLightExportTable.MEDIA_SPECIMEN_URL)] = mediaUris;
2192

    
2193
                }
2194

    
2195
                if (derivedUnit.getDerivedFrom() != null) {
2196
                    for (SpecimenOrObservationBase<?> original : derivedUnit.getDerivedFrom().getOriginals()) {
2197
                        // TODO: What to do if there are more then one
2198
                        // FieldUnit??
2199
                        if (original instanceof FieldUnit) {
2200
                            FieldUnit fieldUnit = (FieldUnit) original;
2201
                            csvLine[table.getIndex(CdmLightExportTable.COLLECTOR_NUMBER)] = fieldUnit.getFieldNumber();
2202

    
2203
                            GatheringEvent gathering = fieldUnit.getGatheringEvent();
2204
                            if (gathering != null) {
2205
                                if (gathering.getLocality() != null) {
2206
                                    csvLine[table.getIndex(CdmLightExportTable.LOCALITY)] = gathering.getLocality()
2207
                                            .getText();
2208
                                }
2209
                                if (gathering.getCountry() != null) {
2210
                                    csvLine[table.getIndex(CdmLightExportTable.COUNTRY)] = gathering.getCountry()
2211
                                            .getLabel();
2212
                                }
2213
                                csvLine[table.getIndex(CdmLightExportTable.COLLECTOR_STRING)] = createCollectorString(
2214
                                        state, gathering, fieldUnit);
2215

    
2216
                                if (gathering.getGatheringDate() != null) {
2217
                                    csvLine[table.getIndex(CdmLightExportTable.COLLECTION_DATE)] = gathering
2218
                                            .getGatheringDate().toString();
2219
                                }
2220
                                if (!gathering.getCollectingAreas().isEmpty()) {
2221
                                    int index = 0;
2222
                                    csvLine[table.getIndex(CdmLightExportTable.FURTHER_AREAS)] = "0";
2223
                                    for (NamedArea area : gathering.getCollectingAreas()) {
2224
                                        if (index == 0) {
2225
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY1)] = area.getLevel() != null?area
2226
                                                    .getLevel().getLabel():"";
2227
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME1)] = area.getLabel();
2228
                                        }
2229
                                        if (index == 1) {
2230
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY2)] = area.getLevel() != null?area
2231
                                                    .getLevel().getLabel():"";
2232
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME2)] = area.getLabel();
2233
                                        }
2234
                                        if (index == 2) {
2235
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY3)] = area.getLevel() != null?area
2236
                                                    .getLevel().getLabel():"";
2237
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME3)] = area.getLabel();
2238
                                        }
2239
                                        if (index == 3) {
2240
                                            csvLine[table.getIndex(CdmLightExportTable.FURTHER_AREAS)] = "1";
2241
                                            break;
2242
                                        }
2243
                                        index++;
2244
                                    }
2245
                                }
2246
                            }
2247
                        }
2248
                    }
2249
                } else {
2250
                    state.getResult().addError("The specimen with uuid " + specimen.getUuid()
2251
                            + " is not an DerivedUnit. Could not be exported.");
2252
                }
2253
            }
2254

    
2255
            state.getProcessor().put(table, specimen, csvLine);
2256
        } catch (Exception e) {
2257
            state.getResult().addException(e, "An unexpected error occurred when handling specimen "
2258
                    + cdmBaseStr(specimen) + ": " + e.getMessage());
2259
        }
2260
    }
2261

    
2262
    private String extractMediaUris(Iterator<MediaRepresentation> it) {
2263

    
2264
        String mediaUriString = "";
2265
        boolean first = true;
2266
        while (it.hasNext()) {
2267
            MediaRepresentation rep = it.next();
2268
            List<MediaRepresentationPart> parts = rep.getParts();
2269
            for (MediaRepresentationPart part : parts) {
2270
                if (first) {
2271
                    if (part.getUri() != null) {
2272
                        mediaUriString += part.getUri().toString();
2273
                        first = false;
2274
                    }
2275
                } else {
2276
                    if (part.getUri() != null) {
2277
                        mediaUriString += ", " + part.getUri().toString();
2278
                    }
2279
                }
2280
            }
2281
        }
2282

    
2283
        return mediaUriString;
2284
    }
2285

    
2286
    private String extractLinkUris(Iterator<ExternalLink> it) {
2287

    
2288
        String linkUriString = "";
2289
        boolean first = true;
2290
        while (it.hasNext()) {
2291
            ExternalLink link = it.next();
2292
            if (first) {
2293
                if (link.getUri() != null) {
2294
                    linkUriString += link.getUri().toString();
2295
                    first = false;
2296
                }
2297
            } else {
2298
                if (link.getUri() != null) {
2299
                    linkUriString += ", " + link.getUri().toString();
2300
                }
2301
            }
2302
        }
2303
        return linkUriString;
2304
    }
2305

    
2306
    private String createCollectorString(CdmLightExportState state, GatheringEvent gathering, FieldUnit fieldUnit) {
2307
        try {
2308
            String collectorString = "";
2309
            AgentBase<?> collectorA = CdmBase.deproxy(gathering.getCollector());
2310
            if (gathering.getCollector() != null) {
2311
                if (collectorA instanceof TeamOrPersonBase && state.getConfig().isHighLightPrimaryCollector()) {
2312

    
2313
                    Person primaryCollector = fieldUnit.getPrimaryCollector();
2314
                    if (collectorA instanceof Team) {
2315
                        Team collectorTeam = (Team) collectorA;
2316
                        boolean isFirst = true;
2317
                        for (Person member : collectorTeam.getTeamMembers()) {
2318
                            if (!isFirst) {
2319
                                collectorString += "; ";
2320
                            }
2321
                            if (member.equals(primaryCollector)) {
2322
                                // highlight
2323
                                collectorString += "<b>" + member.getTitleCache() + "</b>";
2324
                            } else {
2325
                                collectorString += member.getTitleCache();
2326
                            }
2327
                        }
2328
                    }
2329
                } else {
2330
                    collectorString = collectorA.getTitleCache();
2331
                }
2332
            }
2333
            return collectorString;
2334
        } catch (Exception e) {
2335
            state.getResult().addException(e, "An unexpected error occurred when creating collector string for "
2336
                    + cdmBaseStr(fieldUnit) + ": " + e.getMessage());
2337
            return "";
2338
        }
2339
    }
2340

    
2341
    /**
2342
     * Returns a string representation of the {@link CdmBase cdmBase} object for
2343
     * result messages.
2344
     */
2345
    private String cdmBaseStr(CdmBase cdmBase) {
2346
        if (cdmBase == null) {
2347
            return "-no object available-";
2348
        } else {
2349
            return cdmBase.getClass().getSimpleName() + ": " + cdmBase.getUuid();
2350
        }
2351
    }
2352

    
2353
    @Override
2354
    protected boolean doCheck(CdmLightExportState state) {
2355
        return false;
2356
    }
2357

    
2358
    @Override
2359
    protected boolean isIgnore(CdmLightExportState state) {
2360
        return false;
2361
    }
2362

    
2363
}
(1-1/6)