Project

General

Profile

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

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

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

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

    
110
/**
111
 * @author a.mueller
112
 * @date 29.06.2022
113
 */
114
@Component
115
public class WordClassificationExport
116
        extends CdmExportBase<WordClassificationExportConfigurator, WordClassificationExportState, IExportTransformer, File>{
117

    
118
    private static final long serialVersionUID = 5373475508269756045L;
119

    
120
    @Autowired
121
    private IEditGeoService geoService;
122

    
123
    public WordClassificationExport() {
124
        this.ioName = this.getClass().getSimpleName();
125
    }
126

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

    
133
    @Override
134
    protected void doInvoke(WordClassificationExportState state) {
135
        try {
136

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

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

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

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

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

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

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

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

    
196
    private void setOrderIndex(WordClassificationExportState state, OrderHelper order) {
197

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

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

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

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

    
241
    private void handleTaxonNode(WordClassificationExportState state, TaxonNode taxonNode) {
242

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

    
260
                    // add root to node map
261

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

    
274
                }
275
                if (root.hasTaxon()) {
276
                    handleTaxon(state, root);
277

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

    
286
    private void handleTaxon(WordClassificationExportState state, TaxonNode taxonNode) {
287
        try {
288

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

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

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

    
329

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

    
335
//                    state.getProcessor().put(table, taxon, csvLine);
336
                    handleDescriptions(state, taxon);
337
                } catch (Exception e) {
338
                    state.getResult().addException(e,
339
                            "An unexpected problem occurred when trying to export taxon with id " + taxon.getId() + " " + taxon.getTitleCache());
340
                    state.getResult().setState(ExportResultState.INCOMPLETE_WITH_ERROR);
341
                }
342
            }
343

    
344
        } catch (Exception e) {
345
            state.getResult().addException(e, "An unexpected error occurred when handling the taxon node of "
346
                    + cdmBaseStr(taxonNode.getTaxon()) + ", titleCache:"+ taxonNode.getTaxon().getTitleCache()+": " + e.getMessage());
347
        }
348
    }
349

    
350
    private void handleDescriptions(WordClassificationExportState state, CdmBase cdmBase) {
351
        String titleCache = null;
352
        try {
353

    
354
            if (cdmBase instanceof Taxon) {
355
                Taxon taxon = HibernateProxyHelper.deproxy(cdmBase, Taxon.class);
356
                titleCache = taxon.getTitleCache();
357
                Set<TaxonDescription> descriptions = taxon.getDescriptions();
358
                List<DescriptionElementBase> simpleFacts = new ArrayList<>();
359
                List<DescriptionElementBase> specimenFacts = new ArrayList<>();
360
                List<DescriptionElementBase> distributionFacts = new ArrayList<>();
361
                List<DescriptionElementBase> taxonInteractionsFacts = new ArrayList<>();
362
                List<DescriptionElementBase> commonNameFacts = new ArrayList<>();
363
                List<DescriptionElementBase> usageFacts = new ArrayList<>();
364
                for (TaxonDescription description : descriptions) {
365
                    if (description.getElements() != null) {
366
                        for (DescriptionElementBase element : description.getElements()) {
367
                            element = CdmBase.deproxy(element);
368
                            handleAnnotations(element);
369
                            if (element.getFeature().equals(Feature.COMMON_NAME())) {
370
                                commonNameFacts.add(element);
371
                            } else if (element.getFeature().equals(Feature.DISTRIBUTION())) {
372
                                distributionFacts.add(element);
373
                            } else if (element instanceof IndividualsAssociation
374
                                    || isSpecimenFeature(element.getFeature())) {
375
                                specimenFacts.add(element);
376
                            } else if (element.getFeature().isSupportsTaxonInteraction()) {
377
                                taxonInteractionsFacts.add(element);
378
                            } else {
379
                                simpleFacts.add(element);
380
                            }
381
                        }
382
                    }
383
                }
384
                if (!commonNameFacts.isEmpty()) {
385
                    handleCommonNameFacts(state, taxon, commonNameFacts);
386
                }
387
                if (!distributionFacts.isEmpty()) {
388
                    handleDistributionFacts(state, taxon, distributionFacts);
389
                }
390
                if (!specimenFacts.isEmpty()) {
391
                    handleSpecimenFacts(state, taxon, specimenFacts);
392
                }
393
                if (!simpleFacts.isEmpty()) {
394
                    handleSimpleFacts(state, taxon, simpleFacts);
395
                }
396
                if (!taxonInteractionsFacts.isEmpty()) {
397
                    handleTaxonInteractionsFacts(state, taxon, taxonInteractionsFacts);
398
                }
399
            } else if (cdmBase instanceof TaxonName) {
400
                TaxonName name = CdmBase.deproxy(cdmBase, TaxonName.class);
401
                titleCache = name.getTitleCache();
402
                Set<TaxonNameDescription> descriptions = name.getDescriptions();
403
                List<DescriptionElementBase> simpleFacts = new ArrayList<>();
404
                for (TaxonNameDescription description : descriptions) {
405
                    if (description.getElements() != null) {
406
                        for (DescriptionElementBase element : description.getElements()) {
407
                            simpleFacts.add(element);
408
                        }
409
                    }
410
                }
411
                if (!simpleFacts.isEmpty()) {
412
                    handleSimpleFacts(state, name, simpleFacts);
413
                }
414
            }
415
        } catch (Exception e) {
416
            state.getResult().addException(e, "An unexpected error occurred when handling description of "
417
                    + cdmBaseStr(cdmBase) + (titleCache != null? (" " +titleCache) : "")+": " + e.getMessage());
418
        }
419
    }
420

    
421
    private void handleAnnotations(DescriptionElementBase element) {
422
        // TODO Auto-generated method stub
423
    }
424

    
425
    private void handleMetaData(WordClassificationExportState state) {
426
        WordClassificationExportTable table = WordClassificationExportTable.METADATA;
427
        String[] csvLine = new String[table.getSize()];
428
//        csvLine[table.getIndex(CdmLightExportTable.INSTANCE_ID)] = state.getConfig().getInctanceId();
429
//        csvLine[table.getIndex(CdmLightExportTable.INSTANCE_NAME)] = state.getConfig().getInstanceName();
430
        csvLine[table.getIndex(WordClassificationExportTable.DATASET_BASE_URL)] = state.getConfig().getBase_url();
431
        csvLine[table.getIndex(WordClassificationExportTable.DATASET_CONTRIBUTOR)] = state.getConfig().getContributor();
432
        csvLine[table.getIndex(WordClassificationExportTable.DATASET_CREATOR)] = state.getConfig().getCreator();
433
        csvLine[table.getIndex(WordClassificationExportTable.DATASET_DESCRIPTION)] = state.getConfig().getDescription();
434
//        csvLine[table.getIndex(WordClassificationExportTable.DATASET_DOWNLOAD_LINK)] = state.getConfig().getDataset_download_link();
435
//        csvLine[table.getIndex(WordClassificationExportTable.DATASET_KEYWORDS)] = state.getConfig().getKeywords();
436
//        csvLine[table.getIndex(WordClassificationExportTable.DATASET_LANDINGPAGE)] = state.getConfig().getDataSet_landing_page();
437

    
438
        csvLine[table.getIndex(WordClassificationExportTable.DATASET_LANGUAGE)] = state.getConfig().getLanguage() != null? state.getConfig().getLanguage().getLabel(): null;
439
//        csvLine[table.getIndex(WordClassificationExportTable.DATASET_LICENCE)] = state.getConfig().getLicence();
440
        csvLine[table.getIndex(WordClassificationExportTable.DATASET_LOCATION)] = state.getConfig().getLocation();
441
        csvLine[table.getIndex(WordClassificationExportTable.DATASET_RECOMMENDED_CITATTION)] = state.getConfig().getRecommended_citation();
442
        csvLine[table.getIndex(WordClassificationExportTable.DATASET_TITLE)] = state.getConfig().getTitle();
443
        state.getProcessor().put(table, "", csvLine);
444
    }
445

    
446
    private boolean isSpecimenFeature(Feature feature) {
447
        // TODO allow user defined specimen features
448
        if (feature == null) {
449
            return false;
450
        } else if (feature.isSupportsIndividualAssociation()) {
451
            return true;
452
        } else {
453
            return feature.equals(Feature.SPECIMEN()) || feature.equals(Feature.INDIVIDUALS_ASSOCIATION())
454
                    || feature.equals(Feature.MATERIALS_EXAMINED()) || feature.equals(Feature.OBSERVATION())
455
                    || feature.equals(Feature.OCCURRENCE());
456
        }
457
    }
458

    
459
    private void handleSimpleFacts(WordClassificationExportState state, CdmBase cdmBase,
460
            List<DescriptionElementBase> simpleFacts) {
461
        String titleCache = null;
462
        try {
463
            WordClassificationExportTable table;
464
            if (cdmBase instanceof TaxonName) {
465
                titleCache = ((TaxonName)cdmBase).getTitleCache();
466
                table = WordClassificationExportTable.NAME_FACT;
467
            } else {
468
                if (cdmBase instanceof Taxon){
469
                    titleCache = ((Taxon)cdmBase).getTitleCache();
470
                }
471
                table = WordClassificationExportTable.SIMPLE_FACT;
472
            }
473
            WordClassificationExportTable tableMedia = WordClassificationExportTable.MEDIA;
474
            for (DescriptionElementBase element : simpleFacts) {
475
                if (element.getModifyingText().isEmpty() && !element.getMedia().isEmpty()) {
476
                    handleSimpleMediaFact(state, cdmBase, tableMedia, element);
477
                } else {
478
                    handleSingleSimpleFact(state, cdmBase, table, element);
479
                }
480
            }
481
        } catch (Exception e) {
482
            state.getResult().addException(e, "An unexpected error occurred when handling simple facts for "
483
                    + cdmBaseStr(cdmBase) + (titleCache != null? (" " +titleCache) : "")+ ": " + e.getMessage());
484
        }
485
    }
486

    
487
    private void handleTaxonInteractionsFacts(WordClassificationExportState state, CdmBase cdmBase,
488
            List<DescriptionElementBase> taxonInteractionsFacts) {
489
        WordClassificationExportTable table = WordClassificationExportTable.TAXON_INTERACTION_FACT;
490
        String titleCache = null;
491
        if (cdmBase instanceof TaxonBase){
492
            titleCache = ((TaxonBase)cdmBase).getTitleCache();
493
        }
494
        for (DescriptionElementBase element : taxonInteractionsFacts) {
495

    
496
            try {
497

    
498
                String[] csvLine = new String[table.getSize()];
499

    
500
                csvLine[table.getIndex(WordClassificationExportTable.FACT_ID)] = getId(state, element);
501
                handleSource(state, element, table);
502
                csvLine[table.getIndex(WordClassificationExportTable.TAXON_FK)] = getId(state, cdmBase);
503
                csvLine[table.getIndex(WordClassificationExportTable.TAXON2_FK)] = getId(state,
504
                        ((TaxonInteraction) element).getTaxon2());
505
                csvLine[table.getIndex(WordClassificationExportTable.DESCRIPTION)] = createMultilanguageString(
506
                        ((TaxonInteraction) element).getDescription());
507
                state.getProcessor().put(table, element, csvLine);
508

    
509
            } catch (Exception e) {
510
                state.getResult().addException(e, "An unexpected error occurred when handling taxon interaction"
511
                        + cdmBaseStr(element) + (titleCache != null? (" " +titleCache) : "")+ ": " + e.getMessage());
512
            }
513
        }
514
    }
515

    
516
    private void handleSimpleMediaFact(WordClassificationExportState state, CdmBase cdmBase, WordClassificationExportTable table,
517
            DescriptionElementBase element) {
518
        try {
519
            String[] csvLine;
520
            handleSource(state, element, WordClassificationExportTable.MEDIA);
521

    
522
            if (element instanceof TextData) {
523
                TextData textData = (TextData) element;
524
                csvLine = new String[table.getSize()];
525
                csvLine[table.getIndex(WordClassificationExportTable.FACT_ID)] = getId(state, element);
526
                if (cdmBase instanceof Taxon) {
527
                    csvLine[table.getIndex(WordClassificationExportTable.TAXON_FK)] = getId(state, cdmBase);
528
                    csvLine[table.getIndex(WordClassificationExportTable.NAME_FK)] = "";
529
                } else if (cdmBase instanceof TaxonName) {
530
                    csvLine[table.getIndex(WordClassificationExportTable.TAXON_FK)] = "";
531
                    csvLine[table.getIndex(WordClassificationExportTable.NAME_FK)] = getId(state, cdmBase);
532
                }
533

    
534
                String mediaUris = "";
535
                for (Media media : textData.getMedia()) {
536
                    String mediaString = extractMediaUris(media.getRepresentations().iterator());
537
                    if (!StringUtils.isBlank(mediaString)) {
538
                        mediaUris += mediaString + ";";
539
                    } else {
540
                        state.getResult().addWarning("Empty Media object for " + cdmBase.getUserFriendlyTypeName() + " "
541
                                + cdmBase.getUuid() + " (media: " + media.getUuid() + ")");
542
                    }
543
                }
544
                csvLine[table.getIndex(WordClassificationExportTable.MEDIA_URI)] = mediaUris;
545

    
546
            }
547
        } catch (Exception e) {
548
            state.getResult().addException(e, "An unexpected error occurred when handling single simple fact "
549
                    + cdmBaseStr(element) + ": " + e.getMessage());
550
        }
551

    
552
    }
553

    
554
    private void handleSingleSimpleFact(WordClassificationExportState state, CdmBase cdmBase, WordClassificationExportTable table,
555
            DescriptionElementBase element) {
556
        try {
557
            String[] csvLine;
558
            handleSource(state, element, WordClassificationExportTable.SIMPLE_FACT);
559

    
560
            if (element instanceof TextData) {
561
                TextData textData = (TextData) element;
562
                csvLine = new String[table.getSize()];
563
                csvLine[table.getIndex(WordClassificationExportTable.FACT_ID)] = getId(state, element);
564
                if (cdmBase instanceof Taxon) {
565
                    csvLine[table.getIndex(WordClassificationExportTable.TAXON_FK)] = getId(state, cdmBase);
566
                } else if (cdmBase instanceof TaxonName) {
567
                    csvLine[table.getIndex(WordClassificationExportTable.NAME_FK)] = getId(state, cdmBase);
568
                }
569
                csvLine[table.getIndex(WordClassificationExportTable.FACT_CATEGORY)] = textData.getFeature().getLabel();
570

    
571
                String mediaUris = "";
572
                for (Media media : textData.getMedia()) {
573
                    String mediaString = extractMediaUris(media.getRepresentations().iterator());
574
                    if (!StringUtils.isBlank(mediaString)) {
575
                        mediaUris += mediaString + ";";
576
                    } else {
577
                        state.getResult().addWarning("Empty Media object for uuid: " + cdmBase.getUuid()
578
                                + " uuid of media: " + media.getUuid());
579
                    }
580
                }
581
                csvLine[table.getIndex(WordClassificationExportTable.MEDIA_URI)] = mediaUris;
582
                if (textData.getFeature().equals(Feature.CITATION())) {
583
                    state.getProcessor().put(table, textData, csvLine);
584
                } else if (!textData.getMultilanguageText().isEmpty()) {
585
                    for (Language language : textData.getMultilanguageText().keySet()) {
586
                        String[] csvLineLanguage = csvLine.clone();
587
                        LanguageString langString = textData.getLanguageText(language);
588
                        String text = langString.getText();
589
                        if (state.getConfig().isFilterIntextReferences()) {
590
                            text = filterIntextReferences(langString.getText());
591
                        }
592
                        csvLineLanguage[table.getIndex(WordClassificationExportTable.FACT_TEXT)] = text;
593
                        csvLineLanguage[table.getIndex(WordClassificationExportTable.LANGUAGE)] = language.getLabel();
594
                        state.getProcessor().put(table, textData, csvLineLanguage);
595
                    }
596
                } else {
597
                    state.getProcessor().put(table, textData, csvLine);
598
                }
599
            }
600
        } catch (Exception e) {
601
            state.getResult().addException(e, "An unexpected error occurred when handling single simple fact "
602
                    + cdmBaseStr(element) + ": " + e.getMessage());
603
        }
604
    }
605

    
606
    private String filterIntextReferences(String text) {
607
        /*
608
         * (<cdm:reference cdmId='fbd19251-efee-4ded-b780-915000f66d41'
609
         * intextId='1352d42c-e201-4155-a02a-55360d3b563e'>Ridley in Fl. Malay
610
         * Pen. 3 (1924) 22</cdm:reference>)
611
         */
612
        String newText = text.replaceAll("<cdm:reference cdmId='[a-z0-9\\-]*' intextId='[a-z0-9\\-]*'>", "");
613
        newText = newText.replaceAll("</cdm:reference>", "");
614

    
615
        newText = newText.replaceAll("<cdm:key cdmId='[a-z0-9\\-]*' intextId='[a-z0-9\\-]*'>", "");
616
        newText = newText.replaceAll("</cdm:key>", "");
617
        return newText;
618
    }
619

    
620
    private void handleSpecimenFacts(WordClassificationExportState state, Taxon taxon,
621
            List<DescriptionElementBase> specimenFacts) {
622
        WordClassificationExportTable table = WordClassificationExportTable.SPECIMEN_FACT;
623

    
624
        for (DescriptionElementBase element : specimenFacts) {
625
            try {
626
                String[] csvLine = new String[table.getSize()];
627
                csvLine[table.getIndex(WordClassificationExportTable.FACT_ID)] = getId(state, element);
628
                csvLine[table.getIndex(WordClassificationExportTable.TAXON_FK)] = getId(state, taxon);
629
                handleSource(state, element, table);
630
                csvLine[table.getIndex(WordClassificationExportTable.SPECIMEN_NOTES)] = createAnnotationsString(
631
                        element.getAnnotations());
632

    
633
                if (element instanceof IndividualsAssociation) {
634

    
635
                    IndividualsAssociation indAssociation = (IndividualsAssociation) element;
636
                    if (indAssociation.getAssociatedSpecimenOrObservation() == null) {
637
                        state.getResult()
638
                                .addWarning("There is an individual association with no specimen associated (Taxon "
639
                                        + taxon.getTitleCache() + "(" + taxon.getUuid() + "). Could not be exported.");
640
                        continue;
641
                    } else {
642
                        if (!state.getSpecimenStore()
643
                                .contains((indAssociation.getAssociatedSpecimenOrObservation().getUuid()))) {
644
                            SpecimenOrObservationBase<?> specimenBase = HibernateProxyHelper.deproxy(
645
                                    indAssociation.getAssociatedSpecimenOrObservation(),
646
                                    SpecimenOrObservationBase.class);
647

    
648
                            handleSpecimen(state, specimenBase);
649
                            csvLine[table.getIndex(WordClassificationExportTable.SPECIMEN_FK)] = getId(state,
650
                                    indAssociation.getAssociatedSpecimenOrObservation());
651
                        }
652
                    }
653
                } else if (element instanceof TextData) {
654
                    TextData textData = HibernateProxyHelper.deproxy(element, TextData.class);
655
                    csvLine[table.getIndex(WordClassificationExportTable.SPECIMEN_DESCRIPTION)] = createMultilanguageString(
656
                            textData.getMultilanguageText());
657
                }
658
                state.getProcessor().put(table, element, csvLine);
659
            } catch (Exception e) {
660
                state.getResult().addException(e, "An unexpected error occurred when handling single specimen fact "
661
                        + cdmBaseStr(element) + ": " + e.getMessage());
662
            }
663
        }
664
    }
665

    
666
    private String createMultilanguageString(Map<Language, LanguageString> multilanguageText) {
667
        String text = "";
668
        int index = multilanguageText.size();
669
        for (LanguageString langString : multilanguageText.values()) {
670
            text += langString.getText();
671
            if (index > 1) {
672
                text += "; ";
673
            }
674
            index--;
675
        }
676
        return text;
677
    }
678

    
679
    private String createAnnotationsString(Set<Annotation> annotations) {
680
        StringBuffer strBuff = new StringBuffer();
681

    
682
        for (Annotation ann : annotations) {
683
            if (ann.getAnnotationType() == null || !ann.getAnnotationType().equals(AnnotationType.TECHNICAL())) {
684
                strBuff.append(ann.getText());
685
                strBuff.append("; ");
686
            }
687
        }
688

    
689
        if (strBuff.length() > 2) {
690
            return strBuff.substring(0, strBuff.length() - 2);
691
        } else {
692
            return null;
693
        }
694
    }
695

    
696
    private void handleSource(WordClassificationExportState state, DescriptionElementBase element,
697
            WordClassificationExportTable factsTable) {
698
        WordClassificationExportTable table = WordClassificationExportTable.FACT_SOURCES;
699
        try {
700
            Set<DescriptionElementSource> sources = element.getSources();
701

    
702
            for (DescriptionElementSource source : sources) {
703
                if (!(source.getType().equals(OriginalSourceType.Import)
704
                        && state.getConfig().isExcludeImportSources())) {
705
                    String[] csvLine = new String[table.getSize()];
706
                    Reference ref = source.getCitation();
707
                    if ((ref == null) && (source.getNameUsedInSource() == null)) {
708
                        continue;
709
                    }
710
                    if (ref != null) {
711
                        if (!state.getReferenceStore().contains(ref.getUuid())) {
712
                            handleReference(state, ref);
713

    
714
                        }
715
                        csvLine[table.getIndex(WordClassificationExportTable.REFERENCE_FK)] = getId(state, ref);
716
                    }
717
                    csvLine[table.getIndex(WordClassificationExportTable.FACT_FK)] = getId(state, element);
718

    
719
                    csvLine[table.getIndex(WordClassificationExportTable.NAME_IN_SOURCE_FK)] = getId(state,
720
                            source.getNameUsedInSource());
721
                    csvLine[table.getIndex(WordClassificationExportTable.FACT_TYPE)] = factsTable.getTableName();
722
                    if (StringUtils.isBlank(csvLine[table.getIndex(WordClassificationExportTable.REFERENCE_FK)])
723
                            && StringUtils.isBlank(csvLine[table.getIndex(WordClassificationExportTable.NAME_IN_SOURCE_FK)])) {
724
                        continue;
725
                    }
726
                    state.getProcessor().put(table, source, csvLine);
727
                }
728

    
729
            }
730
        } catch (Exception e) {
731
            state.getResult().addException(e, "An unexpected error occurred when handling single source "
732
                    + cdmBaseStr(element) + ": " + e.getMessage());
733
        }
734

    
735
    }
736

    
737
    private void handleDistributionFacts(WordClassificationExportState state, Taxon taxon,
738
            List<DescriptionElementBase> distributionFacts) {
739

    
740
        WordClassificationExportTable table = WordClassificationExportTable.GEOGRAPHIC_AREA_FACT;
741
        Set<Distribution> distributions = new HashSet<>();
742
        for (DescriptionElementBase element : distributionFacts) {
743
            try {
744
                if (element instanceof Distribution) {
745
                    String[] csvLine = new String[table.getSize()];
746
                    Distribution distribution = (Distribution) element;
747
                    distributions.add(distribution);
748
                    csvLine[table.getIndex(WordClassificationExportTable.FACT_ID)] = getId(state, element);
749
                    handleSource(state, element, table);
750
                    csvLine[table.getIndex(WordClassificationExportTable.TAXON_FK)] = getId(state, taxon);
751
                    if (distribution.getArea() != null) {
752
                        csvLine[table.getIndex(WordClassificationExportTable.AREA_LABEL)] = distribution.getArea().getLabel();
753
                    }
754
                    if (distribution.getStatus() != null) {
755
                        csvLine[table.getIndex(WordClassificationExportTable.STATUS_LABEL)] = distribution.getStatus().getLabel();
756
                    }
757
                    state.getProcessor().put(table, distribution, csvLine);
758
                } else {
759
                    state.getResult()
760
                            .addError("The distribution description for the taxon " + taxon.getUuid()
761
                                    + " is not of type distribution. Could not be exported. UUID of the description element: "
762
                                    + element.getUuid());
763
                }
764
            } catch (Exception e) {
765
                state.getResult().addException(e, "An unexpected error occurred when handling single distribution "
766
                        + cdmBaseStr(element) + ": " + e.getMessage());
767
            }
768
        }
769
         if(state.getConfig().isCreateCondensedDistributionString()){
770
             List<Language> langs = new ArrayList<>();
771
             langs.add(Language.ENGLISH());
772

    
773
             CondensedDistribution conDis = geoService.getCondensedDistribution(
774
                     //TODO add CondensedDistributionConfiguration to export configuration
775
                     distributions, true, null, state.getConfig().getCondensedDistributionConfiguration(), langs);
776
             WordClassificationExportTable tableCondensed =
777
                     WordClassificationExportTable.SIMPLE_FACT;
778
             String[] csvLine = new String[tableCondensed.getSize()];
779
             //the computed fact has no uuid, TODO: remember the uuid for later reference assignment
780
             UUID randomUuid = UUID.randomUUID();
781
             csvLine[tableCondensed.getIndex(WordClassificationExportTable.FACT_ID)] =
782
                     randomUuid.toString();
783
             csvLine[tableCondensed.getIndex(WordClassificationExportTable.TAXON_FK)] =
784
                     getId(state, taxon);
785
             csvLine[tableCondensed.getIndex(WordClassificationExportTable.FACT_TEXT)] =
786
                     conDis.toString();
787
             csvLine[tableCondensed.getIndex(WordClassificationExportTable.LANGUAGE)] =Language.ENGLISH().toString();
788

    
789
             csvLine[tableCondensed.getIndex(WordClassificationExportTable.FACT_CATEGORY)] =
790
                     "CondensedDistribution";
791

    
792
             state.getProcessor().put(tableCondensed, taxon, csvLine);
793
         }
794
    }
795

    
796
    private void handleCommonNameFacts(WordClassificationExportState state, Taxon taxon,
797
            List<DescriptionElementBase> commonNameFacts) {
798
        WordClassificationExportTable table = WordClassificationExportTable.COMMON_NAME_FACT;
799

    
800
        for (DescriptionElementBase element : commonNameFacts) {
801
            try {
802
                if (element instanceof CommonTaxonName) {
803
                    String[] csvLine = new String[table.getSize()];
804
                    CommonTaxonName commonName = (CommonTaxonName) element;
805
                    csvLine[table.getIndex(WordClassificationExportTable.FACT_ID)] = getId(state, element);
806
                    handleSource(state, element, table);
807
                    csvLine[table.getIndex(WordClassificationExportTable.TAXON_FK)] = getId(state, taxon);
808
                    if (commonName.getName() != null) {
809
                        csvLine[table.getIndex(WordClassificationExportTable.FACT_TEXT)] = commonName.getName();
810
                    }
811
                    if (commonName.getLanguage() != null) {
812
                        csvLine[table.getIndex(WordClassificationExportTable.LANGUAGE)] = commonName.getLanguage().getLabel();
813
                    }
814
                    if (commonName.getArea() != null) {
815
                        csvLine[table.getIndex(WordClassificationExportTable.AREA_LABEL)] = commonName.getArea().getLabel();
816
                    }
817
                    state.getProcessor().put(table, commonName, csvLine);
818
                } else if (element instanceof TextData){
819
                    String[] csvLine = new String[table.getSize()];
820
                    TextData commonName = (TextData) element;
821
                    csvLine[table.getIndex(WordClassificationExportTable.FACT_ID)] = getId(state, element);
822
                    handleSource(state, element, table);
823
                    csvLine[table.getIndex(WordClassificationExportTable.TAXON_FK)] = getId(state, taxon);
824
                    if (commonName.getMultilanguageText() != null) {
825
                        csvLine[table.getIndex(WordClassificationExportTable.FACT_TEXT)] = createMultilanguageString(commonName.getMultilanguageText());
826
                    }
827
                    state.getProcessor().put(table, commonName, csvLine);
828
                } else {
829
                    state.getResult()
830
                            .addError("The common name description for the taxon " + taxon.getUuid()
831
                                    + " is not of type common name. Could not be exported. UUID of the description element: "
832
                                    + element.getUuid());
833
                }
834
            } catch (Exception e) {
835
                state.getResult().addException(e, "An unexpected error occurred when handling single common name "
836
                        + cdmBaseStr(element) + " - "+taxon.getTitleCache()+ ": " + e.getMessage());
837
            }
838
        }
839
    }
840

    
841
    private String getTitleCache(IIdentifiableEntity identEntity) {
842
        if (identEntity == null) {
843
            return "";
844
        }
845
        // TODO refresh?
846
        return identEntity.getTitleCache();
847
    }
848

    
849
    private String getId(WordClassificationExportState state, ICdmBase cdmBase) {
850
        if (cdmBase == null) {
851
            return "";
852
        }
853
        // TODO make configurable
854
        return cdmBase.getUuid().toString();
855
    }
856

    
857
    private void handleSynonym(WordClassificationExportState state, Synonym synonym, int index) {
858
        try {
859
            if (isUnpublished(state.getConfig(), synonym)) {
860
                return;
861
            }
862
            TaxonName name = synonym.getName();
863
            handleName(state, name, synonym.getAcceptedTaxon());
864

    
865
            WordClassificationExportTable table = WordClassificationExportTable.SYNONYM;
866
            String[] csvLine = new String[table.getSize()];
867

    
868
            csvLine[table.getIndex(WordClassificationExportTable.SYNONYM_ID)] = getId(state, synonym);
869
            csvLine[table.getIndex(WordClassificationExportTable.TAXON_FK)] = getId(state, synonym.getAcceptedTaxon());
870
            csvLine[table.getIndex(WordClassificationExportTable.NAME_FK)] = getId(state, name);
871
            if (synonym.getSec() != null && !state.getReferenceStore().contains(synonym.getSec().getUuid())) {
872
                handleReference(state, synonym.getSec());
873
            }
874
            csvLine[table.getIndex(WordClassificationExportTable.APPENDED_PHRASE)] = synonym.getAppendedPhrase();
875
            csvLine[table.getIndex(WordClassificationExportTable.SYN_SEC_REFERENCE_FK)] = getId(state, synonym.getSec());
876
            csvLine[table.getIndex(WordClassificationExportTable.SYN_SEC_REFERENCE)] = getTitleCache(synonym.getSec());
877
            csvLine[table.getIndex(WordClassificationExportTable.PUBLISHED)] = synonym.isPublish() ? "1" : "0";
878
            csvLine[table.getIndex(WordClassificationExportTable.IS_PRO_PARTE)] = "0";
879
            csvLine[table.getIndex(WordClassificationExportTable.IS_PARTIAL)] = "0";
880
            csvLine[table.getIndex(WordClassificationExportTable.IS_MISAPPLIED)] = "0";
881
            csvLine[table.getIndex(WordClassificationExportTable.SORT_INDEX)] = String.valueOf(index);
882
            state.getProcessor().put(table, synonym, csvLine);
883
        } catch (Exception e) {
884
            state.getResult().addException(e, "An unexpected error occurred when handling synonym "
885
                    + cdmBaseStr(synonym) + ": " + e.getMessage());
886
        }
887
    }
888

    
889
    /**
890
     * Handles misapplied names (including pro parte and partial as well as pro
891
     * parte and partial synonyms
892
     */
893
    private void handleProPartePartialMisapplied(WordClassificationExportState state, Taxon taxon, Taxon accepted, boolean isProParte, boolean isMisapplied, int index) {
894
        try {
895
            Taxon ppSyonym = taxon;
896
            if (isUnpublished(state.getConfig(), ppSyonym)) {
897
                return;
898
            }
899
            TaxonName name = ppSyonym.getName();
900
            handleName(state, name, accepted);
901

    
902
            WordClassificationExportTable table = WordClassificationExportTable.SYNONYM;
903
            String[] csvLine = new String[table.getSize()];
904

    
905
            csvLine[table.getIndex(WordClassificationExportTable.SYNONYM_ID)] = getId(state, ppSyonym);
906
            csvLine[table.getIndex(WordClassificationExportTable.TAXON_FK)] = getId(state, accepted);
907
            csvLine[table.getIndex(WordClassificationExportTable.NAME_FK)] = getId(state, name);
908

    
909
            Reference secRef = ppSyonym.getSec();
910

    
911
            if (secRef != null && !state.getReferenceStore().contains(secRef.getUuid())) {
912
                handleReference(state, secRef);
913
            }
914
            csvLine[table.getIndex(WordClassificationExportTable.SEC_REFERENCE_FK)] = getId(state, secRef);
915
            csvLine[table.getIndex(WordClassificationExportTable.SEC_REFERENCE)] = getTitleCache(secRef);
916
            Set<TaxonRelationship> rels = accepted.getTaxonRelations(ppSyonym);
917
            TaxonRelationship rel = null;
918
            boolean isPartial = false;
919
            if (rels.size() == 1){
920
                rel = rels.iterator().next();
921

    
922
            }else if (rels.size() > 1){
923
                Iterator<TaxonRelationship> iterator = rels.iterator();
924
                while (iterator.hasNext()){
925
                    rel = iterator.next();
926
                    if (isProParte && rel.getType().isAnySynonym()){
927
                        break;
928
                    } else if (isMisapplied && rel.getType().isAnyMisappliedName()){
929
                        break;
930
                    }else{
931
                        rel = null;
932
                    }
933
                }
934
            }
935
            if (rel != null){
936
                Reference synSecRef = rel.getCitation();
937
                if (synSecRef != null && !state.getReferenceStore().contains(synSecRef.getUuid())) {
938
                    handleReference(state, synSecRef);
939
                }
940
                csvLine[table.getIndex(WordClassificationExportTable.SYN_SEC_REFERENCE_FK)] = getId(state, synSecRef);
941
                csvLine[table.getIndex(WordClassificationExportTable.SYN_SEC_REFERENCE)] = getTitleCache(synSecRef);
942
                isProParte = rel.getType().isProParte();
943
                isPartial = rel.getType().isPartial();
944

    
945
            }else{
946
                state.getResult().addWarning("An unexpected error occurred when handling "
947
                        + "pro parte/partial synonym or misapplied name  " + cdmBaseStr(taxon) );
948
            }
949

    
950
            // pro parte type
951

    
952
            csvLine[table.getIndex(WordClassificationExportTable.IS_PRO_PARTE)] = isProParte ? "1" : "0";
953
            csvLine[table.getIndex(WordClassificationExportTable.IS_PARTIAL)] = isPartial ? "1" : "0";
954
            csvLine[table.getIndex(WordClassificationExportTable.IS_MISAPPLIED)] = isMisapplied ? "1" : "0";
955
            csvLine[table.getIndex(WordClassificationExportTable.SORT_INDEX)] = String.valueOf(index);
956
            state.getProcessor().put(table, ppSyonym, csvLine);
957
        } catch (Exception e) {
958
            state.getResult().addException(e, "An unexpected error occurred when handling "
959
                    + "pro parte/partial synonym or misapplied name  " + cdmBaseStr(taxon) + ": " + e.getMessage());
960
        }
961

    
962
    }
963

    
964
    private void handleName(WordClassificationExportState state, TaxonName name, Taxon acceptedTaxon){
965
        handleName(state, name, acceptedTaxon, false);
966
    }
967

    
968
    private void handleName(WordClassificationExportState state, TaxonName name, Taxon acceptedTaxon, boolean acceptedName) {
969
        if (name == null || state.getNameStore().containsKey(name.getId())) {
970
            return;
971
        }
972
        try {
973
            Rank rank = name.getRank();
974
            WordClassificationExportTable table = WordClassificationExportTable.SCIENTIFIC_NAME;
975
            name = HibernateProxyHelper.deproxy(name);
976
            state.getNameStore().put(name.getId(), name.getUuid());
977
            String[] csvLine = new String[table.getSize()];
978

    
979
            csvLine[table.getIndex(WordClassificationExportTable.NAME_ID)] = getId(state, name);
980
            if (name.getLsid() != null) {
981
                csvLine[table.getIndex(WordClassificationExportTable.LSID)] = name.getLsid().getLsid();
982
            } else {
983
                csvLine[table.getIndex(WordClassificationExportTable.LSID)] = "";
984
            }
985

    
986
            handleIdentifier(state, name);
987
            handleDescriptions(state, name);
988

    
989
            csvLine[table.getIndex(WordClassificationExportTable.RANK)] = getTitleCache(rank);
990
            if (rank != null) {
991
                csvLine[table.getIndex(WordClassificationExportTable.RANK_SEQUENCE)] = String.valueOf(rank.getOrderIndex());
992
                if (rank.isInfraGeneric()) {
993
                    try {
994
                        csvLine[table.getIndex(WordClassificationExportTable.INFRAGENERIC_RANK)] = name.getRank()
995
                                .getInfraGenericMarker();
996
                    } catch (UnknownCdmTypeException e) {
997
                        state.getResult().addError("Infrageneric marker expected but not available for rank "
998
                                + name.getRank().getTitleCache());
999
                    }
1000
                }
1001
                if (rank.isInfraSpecific()) {
1002
                    csvLine[table.getIndex(WordClassificationExportTable.INFRASPECIFIC_RANK)] = name.getRank().getAbbreviation();
1003
                }
1004
            } else {
1005
                csvLine[table.getIndex(WordClassificationExportTable.RANK_SEQUENCE)] = "";
1006
            }
1007
            if (name.isProtectedTitleCache()) {
1008
                csvLine[table.getIndex(WordClassificationExportTable.FULL_NAME_WITH_AUTHORS)] = name.getTitleCache();
1009
            } else {
1010
                // TODO: adapt the tropicos titlecache creation
1011
                csvLine[table.getIndex(WordClassificationExportTable.FULL_NAME_WITH_AUTHORS)] = name.getTitleCache();
1012
            }
1013

    
1014

    
1015
            if (!state.getConfig().isAddHTML()) {
1016
                csvLine[table.getIndex(WordClassificationExportTable.FULL_NAME_WITH_REF)] = name.getFullTitleCache();
1017
            } else {
1018
                List<TaggedText> taggedFullTitleCache = name.getTaggedFullTitle();
1019
                List<TaggedText> taggedName = name.getTaggedName();
1020

    
1021
                String fullTitleWithHtml = createNameWithItalics(taggedFullTitleCache);
1022
                // TODO: adapt the tropicos titlecache creation
1023
                csvLine[table.getIndex(WordClassificationExportTable.FULL_NAME_WITH_REF)] = fullTitleWithHtml.trim();
1024
            }
1025

    
1026
            csvLine[table.getIndex(WordClassificationExportTable.FULL_NAME_NO_AUTHORS)] = name.getNameCache();
1027
            csvLine[table.getIndex(WordClassificationExportTable.GENUS_UNINOMIAL)] = name.getGenusOrUninomial();
1028

    
1029
            csvLine[table.getIndex(WordClassificationExportTable.INFRAGENERIC_EPITHET)] = name.getInfraGenericEpithet();
1030
            csvLine[table.getIndex(WordClassificationExportTable.SPECIFIC_EPITHET)] = name.getSpecificEpithet();
1031

    
1032
            csvLine[table.getIndex(WordClassificationExportTable.INFRASPECIFIC_EPITHET)] = name.getInfraSpecificEpithet();
1033

    
1034
            csvLine[table.getIndex(WordClassificationExportTable.APPENDED_PHRASE)] = name.getAppendedPhrase();
1035

    
1036
            csvLine[table.getIndex(WordClassificationExportTable.BAS_AUTHORTEAM_FK)] = getId(state, name.getBasionymAuthorship());
1037
            if (name.getBasionymAuthorship() != null) {
1038
                if (state.getAuthorFromStore(name.getBasionymAuthorship().getId()) == null) {
1039
                    handleAuthor(state, name.getBasionymAuthorship());
1040
                }
1041
            }
1042
            csvLine[table.getIndex(WordClassificationExportTable.BAS_EX_AUTHORTEAM_FK)] = getId(state,
1043
                    name.getExBasionymAuthorship());
1044
            if (name.getExBasionymAuthorship() != null) {
1045
                if (state.getAuthorFromStore(name.getExBasionymAuthorship().getId()) == null) {
1046
                    handleAuthor(state, name.getExBasionymAuthorship());
1047
                }
1048

    
1049
            }
1050
            csvLine[table.getIndex(WordClassificationExportTable.COMB_AUTHORTEAM_FK)] = getId(state,
1051
                    name.getCombinationAuthorship());
1052
            if (name.getCombinationAuthorship() != null) {
1053
                if (state.getAuthorFromStore(name.getCombinationAuthorship().getId()) == null) {
1054
                    handleAuthor(state, name.getCombinationAuthorship());
1055
                }
1056
            }
1057
            csvLine[table.getIndex(WordClassificationExportTable.COMB_EX_AUTHORTEAM_FK)] = getId(state,
1058
                    name.getExCombinationAuthorship());
1059
            if (name.getExCombinationAuthorship() != null) {
1060
                if (state.getAuthorFromStore(name.getExCombinationAuthorship().getId()) == null) {
1061
                    handleAuthor(state, name.getExCombinationAuthorship());
1062
                }
1063

    
1064
            }
1065

    
1066
            csvLine[table.getIndex(WordClassificationExportTable.AUTHOR_TEAM_STRING)] = name.getAuthorshipCache();
1067

    
1068
            Reference nomRef = name.getNomenclaturalReference();
1069

    
1070
            NomenclaturalSource nomenclaturalSource = name.getNomenclaturalSource();
1071
            if (nomenclaturalSource != null &&nomenclaturalSource.getNameUsedInSource() != null){
1072
                handleName(state, nomenclaturalSource.getNameUsedInSource(), null);
1073
                csvLine[table.getIndex(WordClassificationExportTable.NAME_USED_IN_SOURCE)] = getId(state, nomenclaturalSource.getNameUsedInSource());
1074
            }
1075

    
1076
            if (nomRef != null) {
1077
                if (!state.getReferenceStore().contains(nomRef.getUuid())) {
1078
                    handleReference(state, nomRef);
1079
                }
1080
                csvLine[table.getIndex(WordClassificationExportTable.REFERENCE_FK)] = getId(state, nomRef);
1081
                csvLine[table.getIndex(WordClassificationExportTable.PUBLICATION_TYPE)] = nomRef.getType().name();
1082
                if (nomRef.getVolume() != null) {
1083
                    csvLine[table.getIndex(WordClassificationExportTable.VOLUME_ISSUE)] = nomRef.getVolume();
1084
                    csvLine[table.getIndex(WordClassificationExportTable.COLLATION)] = createCollatation(name);
1085
                }
1086
                if (nomRef.getDatePublished() != null) {
1087
                    csvLine[table.getIndex(WordClassificationExportTable.DATE_PUBLISHED)] = nomRef.getTimePeriodPublishedString();
1088
                    csvLine[table.getIndex(WordClassificationExportTable.YEAR_PUBLISHED)] = nomRef.getDatePublished().getYear();
1089
                    csvLine[table.getIndex(WordClassificationExportTable.VERBATIM_DATE)] = nomRef.getDatePublished()
1090
                            .getVerbatimDate();
1091
                }
1092
                if (name.getNomenclaturalMicroReference() != null) {
1093
                    csvLine[table.getIndex(WordClassificationExportTable.DETAIL)] = name.getNomenclaturalMicroReference();
1094
                }
1095
                nomRef = HibernateProxyHelper.deproxy(nomRef);
1096
                if (nomRef.getInReference() != null) {
1097
                    Reference inReference = nomRef.getInReference();
1098
                    if (inReference.getDatePublished() != null && nomRef.getDatePublished() == null) {
1099
                        csvLine[table.getIndex(WordClassificationExportTable.DATE_PUBLISHED)] = inReference
1100
                                .getDatePublishedString();
1101
                        csvLine[table.getIndex(WordClassificationExportTable.YEAR_PUBLISHED)] = inReference.getDatePublished()
1102
                                .getYear();
1103
                    }
1104
                    if (nomRef.getVolume() == null && inReference.getVolume() != null) {
1105
                        csvLine[table.getIndex(WordClassificationExportTable.VOLUME_ISSUE)] = inReference.getVolume();
1106
                        csvLine[table.getIndex(WordClassificationExportTable.COLLATION)] = createCollatation(name);
1107
                    }
1108
                    if (inReference.getInReference() != null) {
1109
                        inReference = inReference.getInReference();
1110
                    }
1111
                    if (inReference.getAbbrevTitle() == null) {
1112
                        csvLine[table.getIndex(WordClassificationExportTable.ABBREV_TITLE)] = CdmUtils
1113
                                .Nz(inReference.getTitle());
1114
                    } else {
1115
                        csvLine[table.getIndex(WordClassificationExportTable.ABBREV_TITLE)] = CdmUtils
1116
                                .Nz(inReference.getAbbrevTitle());
1117
                    }
1118
                    if (inReference.getTitle() == null) {
1119
                        csvLine[table.getIndex(WordClassificationExportTable.FULL_TITLE)] = CdmUtils
1120
                                .Nz(inReference.getAbbrevTitle()!= null? inReference.getAbbrevTitle(): inReference.getTitleCache());
1121
                    } else {
1122
                        csvLine[table.getIndex(WordClassificationExportTable.FULL_TITLE)] = CdmUtils.Nz(inReference.getTitle());
1123
                    }
1124

    
1125
                    TeamOrPersonBase<?> author = inReference.getAuthorship();
1126
                    if (author != null
1127
                            && (nomRef.isOfType(ReferenceType.BookSection) || nomRef.isOfType(ReferenceType.Section))) {
1128
                        csvLine[table.getIndex(WordClassificationExportTable.ABBREV_REF_AUTHOR)] = author.isProtectedTitleCache()
1129
                                ? author.getTitleCache() : CdmUtils.Nz(author.getNomenclaturalTitleCache());
1130
                        csvLine[table.getIndex(WordClassificationExportTable.FULL_REF_AUTHOR)] = CdmUtils
1131
                                .Nz(author.getTitleCache());
1132
                    } else {
1133
                        csvLine[table.getIndex(WordClassificationExportTable.ABBREV_REF_AUTHOR)] = "";
1134
                        csvLine[table.getIndex(WordClassificationExportTable.FULL_REF_AUTHOR)] = "";
1135
                    }
1136
                } else {
1137
                    if (nomRef.getAbbrevTitle() == null) {
1138
                        csvLine[table.getIndex(WordClassificationExportTable.ABBREV_TITLE)] = CdmUtils
1139
                                .Nz(nomRef.getTitle()!= null? nomRef.getTitle():nomRef.getAbbrevTitleCache());
1140
                    } else {
1141
                        csvLine[table.getIndex(WordClassificationExportTable.ABBREV_TITLE)] = CdmUtils
1142
                                .Nz(nomRef.getAbbrevTitle());
1143
                    }
1144
                    if (nomRef.getTitle() == null) {
1145
                        csvLine[table.getIndex(WordClassificationExportTable.FULL_TITLE)] =  CdmUtils
1146
                                .Nz(nomRef.getAbbrevTitle()!= null? nomRef.getAbbrevTitle(): nomRef.getTitleCache());
1147
                    } else {
1148
                        csvLine[table.getIndex(WordClassificationExportTable.FULL_TITLE)] = CdmUtils.Nz(nomRef.getTitle());
1149
                    }
1150
                    TeamOrPersonBase<?> author = nomRef.getAuthorship();
1151
                    if (author != null) {
1152
                        csvLine[table.getIndex(WordClassificationExportTable.ABBREV_REF_AUTHOR)] = author.isProtectedTitleCache()
1153
                                ? author.getTitleCache() : CdmUtils.Nz(author.getNomenclaturalTitleCache());
1154
                        csvLine[table.getIndex(WordClassificationExportTable.FULL_REF_AUTHOR)] = CdmUtils
1155
                                .Nz(author.getTitleCache());
1156
                    } else {
1157
                        csvLine[table.getIndex(WordClassificationExportTable.ABBREV_REF_AUTHOR)] = "";
1158
                        csvLine[table.getIndex(WordClassificationExportTable.FULL_REF_AUTHOR)] = "";
1159
                    }
1160

    
1161
                }
1162
            } else {
1163
                csvLine[table.getIndex(WordClassificationExportTable.PUBLICATION_TYPE)] = "";
1164
            }
1165

    
1166
            /*
1167
             * Collation
1168
             *
1169
             * Detail
1170
             *
1171
             * TitlePageYear
1172
             */
1173
            String protologueUriString = extractProtologueURIs(state, name);
1174

    
1175
            csvLine[table.getIndex(WordClassificationExportTable.PROTOLOGUE_URI)] = protologueUriString;
1176
            Collection<TypeDesignationBase> specimenTypeDesignations = new ArrayList<>();
1177
            List<TextualTypeDesignation> textualTypeDesignations = new ArrayList<>();
1178
            for (TypeDesignationBase<?> typeDesignation : name.getTypeDesignations()) {
1179
                if (typeDesignation.isInstanceOf(TextualTypeDesignation.class)) {
1180

    
1181
                    if (((TextualTypeDesignation) typeDesignation).isVerbatim() ){
1182
                        Set<IdentifiableSource> sources =  typeDesignation.getSources();
1183
                        boolean isProtologue = false;
1184
                        if (sources != null && !sources.isEmpty()){
1185
                            IdentifiableSource source = sources.iterator().next();
1186
                            if (name.getNomenclaturalReference() != null){
1187
                                isProtologue = source.getCitation() != null? source.getCitation().getUuid().equals(name.getNomenclaturalReference().getUuid()): false;
1188
                            }
1189
                        }
1190
                        if (isProtologue){
1191
                            csvLine[table.getIndex(WordClassificationExportTable.PROTOLOGUE_TYPE_STATEMENT)] = ((TextualTypeDesignation) typeDesignation)
1192
                                    .getPreferredText(Language.DEFAULT());
1193
                        }else{
1194
                            textualTypeDesignations.add((TextualTypeDesignation) typeDesignation);
1195
                        }
1196

    
1197
                    } else {
1198
                        textualTypeDesignations.add((TextualTypeDesignation) typeDesignation);
1199
                    }
1200
                } else if (typeDesignation.isInstanceOf(SpecimenTypeDesignation.class)) {
1201
                    SpecimenTypeDesignation specimenType = HibernateProxyHelper.deproxy(typeDesignation, SpecimenTypeDesignation.class);
1202
                    specimenTypeDesignations.add(specimenType);
1203
                    handleSpecimenType(state, specimenType);
1204

    
1205

    
1206
                }else if (typeDesignation instanceof NameTypeDesignation){
1207
                    specimenTypeDesignations.add(HibernateProxyHelper.deproxy(typeDesignation, NameTypeDesignation.class));
1208
                }
1209
            }
1210
            TypeDesignationSetContainer manager = new TypeDesignationSetContainer(specimenTypeDesignations, name, TypeDesignationSetComparator.ORDER_BY.TYPE_STATUS);
1211
            HTMLTagRules rules = new HTMLTagRules();
1212
            rules.addRule(TagEnum.name, "i");
1213

    
1214
            csvLine[table.getIndex(WordClassificationExportTable.TYPE_SPECIMEN)] = manager.print(false, false, false, rules);
1215

    
1216
            StringBuilder stringbuilder = new StringBuilder();
1217
            int i = 1;
1218
            for (TextualTypeDesignation typeDesignation : textualTypeDesignations) {
1219
                stringbuilder.append(typeDesignation.getPreferredText(Language.DEFAULT()));
1220
                if (typeDesignation.getSources() != null && !typeDesignation.getSources().isEmpty() ){
1221
                    stringbuilder.append( " [");
1222
                    int index = 1;
1223
                    for (IdentifiableSource source: typeDesignation.getSources()){
1224
                        if (source.getCitation() != null){
1225
                            stringbuilder.append(OriginalSourceFormatter.INSTANCE.format(source));
1226
                        }
1227
                        if (index < typeDesignation.getSources().size()) {
1228
                            stringbuilder.append( ", ");
1229
                        }
1230
                        index++;
1231
                    }
1232
                    stringbuilder.append( "]");
1233
                }
1234
                if (i < textualTypeDesignations.size()) {
1235
                    stringbuilder.append( "; ");
1236
                } else {
1237
                    stringbuilder.append(".");
1238
                }
1239
                i++;
1240
            }
1241
            csvLine[table.getIndex(WordClassificationExportTable.TYPE_STATEMENT)] = stringbuilder.toString();
1242

    
1243

    
1244
            if (name.getStatus() == null || name.getStatus().isEmpty()) {
1245
                csvLine[table.getIndex(WordClassificationExportTable.NOM_STATUS)] = "";
1246
                csvLine[table.getIndex(WordClassificationExportTable.NOM_STATUS_ABBREV)] = "";
1247
            } else {
1248

    
1249
                String statusStringAbbrev = extractStatusString(state, name, true);
1250
                String statusString = extractStatusString(state, name, false);
1251

    
1252
                csvLine[table.getIndex(WordClassificationExportTable.NOM_STATUS)] = statusString.trim();
1253
                csvLine[table.getIndex(WordClassificationExportTable.NOM_STATUS_ABBREV)] = statusStringAbbrev.trim();
1254
            }
1255

    
1256
            HomotypicalGroup group = HibernateProxyHelper.deproxy(name.getHomotypicalGroup(), HomotypicalGroup.class);
1257

    
1258
            csvLine[table.getIndex(WordClassificationExportTable.HOMOTYPIC_GROUP_FK)] = getId(state, group);
1259
            List<TaxonName> typifiedNames = new ArrayList<>();
1260
            if (acceptedTaxon != null){
1261
                HomotypicGroupTaxonComparator comparator = new HomotypicGroupTaxonComparator(acceptedTaxon);
1262
                List<Synonym> synonymsInGroup = null;
1263
                if (group.equals(acceptedTaxon.getHomotypicGroup())){
1264
                    synonymsInGroup = acceptedTaxon.getHomotypicSynonymsByHomotypicGroup(comparator);
1265
                    typifiedNames.add(name);
1266
                }else{
1267
                    synonymsInGroup = acceptedTaxon.getSynonymsInGroup(group, comparator);
1268
                }
1269

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

    
1272
            }else{
1273
                typifiedNames.addAll(group.getTypifiedNames());
1274
            }
1275

    
1276

    
1277
            Integer seqNumber = typifiedNames.indexOf(name);
1278
            csvLine[table.getIndex(WordClassificationExportTable.HOMOTYPIC_GROUP_SEQ)] = String.valueOf(seqNumber);
1279
            state.getProcessor().put(table, name, csvLine);
1280
            handleNameRelationships(state, name);
1281

    
1282
        } catch (Exception e) {
1283
            state.getResult().addException(e,
1284
                    "An unexpected error occurred when handling the name " + cdmBaseStr(name) + ": " + name.getTitleCache() + ": " + e.getMessage());
1285

    
1286
            e.printStackTrace();
1287
        }
1288
    }
1289

    
1290
    /**
1291
     * @param specimenType
1292
     */
1293
    private void handleSpecimenType_(WordClassificationExportState state, SpecimenTypeDesignation specimenType) {
1294
        if (specimenType.getTypeSpecimen() != null){
1295
            DerivedUnit specimen =  specimenType.getTypeSpecimen();
1296
            if(specimen != null && !state.getSpecimenStore().contains( specimen.getUuid())){
1297
               handleSpecimen(state, specimen);
1298
            }
1299
        }
1300
        WordClassificationExportTable table = WordClassificationExportTable.TYPE_DESIGNATION;
1301
        String[] csvLine = new String[table.getSize()];
1302
        //TYPE_ID, SPECIMEN_FK, TYPE_VERBATIM_CITATION, TYPE_STATUS, TYPE_DESIGNATED_BY_STRING, TYPE_DESIGNATED_BY_REF_FK};
1303
        //Specimen_Fk und den Typusangaben (Art des Typus [holo, lecto, etc.], Quelle, Designation-Quelle, +
1304
        Set<TaxonName> typifiedNames = specimenType.getTypifiedNames();
1305
        for (TaxonName name: typifiedNames){
1306
            csvLine[table.getIndex(WordClassificationExportTable.TYPE_STATUS)] = specimenType.getTypeStatus() != null? specimenType.getTypeStatus().getDescription(): "";
1307
            csvLine[table.getIndex(WordClassificationExportTable.TYPE_ID)] = getId(state, specimenType);
1308
            csvLine[table.getIndex(WordClassificationExportTable.TYPIFIED_NAME_FK)] = getId(state, name);
1309
            csvLine[table.getIndex(WordClassificationExportTable.SPECIMEN_FK)] = getId(state, specimenType.getTypeSpecimen());
1310
            if (specimenType.getSources() != null && !specimenType.getSources().isEmpty()){
1311
                String sourceString = "";
1312
                int index = 0;
1313
                for (IdentifiableSource source: specimenType.getSources()){
1314
                    if (source.getCitation()!= null){
1315
                        sourceString = sourceString.concat(source.getCitation().getCitation());
1316
                    }
1317
                    index++;
1318
                    if (index != specimenType.getSources().size()){
1319
                        sourceString.concat(", ");
1320
                    }
1321
                }
1322
                csvLine[table.getIndex(WordClassificationExportTable.TYPE_INFORMATION_REF_STRING)] = sourceString;
1323
            }
1324
            if (specimenType.getDesignationSource() != null && specimenType.getDesignationSource().getCitation() != null && !state.getReferenceStore().contains(specimenType.getDesignationSource().getCitation().getUuid())){
1325
                handleReference(state, specimenType.getDesignationSource().getCitation());
1326
                csvLine[table.getIndex(WordClassificationExportTable.TYPE_DESIGNATED_BY_REF_FK)] = specimenType.getDesignationSource() != null ? getId(state, specimenType.getDesignationSource().getCitation()): "";
1327
            }
1328

    
1329
            state.getProcessor().put(table, specimenType, csvLine);
1330
        }
1331
    }
1332

    
1333

    
1334
    /**
1335
     * @param specimenType
1336
     */
1337
    private void handleSpecimenType(WordClassificationExportState state, SpecimenTypeDesignation specimenType) {
1338
        if (specimenType.getTypeSpecimen() != null){
1339
            DerivedUnit specimen =  specimenType.getTypeSpecimen();
1340
            if(specimen != null && !state.getSpecimenStore().contains( specimen.getUuid())){
1341
               handleSpecimen(state, specimen);
1342
            }
1343
        }
1344
        WordClassificationExportTable table = WordClassificationExportTable.TYPE_DESIGNATION;
1345
        String[] csvLine = new String[table.getSize()];
1346

    
1347
        csvLine[table.getIndex(WordClassificationExportTable.TYPE_STATUS)] = specimenType.getTypeStatus() != null? specimenType.getTypeStatus().getDescription(): "";
1348
        csvLine[table.getIndex(WordClassificationExportTable.TYPE_ID)] = getId(state, specimenType);
1349
        csvLine[table.getIndex(WordClassificationExportTable.SPECIMEN_FK)] = getId(state, specimenType.getTypeSpecimen());
1350
        if (specimenType.getSources() != null && !specimenType.getSources().isEmpty()){
1351
            String sourceString = "";
1352
            int index = 0;
1353
            List<IdentifiableSource> sources = new ArrayList<>(specimenType.getSources());
1354
            Comparator<IdentifiableSource> compareByYear = new Comparator<IdentifiableSource>() {
1355
                @Override
1356
                public int compare(IdentifiableSource o1, IdentifiableSource o2) {
1357
                    if (o1 == o2){
1358
                        return 0;
1359
                    }
1360
                    if (o1.getCitation() == null && o2.getCitation() != null){
1361
                        return -1;
1362
                    }
1363
                    if (o2.getCitation() == null && o1.getCitation() != null){
1364
                        return 1;
1365
                    }
1366
                    if (o1.getCitation().equals(o2.getCitation())){
1367
                        return 0;
1368
                    }
1369
                    if (o1.getCitation().getDatePublished() == null && o2.getCitation().getDatePublished() != null){
1370
                        return -1;
1371
                    }
1372
                    if (o1.getCitation().getDatePublished() != null && o2.getCitation().getDatePublished() == null){
1373
                        return 1;
1374
                    }
1375
                    if (o1.getCitation().getDatePublished().getYear() == null && o2.getCitation().getDatePublished().getYear() != null){
1376
                        return -1;
1377
                    }
1378
                    if (o1.getCitation().getDatePublished().getYear() != null && o2.getCitation().getDatePublished().getYear() == null){
1379
                        return 1;
1380
                    }
1381
                    return o1.getCitation().getDatePublished().getYear().compareTo(o2.getCitation().getDatePublished().getYear());
1382
                }
1383
            };
1384
            Collections.sort(sources, compareByYear);
1385
            for (IdentifiableSource source: sources){
1386
                if (source.getCitation()!= null){
1387
                    sourceString = sourceString.concat(source.getCitation().getCitation());
1388
                    handleReference(state, source.getCitation());
1389
                }
1390
                index++;
1391
                if (index <= specimenType.getSources().size()){
1392
                    sourceString = sourceString.concat("; ");
1393
                }
1394
            }
1395

    
1396
            csvLine[table.getIndex(WordClassificationExportTable.TYPE_INFORMATION_REF_STRING)] = sourceString;
1397
            if (sources.get(0).getCitation() != null ){
1398
                csvLine[table.getIndex(WordClassificationExportTable.TYPE_INFORMATION_REF_FK)] = getId(state, sources.get(0).getCitation());
1399
            }
1400
        }
1401
        if (specimenType.getDesignationSource() != null && specimenType.getDesignationSource().getCitation() != null && !state.getReferenceStore().contains(specimenType.getDesignationSource().getCitation().getUuid())){
1402
            handleReference(state, specimenType.getDesignationSource().getCitation());
1403
            csvLine[table.getIndex(WordClassificationExportTable.TYPE_DESIGNATED_BY_REF_FK)] = specimenType.getDesignationSource() != null ? getId(state, specimenType.getDesignationSource().getCitation()): "";
1404
        }
1405

    
1406

    
1407
        Set<TaxonName> typifiedNames = specimenType.getTypifiedNames();
1408

    
1409
        if (typifiedNames.size() > 1){
1410
            state.getResult().addWarning("Please check the specimen type  "
1411
                    + cdmBaseStr(specimenType) + " there are more then one typified name.");
1412
        }
1413
        if (typifiedNames.iterator().hasNext()){
1414
            TaxonName name = typifiedNames.iterator().next();
1415
            csvLine[table.getIndex(WordClassificationExportTable.TYPIFIED_NAME_FK)] = getId(state, name);
1416
        }
1417
        state.getProcessor().put(table, specimenType, csvLine);
1418

    
1419

    
1420

    
1421

    
1422

    
1423
    }
1424

    
1425

    
1426
    private String createNameWithItalics(List<TaggedText> taggedName) {
1427

    
1428
        String fullTitleWithHtml = "";
1429
        for (TaggedText taggedText: taggedName){
1430
            if (taggedText.getType().equals(TagEnum.name)){
1431
                fullTitleWithHtml += "<i>" + taggedText.getText() + "</i> ";
1432
            }else if (taggedText.getType().equals(TagEnum.separator)){
1433
                fullTitleWithHtml = fullTitleWithHtml.trim() + taggedText.getText() ;
1434
            }else{
1435
                fullTitleWithHtml += taggedText.getText() + " ";
1436
            }
1437
        }
1438
        return fullTitleWithHtml;
1439
    }
1440

    
1441
    private void handleNameRelationships(WordClassificationExportState state, TaxonName name) {
1442
        Set<NameRelationship> rels = name.getRelationsFromThisName();
1443
        WordClassificationExportTable table = WordClassificationExportTable.NAME_RELATIONSHIP;
1444
        String[] csvLine = new String[table.getSize()];
1445

    
1446
        for (NameRelationship rel : rels) {
1447
            NameRelationshipType type = rel.getType();
1448
            TaxonName name2 = rel.getToName();
1449
            name2 = HibernateProxyHelper.deproxy(name2, TaxonName.class);
1450
            if (!state.getNameStore().containsKey(name2.getId())) {
1451
                handleName(state, name2, null);
1452
            }
1453

    
1454
            csvLine[table.getIndex(WordClassificationExportTable.NAME_REL_TYPE)] = type.getLabel();
1455
            csvLine[table.getIndex(WordClassificationExportTable.NAME1_FK)] = getId(state, name);
1456
            csvLine[table.getIndex(WordClassificationExportTable.NAME2_FK)] = getId(state, name2);
1457
            state.getProcessor().put(table, name, csvLine);
1458
        }
1459

    
1460
        rels = name.getRelationsToThisName();
1461

    
1462
        csvLine = new String[table.getSize()];
1463

    
1464
        for (NameRelationship rel : rels) {
1465
            NameRelationshipType type = rel.getType();
1466
            TaxonName name2 = rel.getFromName();
1467
            name2 = HibernateProxyHelper.deproxy(name2, TaxonName.class);
1468
            if (!state.getNameStore().containsKey(name2.getId())) {
1469
                handleName(state, name2, null);
1470
            }
1471

    
1472

    
1473
        }
1474
    }
1475

    
1476
    private String createCollatation(TaxonName name) {
1477
        String collation = "";
1478
        if (name.getNomenclaturalReference() != null) {
1479
            Reference ref = name.getNomenclaturalReference();
1480
            collation = getVolume(ref);
1481
        }
1482
        if (name.getNomenclaturalMicroReference() != null) {
1483
            if (!StringUtils.isBlank(collation)) {
1484
                collation += ":";
1485
            }
1486
            collation += name.getNomenclaturalMicroReference();
1487
        }
1488

    
1489
        return collation;
1490
    }
1491

    
1492
    private String getVolume(Reference reference) {
1493
        if (reference.getVolume() != null) {
1494
            return reference.getVolume();
1495
        } else if (reference.getInReference() != null) {
1496
            if (reference.getInReference().getVolume() != null) {
1497
                return reference.getInReference().getVolume();
1498
            }
1499
        }
1500
        return null;
1501
    }
1502

    
1503
    private void handleIdentifier(WordClassificationExportState state, CdmBase cdmBase) {
1504
        WordClassificationExportTable table = WordClassificationExportTable.IDENTIFIER;
1505
        String[] csvLine;
1506
        try {
1507
            if (cdmBase instanceof TaxonName){
1508
                TaxonName name = (TaxonName)cdmBase;
1509

    
1510
                try{
1511
                    List<Identifier> identifiers = name.getIdentifiers();
1512

    
1513
                    //first check which kind of identifiers are available and then sort and create table entries
1514
                    Map<DefinedTerm, Set<Identifier>> identifierTypes = new HashMap<>();
1515
                    for (Identifier identifier: identifiers){
1516
                        DefinedTerm type = identifier.getType();
1517
                        if (identifierTypes.containsKey(type)){
1518
                            identifierTypes.get(type).add(identifier);
1519
                        }else{
1520
                            Set<Identifier> tempList = new HashSet<>();
1521
                            tempList.add(identifier);
1522
                            identifierTypes.put(type, tempList);
1523
                        }
1524
                    }
1525

    
1526
                    for (DefinedTerm type:identifierTypes.keySet()){
1527
                        Set<Identifier> identifiersByType = identifierTypes.get(type);
1528
                        csvLine = new String[table.getSize()];
1529
                        csvLine[table.getIndex(WordClassificationExportTable.FK)] = getId(state, name);
1530
                        csvLine[table.getIndex(WordClassificationExportTable.REF_TABLE)] = "ScientificName";
1531
                        csvLine[table.getIndex(WordClassificationExportTable.IDENTIFIER_TYPE)] = type.getLabel();
1532
                        csvLine[table.getIndex(WordClassificationExportTable.EXTERNAL_NAME_IDENTIFIER)] = extractIdentifier(
1533
                                identifiersByType);
1534
                        state.getProcessor().put(table, name.getUuid() + ", " + type.getLabel(), csvLine);
1535
                    }
1536

    
1537

    
1538
//                    Set<String> IPNIidentifiers = name.getIdentifiers(DefinedTerm.IDENTIFIER_NAME_IPNI());
1539
//                    Set<String> tropicosIdentifiers = name.getIdentifiers(DefinedTerm.IDENTIFIER_NAME_TROPICOS());
1540
//                    Set<String> WFOIdentifiers = name.getIdentifiers(DefinedTerm.uuidWfoNameIdentifier);
1541
//                    if (!IPNIidentifiers.isEmpty()) {
1542
//                        csvLine = new String[table.getSize()];
1543
//                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, name);
1544
//                        csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = "ScientificName";
1545
//                        csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = IPNI_NAME_IDENTIFIER;
1546
//                        csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = extractIdentifier(
1547
//                                IPNIidentifiers);
1548
//                        state.getProcessor().put(table, name.getUuid() + ", " + IPNI_NAME_IDENTIFIER, csvLine);
1549
//                    }
1550
//                    if (!tropicosIdentifiers.isEmpty()) {
1551
//                        csvLine = new String[table.getSize()];
1552
//                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, name);
1553
//                        csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = "ScientificName";
1554
//                        csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = TROPICOS_NAME_IDENTIFIER;
1555
//                        csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = extractIdentifier(
1556
//                                tropicosIdentifiers);
1557
//                        state.getProcessor().put(table, name.getUuid() + ", " + IPNI_NAME_IDENTIFIER, csvLine);
1558
//                    }
1559
//                    if (!WFOIdentifiers.isEmpty()) {
1560
//                        csvLine = new String[table.getSize()];
1561
//                        csvLine[table.getIndex(CdmLightExportTable.FK)] = getId(state, name);
1562
//                        csvLine[table.getIndex(CdmLightExportTable.REF_TABLE)] = "ScientificName";
1563
//                        csvLine[table.getIndex(CdmLightExportTable.IDENTIFIER_TYPE)] = WFO_NAME_IDENTIFIER;
1564
//                        csvLine[table.getIndex(CdmLightExportTable.EXTERNAL_NAME_IDENTIFIER)] = extractIdentifier(
1565
//                                WFOIdentifiers);
1566
//                        state.getProcessor().put(table, name.getUuid() + ", " + WFO_NAME_IDENTIFIER, csvLine);
1567
//                    }
1568
                }catch(Exception e){
1569
                    state.getResult().addWarning("Please check the identifiers for "
1570
                            + cdmBaseStr(cdmBase) + " maybe there is an empty identifier");
1571

    
1572

    
1573
                }
1574
            }else{
1575
                if (cdmBase instanceof IdentifiableEntity){
1576
                    IdentifiableEntity<?> identifiableEntity = (IdentifiableEntity<?>) cdmBase;
1577
                    List<Identifier> identifiers = identifiableEntity.getIdentifiers();
1578
                    String tableName = null;
1579
                    if (cdmBase instanceof Reference){
1580
                        tableName = "Reference";
1581
                    }else if (cdmBase instanceof SpecimenOrObservationBase){
1582
                        tableName = "Specimen";
1583
                    }else if (cdmBase instanceof Taxon){
1584
                        tableName = "Taxon";
1585
                    }else if (cdmBase instanceof Synonym){
1586
                        tableName = "Synonym";
1587
                    }else if (cdmBase instanceof TeamOrPersonBase){
1588
                        tableName = "PersonOrTeam";
1589
                    }
1590

    
1591
                    for (Identifier identifier: identifiers){
1592
                        if (identifier.getType() == null && identifier.getIdentifier() == null){
1593
                            state.getResult().addWarning("Please check the identifiers for "
1594
                                    + cdmBaseStr(cdmBase) + " there is an empty identifier");
1595
                            continue;
1596
                        }
1597

    
1598
                        csvLine = new String[table.getSize()];
1599
                        csvLine[table.getIndex(WordClassificationExportTable.FK)] = getId(state, cdmBase);
1600

    
1601
                        if (tableName != null){
1602
                            csvLine[table.getIndex(WordClassificationExportTable.REF_TABLE)] = tableName;
1603
                            csvLine[table.getIndex(WordClassificationExportTable.IDENTIFIER_TYPE)] = identifier.getType() != null? identifier.getType().getLabel():null;
1604
                            csvLine[table.getIndex(WordClassificationExportTable.EXTERNAL_NAME_IDENTIFIER)] = identifier.getIdentifier();
1605
                            state.getProcessor().put(table, cdmBase.getUuid() + (identifier.getType() != null? identifier.getType().getLabel():null), csvLine);
1606
                        }
1607
                    }
1608
                    if (cdmBase instanceof Reference ){
1609
                        Reference ref = (Reference)cdmBase;
1610
                        if (ref.getDoi() != null){
1611
                            csvLine = new String[table.getSize()];
1612
                            csvLine[table.getIndex(WordClassificationExportTable.FK)] = getId(state, cdmBase);
1613
                            csvLine[table.getIndex(WordClassificationExportTable.REF_TABLE)] = tableName;
1614
                            csvLine[table.getIndex(WordClassificationExportTable.IDENTIFIER_TYPE)] = "DOI";
1615
                            csvLine[table.getIndex(WordClassificationExportTable.EXTERNAL_NAME_IDENTIFIER)] = ref.getDoiString();
1616
                            state.getProcessor().put(table, cdmBase.getUuid() + "DOI", csvLine);
1617
                        }
1618
                    }
1619

    
1620
                    if (cdmBase instanceof TeamOrPersonBase){
1621
                        TeamOrPersonBase<?> person= HibernateProxyHelper.deproxy(cdmBase, TeamOrPersonBase.class);
1622
                        if (person instanceof Person &&  ((Person)person).getOrcid() != null){
1623
                            csvLine = new String[table.getSize()];
1624
                            csvLine[table.getIndex(WordClassificationExportTable.FK)] = getId(state, cdmBase);
1625
                            csvLine[table.getIndex(WordClassificationExportTable.REF_TABLE)] = tableName;
1626
                            csvLine[table.getIndex(WordClassificationExportTable.IDENTIFIER_TYPE)] = "ORCID";
1627
                            csvLine[table.getIndex(WordClassificationExportTable.EXTERNAL_NAME_IDENTIFIER)]=  ((Person)person).getOrcid().asURI();
1628
                            state.getProcessor().put(table, cdmBase.getUuid() + "ORCID", csvLine);
1629
                        }
1630
                    }
1631
                }
1632
            }
1633
        } catch (Exception e) {
1634
            state.getResult().addException(e, "An unexpected error occurred when handling identifiers for "
1635
                    + cdmBaseStr(cdmBase) + ": " + e.getMessage());
1636
            e.printStackTrace();
1637
        }
1638
    }
1639

    
1640
    private String extractIdentifier(Set<Identifier> identifierSet) {
1641

    
1642
        String identifierString = "";
1643
        for (Identifier identifier : identifierSet) {
1644
            if (!StringUtils.isBlank(identifierString)) {
1645
                identifierString += ", ";
1646
            }
1647
            identifierString += identifier.getIdentifier();
1648
        }
1649
        return identifierString;
1650
    }
1651

    
1652
    private String extractProtologueURIs(WordClassificationExportState state, TaxonName name) {
1653
        if (name.getNomenclaturalSource() != null){
1654
            Set<ExternalLink> links = name.getNomenclaturalSource().getLinks();
1655
            return extractLinkUris(links.iterator());
1656
        }else{
1657
            return null;
1658
        }
1659
    }
1660

    
1661
    private String extractMediaURIs(WordClassificationExportState state, Set<? extends DescriptionBase<?>> descriptionsSet,
1662
            Feature feature) {
1663

    
1664
        String mediaUriString = "";
1665
        Set<DescriptionElementBase> elements = new HashSet<>();
1666
        for (DescriptionBase<?> description : descriptionsSet) {
1667
            try {
1668
                if (!description.getElements().isEmpty()) {
1669
                    elements = description.getElements();
1670

    
1671
                    for (DescriptionElementBase element : elements) {
1672
                        Feature entityFeature = HibernateProxyHelper.deproxy(element.getFeature());
1673
                        if (entityFeature.equals(feature)) {
1674
                            if (!element.getMedia().isEmpty()) {
1675
                                List<Media> media = element.getMedia();
1676
                                for (Media mediaElement : media) {
1677
                                    Iterator<MediaRepresentation> it = mediaElement.getRepresentations().iterator();
1678
                                    mediaUriString = extractMediaUris(it);
1679
                                }
1680
                            }
1681
                        }
1682
                    }
1683
                }
1684
            } catch (Exception e) {
1685
                state.getResult().addException(e, "An unexpected error occurred when extracting media URIs for "
1686
                        + cdmBaseStr(description) + ": " + e.getMessage());
1687
            }
1688
        }
1689
        return mediaUriString;
1690
    }
1691

    
1692
    private void handleAuthor(WordClassificationExportState state, TeamOrPersonBase<?> author) {
1693
        try {
1694
            if (state.getAuthorFromStore(author.getId()) != null) {
1695
                return;
1696
            }
1697
            state.addAuthorToStore(author);
1698
            handleIdentifier(state, author);
1699
            WordClassificationExportTable table = WordClassificationExportTable.NOMENCLATURAL_AUTHOR;
1700
            String[] csvLine = new String[table.getSize()];
1701
            WordClassificationExportTable tableAuthorRel = WordClassificationExportTable.NOMENCLATURAL_AUTHOR_TEAM_RELATION;
1702
            String[] csvLineRel = new String[tableAuthorRel.getSize()];
1703
            String[] csvLineMember = new String[table.getSize()];
1704
            csvLine[table.getIndex(WordClassificationExportTable.AUTHOR_ID)] = getId(state, author);
1705
            csvLine[table.getIndex(WordClassificationExportTable.ABBREV_AUTHOR)] = author.isProtectedTitleCache()
1706
                    ? author.getTitleCache() : author.getNomenclaturalTitleCache();
1707
            csvLine[table.getIndex(WordClassificationExportTable.AUTHOR_TITLE)] = author.getTitleCache();
1708
            author = HibernateProxyHelper.deproxy(author);
1709
            if (author instanceof Person) {
1710
                Person authorPerson = (Person) author;
1711
                csvLine[table.getIndex(WordClassificationExportTable.AUTHOR_GIVEN_NAME)] = authorPerson.getGivenName();
1712
                csvLine[table.getIndex(WordClassificationExportTable.AUTHOR_FAMILY_NAME)] = authorPerson.getFamilyName();
1713
                csvLine[table.getIndex(WordClassificationExportTable.AUTHOR_PREFIX)] = authorPerson.getPrefix();
1714
                csvLine[table.getIndex(WordClassificationExportTable.AUTHOR_SUFFIX)] = authorPerson.getSuffix();
1715
            } else {
1716
                // create an entry in rel table and all members in author table,
1717
                // check whether the team members already in author table
1718

    
1719
                Team authorTeam = (Team) author;
1720
                int index = 0;
1721
                for (Person member : authorTeam.getTeamMembers()) {
1722
                    csvLineRel = new String[tableAuthorRel.getSize()];
1723
                    csvLineRel[tableAuthorRel.getIndex(WordClassificationExportTable.AUTHOR_TEAM_FK)] = getId(state, authorTeam);
1724
                    csvLineRel[tableAuthorRel.getIndex(WordClassificationExportTable.AUTHOR_FK)] = getId(state, member);
1725
                    csvLineRel[tableAuthorRel.getIndex(WordClassificationExportTable.AUTHOR_TEAM_SEQ_NUMBER)] = String
1726
                            .valueOf(index);
1727
                    state.getProcessor().put(tableAuthorRel, authorTeam.getId() + ":" + member.getId(), csvLineRel);
1728

    
1729
                    if (state.getAuthorFromStore(member.getId()) == null) {
1730
                        state.addAuthorToStore(member);
1731
                        csvLineMember = new String[table.getSize()];
1732
                        csvLineMember[table.getIndex(WordClassificationExportTable.AUTHOR_ID)] = getId(state, member);
1733
                        csvLineMember[table.getIndex(WordClassificationExportTable.ABBREV_AUTHOR)] = member
1734
                                .isProtectedTitleCache() ? member.getTitleCache() : member.getNomenclaturalTitleCache();
1735
                        csvLineMember[table.getIndex(WordClassificationExportTable.AUTHOR_TITLE)] = member.getTitleCache();
1736
                        csvLineMember[table.getIndex(WordClassificationExportTable.AUTHOR_GIVEN_NAME)] = member.getGivenName();
1737
                        csvLineMember[table.getIndex(WordClassificationExportTable.AUTHOR_FAMILY_NAME)] = member.getFamilyName();
1738
                        csvLineMember[table.getIndex(WordClassificationExportTable.AUTHOR_PREFIX)] = member.getPrefix();
1739
                        csvLineMember[table.getIndex(WordClassificationExportTable.AUTHOR_SUFFIX)] = member.getSuffix();
1740
                        state.getProcessor().put(table, member, csvLineMember);
1741
                    }
1742
                    index++;
1743
                }
1744
            }
1745
            state.getProcessor().put(table, author, csvLine);
1746
        } catch (Exception e) {
1747
            state.getResult().addException(e,
1748
                    "An unexpected error occurred when handling author " + cdmBaseStr(author) + ": " + e.getMessage());
1749
        }
1750
    }
1751

    
1752
    private String extractStatusString(WordClassificationExportState state, TaxonName name, boolean abbrev) {
1753
        try {
1754
            Set<NomenclaturalStatus> status = name.getStatus();
1755
            if (status.isEmpty()) {
1756
                return "";
1757
            }
1758
            String statusString = "";
1759
            for (NomenclaturalStatus nameStatus : status) {
1760
                if (nameStatus != null) {
1761
                    if (abbrev) {
1762
                        if (nameStatus.getType() != null) {
1763
                            statusString += nameStatus.getType().getIdInVocabulary();
1764
                        }
1765
                    } else {
1766
                        if (nameStatus.getType() != null) {
1767
                            statusString += nameStatus.getType().getTitleCache();
1768
                        }
1769
                    }
1770
                    if (!abbrev) {
1771

    
1772
                        if (nameStatus.getRuleConsidered() != null
1773
                                && !StringUtils.isBlank(nameStatus.getRuleConsidered())) {
1774
                            statusString += ": " + nameStatus.getRuleConsidered();
1775
                        }
1776
                        if (nameStatus.getCitation() != null) {
1777
                            String shortCitation = OriginalSourceFormatter.INSTANCE.format(nameStatus.getCitation(), null);
1778
                            statusString += " (" + shortCitation + ")";
1779
                        }
1780
//                        if (nameStatus.getCitationMicroReference() != null
1781
//                                && !StringUtils.isBlank(nameStatus.getCitationMicroReference())) {
1782
//                            statusString += " " + nameStatus.getCitationMicroReference();
1783
//                        }
1784
                    }
1785
                    statusString += " ";
1786
                }
1787
            }
1788
            return statusString;
1789
        } catch (Exception e) {
1790
            state.getResult().addException(e, "An unexpected error occurred when extracting status string for "
1791
                    + cdmBaseStr(name) + ": " + e.getMessage());
1792
            return "";
1793
        }
1794
    }
1795

    
1796
    private void handleHomotypicalGroup(WordClassificationExportState state, HomotypicalGroup group, Taxon acceptedTaxon, int sortIndex) {
1797
        try {
1798
            state.addHomotypicalGroupToStore(group);
1799
            WordClassificationExportTable table = WordClassificationExportTable.HOMOTYPIC_GROUP;
1800
            String[] csvLine = new String[table.getSize()];
1801
            csvLine[table.getIndex(WordClassificationExportTable.SORT_INDEX)] = String.valueOf(sortIndex);
1802
            csvLine[table.getIndex(WordClassificationExportTable.HOMOTYPIC_GROUP_ID)] = getId(state, group);
1803

    
1804
            List<TaxonName> typifiedNames = new ArrayList<>();
1805
            if (acceptedTaxon != null){
1806
                List<Synonym> synonymsInGroup = acceptedTaxon.getSynonymsInGroup(group);
1807
                if (group.equals(acceptedTaxon.getHomotypicGroup())){
1808
                    typifiedNames.add(acceptedTaxon.getName());
1809
                }
1810
                synonymsInGroup.stream().forEach(synonym -> typifiedNames.add(CdmBase.deproxy(synonym.getName())));
1811
            }
1812

    
1813

    
1814
            TaxonName firstname = null;
1815
            for (TaxonName name: typifiedNames){
1816
                Iterator<Taxon> taxa = name.getTaxa().iterator();
1817
                while(taxa.hasNext()){
1818
                    Taxon taxon = taxa.next();
1819
                    if(!(taxon.isMisapplication() || taxon.isProparteSynonym())){
1820
                        firstname = name;
1821
                        break;
1822
                    }
1823
                }
1824
            }
1825

    
1826
//            Collections.sort(typifiedNames, new HomotypicalGroupNameComparator(firstname, true));
1827
            String typifiedNamesString = "";
1828
            String typifiedNamesWithSecString = "";
1829
            String typifiedNamesWithoutAccepted = "";
1830
            String typifiedNamesWithoutAcceptedWithSec = "";
1831
            int index = 0;
1832
            for (TaxonName name : typifiedNames) {
1833
                // Concatenated output string for homotypic group (names and
1834
                // citations) + status + some name relations (e.g. “non”)
1835
                // TODO: nameRelations, which and how to display
1836
                Set<TaxonBase> taxonBases = name.getTaxonBases();
1837
                TaxonBase<?> taxonBase;
1838

    
1839
                String sec = "";
1840
                String nameString = name.getFullTitleCache();
1841
                String doubtful = "";
1842

    
1843
                if (state.getConfig().isAddHTML()){
1844
                    nameString = createNameWithItalics(name.getTaggedFullTitle()) ;
1845
                }
1846

    
1847
                Set<NameRelationship> related = name.getNameRelations();
1848
                List<NameRelationship> relatedList = new ArrayList<>(related);
1849

    
1850
                Collections.sort(relatedList, new Comparator<NameRelationship>() {
1851
                    @Override
1852
                    public int compare(NameRelationship nr1, NameRelationship nr2) {
1853
                        return nr1.getType().compareTo(nr2.getType());
1854
                    }
1855

    
1856
                });
1857

    
1858
                List<NameRelationship> nonNames = new ArrayList<>();
1859
                List<NameRelationship> otherRelationships = new ArrayList<>();
1860

    
1861
                for (NameRelationship rel: relatedList){
1862
                    //no inverse relations
1863
                    if (rel.getFromName().equals(name)){
1864
                     // alle Homonyme und inverse blocking names
1865
                        if (rel.getType().equals(NameRelationshipType.LATER_HOMONYM())
1866
                                || rel.getType().equals(NameRelationshipType.TREATED_AS_LATER_HOMONYM())
1867
                                || (rel.getType().equals(NameRelationshipType.BLOCKING_NAME_FOR()))
1868
                                || (rel.getType().equals(NameRelationshipType.UNSPECIFIC_NON()))){
1869
                            nonNames.add(rel);
1870
                        }else if (!rel.getType().isBasionymRelation()){
1871
                            otherRelationships.add(rel);
1872
                        }
1873
                    }
1874
                }
1875

    
1876
                String nonRelNames = "";
1877
                String relNames = "";
1878

    
1879
                if (nonNames.size() > 0){
1880
                    nonRelNames += " [";
1881
                }
1882
                for (NameRelationship relName: nonNames){
1883
                    String label = "non ";
1884
                    TaxonName relatedName = null;
1885
                    if (relName.getFromName().equals(name)){
1886
                        relatedName = relName.getToName();
1887
                        nonRelNames += label + relatedName.getTitleCache() + " ";
1888
                    }
1889
//                    else{
1890
//                        label = relName.getType().getInverseLabel() + " ";
1891
//                        relatedName = relName.getFromName();
1892
//                        nonRelNames += label + relatedName.getTitleCache() + " ";
1893
//                    }
1894

    
1895

    
1896
                }
1897
                relNames.trim();
1898
                if (nonNames.size() > 0){
1899
                    nonRelNames = StringUtils.strip(nonRelNames, null);
1900
                    nonRelNames += "] ";
1901
                }
1902

    
1903
                if (otherRelationships.size() > 0){
1904
                    relNames += " [";
1905
                }
1906
                for (NameRelationship rel: otherRelationships){
1907
                    String label = "";
1908
                    TaxonName relatedName = null;
1909
                    if (rel.getFromName().equals(name)){
1910
                        label = rel.getType().getLabel() + " ";
1911
                        relatedName = rel.getToName();
1912
                        if (state.getConfig().isAddHTML()){
1913
                            relNames += label + createNameWithItalics(relatedName.getTaggedName())+ " ";
1914
                        }else{
1915
                            relNames += label + relatedName.getTitleCache();
1916
                        }
1917
                    }
1918
//                    else {
1919
//                        label = rel.getType().getInverseLabel() + " ";
1920
//                        relatedName = rel.getFromName();
1921
//                    }
1922

    
1923
                }
1924
                relNames.trim();
1925
                if (otherRelationships.size() > 0){
1926
                    relNames = StringUtils.stripEnd(relNames, null);
1927
                    relNames += "] ";
1928
                }
1929

    
1930
                String synonymSign = "";
1931
                if (index > 0){
1932
                    if (name.isInvalid()){
1933
                        synonymSign = "\u2212 ";
1934
                    }else{
1935
                        synonymSign = "\u2261 ";
1936
                    }
1937
                }else{
1938
                    if (name.isInvalid() ){
1939
                        synonymSign = "\u2212 ";
1940
                    }else{
1941
                        synonymSign = "\u003D ";
1942
                    }
1943
                }
1944
                boolean isAccepted = false;
1945

    
1946
                if (taxonBases.size() == 1){
1947
                     taxonBase = HibernateProxyHelper.deproxy(taxonBases.iterator().next());
1948

    
1949
                     if (taxonBase.getSec() != null){
1950
                         sec = OriginalSourceFormatter.INSTANCE_WITH_YEAR_BRACKETS.format(taxonBase.getSecSource());
1951
                     }
1952
                     if (taxonBase.isDoubtful()){
1953
                         doubtful = "?";
1954
                     }else{
1955
                         doubtful = "";
1956
                     }
1957
                     if (taxonBase instanceof Synonym){
1958
                         if (isNotBlank(sec)){
1959
                             sec = " syn. sec. " + sec + " ";
1960
                         }else {
1961
                             sec = "";
1962
                         }
1963

    
1964
                         typifiedNamesWithoutAccepted += synonymSign + doubtful + nameString + nonRelNames + relNames;
1965
                         typifiedNamesWithoutAcceptedWithSec += synonymSign + doubtful + nameString + sec + nonRelNames + relNames;
1966
                     }else{
1967
//                         sec = "";
1968
                         if (!(((Taxon)taxonBase).isProparteSynonym() || ((Taxon)taxonBase).isMisapplication())){
1969
                             isAccepted = true;
1970
                         }else {
1971
                             synonymSign = "\u003D ";
1972
                         }
1973

    
1974
                     }
1975
                     if (taxonBase.getAppendedPhrase() != null){
1976
                         if (state.getConfig().isAddHTML()){
1977
                             String taxonString = createNameWithItalics(taxonBase.getTaggedTitle()) ;
1978
                             taxonString = taxonString.replace("sec "+sec, "");
1979
                             String nameCacheWithItalics = createNameWithItalics(name.getTaggedName());
1980
                             nameString = nameString.replace(nameCacheWithItalics, taxonString);
1981
                         }
1982
                     }
1983
                }else{
1984
                    //there are names used more than once?
1985
                    for (TaxonBase<?> tb: taxonBases){
1986
                        if (tb.getSec() != null){
1987
                            sec = OriginalSourceFormatter.INSTANCE_WITH_YEAR_BRACKETS.format(tb.getSecSource());
1988
                        }
1989
                        if (tb.isDoubtful()){
1990
                            doubtful = "?";
1991
                        }else{
1992
                            doubtful = "";
1993
                        }
1994
                        if (tb instanceof Synonym){
1995
                            if (StringUtils.isNotBlank(sec)){
1996
                                sec = " syn. sec. " + sec + " ";
1997
                            }else {
1998
                                sec = "";
1999
                            }
2000

    
2001
                            break;
2002
                        }else{
2003
                            sec = "";
2004
                            if (!(((Taxon)tb).isProparteSynonym() || ((Taxon)tb).isMisapplication())){
2005
                                isAccepted = true;
2006
                                break;
2007
                            }else {
2008
                                synonymSign = "\u003D ";
2009
                            }
2010

    
2011
                        }
2012
                    }
2013
                    if (!isAccepted){
2014
                        typifiedNamesWithoutAccepted += synonymSign + doubtful + nameString + "; ";
2015
                        typifiedNamesWithoutAcceptedWithSec += synonymSign + doubtful + nameString + sec;
2016
                        typifiedNamesWithoutAcceptedWithSec = typifiedNamesWithoutAcceptedWithSec.trim() + "; ";
2017
                    }
2018
                }
2019
                typifiedNamesString += synonymSign + doubtful + nameString + nonRelNames + relNames;
2020
                typifiedNamesWithSecString += synonymSign + doubtful + nameString + sec + nonRelNames + relNames;
2021

    
2022

    
2023
                csvLine[table.getIndex(WordClassificationExportTable.HOMOTYPIC_GROUP_STRING)] = typifiedNamesString.trim();
2024

    
2025
                csvLine[table.getIndex(WordClassificationExportTable.HOMOTYPIC_GROUP_WITH_SEC_STRING)] = typifiedNamesWithSecString.trim();
2026

    
2027
                if (typifiedNamesWithoutAccepted != null && firstname != null) {
2028
                    csvLine[table.getIndex(WordClassificationExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTED)] = typifiedNamesWithoutAccepted.trim();
2029
                } else {
2030
                    csvLine[table.getIndex(WordClassificationExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTED)] = "";
2031
                }
2032

    
2033
                if (typifiedNamesWithoutAcceptedWithSec != null && firstname != null) {
2034
                    csvLine[table.getIndex(WordClassificationExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTEDWITHSEC)] = typifiedNamesWithoutAcceptedWithSec.trim();
2035
                } else {
2036
                    csvLine[table.getIndex(WordClassificationExportTable.HOMOTYPIC_GROUP_WITHOUT_ACCEPTEDWITHSEC)] = "";
2037
                }
2038
                index++;
2039
            }
2040

    
2041
            Set<TypeDesignationBase<?>> typeDesigantionSet = group.getTypeDesignations();
2042
            List<TypeDesignationBase<?>> designationList = new ArrayList<>();
2043
            designationList.addAll(typeDesigantionSet);
2044
            Collections.sort(designationList, new TypeComparator());
2045

    
2046
            List<TaggedText> list = new ArrayList<>();
2047
            if (!designationList.isEmpty()) {
2048
                TypeDesignationSetContainer manager = new TypeDesignationSetContainer(group);
2049
                list.addAll(new TypeDesignationSetFormatter(true, false, false).toTaggedText(manager));
2050
            }
2051
            String typeTextDesignations = "";
2052
            //The typeDesignationManager does not handle the textual typeDesignations
2053
            for (TypeDesignationBase<?> typeDes: designationList) {
2054
            	if (typeDes instanceof TextualTypeDesignation) {
2055
            		typeTextDesignations = typeTextDesignations + ((TextualTypeDesignation)typeDes).getText(Language.getDefaultLanguage());
2056
            		String typeDesStateRefs = "";
2057
                    if (typeDes.getDesignationSource() != null ){
2058
                        typeDesStateRefs = "[";
2059
                        NamedSource source = typeDes.getDesignationSource();
2060
                        if (source.getCitation() != null){
2061
                            typeDesStateRefs += "fide " + OriginalSourceFormatter.INSTANCE.format(source.getCitation(), null);
2062
                        }
2063
                        typeDesStateRefs += "]";
2064
                    }else if (typeDes.getSources() != null && !typeDes.getSources().isEmpty()){
2065
                        typeDesStateRefs = "[";
2066
                        for (IdentifiableSource source: typeDes.getSources()) {
2067
                            if (source.getCitation() != null){
2068
                                typeDesStateRefs += "fide " +OriginalSourceFormatter.INSTANCE.format(source.getCitation(), null);
2069
                            }
2070
                        }
2071

    
2072
                        typeDesStateRefs += "]";
2073
                    }
2074

    
2075
            		typeTextDesignations =  typeTextDesignations + typeDesStateRefs +"; ";
2076

    
2077
            	}else if (typeDes instanceof SpecimenTypeDesignation){
2078
            	    DerivedUnit specimen =  ((SpecimenTypeDesignation)typeDes).getTypeSpecimen();
2079
            	    if(specimen != null && !state.getSpecimenStore().contains( specimen.getUuid())){
2080
            	        handleSpecimen(state, specimen);
2081
            	    }
2082
            	}
2083
            }
2084
            if (typeTextDesignations.equals("; ")) {
2085
            	typeTextDesignations = "";
2086
            }
2087
            if (StringUtils.isNotBlank(typeTextDesignations)) {
2088
            	typeTextDesignations = typeTextDesignations.substring(0, typeTextDesignations.length()-2);
2089
            }
2090
            String specimenTypeString = !list.isEmpty()? createTypeDesignationString(list, true, typifiedNames.get(0).isSpecies() || typifiedNames.get(0).isInfraSpecific()):"";
2091

    
2092
            if (StringUtils.isNotBlank(specimenTypeString)) {
2093
                if (!specimenTypeString.endsWith(".")) {
2094
                	specimenTypeString = specimenTypeString + ".";
2095
                }
2096
                csvLine[table.getIndex(WordClassificationExportTable.TYPE_STRING)] = specimenTypeString;
2097

    
2098
            } else {
2099
                csvLine[table.getIndex(WordClassificationExportTable.TYPE_STRING)] = "";
2100
            }
2101
            if (StringUtils.isNotBlank(typeTextDesignations)) {
2102
                if (!typeTextDesignations.endsWith(".")) {
2103
                	typeTextDesignations = typeTextDesignations + ".";
2104
                }
2105
                csvLine[table.getIndex(WordClassificationExportTable.TYPE_CACHE)] = typeTextDesignations;
2106

    
2107
            } else {
2108
                csvLine[table.getIndex(WordClassificationExportTable.TYPE_CACHE)] = "";
2109
            }
2110
            state.getProcessor().put(table, String.valueOf(group.getId()), csvLine);
2111
        } catch (Exception e) {
2112
            state.getResult().addException(e, "An unexpected error occurred when handling homotypic group "
2113
                    + cdmBaseStr(group) + ": " + e.getMessage());
2114
        }
2115
    }
2116

    
2117
    private String createTypeDesignationString(List<TaggedText> list, boolean isHomotypicGroup, boolean isSpecimenTypeDesignation) {
2118
        StringBuffer homotypicalGroupTypeDesignationString = new StringBuffer();
2119

    
2120
        for (TaggedText text : list) {
2121
            if (text == null || text.getText() == null){
2122
                continue;  //just in case
2123
            }
2124
            if ((text.getText().equalsIgnoreCase("Type:")  //should not happen anymore
2125
                    || text.getText().equalsIgnoreCase("Nametype:")  //should not happen anymore
2126
                    || (text.getType().equals(TagEnum.name) && !isHomotypicGroup))) {
2127
                // do nothing
2128
            }else if (text.getType().equals(TagEnum.reference)) {
2129
                homotypicalGroupTypeDesignationString.append(text.getText());
2130
            }else if (text.getType().equals(TagEnum.name)){
2131
                if (!isSpecimenTypeDesignation){
2132
                    homotypicalGroupTypeDesignationString
2133
                        .append("<i>"+text.getText()+"</i> ");
2134
                }
2135
            }else if (text.getType().equals(TagEnum.typeDesignation) ) {
2136
                if(isSpecimenTypeDesignation){
2137
                    homotypicalGroupTypeDesignationString
2138
                        .append(text.getText().replace(").", "").replace("(", "").replace(")", ""));
2139
                }else{
2140
                    homotypicalGroupTypeDesignationString
2141
                        .append(text.getText());
2142
                }
2143

    
2144
            } else {
2145
                homotypicalGroupTypeDesignationString.append(text.getText());
2146
            }
2147
        }
2148

    
2149
        String typeDesignations = homotypicalGroupTypeDesignationString.toString();
2150
        typeDesignations = typeDesignations.trim();
2151

    
2152
        if (typeDesignations.endsWith(";")){
2153
            typeDesignations = typeDesignations.substring(0, typeDesignations.length()-1);
2154
        }
2155
        typeDesignations += ".";
2156
        typeDesignations = typeDesignations.replace("..", ".");
2157
        typeDesignations = typeDesignations.replace(". .", ".");
2158
        typeDesignations = typeDesignations.replace("; \u2261", " \u2261 ");
2159

    
2160
        if (typeDesignations.trim().equals(".")) {
2161
            typeDesignations = null;
2162
        }
2163

    
2164
        return typeDesignations;
2165
    }
2166

    
2167
    private String getTropicosTitleCache(WordClassificationExportState state, TaxonName name) {
2168
        try {
2169
            String basionymStart = "(";
2170
            String basionymEnd = ") ";
2171
            String exAuthorSeperator = " ex ";
2172
            TeamOrPersonBase<?> combinationAuthor = name.getCombinationAuthorship();
2173
            TeamOrPersonBase<?> exCombinationAuthor = name.getExCombinationAuthorship();
2174
            TeamOrPersonBase<?> basionymAuthor = name.getBasionymAuthorship();
2175
            TeamOrPersonBase<?> exBasionymAuthor = name.getExBasionymAuthorship();
2176

    
2177
            String combinationAuthorString = "";
2178
            if (combinationAuthor != null) {
2179
                combinationAuthor = HibernateProxyHelper.deproxy(combinationAuthor);
2180
                if (combinationAuthor instanceof Team) {
2181
                    combinationAuthorString = createTropicosTeamTitle(combinationAuthor);
2182
                } else {
2183
                    Person person = HibernateProxyHelper.deproxy(combinationAuthor, Person.class);
2184
                    combinationAuthorString = createTropicosAuthorString(person);
2185
                }
2186
            }
2187
            String exCombinationAuthorString = "";
2188
            if (exCombinationAuthor != null) {
2189
                exCombinationAuthor = HibernateProxyHelper.deproxy(exCombinationAuthor);
2190
                if (exCombinationAuthor instanceof Team) {
2191
                    exCombinationAuthorString = createTropicosTeamTitle(exCombinationAuthor);
2192
                } else {
2193
                    Person person = HibernateProxyHelper.deproxy(exCombinationAuthor, Person.class);
2194
                    exCombinationAuthorString = createTropicosAuthorString(person);
2195
                }
2196
            }
2197

    
2198
            String basionymAuthorString = "";
2199
            if (basionymAuthor != null) {
2200
                basionymAuthor = HibernateProxyHelper.deproxy(basionymAuthor);
2201
                if (basionymAuthor instanceof Team) {
2202
                    basionymAuthorString = createTropicosTeamTitle(basionymAuthor);
2203
                } else {
2204
                    Person person = HibernateProxyHelper.deproxy(basionymAuthor, Person.class);
2205
                    basionymAuthorString = createTropicosAuthorString(person);
2206
                }
2207
            }
2208

    
2209
            String exBasionymAuthorString = "";
2210

    
2211
            if (exBasionymAuthor != null) {
2212
                exBasionymAuthor = HibernateProxyHelper.deproxy(exBasionymAuthor);
2213
                if (exBasionymAuthor instanceof Team) {
2214
                    exBasionymAuthorString = createTropicosTeamTitle(exBasionymAuthor);
2215

    
2216
                } else {
2217
                    Person person = HibernateProxyHelper.deproxy(exBasionymAuthor, Person.class);
2218
                    exBasionymAuthorString = createTropicosAuthorString(person);
2219
                }
2220
            }
2221
            String completeAuthorString = name.getNameCache() + " ";
2222

    
2223
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString)
2224
                    || !CdmUtils.isBlank(basionymAuthorString)) ? basionymStart : "";
2225
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString))
2226
                    ? (CdmUtils.Nz(exBasionymAuthorString) + exAuthorSeperator) : "";
2227
            completeAuthorString += (!CdmUtils.isBlank(basionymAuthorString)) ? CdmUtils.Nz(basionymAuthorString) : "";
2228
            completeAuthorString += (!CdmUtils.isBlank(exBasionymAuthorString)
2229
                    || !CdmUtils.isBlank(basionymAuthorString)) ? basionymEnd : "";
2230
            completeAuthorString += (!CdmUtils.isBlank(exCombinationAuthorString))
2231
                    ? (CdmUtils.Nz(exCombinationAuthorString) + exAuthorSeperator) : "";
2232
            completeAuthorString += (!CdmUtils.isBlank(combinationAuthorString)) ? CdmUtils.Nz(combinationAuthorString)
2233
                    : "";
2234

    
2235
            return completeAuthorString;
2236
        } catch (Exception e) {
2237
            state.getResult().addException(e, "An unexpected error occurred when handling tropicos title cache for "
2238
                    + cdmBaseStr(name) + ": " + e.getMessage());
2239
            return null;
2240
        }
