Project

General

Profile

Download (126 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.NamedSource;
90
import eu.etaxonomy.cdm.model.reference.OriginalSourceType;
91
import eu.etaxonomy.cdm.model.reference.Reference;
92
import eu.etaxonomy.cdm.model.reference.ReferenceType;
93
import eu.etaxonomy.cdm.model.taxon.Classification;
94
import eu.etaxonomy.cdm.model.taxon.Synonym;
95
import eu.etaxonomy.cdm.model.taxon.Taxon;
96
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
97
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
98
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
99
import eu.etaxonomy.cdm.model.term.DefinedTerm;
100
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
101
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDtoByRankAndNameComparator;
102
import eu.etaxonomy.cdm.strategy.cache.HTMLTagRules;
103
import eu.etaxonomy.cdm.strategy.cache.TagEnum;
104
import eu.etaxonomy.cdm.strategy.cache.TaggedText;
105
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
106

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

    
115
    private static final long serialVersionUID = 2518643632756927053L;
116
    private static final String STD_TEAM_CONCATINATION = ", ";
117
    private static final String FINAL_TEAM_CONCATINATION = " & ";
118

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

    
123
    @Autowired
124
    IEditGeoService geoService;
125

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

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

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

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

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

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

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

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

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

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

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

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

    
202
        // String sortIndex = StringUtils.isBlank(sort_index)?
203
        // String.valueOf(order.getOrderIndex()): sort_index+ "_"
204
        // +String.valueOf(order.getOrderIndex());
205

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

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

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

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

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

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

    
268
                    // add root to node map
269

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

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

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

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

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

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

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

    
337

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

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

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

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

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

    
397
            taxonNode.removeNullValueFromChildren();
398

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

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

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

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

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

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

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

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

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

    
551
            try {
552

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

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

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

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

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

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

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

    
607
    }
608

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

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

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

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

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

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

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

    
688
                if (element instanceof IndividualsAssociation) {
689

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

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

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

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

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

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

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

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

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

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

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

    
790
    }
791

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
967
            Reference secRef = ppSyonym.getSec();
968

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

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

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

    
1008
            // pro parte type
1009

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

    
1020
    }
1021

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

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

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

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

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

    
1072

    
1073
            if (!state.getConfig().isAddHTML()) {
1074
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_REF)] = name.getFullTitleCache();
1075
            } else {
1076
                List<TaggedText> taggedFullTitleCache = name.getTaggedFullTitle();
1077
                List<TaggedText> taggedName = name.getTaggedName();
1078

    
1079
                String fullTitleWithHtml = createNameWithItalics(taggedFullTitleCache);
1080
                // TODO: adapt the tropicos titlecache creation
1081
                csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_WITH_REF)] = fullTitleWithHtml.trim();
1082
            }
1083

    
1084
            csvLine[table.getIndex(CdmLightExportTable.FULL_NAME_NO_AUTHORS)] = name.getNameCache();
1085
            csvLine[table.getIndex(CdmLightExportTable.GENUS_UNINOMIAL)] = name.getGenusOrUninomial();
1086

    
1087
            csvLine[table.getIndex(CdmLightExportTable.INFRAGENERIC_EPITHET)] = name.getInfraGenericEpithet();
1088
            csvLine[table.getIndex(CdmLightExportTable.SPECIFIC_EPITHET)] = name.getSpecificEpithet();
1089

    
1090
            csvLine[table.getIndex(CdmLightExportTable.INFRASPECIFIC_EPITHET)] = name.getInfraSpecificEpithet();
1091

    
1092
            csvLine[table.getIndex(CdmLightExportTable.APPENDED_PHRASE)] = name.getAppendedPhrase();
1093

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

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

    
1122
            }
1123

    
1124
            csvLine[table.getIndex(CdmLightExportTable.AUTHOR_TEAM_STRING)] = name.getAuthorshipCache();
1125

    
1126
            Reference nomRef = name.getNomenclaturalReference();
1127

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

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

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

    
1219
                }
1220
            } else {
1221
                csvLine[table.getIndex(CdmLightExportTable.PUBLICATION_TYPE)] = "";
1222
            }
1223

    
1224
            /*
1225
             * Collation
1226
             *
1227
             * Detail
1228
             *
1229
             * TitlePageYear
1230
             */
1231
            String protologueUriString = extractProtologueURIs(state, name);
1232

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

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

    
1255
                    } else {
1256
                        textualTypeDesignations.add((TextualTypeDesignation) typeDesignation);
1257
                    }
1258
                } else if (typeDesignation.isInstanceOf(SpecimenTypeDesignation.class)) {
1259

    
1260
                    specimenTypeDesignations.add(HibernateProxyHelper.deproxy(typeDesignation, SpecimenTypeDesignation.class));
1261

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

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

    
1299

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

    
1305
                String statusStringAbbrev = extractStatusString(state, name, true);
1306
                String statusString = extractStatusString(state, name, false);
1307

    
1308
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS)] = statusString.trim();
1309
                csvLine[table.getIndex(CdmLightExportTable.NOM_STATUS_ABBREV)] = statusStringAbbrev.trim();
1310
            }
1311

    
1312
            HomotypicalGroup group = HibernateProxyHelper.deproxy(name.getHomotypicalGroup(), HomotypicalGroup.class);
1313

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

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

    
1328
            }else{
1329
                typifiedNames.addAll(group.getTypifiedNames());
1330
            }
1331

    
1332

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

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

    
1342
            e.printStackTrace();
1343
        }
1344
    }