2241
    }
2242

    
2243
    private String createTropicosTeamTitle(TeamOrPersonBase<?> combinationAuthor) {
2244
        String combinationAuthorString;
2245
        Team team = HibernateProxyHelper.deproxy(combinationAuthor, Team.class);
2246
        Team tempTeam = Team.NewInstance();
2247
        for (Person teamMember : team.getTeamMembers()) {
2248
            combinationAuthorString = createTropicosAuthorString(teamMember);
2249
            Person tempPerson = Person.NewTitledInstance(combinationAuthorString);
2250
            tempTeam.addTeamMember(tempPerson);
2251
        }
2252
        combinationAuthorString = tempTeam.generateTitle();
2253
        return combinationAuthorString;
2254
    }
2255

    
2256
    private String createTropicosAuthorString(Person teamMember) {
2257
        String nomAuthorString = "";
2258
        String[] splittedAuthorString = null;
2259
        if (teamMember == null) {
2260
            return nomAuthorString;
2261
        }
2262

    
2263
        if (teamMember.getGivenName() != null) {
2264
            String givenNameString = teamMember.getGivenName().replaceAll("\\.", "\\. ");
2265
            splittedAuthorString = givenNameString.split("\\s");
2266
            for (String split : splittedAuthorString) {
2267
                if (!StringUtils.isBlank(split)) {
2268
                    nomAuthorString += split.substring(0, 1);
2269
                    nomAuthorString += ".";
2270
                }
2271
            }
2272
        }
2273
        if (teamMember.getFamilyName() != null) {
2274
            String familyNameString = teamMember.getFamilyName().replaceAll("\\.", "\\. ");
2275
            splittedAuthorString = familyNameString.split("\\s");
2276
            for (String split : splittedAuthorString) {
2277
                nomAuthorString += " " + split;
2278
            }
2279
        }
2280
        if (isBlank(nomAuthorString.trim())) {
2281
            if (teamMember.getTitleCache() != null) {
2282
                String titleCacheString = teamMember.getTitleCache().replaceAll("\\.", "\\. ");
2283
                splittedAuthorString = titleCacheString.split("\\s");
2284
            } else {
2285
                splittedAuthorString = new String[0];
2286
            }
2287

    
2288
            int index = 0;
2289
            for (String split : splittedAuthorString) {
2290
                if (index < splittedAuthorString.length - 1 && (split.length() == 1 || split.endsWith("."))) {
2291
                    nomAuthorString += split;
2292
                } else {
2293
                    nomAuthorString = nomAuthorString + " " + split;
2294
                }
2295
                index++;
2296
            }
2297
        }
2298
        return nomAuthorString.trim();
2299
    }
2300

    
2301
    private void handleReference(WordClassificationExportState state, Reference reference) {
2302
        try {
2303
            state.addReferenceToStore(reference);
2304
            WordClassificationExportTable table = WordClassificationExportTable.REFERENCE;
2305
            reference = HibernateProxyHelper.deproxy(reference);
2306

    
2307
            handleIdentifier(state, reference);
2308
            String[] csvLine = new String[table.getSize()];
2309
            csvLine[table.getIndex(WordClassificationExportTable.REFERENCE_ID)] = getId(state, reference);
2310
            // TODO short citations correctly
2311
            String shortCitation = OriginalSourceFormatter.INSTANCE_WITH_YEAR_BRACKETS.format(reference, null); // Should be Author(year) like in Taxon.sec
2312
            csvLine[table.getIndex(WordClassificationExportTable.BIBLIO_SHORT_CITATION)] = shortCitation;
2313
            // TODO get preferred title
2314
            csvLine[table.getIndex(WordClassificationExportTable.REF_TITLE)] = reference.isProtectedTitleCache()
2315
                    ? reference.getTitleCache() : reference.getTitle();
2316
            csvLine[table.getIndex(WordClassificationExportTable.ABBREV_REF_TITLE)] = reference.isProtectedAbbrevTitleCache()
2317
                    ? reference.getAbbrevTitleCache() : reference.getAbbrevTitle();
2318
            csvLine[table.getIndex(WordClassificationExportTable.DATE_PUBLISHED)] = reference.getDatePublishedString();
2319
            // TBC
2320
            csvLine[table.getIndex(WordClassificationExportTable.EDITION)] = reference.getEdition();
2321
            csvLine[table.getIndex(WordClassificationExportTable.EDITOR)] = reference.getEditor();
2322
            csvLine[table.getIndex(WordClassificationExportTable.ISBN)] = reference.getIsbn();
2323
            csvLine[table.getIndex(WordClassificationExportTable.ISSN)] = reference.getIssn();
2324
            csvLine[table.getIndex(WordClassificationExportTable.ORGANISATION)] = reference.getOrganization();
2325
            csvLine[table.getIndex(WordClassificationExportTable.PAGES)] = reference.getPages();
2326
            csvLine[table.getIndex(WordClassificationExportTable.PLACE_PUBLISHED)] = reference.getPlacePublished();
2327
            csvLine[table.getIndex(WordClassificationExportTable.PUBLISHER)] = reference.getPublisher();
2328
            csvLine[table.getIndex(WordClassificationExportTable.REF_ABSTRACT)] = reference.getReferenceAbstract();
2329
            csvLine[table.getIndex(WordClassificationExportTable.SERIES_PART)] = reference.getSeriesPart();
2330
            csvLine[table.getIndex(WordClassificationExportTable.VOLUME)] = reference.getVolume();
2331
            csvLine[table.getIndex(WordClassificationExportTable.YEAR)] = reference.getYear();
2332

    
2333
            if (reference.getAuthorship() != null) {
2334
                csvLine[table.getIndex(WordClassificationExportTable.AUTHORSHIP_TITLE)] = createFullAuthorship(reference);
2335
                csvLine[table.getIndex(WordClassificationExportTable.AUTHOR_FK)] = getId(state, reference.getAuthorship());
2336
            }
2337

    
2338
            csvLine[table.getIndex(WordClassificationExportTable.IN_REFERENCE)] = getId(state, reference.getInReference());
2339
            if (reference.getInReference() != null
2340
                    && !state.getReferenceStore().contains(reference.getInReference().getUuid())) {
2341
                handleReference(state, reference.getInReference());
2342
            }
2343
            if (reference.getInstitution() != null) {
2344
                csvLine[table.getIndex(WordClassificationExportTable.INSTITUTION)] = reference.getInstitution().getTitleCache();
2345
            }
2346
            if (reference.getLsid() != null) {
2347
                csvLine[table.getIndex(WordClassificationExportTable.LSID)] = reference.getLsid().getLsid();
2348
            }
2349
            if (reference.getSchool() != null) {
2350
                csvLine[table.getIndex(WordClassificationExportTable.SCHOOL)] = reference.getSchool().getTitleCache();
2351
            }
2352
            if (reference.getUri() != null) {
2353
                csvLine[table.getIndex(WordClassificationExportTable.URI)] = reference.getUri().toString();
2354
            }
2355
            csvLine[table.getIndex(WordClassificationExportTable.REF_TYPE)] = reference.getType().getKey();
2356

    
2357
            state.getProcessor().put(table, reference, csvLine);
2358
        } catch (Exception e) {
2359
            state.getResult().addException(e, "An unexpected error occurred when handling reference "
2360
                    + cdmBaseStr(reference) + ": " + e.getMessage());
2361
        }
2362
    }