1345

    
1346
    private String createNameWithItalics(List<TaggedText> taggedName) {
1347

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

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

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

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

    
1380
        rels = name.getRelationsToThisName();
1381

    
1382
        csvLine = new String[table.getSize()];
1383

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

    
1392

    
1393
        }
1394
    }
1395

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

    
1409
        return collation;
1410
    }
1411

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

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

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

    
1465

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

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

    
1491
                        csvLine = new String[table.getSize()];
1492
                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, cdmBase);
1493

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

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

    
1533
    private String extractIdentifier(Set<String> identifierSet) {
1534

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

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

    
1554
    private String extractMediaURIs(CdmLightExportState state, Set<? extends DescriptionBase<?>> descriptionsSet,
1555
            Feature feature) {
1556

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

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

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

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

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

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

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

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

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

    
1706

    
1707
            TaxonName firstname = null;
1708
            for (TaxonName name: typifiedNames){
1709
                Iterator<Taxon> taxa = name.getTaxa().iterator();
1710
                while(taxa.hasNext()){
1711
                    Taxon taxon = taxa.next();
1712
                    if(!(taxon.isMisapplication() || taxon.isProparteSynonym())){
1713
                        firstname = name;
1714
                        break;
1715
                    }
1716
                }
1717
            }
1718

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

    
1732
                String sec = "";
1733
                String nameString = name.getFullTitleCache();
1734
                String doubtful = "";
1735

    
1736
                if (state.getConfig().isAddHTML()){
1737
                    nameString = createNameWithItalics(name.getTaggedFullTitle()) ;
1738
                }
1739

    
1740
                Set<NameRelationship> related = name.getNameRelations();
1741
                List<NameRelationship> relatedList = new ArrayList<>(related);
1742

    
1743
                Collections.sort(relatedList, new Comparator<NameRelationship>() {
1744
                    @Override
1745
                    public int compare(NameRelationship nr1, NameRelationship nr2) {
1746
                        return nr1.getType().compareTo(nr2.getType());
1747
                    }
1748

    
1749
                });
1750

    
1751
                List<NameRelationship> nonNames = new ArrayList<>();
1752
                List<NameRelationship> otherRelationships = new ArrayList<>();
1753

    
1754
                for (NameRelationship rel: relatedList){
1755
                    //no inverse relations
1756
                    if (rel.getFromName().equals(name)){
1757
                     // alle Homonyme und inverse blocking names
1758
                        if (rel.getType().equals(NameRelationshipType.LATER_HOMONYM())
1759
                                || rel.getType().equals(NameRelationshipType.TREATED_AS_LATER_HOMONYM())
1760
                                || (rel.getType().equals(NameRelationshipType.BLOCKING_NAME_FOR()))
1761
                                || (rel.getType().equals(NameRelationshipType.UNSPECIFIC_NON()))){
1762
                            nonNames.add(rel);
1763
                        }else if (!rel.getType().isBasionymRelation()){
1764
                            otherRelationships.add(rel);
1765
                        }
1766
                    }
1767
                }
1768

    
1769
                String nonRelNames = "";
1770
                String relNames = "";
1771

    
1772
                if (nonNames.size() > 0){
1773
                    nonRelNames += " [";
1774
                }
1775
                for (NameRelationship relName: nonNames){
1776
                    String label = "non ";
1777
                    TaxonName relatedName = null;
1778
                    if (relName.getFromName().equals(name)){
1779
                        relatedName = relName.getToName();
1780
                        nonRelNames += label + relatedName.getTitleCache() + " ";
1781
                    }
1782
//                    else{
1783
//                        label = relName.getType().getInverseLabel() + " ";
1784
//                        relatedName = relName.getFromName();
1785
//                        nonRelNames += label + relatedName.getTitleCache() + " ";
1786
//                    }
1787

    
1788

    
1789
                }
1790
                relNames.trim();
1791
                if (nonNames.size() > 0){
1792
                    nonRelNames = StringUtils.strip(nonRelNames, null);
1793
                    nonRelNames += "] ";
1794
                }
1795

    
1796
                if (otherRelationships.size() > 0){
1797
                    relNames += " [";
1798
                }
1799
                for (NameRelationship rel: otherRelationships){
1800
                    String label = "";
1801
                    TaxonName relatedName = null;
1802
                    if (rel.getFromName().equals(name)){
1803
                        label = rel.getType().getLabel() + " ";
1804
                        relatedName = rel.getToName();
1805
                        if (state.getConfig().isAddHTML()){
1806
                            relNames += label + createNameWithItalics(relatedName.getTaggedName())+ " ";
1807
                        }else{
1808
                            relNames += label + relatedName.getTitleCache();
1809
                        }
1810
                    }
1811
//                    else {
1812
//                        label = rel.getType().getInverseLabel() + " ";
1813
//                        relatedName = rel.getFromName();
1814
//                    }
1815

    
1816
                }
1817
                relNames.trim();
1818
                if (otherRelationships.size() > 0){
1819
                    relNames = StringUtils.stripEnd(relNames, null);
1820
                    relNames += "] ";
1821
                }
1822

    
1823
                String synonymSign = "";
1824
                if (index > 0){
1825
                    if (name.isInvalid()){
1826
                        synonymSign = "\u2212 ";
1827
                    }else{
1828
                        synonymSign = "\u2261 ";
1829
                    }
1830
                }
1831
                boolean isAccepted = false;
1832

    
1833
                if (taxonBases.size() == 1){
1834
                     taxonBase = HibernateProxyHelper.deproxy(taxonBases.iterator().next());
1835

    
1836
                     if (taxonBase.getSec() != null){
1837
                         sec = OriginalSourceFormatter.INSTANCE_WITH_YEAR_BRACKETS.format(taxonBase.getSecSource());
1838
                     }
1839
                     if (taxonBase.isDoubtful()){
1840
                         doubtful = "?";
1841
                     }else{
1842
                         doubtful = "";
1843
                     }
1844
                     if (taxonBase instanceof Synonym){
1845
                         if (isNotBlank(sec)){
1846
                             sec = " syn. sec. " + sec + " ";
1847
                         }else {
1848
                             sec = "";
1849
                         }
1850

    
1851
                         typifiedNamesWithoutAccepted += synonymSign + doubtful + nameString + nonRelNames + relNames;
1852
                         typifiedNamesWithoutAcceptedWithSec += synonymSign + doubtful + nameString + sec + nonRelNames + relNames;
1853
                     }else{
1854
//                         sec = "";
1855
                         if (!(((Taxon)taxonBase).isProparteSynonym() || ((Taxon)taxonBase).isMisapplication())){
1856
                             isAccepted = true;
1857
                         }
1858
                     }
1859
                     if (taxonBase.getAppendedPhrase() != null){
1860
                         if (state.getConfig().isAddHTML()){
1861
                             String taxonString = createNameWithItalics(taxonBase.getTaggedTitle()) ;
1862
                             taxonString = taxonString.replace("sec "+sec, "");
1863
                             String nameCacheWithItalics = createNameWithItalics(name.getTaggedName());
1864
                             nameString = nameString.replace(nameCacheWithItalics, taxonString);
1865
                         }
1866
                     }
1867
                }else{
1868
                    //there are names used more than once?
1869
                    for (TaxonBase<?> tb: taxonBases){
1870
                        if (tb.getSec() != null){
1871
                            sec = OriginalSourceFormatter.INSTANCE_WITH_YEAR_BRACKETS.format(tb.getSecSource());
1872
                        }
1873
                        if (tb.isDoubtful()){
1874
                            doubtful = "?";
1875
                        }else{
1876
                            doubtful = "";
1877
                        }
1878
                        if (tb instanceof Synonym){
1879
                            if (StringUtils.isNotBlank(sec)){
1880
                                sec = " syn. sec. " + sec + " ";
1881
                            }else {
1882
                                sec = "";
1883
                            }
1884

    
1885
                            break;
1886
                        }else{
1887
                            sec = "";
1888
                            if (!(((Taxon)tb).isProparteSynonym() || ((Taxon)tb).isMisapplication())){
1889
                                isAccepted = true;
1890
                                break;
1891
                            }
1892

    
1893
                        }
1894
                    }
1895
                    if (!isAccepted){
1896
                        typifiedNamesWithoutAccepted += synonymSign + doubtful + nameString + "; ";
1897
                        typifiedNamesWithoutAcceptedWithSec += synonymSign + doubtful + nameString + sec;
1898
                        typifiedNamesWithoutAcceptedWithSec = typifiedNamesWithoutAcceptedWithSec.trim() + "; ";
1899
                    }
1900
                }
1901
                typifiedNamesString += synonymSign + doubtful + nameString + nonRelNames + relNames;
1902
                typifiedNamesWithSecString += synonymSign + doubtful + nameString + sec + nonRelNames + relNames;
1903

    
1904

    
1905
                csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_STRING)] = typifiedNamesString.trim();