2363

    
2364
    private String createFullAuthorship(Reference reference) {
2365
        TeamOrPersonBase<?> authorship = reference.getAuthorship();
2366
        String fullAuthorship = "";
2367
        if (authorship == null) {
2368
            return null;
2369
        }
2370
        authorship = HibernateProxyHelper.deproxy(authorship);
2371
        if (authorship instanceof Person) {
2372
            fullAuthorship = ((Person) authorship).getTitleCache();
2373

    
2374
        } else if (authorship instanceof Team) {
2375

    
2376
            Team authorTeam = (Team)authorship;
2377
            fullAuthorship = authorTeam.cacheStrategy().getTitleCache(authorTeam);
2378
        }
2379
        return fullAuthorship;
2380
    }
2381

    
2382
    private void handleSpecimen(WordClassificationExportState state, SpecimenOrObservationBase<?> specimen) {
2383
        try {
2384
            state.addSpecimenToStore(specimen);
2385
            WordClassificationExportTable table = WordClassificationExportTable.SPECIMEN;
2386
            String specimenId = getId(state, specimen);
2387
            String[] csvLine = new String[table.getSize()];
2388

    
2389
            /*
2390
             * SpecimenCitation = “El Salvador, Municipio La Libertad, San
2391
             * Diego, El Amatal, 14.4.1993, González 159” [Auch ohne Punkt] ->
2392
             * FieldUnit TitleCache HerbariumAbbrev = “B” [wie gehabt]
2393
             * HerbariumCode
2394
             *
2395
             */
2396

    
2397
            csvLine[table.getIndex(WordClassificationExportTable.SPECIMEN_ID)] = specimenId;
2398
            csvLine[table.getIndex(WordClassificationExportTable.SPECIMEN_CITATION)] = specimen.getTitleCache();
2399
            Collection<FieldUnit> fieldUnits = this.getOccurrenceService().findFieldUnits(specimen.getUuid(), null);
2400
            if (fieldUnits.size() == 1) {
2401
                Iterator<FieldUnit> iterator = fieldUnits.iterator();
2402
                if (iterator.hasNext()){
2403
                    FieldUnit fieldUnit = iterator.next();
2404
                    csvLine[table.getIndex(WordClassificationExportTable.FIELDUNIT_CITATION)] = fieldUnit.getTitleCache();
2405
                }
2406
            }
2407
            if (specimen.isInstanceOf(DerivedUnit.class)){
2408
                DerivedUnit derivedUnit = (DerivedUnit) specimen;
2409
                if (!StringUtils.isBlank(derivedUnit.getBarcode())){
2410
                    csvLine[table.getIndex(WordClassificationExportTable.BARCODE)] = derivedUnit.getBarcode();
2411
                }
2412
                if (!StringUtils.isBlank(derivedUnit.getAccessionNumber())){
2413
                    csvLine[table.getIndex(WordClassificationExportTable.ACCESSION_NUMBER)] = derivedUnit.getAccessionNumber();
2414
                }
2415
                if (!StringUtils.isBlank(derivedUnit.getCatalogNumber())){
2416
                    csvLine[table.getIndex(WordClassificationExportTable.CATALOGUE_NUMBER)] = derivedUnit.getCatalogNumber();
2417
                }
2418
            }
2419

    
2420
            csvLine[table.getIndex(WordClassificationExportTable.PREFERREDSTABLE_ID)] = specimen.getPreferredStableUri() != null? specimen.getPreferredStableUri().toString(): null;
2421
            csvLine[table.getIndex(WordClassificationExportTable.SPECIMEN_IMAGE_URIS)] = extractMediaURIs(state,
2422
                    specimen.getDescriptions(), Feature.IMAGE());
2423
            if (specimen instanceof DerivedUnit) {
2424
                DerivedUnit derivedUnit = HibernateProxyHelper.deproxy(specimen, DerivedUnit.class);
2425
                if (derivedUnit.getCollection() != null) {
2426
                    csvLine[table.getIndex(WordClassificationExportTable.HERBARIUM_ABBREV)] = derivedUnit.getCollection()
2427
                            .getCode();
2428
                }
2429

    
2430
                if (specimen instanceof MediaSpecimen) {
2431
                    MediaSpecimen mediaSpecimen = (MediaSpecimen) specimen;
2432
                    Iterator<MediaRepresentation> it = mediaSpecimen.getMediaSpecimen().getRepresentations().iterator();
2433
                    String mediaUris = extractMediaUris(it);
2434
                    csvLine[table.getIndex(WordClassificationExportTable.MEDIA_SPECIMEN_URL)] = mediaUris;
2435

    
2436
                }
2437

    
2438
                if (derivedUnit.getDerivedFrom() != null) {
2439
                    for (SpecimenOrObservationBase<?> original : derivedUnit.getDerivedFrom().getOriginals()) {
2440
                        // TODO: What to do if there are more then one
2441
                        // FieldUnit??
2442
                        if (original instanceof FieldUnit) {
2443
                            FieldUnit fieldUnit = (FieldUnit) original;
2444
                            csvLine[table.getIndex(WordClassificationExportTable.COLLECTOR_NUMBER)] = fieldUnit.getFieldNumber();
2445

    
2446
                            GatheringEvent gathering = fieldUnit.getGatheringEvent();
2447
                            if (gathering != null) {
2448
                                if (gathering.getLocality() != null) {
2449
                                    csvLine[table.getIndex(WordClassificationExportTable.LOCALITY)] = gathering.getLocality()
2450
                                            .getText();
2451
                                }
2452
                                if (gathering.getCountry() != null) {
2453
                                    csvLine[table.getIndex(WordClassificationExportTable.COUNTRY)] = gathering.getCountry()
2454
                                            .getLabel();
2455
                                }
2456
                                csvLine[table.getIndex(WordClassificationExportTable.COLLECTOR_STRING)] = createCollectorString(
2457
                                        state, gathering, fieldUnit);
2458

    
2459
                                if (gathering.getGatheringDate() != null) {
2460
                                    csvLine[table.getIndex(WordClassificationExportTable.COLLECTION_DATE)] = gathering
2461
                                            .getGatheringDate().toString();
2462
                                }
2463
                                if (!gathering.getCollectingAreas().isEmpty()) {
2464
                                    int index = 0;
2465
                                    csvLine[table.getIndex(WordClassificationExportTable.FURTHER_AREAS)] = "0";
2466
                                    for (NamedArea area : gathering.getCollectingAreas()) {
2467
                                        if (index == 0) {
2468
                                            csvLine[table.getIndex(WordClassificationExportTable.AREA_CATEGORY1)] = area.getLevel() != null?area
2469
                                                    .getLevel().getLabel():"";
2470
                                            csvLine[table.getIndex(WordClassificationExportTable.AREA_NAME1)] = area.getLabel();
2471
                                        }
2472
                                        if (index == 1) {
2473
                                            csvLine[table.getIndex(WordClassificationExportTable.AREA_CATEGORY2)] = area.getLevel() != null?area
2474
                                                    .getLevel().getLabel():"";
2475
                                            csvLine[table.getIndex(WordClassificationExportTable.AREA_NAME2)] = area.getLabel();
2476
                                        }
2477
                                        if (index == 2) {
2478
                                            csvLine[table.getIndex(WordClassificationExportTable.AREA_CATEGORY3)] = area.getLevel() != null?area
2479
                                                    .getLevel().getLabel():"";
2480
                                            csvLine[table.getIndex(WordClassificationExportTable.AREA_NAME3)] = area.getLabel();
2481
                                        }
2482
                                        if (index == 3) {
2483
                                            csvLine[table.getIndex(WordClassificationExportTable.FURTHER_AREAS)] = "1";
2484
                                            break;
2485
                                        }
2486
                                        index++;
2487
                                    }
2488
                                }
2489
                            }
2490
                        }
2491
                    }
2492
                } else {
2493
                    state.getResult().addWarning("The specimen with uuid " + specimen.getUuid()
2494
                            + " is not an DerivedUnit.");
2495
                }
2496
            }
2497

    
2498
            state.getProcessor().put(table, specimen, csvLine);
2499
        } catch (Exception e) {
2500
            state.getResult().addException(e, "An unexpected error occurred when handling specimen "
2501
                    + cdmBaseStr(specimen) + ": " + e.getMessage());
2502
        }
2503
    }