1906

    
1907
                csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITH_SEC_STRING)] = typifiedNamesWithSecString.trim();
1908

    
1909
                if (typifiedNamesWithoutAccepted != null && firstname != null) {
1910
                    csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTED)] = typifiedNamesWithoutAccepted.trim();
1911
                } else {
1912
                    csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTED)] = "";
1913
                }
1914

    
1915
                if (typifiedNamesWithoutAcceptedWithSec != null && firstname != null) {
1916
                    csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTEDWITHSEC)] = typifiedNamesWithoutAcceptedWithSec.trim();
1917
                } else {
1918
                    csvLine[table.getIndex(CdmLightExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTEDWITHSEC)] = "";
1919
                }
1920
                index++;
1921
            }
1922

    
1923
            Set<TypeDesignationBase<?>> typeDesigantionSet = group.getTypeDesignations();
1924
            List<TypeDesignationBase<?>> designationList = new ArrayList<>();
1925
            designationList.addAll(typeDesigantionSet);
1926
            Collections.sort(designationList, new TypeComparator());
1927

    
1928
            List<TaggedText> list = new ArrayList<>();
1929
            if (!designationList.isEmpty()) {
1930
                TypeDesignationSetManager manager = new TypeDesignationSetManager(group);
1931
                list.addAll(new TypeDesignationSetFormatter(false, false, false).toTaggedText(manager));
1932
            }
1933
            String typeTextDesignations = "";
1934
            //The typeDesignationManager does not handle the textual typeDesignations
1935
            for (TypeDesignationBase<?> typeDes: designationList) {
1936
            	if (typeDes instanceof TextualTypeDesignation) {
1937
            		typeTextDesignations = typeTextDesignations + ((TextualTypeDesignation)typeDes).getText(Language.getDefaultLanguage());
1938
            		String typeDesStateRefs = "";
1939
                    if (typeDes.getDesignationSource() != null ){
1940
                        typeDesStateRefs = "[";
1941
                        NamedSource source = typeDes.getDesignationSource();
1942
                        if (source.getCitation() != null){
1943
                            typeDesStateRefs += "fide " + OriginalSourceFormatter.INSTANCE.format(source.getCitation(), null);
1944
                        }
1945
                        typeDesStateRefs += "]";
1946
                    }else if (typeDes.getSources() != null && !typeDes.getSources().isEmpty()){
1947
                        typeDesStateRefs = "[";
1948
                        for (IdentifiableSource source: typeDes.getSources()) {
1949
                            if (source.getCitation() != null){
1950
                                typeDesStateRefs += "fide " +OriginalSourceFormatter.INSTANCE.format(source.getCitation(), null);
1951
                            }
1952
                        }
1953

    
1954
                        typeDesStateRefs += "]";
1955
                    }
1956

    
1957
            		typeTextDesignations =  typeTextDesignations + typeDesStateRefs +"; ";
1958

    
1959
            	}
1960
            }
1961
            if (typeTextDesignations.equals("; ")) {
1962
            	typeTextDesignations = "";
1963
            }
1964
            if (StringUtils.isNotBlank(typeTextDesignations)) {
1965
            	typeTextDesignations = typeTextDesignations.substring(0, typeTextDesignations.length()-2);
1966
            }
1967
            String specimenTypeString = !list.isEmpty()? createTypeDesignationString(list, true, typifiedNames.get(0).isSpecies() || typifiedNames.get(0).isInfraSpecific()):"";
1968

    
1969
            if (StringUtils.isNotBlank(specimenTypeString)) {
1970
                if (!specimenTypeString.endsWith(".")) {
1971
                	specimenTypeString = specimenTypeString + ".";
1972
                }
1973
                csvLine[table.getIndex(CdmLightExportTable.TYPE_STRING)] = specimenTypeString;
1974

    
1975
            } else {
1976
                csvLine[table.getIndex(CdmLightExportTable.TYPE_STRING)] = "";
1977
            }
1978
            if (StringUtils.isNotBlank(typeTextDesignations)) {
1979
                if (!typeTextDesignations.endsWith(".")) {
1980
                	typeTextDesignations = typeTextDesignations + ".";
1981
                }
1982
                csvLine[table.getIndex(CdmLightExportTable.TYPE_CACHE)] = typeTextDesignations;
1983

    
1984
            } else {
1985
                csvLine[table.getIndex(CdmLightExportTable.TYPE_CACHE)] = "";
1986
            }
1987
            state.getProcessor().put(table, String.valueOf(group.getId()), csvLine);
1988
        } catch (Exception e) {
1989
            state.getResult().addException(e, "An unexpected error occurred when handling homotypic group "
1990
                    + cdmBaseStr(group) + ": " + e.getMessage());
1991
        }
1992
    }
1993

    
1994
    private String createTypeDesignationString(List<TaggedText> list, boolean isHomotypicGroup, boolean isSpecimenTypeDesignation) {
1995
        StringBuffer homotypicalGroupTypeDesignationString = new StringBuffer();
1996

    
1997
        for (TaggedText text : list) {
1998
            if (text != null && text.getText() != null
1999
                    && (text.getText().equals("Type:") || text.getText().equals("NameType:") || (text.getType().equals(TagEnum.name) && !isHomotypicGroup))) {
2000
                // do nothing
2001
            } else if (text.getType().equals(TagEnum.reference)) {
2002
                homotypicalGroupTypeDesignationString.append(text.getText());
2003
            }else if (text.getType().equals(TagEnum.name)){
2004
                if (!isSpecimenTypeDesignation){
2005
                    homotypicalGroupTypeDesignationString
2006
                    .append("<i>"+text.getText()+"</i> ");
2007
                }
2008
            }else if (text.getType().equals(TagEnum.typeDesignation) ) {
2009
                if(isSpecimenTypeDesignation){
2010
                    homotypicalGroupTypeDesignationString
2011
                        .append(text.getText().replace(").", "").replace("(", "").replace(")", ""));
2012
                }else{
2013
                    homotypicalGroupTypeDesignationString
2014
                        .append(text.getText());
2015
                }
2016

    
2017
            } else {
2018
                homotypicalGroupTypeDesignationString.append(text.getText());
2019
            }
2020
        }
2021

    
2022
        String typeDesignations = homotypicalGroupTypeDesignationString.toString();
2023
        typeDesignations = typeDesignations.trim();
2024

    
2025
        if (typeDesignations.endsWith(";")){
2026
            typeDesignations = typeDesignations.substring(0, typeDesignations.length()-1);
2027
        }
2028
        typeDesignations += ".";
2029
        typeDesignations = typeDesignations.replace("..", ".");
2030
        typeDesignations = typeDesignations.replace(". .", ".");
2031

    
2032
        if (typeDesignations.trim().equals(".")) {
2033
            typeDesignations = null;
2034
        }
2035

    
2036
        return typeDesignations;
2037
    }