2504

    
2505
    private String extractMediaUris(Iterator<MediaRepresentation> it) {
2506

    
2507
        String mediaUriString = "";
2508
        boolean first = true;
2509
        while (it.hasNext()) {
2510
            MediaRepresentation rep = it.next();
2511
            List<MediaRepresentationPart> parts = rep.getParts();
2512
            for (MediaRepresentationPart part : parts) {
2513
                if (first) {
2514
                    if (part.getUri() != null) {
2515
                        mediaUriString += part.getUri().toString();
2516
                        first = false;
2517
                    }
2518
                } else {
2519
                    if (part.getUri() != null) {
2520
                        mediaUriString += ", " + part.getUri().toString();
2521
                    }
2522
                }
2523
            }
2524
        }
2525

    
2526
        return mediaUriString;
2527
    }
2528

    
2529
    private String extractLinkUris(Iterator<ExternalLink> it) {
2530

    
2531
        String linkUriString = "";
2532
        boolean first = true;
2533
        while (it.hasNext()) {
2534
            ExternalLink link = it.next();
2535
            if (first) {
2536
                if (link.getUri() != null) {
2537
                    linkUriString += link.getUri().toString();
2538
                    first = false;
2539
                }
2540
            } else {
2541
                if (link.getUri() != null) {
2542
                    linkUriString += ", " + link.getUri().toString();
2543
                }
2544
            }
2545
        }
2546
        return linkUriString;
2547
    }