2038

    
2039
    private String getTropicosTitleCache(CdmLightExportState state, TaxonName name) {
2040
        try {
2041
            String basionymStart = "(";
2042
            String basionymEnd = ") ";
2043
            String exAuthorSeperator = " ex ";
2044
            TeamOrPersonBase<?> combinationAuthor = name.getCombinationAuthorship();
2045
            TeamOrPersonBase<?> exCombinationAuthor = name.getExCombinationAuthorship();
2046
            TeamOrPersonBase<?> basionymAuthor = name.getBasionymAuthorship();
2047
            TeamOrPersonBase<?> exBasionymAuthor = name.getExBasionymAuthorship();
2048

    
2049
            String combinationAuthorString = "";
2050
            if (combinationAuthor != null) {
2051
                combinationAuthor = HibernateProxyHelper.deproxy(combinationAuthor);
2052
                if (combinationAuthor instanceof Team) {
2053
                    combinationAuthorString = createTropicosTeamTitle(combinationAuthor);
2054
                } else {
2055
                    Person person = HibernateProxyHelper.deproxy(combinationAuthor, Person.class);
2056
                    combinationAuthorString = createTropicosAuthorString(person);
2057
                }
2058
            }
2059
            String exCombinationAuthorString = "";
2060
            if (exCombinationAuthor != null) {
2061
                exCombinationAuthor = HibernateProxyHelper.deproxy(exCombinationAuthor);
2062
                if (exCombinationAuthor instanceof Team) {
2063
                    exCombinationAuthorString = createTropicosTeamTitle(exCombinationAuthor);
2064
                } else {
2065
                    Person person = HibernateProxyHelper.deproxy(exCombinationAuthor, Person.class);
2066
                    exCombinationAuthorString = createTropicosAuthorString(person);
2067
                }
2068
            }
2069

    
2070
            String basionymAuthorString = "";
2071
            if (basionymAuthor != null) {
2072
                basionymAuthor = HibernateProxyHelper.deproxy(basionymAuthor);
2073
                if (basionymAuthor instanceof Team) {
2074
                    basionymAuthorString = createTropicosTeamTitle(basionymAuthor);
2075
                } else {
2076
                    Person person = HibernateProxyHelper.deproxy(basionymAuthor, Person.class);
2077
                    basionymAuthorString = createTropicosAuthorString(person);
2078
                }
2079
            }
2080

    
2081
            String exBasionymAuthorString = "";
2082

    
2083
            if (exBasionymAuthor != null) {
2084
                exBasionymAuthor = HibernateProxyHelper.deproxy(exBasionymAuthor);
2085
                if (exBasionymAuthor instanceof Team) {
2086
                    exBasionymAuthorString = createTropicosTeamTitle(exBasionymAuthor);
2087

    
2088
                } else {
2089
                    Person person = HibernateProxyHelper.deproxy(exBasionymAuthor, Person.class);
2090
                    exBasionymAuthorString = createTropicosAuthorString(person);
2091
                }
2092
            }
2093
            String completeAuthorString = name.getNameCache() + " ";
2094

    
2095
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString)
2096
                    || !CdmUtils.isBlank(basionymAuthorString)) ? basionymStart : "";
2097
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString))
2098
                    ? (CdmUtils.Nz(exBasionymAuthorString) + exAuthorSeperator) : "";
2099
            completeAuthorString += (!CdmUtils.isBlank(basionymAuthorString)) ? CdmUtils.Nz(basionymAuthorString) : "";
2100
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString)
2101
                    || !CdmUtils.isBlank(basionymAuthorString)) ? basionymEnd : "";
2102
            completeAuthorString += (!CdmUtils.isBlank(exCombinationAuthorString))
2103
                    ? (CdmUtils.Nz(exCombinationAuthorString) + exAuthorSeperator) : "";
2104
            completeAuthorString += (!CdmUtils.isBlank(combinationAuthorString)) ? CdmUtils.Nz(combinationAuthorString)
2105
                    : "";
2106

    
2107
            return completeAuthorString;
2108
        } catch (Exception e) {
2109
            state.getResult().addException(e, "An unexpected error occurred when handling tropicos title cache for "
2110
                    + cdmBaseStr(name) + ": " + e.getMessage());
2111
            return null;
2112
        }
2113
    }
2114

    
2115
    private String createTropicosTeamTitle(TeamOrPersonBase<?> combinationAuthor) {
2116
        String combinationAuthorString;
2117
        Team team = HibernateProxyHelper.deproxy(combinationAuthor, Team.class);
2118
        Team tempTeam = Team.NewInstance();
2119
        for (Person teamMember : team.getTeamMembers()) {
2120
            combinationAuthorString = createTropicosAuthorString(teamMember);
2121
            Person tempPerson = Person.NewTitledInstance(combinationAuthorString);
2122
            tempTeam.addTeamMember(tempPerson);
2123
        }
2124
        combinationAuthorString = tempTeam.generateTitle();
2125
        return combinationAuthorString;
2126
    }
2127

    
2128
    private String createTropicosAuthorString(Person teamMember) {
2129
        String nomAuthorString = "";
2130
        String[] splittedAuthorString = null;
2131
        if (teamMember == null) {
2132
            return nomAuthorString;
2133
        }
2134

    
2135
        if (teamMember.getGivenName() != null) {
2136
            String givenNameString = teamMember.getGivenName().replaceAll("\\.", "\\. ");
2137
            splittedAuthorString = givenNameString.split("\\s");
2138
            for (String split : splittedAuthorString) {
2139
                if (!StringUtils.isBlank(split)) {
2140
                    nomAuthorString += split.substring(0, 1);
2141
                    nomAuthorString += ".";
2142
                }
2143
            }
2144
        }
2145
        if (teamMember.getFamilyName() != null) {
2146
            String familyNameString = teamMember.getFamilyName().replaceAll("\\.", "\\. ");
2147
            splittedAuthorString = familyNameString.split("\\s");
2148
            for (String split : splittedAuthorString) {
2149
                nomAuthorString += " " + split;
2150
            }
2151
        }
2152
        if (isBlank(nomAuthorString.trim())) {
2153
            if (teamMember.getTitleCache() != null) {
2154
                String titleCacheString = teamMember.getTitleCache().replaceAll("\\.", "\\. ");
2155
                splittedAuthorString = titleCacheString.split("\\s");
2156
            } else {
2157
                splittedAuthorString = new String[0];
2158
            }
2159

    
2160
            int index = 0;
2161
            for (String split : splittedAuthorString) {
2162
                if (index < splittedAuthorString.length - 1 && (split.length() == 1 || split.endsWith("."))) {
2163
                    nomAuthorString += split;
2164
                } else {
2165
                    nomAuthorString = nomAuthorString + " " + split;
2166
                }
2167
                index++;
2168
            }
2169
        }
2170
        return nomAuthorString.trim();
2171
    }
2172

    
2173
    private void handleReference(CdmLightExportState state, Reference reference) {
2174
        try {
2175
            state.addReferenceToStore(reference);
2176
            CdmLightExportTable table = CdmLightExportTable.REFERENCE;
2177
            reference = HibernateProxyHelper.deproxy(reference);
2178

    
2179
            handleIdentifier(state, reference);
2180
            String[] csvLine = new String[table.getSize()];
2181
            csvLine[table.getIndex(CdmLightExportTable.REFERENCE_ID)] = getId(state, reference);
2182
            // TODO short citations correctly
2183
            String shortCitation = OriginalSourceFormatter.INSTANCE_WITH_YEAR_BRACKETS.format(reference, null); // Should be Author(year) like in Taxon.sec
2184
            csvLine[table.getIndex(CdmLightExportTable.BIBLIO_SHORT_CITATION)] = shortCitation;
2185
            // TODO get preferred title
2186
            csvLine[table.getIndex(CdmLightExportTable.REF_TITLE)] = reference.isProtectedTitleCache()
2187
                    ? reference.getTitleCache() : reference.getTitle();
2188
            csvLine[table.getIndex(CdmLightExportTable.ABBREV_REF_TITLE)] = reference.isProtectedAbbrevTitleCache()
2189
                    ? reference.getAbbrevTitleCache() : reference.getAbbrevTitle();
2190
            csvLine[table.getIndex(CdmLightExportTable.DATE_PUBLISHED)] = reference.getDatePublishedString();
2191
            // TBC
2192
            csvLine[table.getIndex(CdmLightExportTable.EDITION)] = reference.getEdition();
2193
            csvLine[table.getIndex(CdmLightExportTable.EDITOR)] = reference.getEditor();
2194
            csvLine[table.getIndex(CdmLightExportTable.ISBN)] = reference.getIsbn();
2195
            csvLine[table.getIndex(CdmLightExportTable.ISSN)] = reference.getIssn();
2196
            csvLine[table.getIndex(CdmLightExportTable.ORGANISATION)] = reference.getOrganization();
2197
            csvLine[table.getIndex(CdmLightExportTable.PAGES)] = reference.getPages();
2198
            csvLine[table.getIndex(CdmLightExportTable.PLACE_PUBLISHED)] = reference.getPlacePublished();
2199
            csvLine[table.getIndex(CdmLightExportTable.PUBLISHER)] = reference.getPublisher();
2200
            csvLine[table.getIndex(CdmLightExportTable.REF_ABSTRACT)] = reference.getReferenceAbstract();
2201
            csvLine[table.getIndex(CdmLightExportTable.SERIES_PART)] = reference.getSeriesPart();
2202
            csvLine[table.getIndex(CdmLightExportTable.VOLUME)] = reference.getVolume();
2203
            csvLine[table.getIndex(CdmLightExportTable.YEAR)] = reference.getYear();
2204

    
2205
            if (reference.getAuthorship() != null) {
2206
                csvLine[table.getIndex(CdmLightExportTable.AUTHORSHIP_TITLE)] = createFullAuthorship(reference);
2207
                csvLine[table.getIndex(CdmLightExportTable.AUTHOR_FK)] = getId(state, reference.getAuthorship());
2208
            }
2209

    
2210
            csvLine[table.getIndex(CdmLightExportTable.IN_REFERENCE)] = getId(state, reference.getInReference());
2211
            if (reference.getInReference() != null
2212
                    && !state.getReferenceStore().contains(reference.getInReference().getUuid())) {
2213
                handleReference(state, reference.getInReference());
2214
            }
2215
            if (reference.getInstitution() != null) {
2216
                csvLine[table.getIndex(CdmLightExportTable.INSTITUTION)] = reference.getInstitution().getTitleCache();
2217
            }
2218
            if (reference.getLsid() != null) {
2219
                csvLine[table.getIndex(CdmLightExportTable.LSID)] = reference.getLsid().getLsid();
2220
            }
2221
            if (reference.getSchool() != null) {
2222
                csvLine[table.getIndex(CdmLightExportTable.SCHOOL)] = reference.getSchool().getTitleCache();
2223
            }
2224
            if (reference.getUri() != null) {
2225
                csvLine[table.getIndex(CdmLightExportTable.URI)] = reference.getUri().toString();
2226
            }
2227
            csvLine[table.getIndex(CdmLightExportTable.REF_TYPE)] = reference.getType().getKey();
2228

    
2229
            state.getProcessor().put(table, reference, csvLine);
2230
        } catch (Exception e) {
2231
            state.getResult().addException(e, "An unexpected error occurred when handling reference "
2232
                    + cdmBaseStr(reference) + ": " + e.getMessage());
2233
        }
2234
    }
2235

    
2236
    private String createFullAuthorship(Reference reference) {
2237
        TeamOrPersonBase<?> authorship = reference.getAuthorship();
2238
        String fullAuthorship = "";
2239
        if (authorship == null) {
2240
            return null;
2241
        }
2242
        authorship = HibernateProxyHelper.deproxy(authorship);
2243
        if (authorship instanceof Person) {
2244
            fullAuthorship = ((Person) authorship).getTitleCache();
2245

    
2246
        } else if (authorship instanceof Team) {
2247

    
2248
            Team authorTeam = (Team)authorship;
2249
            fullAuthorship = authorTeam.getCacheStrategy().getTitleCache(authorTeam);
2250
        }
2251
        return fullAuthorship;
2252
    }