2548

    
2549
    private String createCollectorString(WordClassificationExportState state, GatheringEvent gathering, FieldUnit fieldUnit) {
2550
        try {
2551
            String collectorString = "";
2552
            AgentBase<?> collectorA = CdmBase.deproxy(gathering.getCollector());
2553
            if (gathering.getCollector() != null) {
2554
                if (collectorA instanceof TeamOrPersonBase && state.getConfig().isHighLightPrimaryCollector()) {
2555

    
2556
                    Person primaryCollector = fieldUnit.getPrimaryCollector();
2557
                    if (collectorA instanceof Team) {
2558
                        Team collectorTeam = (Team) collectorA;
2559
                        boolean isFirst = true;
2560
                        for (Person member : collectorTeam.getTeamMembers()) {
2561
                            if (!isFirst) {
2562
                                collectorString += "; ";
2563
                            }
2564
                            if (member.equals(primaryCollector)) {
2565
                                // highlight
2566
                                collectorString += "<b>" + member.getTitleCache() + "</b>";
2567
                            } else {
2568
                                collectorString += member.getTitleCache();
2569
                            }
2570
                        }
2571
                    }
2572
                } else {
2573
                    collectorString = collectorA.getTitleCache();
2574
                }
2575
            }
2576
            return collectorString;
2577
        } catch (Exception e) {
2578
            state.getResult().addException(e, "An unexpected error occurred when creating collector string for "
2579
                    + cdmBaseStr(fieldUnit) + ": " + e.getMessage());
2580
            return "";
2581
        }
2582
    }
2583

    
2584
    /**
2585
     * Returns a string representation of the {@link CdmBase cdmBase} object for
2586
     * result messages.
2587
     */
2588
    private String cdmBaseStr(CdmBase cdmBase) {
2589
        if (cdmBase == null) {
2590
            return "-no object available-";
2591
        } else {
2592
            return cdmBase.getClass().getSimpleName() + ": " + cdmBase.getUuid();
2593
        }
2594
    }
2595

    
2596
    @Override
2597
    protected boolean doCheck(WordClassificationExportState state) {
2598
        return false;
2599
    }
2600

    
2601
    @Override
2602
    protected boolean isIgnore(WordClassificationExportState state) {
2603
        return false;
2604
    }
2605

    
2606
}
(1-1/5)