2253

    
2254
    private void handleSpecimen(CdmLightExportState state, SpecimenOrObservationBase<?> specimen) {
2255
        try {
2256
            state.addSpecimenToStore(specimen);
2257
            CdmLightExportTable table = CdmLightExportTable.SPECIMEN;
2258
            String specimenId = getId(state, specimen);
2259
            String[] csvLine = new String[table.getSize()];
2260

    
2261
            /*
2262
             * SpecimenCitation = “El Salvador, Municipio La Libertad, San
2263
             * Diego, El Amatal, 14.4.1993, González 159” [Auch ohne Punkt] ->
2264
             * FieldUnit TitleCache HerbariumAbbrev = “B” [wie gehabt]
2265
             * HerbariumCode
2266
             *
2267
             */
2268

    
2269
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_ID)] = specimenId;
2270
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_CITATION)] = specimen.getTitleCache();
2271
            Collection<FieldUnit> fieldUnits = this.getOccurrenceService().findFieldUnits(specimen.getUuid(), null);
2272
            if (fieldUnits.size() == 1) {
2273
                Iterator<FieldUnit> iterator = fieldUnits.iterator();
2274
                if (iterator.hasNext()){
2275
                    FieldUnit fieldUnit = iterator.next();
2276
                    csvLine[table.getIndex(CdmLightExportTable.FIELDUNIT_CITATION)] = fieldUnit.getTitleCache();
2277
                }
2278
            }
2279
            if (specimen.isInstanceOf(DerivedUnit.class)){
2280
                DerivedUnit derivedUnit = (DerivedUnit) specimen;
2281
                if (!StringUtils.isBlank(derivedUnit.getBarcode())){
2282
                    csvLine[table.getIndex(CdmLightExportTable.BARCODE)] = derivedUnit.getBarcode();
2283
                }
2284
                if (!StringUtils.isBlank(derivedUnit.getAccessionNumber())){
2285
                    csvLine[table.getIndex(CdmLightExportTable.ACCESSION_NUMBER)] = derivedUnit.getAccessionNumber();
2286
                }
2287
                if (!StringUtils.isBlank(derivedUnit.getCatalogNumber())){
2288
                    csvLine[table.getIndex(CdmLightExportTable.CATALOGUE_NUMBER)] = derivedUnit.getCatalogNumber();
2289
                }
2290
            }
2291

    
2292
            csvLine[table.getIndex(CdmLightExportTable.PREFERREDSTABLE_ID)] = specimen.getPreferredStableUri() != null? specimen.getPreferredStableUri().toString(): null;
2293
            csvLine[table.getIndex(CdmLightExportTable.SPECIMEN_IMAGE_URIS)] = extractMediaURIs(state,
2294
                    specimen.getDescriptions(), Feature.IMAGE());
2295
            if (specimen instanceof DerivedUnit) {
2296
                DerivedUnit derivedUnit = (DerivedUnit) specimen;
2297
                if (derivedUnit.getCollection() != null) {
2298
                    csvLine[table.getIndex(CdmLightExportTable.HERBARIUM_ABBREV)] = derivedUnit.getCollection()
2299
                            .getCode();
2300
                }
2301

    
2302
                if (specimen instanceof MediaSpecimen) {
2303
                    MediaSpecimen mediaSpecimen = (MediaSpecimen) specimen;
2304
                    Iterator<MediaRepresentation> it = mediaSpecimen.getMediaSpecimen().getRepresentations().iterator();
2305
                    String mediaUris = extractMediaUris(it);
2306
                    csvLine[table.getIndex(CdmLightExportTable.MEDIA_SPECIMEN_URL)] = mediaUris;
2307

    
2308
                }
2309

    
2310
                if (derivedUnit.getDerivedFrom() != null) {
2311
                    for (SpecimenOrObservationBase<?> original : derivedUnit.getDerivedFrom().getOriginals()) {
2312
                        // TODO: What to do if there are more then one
2313
                        // FieldUnit??
2314
                        if (original instanceof FieldUnit) {
2315
                            FieldUnit fieldUnit = (FieldUnit) original;
2316
                            csvLine[table.getIndex(CdmLightExportTable.COLLECTOR_NUMBER)] = fieldUnit.getFieldNumber();
2317

    
2318
                            GatheringEvent gathering = fieldUnit.getGatheringEvent();
2319
                            if (gathering != null) {
2320
                                if (gathering.getLocality() != null) {
2321
                                    csvLine[table.getIndex(CdmLightExportTable.LOCALITY)] = gathering.getLocality()
2322
                                            .getText();
2323
                                }
2324
                                if (gathering.getCountry() != null) {
2325
                                    csvLine[table.getIndex(CdmLightExportTable.COUNTRY)] = gathering.getCountry()
2326
                                            .getLabel();
2327
                                }
2328
                                csvLine[table.getIndex(CdmLightExportTable.COLLECTOR_STRING)] = createCollectorString(
2329
                                        state, gathering, fieldUnit);
2330

    
2331
                                if (gathering.getGatheringDate() != null) {
2332
                                    csvLine[table.getIndex(CdmLightExportTable.COLLECTION_DATE)] = gathering
2333
                                            .getGatheringDate().toString();
2334
                                }
2335
                                if (!gathering.getCollectingAreas().isEmpty()) {
2336
                                    int index = 0;
2337
                                    csvLine[table.getIndex(CdmLightExportTable.FURTHER_AREAS)] = "0";
2338
                                    for (NamedArea area : gathering.getCollectingAreas()) {
2339
                                        if (index == 0) {
2340
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY1)] = area.getLevel() != null?area
2341
                                                    .getLevel().getLabel():"";
2342
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME1)] = area.getLabel();
2343
                                        }
2344
                                        if (index == 1) {
2345
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY2)] = area.getLevel() != null?area
2346
                                                    .getLevel().getLabel():"";
2347
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME2)] = area.getLabel();
2348
                                        }
2349
                                        if (index == 2) {
2350
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_CATEGORY3)] = area.getLevel() != null?area
2351
                                                    .getLevel().getLabel():"";
2352
                                            csvLine[table.getIndex(CdmLightExportTable.AREA_NAME3)] = area.getLabel();
2353
                                        }
2354
                                        if (index == 3) {
2355
                                            csvLine[table.getIndex(CdmLightExportTable.FURTHER_AREAS)] = "1";
2356
                                            break;
2357
                                        }
2358
                                        index++;
2359
                                    }
2360
                                }
2361
                            }
2362
                        }
2363
                    }
2364
                } else {
2365
                    state.getResult().addError("The specimen with uuid " + specimen.getUuid()
2366
                            + " is not an DerivedUnit. Could not be exported.");
2367
                }
2368
            }
2369

    
2370
            state.getProcessor().put(table, specimen, csvLine);
2371
        } catch (Exception e) {
2372
            state.getResult().addException(e, "An unexpected error occurred when handling specimen "
2373
                    + cdmBaseStr(specimen) + ": " + e.getMessage());
2374
        }
2375
    }
2376

    
2377
    private String extractMediaUris(Iterator<MediaRepresentation> it) {
2378

    
2379
        String mediaUriString = "";
2380
        boolean first = true;
2381
        while (it.hasNext()) {
2382
            MediaRepresentation rep = it.next();
2383
            List<MediaRepresentationPart> parts = rep.getParts();
2384
            for (MediaRepresentationPart part : parts) {
2385
                if (first) {
2386
                    if (part.getUri() != null) {
2387
                        mediaUriString += part.getUri().toString();
2388
                        first = false;
2389
                    }
2390
                } else {
2391
                    if (part.getUri() != null) {
2392
                        mediaUriString += ", " + part.getUri().toString();
2393
                    }
2394
                }
2395
            }
2396
        }
2397

    
2398
        return mediaUriString;
2399
    }
2400

    
2401
    private String extractLinkUris(Iterator<ExternalLink> it) {
2402

    
2403
        String linkUriString = "";
2404
        boolean first = true;
2405
        while (it.hasNext()) {
2406
            ExternalLink link = it.next();
2407
            if (first) {
2408
                if (link.getUri() != null) {
2409
                    linkUriString += link.getUri().toString();
2410
                    first = false;
2411
                }
2412
            } else {
2413
                if (link.getUri() != null) {
2414
                    linkUriString += ", " + link.getUri().toString();
2415
                }
2416
            }
2417
        }
2418
        return linkUriString;
2419
    }
2420

    
2421
    private String createCollectorString(CdmLightExportState state, GatheringEvent gathering, FieldUnit fieldUnit) {
2422
        try {
2423
            String collectorString = "";
2424
            AgentBase<?> collectorA = CdmBase.deproxy(gathering.getCollector());
2425
            if (gathering.getCollector() != null) {
2426
                if (collectorA instanceof TeamOrPersonBase && state.getConfig().isHighLightPrimaryCollector()) {
2427

    
2428
                    Person primaryCollector = fieldUnit.getPrimaryCollector();
2429
                    if (collectorA instanceof Team) {
2430
                        Team collectorTeam = (Team) collectorA;
2431
                        boolean isFirst = true;
2432
                        for (Person member : collectorTeam.getTeamMembers()) {
2433
                            if (!isFirst) {
2434
                                collectorString += "; ";
2435
                            }
2436
                            if (member.equals(primaryCollector)) {
2437
                                // highlight
2438
                                collectorString += "<b>" + member.getTitleCache() + "</b>";
2439
                            } else {
2440
                                collectorString += member.getTitleCache();
2441
                            }
2442
                        }
2443
                    }
2444
                } else {
2445
                    collectorString = collectorA.getTitleCache();
2446
                }
2447
            }
2448
            return collectorString;
2449
        } catch (Exception e) {
2450
            state.getResult().addException(e, "An unexpected error occurred when creating collector string for "
2451
                    + cdmBaseStr(fieldUnit) + ": " + e.getMessage());
2452
            return "";
2453
        }
2454
    }
2455

    
2456
    /**
2457
     * Returns a string representation of the {@link CdmBase cdmBase} object for
2458
     * result messages.
2459
     */
2460
    private String cdmBaseStr(CdmBase cdmBase) {
2461
        if (cdmBase == null) {
2462
            return "-no object available-";
2463
        } else {
2464
            return cdmBase.getClass().getSimpleName() + ": " + cdmBase.getUuid();
2465
        }
2466
    }
2467

    
2468
    @Override
2469
    protected boolean doCheck(CdmLightExportState state) {
2470
        return false;
2471
    }
2472

    
2473
    @Override
2474
    protected boolean isIgnore(CdmLightExportState state) {
2475
        return false;
2476
    }
2477

    
2478
}
(1-1/6)