Project

General

Profile

Download (67.7 KB) Statistics
| Branch: | Revision:
1
/**
2
 * Copyright (C) 2007 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

    
10
package eu.etaxonomy.cdm.io.cuba;
11

    
12
import java.util.ArrayList;
13
import java.util.Arrays;
14
import java.util.HashMap;
15
import java.util.HashSet;
16
import java.util.List;
17
import java.util.Set;
18
import java.util.UUID;
19
import java.util.regex.Matcher;
20
import java.util.regex.Pattern;
21

    
22
import org.apache.commons.lang.StringUtils;
23
import org.apache.log4j.Logger;
24
import org.springframework.stereotype.Component;
25

    
26
import eu.etaxonomy.cdm.common.CdmUtils;
27
import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
28
import eu.etaxonomy.cdm.io.excel.common.ExcelImporterBase;
29
import eu.etaxonomy.cdm.model.agent.Person;
30
import eu.etaxonomy.cdm.model.agent.Team;
31
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
32
import eu.etaxonomy.cdm.model.common.Annotation;
33
import eu.etaxonomy.cdm.model.common.AnnotationType;
34
import eu.etaxonomy.cdm.model.common.CdmBase;
35
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
36
import eu.etaxonomy.cdm.model.common.Language;
37
import eu.etaxonomy.cdm.model.common.OriginalSourceType;
38
import eu.etaxonomy.cdm.model.common.Representation;
39
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
40
import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
41
import eu.etaxonomy.cdm.model.description.Distribution;
42
import eu.etaxonomy.cdm.model.description.Feature;
43
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
44
import eu.etaxonomy.cdm.model.description.TaxonDescription;
45
import eu.etaxonomy.cdm.model.description.TaxonInteraction;
46
import eu.etaxonomy.cdm.model.description.TextData;
47
import eu.etaxonomy.cdm.model.location.NamedArea;
48
import eu.etaxonomy.cdm.model.name.BotanicalName;
49
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
50
import eu.etaxonomy.cdm.model.name.NameRelationship;
51
import eu.etaxonomy.cdm.model.name.NameRelationshipType;
52
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
53
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
54
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
55
import eu.etaxonomy.cdm.model.name.Rank;
56
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
57
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
58
import eu.etaxonomy.cdm.model.reference.Reference;
59
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
60
import eu.etaxonomy.cdm.model.taxon.Classification;
61
import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
62
import eu.etaxonomy.cdm.model.taxon.Synonym;
63
import eu.etaxonomy.cdm.model.taxon.SynonymType;
64
import eu.etaxonomy.cdm.model.taxon.Taxon;
65
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
66
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
67
import eu.etaxonomy.cdm.strategy.parser.INonViralNameParser;
68
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
69

    
70
/**
71
 * @author a.mueller
72
 * @created 05.01.2016
73
 */
74

    
75
@Component
76
public class CubaExcelImport extends ExcelImporterBase<CubaImportState> {
77
    private static final long serialVersionUID = -747486709409732371L;
78
    private static final Logger logger = Logger.getLogger(CubaExcelImport.class);
79

    
80
    private static final String HOMONYM_MARKER = "\\s+homon.?$";
81
    private static final String DOUBTFUL_MARKER = "^\\?\\s?";
82

    
83

    
84
    private static UUID rootUuid = UUID.fromString("206d42e4-ac32-4f20-a093-14826014e667");
85
    private static UUID plantaeUuid = UUID.fromString("139e7314-dd19-4286-a01d-8cc94ef77a09");
86

    
87
    private static INonViralNameParser<?> nameParser = NonViralNameParserImpl.NewInstance();
88
    private static NomenclaturalCode nc = NomenclaturalCode.ICNAFP;
89

    
90
    private  static List<String> expectedKeys= Arrays.asList(new String[]{
91
            "Fam. default","Fam. FRC","Fam. A&S","Fam. FC",
92
            "Taxón","(Notas)","Syn.","End","Ind","Ind? D","Nat","Dud P","Adv","Cult C","CuW","PR PR*","Art","Hab(*)","May","Mat","IJ","CuC","VC","Ci","SS","CA","Cam","LT","CuE","Gr","Ho","SC","Gu","Esp","Ja","PR","Men","Bah","Cay","AmN","AmC","AmS","VM"});
93

    
94
	@Override
95
    protected void analyzeRecord(HashMap<String, String> record, CubaImportState state) {
96
	    //we do everything in firstPass here
97
    	return;
98
    }
99

    
100

    
101
    /**
102
     * @param record
103
     * @param state
104
     * @param taxon
105
     */
106
    private void makeCubanDistribution(HashMap<String, String> record, CubaImportState state) {
107
        try {
108
            NamedArea cuba = getNamedArea(state, state.getTransformer().getNamedAreaUuid("Cu"), null, null, null, null, null);
109
            TaxonDescription desc = getTaxonDescription(state.getCurrentTaxon(), false, true);
110
            List<PresenceAbsenceTerm> statuss =  makeCubanStatuss(record, state);
111
            for (PresenceAbsenceTerm status : statuss){
112
                Distribution distribution = Distribution.NewInstance(cuba, status);
113
                desc.addElement(distribution);
114
                distribution.addSource(makeDescriptionSource(state));
115
            }
116
        } catch (UndefinedTransformerMethodException e) {
117
            e.printStackTrace();
118
        }
119
    }
120

    
121

    
122
    /**
123
     * @param record
124
     * @param state
125
     * @return
126
     * @throws UndefinedTransformerMethodException
127
     */
128
    private List<PresenceAbsenceTerm> makeCubanStatuss(HashMap<String, String> record, CubaImportState state) throws UndefinedTransformerMethodException {
129
        PresenceAbsenceTerm highestStatus = null;
130

    
131
        String line = state.getCurrentLine() + ": ";
132
        List<PresenceAbsenceTerm> result = new ArrayList<>();
133

    
134
        String endemicStr = getValue(record, "End");
135
        String indigenousStr = getValue(record, "Ind");
136
        String indigenousDoubtStr = getValue(record, "Ind? D");
137
        String naturalisedStr = getValue(record, "Nat");
138
        String dudStr = getValue(record, "Dud P");
139
        String advStr = getValue(record, "Adv");
140
        String cultStr = getValue(record, "Cult C");
141

    
142
        state.setEndemic(false);
143

    
144
        if (endemicStr != null){
145
            if(endemicStr.equals("+")){
146
                PresenceAbsenceTerm endemicState = state.getTransformer().getPresenceTermByKey("E");
147
                result.add(endemicState);
148
                highestStatus = endemicState;
149
                state.setEndemic(true);
150
            }else if(isMinus(endemicStr)){
151
                UUID endemicUuid = state.getTransformer().getPresenceTermUuid("-E");
152
                PresenceAbsenceTerm endemicState = getPresenceTerm(state, endemicUuid, null, null, null, false);
153
                result.add(endemicState);
154
                checkAbsentHighestState(highestStatus, line, "endemic", false);
155
            }else if(endemicStr.equals("?")){
156
                UUID endemicDoubtfulUuid = state.getTransformer().getPresenceTermUuid("?E");
157
                PresenceAbsenceTerm endemicState = getPresenceTerm(state, endemicDoubtfulUuid, null, null, null, false);
158
                result.add(endemicState);
159
                checkAbsentHighestState(highestStatus, line, "endemic", false);
160
            }else{
161
                logger.warn(line + "Endemic not recognized: " + endemicStr);
162
            }
163
        }
164
        if (indigenousStr != null){
165
            if(indigenousStr.equals("+")){
166
                PresenceAbsenceTerm indigenousState = state.getTransformer().getPresenceTermByKey("Ind.");
167
//                PresenceAbsenceTerm indigenousState = getPresenceTerm(state, indigenousUuid, null, null, null, false);
168
                result.add(indigenousState);
169
                highestStatus = highestStatus != null ? highestStatus : indigenousState;
170
            }else if(isMinus(indigenousStr)){
171
                PresenceAbsenceTerm indigenousState = state.getTransformer().getPresenceTermByKey("-Ind.");
172
                result.add(indigenousState);
173
                checkAbsentHighestState(highestStatus, line, "indigenous", false);
174
            }else if(indigenousStr.equals("?")){
175
                PresenceAbsenceTerm indigenousDoubtState = state.getTransformer().getPresenceTermByKey("?Ind.");
176
//                PresenceAbsenceTerm indigenousDoubtState = getPresenceTerm(state, indigenousDoubtUuid, null, null, null, false);
177
                result.add(indigenousDoubtState);
178
                checkAbsentHighestState(highestStatus, line, "indigenous", true);
179
            }else{
180
                logger.warn(line + "Indigenous not recognized: " + indigenousStr);
181
            }
182
        }
183
        if(indigenousDoubtStr != null){
184
            if(indigenousDoubtStr.equals("D")){
185
                PresenceAbsenceTerm doubtIndigenousState = state.getTransformer().getPresenceTermByKey("Ind.?");
186
//                PresenceAbsenceTerm doubtIndigenousState = getPresenceTerm(state, doubtIndigenousUuid, null, null, null, false);
187
                result.add(doubtIndigenousState);
188
                highestStatus = highestStatus != null ? highestStatus : doubtIndigenousState;
189
            }else if(isMinus(indigenousDoubtStr)){
190
                UUID doubtIndigenousErrorUuid = state.getTransformer().getPresenceTermUuid("-Ind.?");
191
                PresenceAbsenceTerm doubtIndigenousErrorState = getPresenceTerm(state, doubtIndigenousErrorUuid, null, null, null, false);
192
                result.add(doubtIndigenousErrorState);
193
                checkAbsentHighestState(highestStatus, line, "doubtfully indigenous", true);
194
            }else{
195
                logger.warn(line + "doubtfully indigenous not recognized: " + indigenousDoubtStr);
196
            }
197
        }
198
        if(naturalisedStr != null){
199
            if(naturalisedStr.equals("N")){
200
                PresenceAbsenceTerm haturalizedState = state.getTransformer().getPresenceTermByKey("Nat.");
201
                result.add(haturalizedState);
202
                highestStatus = highestStatus != null ? highestStatus : haturalizedState;
203
            }else if(isMinus(naturalisedStr)){
204
                UUID naturalisedErrorUuid = state.getTransformer().getPresenceTermUuid("-Nat.");
205
                PresenceAbsenceTerm naturalisedErrorState = getPresenceTerm(state, naturalisedErrorUuid, null, null, null, false);
206
                result.add(naturalisedErrorState);
207
                checkAbsentHighestState(highestStatus, line, "naturalized", false);
208
            }else if(naturalisedStr.equals("?")){
209
                UUID naturalisedDoubtUuid = state.getTransformer().getPresenceTermUuid("?Nat.");
210
                PresenceAbsenceTerm naturalisedDoubtState = getPresenceTerm(state, naturalisedDoubtUuid, null, null, null, false);
211
                result.add(naturalisedDoubtState);
212
                checkAbsentHighestState(highestStatus, line, "naturalized", true);
213
            }else{
214
                logger.warn(line + "Naturalized not recognized: " + naturalisedStr);
215
            }
216
        }
217
        if(dudStr != null){
218
            if(dudStr.equals("P")){
219
                UUID dudUuid = state.getTransformer().getPresenceTermUuid("Dud.");
220
                PresenceAbsenceTerm dudState = getPresenceTerm(state, dudUuid, null, null, null, false);
221
                result.add(dudState);
222
                highestStatus = highestStatus != null ? highestStatus : dudState;
223
            }else if(isMinus(dudStr)){
224
                UUID nonNativeErrorUuid = state.getTransformer().getPresenceTermUuid("-Dud.");
225
                PresenceAbsenceTerm nonNativeErrorState = getPresenceTerm(state, nonNativeErrorUuid, null, null, null, false);
226
                result.add(nonNativeErrorState);
227
                checkAbsentHighestState(highestStatus, line, "non-native and doubtfully naturalised", false);
228
            }else if(dudStr.equals("?")){
229
                UUID naturalisedDoubtUuid = state.getTransformer().getPresenceTermUuid("?Dud.");
230
                PresenceAbsenceTerm naturalisedDoubtState = getPresenceTerm(state, naturalisedDoubtUuid, null, null, null, false);
231
                result.add(naturalisedDoubtState);
232
                checkAbsentHighestState(highestStatus, line, "non-native and doubtfully naturalised", true);
233
            }else{
234
                logger.warn(line + "non-native and doubtfully naturalised not recognized: " + dudStr);
235
            }
236
        }
237
        if(advStr != null){
238
            if(advStr.equals("A")){
239
                PresenceAbsenceTerm advState = state.getTransformer().getPresenceTermByKey("Adv.");
240
//                PresenceAbsenceTerm advState = getPresenceTerm(state, advUuid, null, null, null, false);
241
                result.add(advState);
242
                highestStatus = highestStatus != null ? highestStatus : advState;
243
            }else if(isMinus(advStr)){
244
                UUID advUuid = state.getTransformer().getPresenceTermUuid("-Adv.");
245
                PresenceAbsenceTerm advState = getPresenceTerm(state, advUuid, null, null, null, false);
246
                result.add(advState);
247
                checkAbsentHighestState(highestStatus, line, "adventive", false);
248
            }else if(advStr.equals("(A)")){
249
                UUID rareCasualUuid = state.getTransformer().getPresenceTermUuid("(A)");
250
                PresenceAbsenceTerm rareCasual = getPresenceTerm(state, rareCasualUuid, null, null, null, false);
251
                result.add(rareCasual);
252
            }else{
253
                logger.warn(line + "'adventive (casual) alien' not recognized: " + advStr);
254
            }
255
        }else if(cultStr != null){
256
            if (! (cultStr.matches("(C|\\(C\\)|\\?|–)"))){
257
                logger.warn("'cultivated' not recognized: " + cultStr);
258
            }else if(cultStr.equals("C")){
259
                PresenceAbsenceTerm cultivatedState = state.getTransformer().getPresenceTermByKey("Cult.");
260
                result.add(cultivatedState);
261
                highestStatus = highestStatus != null ? highestStatus : cultivatedState;
262
            }else if(cultStr.equals("?")){
263
                PresenceAbsenceTerm cultivatedState = state.getTransformer().getPresenceTermByKey("?Cult.");
264
                result.add(cultivatedState);
265
                checkAbsentHighestState(highestStatus, line, "cultivated", true);
266
            }else if(cultStr.equals("(C)")){
267
                UUID ocassualCultUuid = state.getTransformer().getPresenceTermUuid("(C)");
268
                PresenceAbsenceTerm cultivatedState = getPresenceTerm(state, ocassualCultUuid, null, null, null, false);
269
                result.add(cultivatedState);
270
            }else if(isMinus(cultStr)){
271
                PresenceAbsenceTerm cultivatedState = state.getTransformer().getPresenceTermByKey("-Cult.");
272
                result.add(cultivatedState);
273
                checkAbsentHighestState(highestStatus, line, "cultivated", false);
274
            }else{
275
                logger.warn(line + "'cultivated' not recognized: " + cultStr);
276
            }
277
        }
278
        state.setHighestStatusForTaxon(highestStatus);
279
        return result;
280
    }
281

    
282

    
283
    /**
284
     * @param highestStatus
285
     * @param line
286
     */
287
    private void checkAbsentHighestState(PresenceAbsenceTerm highestStatus, String line, String stateLabel, boolean doubtful) {
288
        //can be removed, highest status is not used anymore
289
        if (highestStatus == null){
290
            String absentStr = doubtful ? "doubtful" : "absent";
291
            logger.info(line + "Highest cuban state is " + absentStr + " " + stateLabel);
292
        }
293

    
294
    }
295

    
296

    
297
    /**
298
     * @param indigenousStr
299
     * @return
300
     */
301
    private boolean isMinus(String str) {
302
        return str.equals("-") || str.equals("–") || str.equals("‒");
303
    }
304

    
305

    
306
    /**
307
     * @param indigenousStr
308
     * @return
309
     */
310
    private boolean checkPlusMinusDoubt(String str) {
311
        return str.equals("+") || isMinus(str)|| str.equals("?");
312
    }
313

    
314

    
315
    /**
316
     * @param indigenousStr
317
     * @param indigenousDoubtStr
318
     * @param naturalisedStr
319
     * @param dudStr
320
     * @param advStr
321
     * @param cultStr
322
     */
323
    private boolean checkAllNull(String ... others) {
324
        for (String other : others){
325
            if (other != null){
326
                return false;
327
            }
328
        }
329
        return true;
330
    }
331

    
332

    
333
    private static final String acceptedRegExStr = "\\(([^\\[\\]“”]{6,})\\)";
334
//    String heterotypicRegExStr2 = "([^\\(]{5,}" +"(\\(.+\\))?" + "[^\\)\\(]{2,})" +
335
//                    + "(\\((.{6,})\\))?";
336
    private static final String heterotypicRegExStr = "([^\\(\\[\\]“”]{5,})"
337
                                                     +"(\\((.{6,})\\))?";
338
    private static final String heterotypicRegExStr_TEST = "([^\\(]{5,}" +"(\\(.+\\))?" + "[^\\)\\(]{2,})"
339
            +"(\\((.{6,})\\))?";
340
    private static final String auctRegExStr = "auct\\."
341
            +"((\\sFC(\\-S)?(\\s&\\sA&S)?)|(\\sA&S)|\\sSagra|\\sCombs|\\sBritton|\\sGriseb\\.(\\sFC-S|\\sA&S)?|\\sWright"
342
            + "|\\sHammer|\\sEngl\\.||\\sMaza|\\sMiers|\\sRoig|\\sBorhidi|\\sFRC|\\sCoL"
343
            + "|\\sAckerman|\\sMújica|\\sDíaz|\\sUrb\\.)?(\\s+p\\.\\s*p\\.)?";
344

    
345

    
346
    private static final String missapliedRegExStr = "(\\?\\s)?“(.*{5,})”\\s+(" + auctRegExStr + "|sensu\\s+.{2,})";
347
    private static final String sphalmRegExStr = "“(.*{5,})”\\s+((FC-S|A&S)\\s)?sphalm\\.(\\s(FC(-S)?|A&S|inval\\.))?";
348
    private static final String nomInvalRegExStr = "“(.*{5,})”\\s+nom\\.\\s+inval\\.(\\s(West|Moldenke|FC|Jacq.))?";
349
    private static final String homonymRegExStr = "\\s*(\\[.*\\])*\\s*";
350

    
351
    private static final Pattern acceptedRegEx = Pattern.compile(acceptedRegExStr + homonymRegExStr);
352
    private static final Pattern heterotypicRegEx = Pattern.compile(heterotypicRegExStr + homonymRegExStr);
353
    private static final Pattern missapliedRegEx = Pattern.compile(missapliedRegExStr);
354
    private static final Pattern nomInvalRegEx = Pattern.compile(nomInvalRegExStr);
355
    private static final Pattern sphalmRegEx = Pattern.compile(sphalmRegExStr);
356

    
357
    /**
358
     * @param record
359
     * @param state
360
     * @param taxon
361
     */
362
    private void makeSynonyms(HashMap<String, String> record, CubaImportState state, boolean isFirstSynonym) {
363
//        boolean forAccepted = true;
364
        String synonymStr = record.get("Syn.");
365
        String line = state.getCurrentLine() + ": ";
366

    
367

    
368
        if (synonymStr == null){
369
            //TODO test that this is not a synonym only line
370
            return;
371
        }
372

    
373
        if (state.getCurrentTaxon() == null){
374
            logger.error(line + "Current taxon is null for synonym");
375
            return;
376
        }
377

    
378

    
379
        synonymStr = synonymStr.trim();
380
        synonymStr = synonymStr.replace("[taxon]", "[infraspec.]");
381

    
382
//        String heterotypicRegExStr = "([^\\(]{5,}(\\(.+\\))?[^\\)\\(]{2,})(\\((.{6,})\\))?";
383
//        String heterotypicRegExStr = "([^\\(]{5,})(\\((.{6,})\\))?";
384

    
385
//        Pattern heterotypicRegEx = Pattern.compile(heterotypicRegExStr + homonymRegExStr);
386

    
387

    
388
        Matcher missapliedMatcher = missapliedRegEx.matcher(synonymStr);
389
        Matcher nomInvalMatcher = nomInvalRegEx.matcher(synonymStr);
390
        Matcher acceptedMatcher = acceptedRegEx.matcher(synonymStr);
391
        Matcher heterotypicMatcher = heterotypicRegEx.matcher(synonymStr);
392
        Matcher sphalmMatcher = sphalmRegEx.matcher(synonymStr);
393

    
394
        List<BotanicalName> homonyms = new ArrayList<>();
395
        if (missapliedMatcher.matches()){
396
            boolean doubtful = missapliedMatcher.group(1) != null;
397
            String firstPart = missapliedMatcher.group(2);
398
            BotanicalName name = (BotanicalName)nameParser.parseSimpleName(firstPart, state.getConfig().getNomenclaturalCode(), Rank.SPECIES());
399
            name.addSource(makeOriginalSource(state));
400

    
401
            String secondPart = missapliedMatcher.group(3);
402
            Taxon misappliedNameTaxon = Taxon.NewInstance(name, null);
403
            misappliedNameTaxon.addSource(makeOriginalSource(state));
404
            misappliedNameTaxon.setDoubtful(doubtful);
405
            if (secondPart.startsWith("sensu")){
406
                secondPart = secondPart.substring(5).trim();
407
                if (secondPart.contains(" ")){
408
                    logger.warn(line + "CHECK: Second part contains more than 1 word. Check if this is correct: " + secondPart);
409
                }
410
                Reference sensu = ReferenceFactory.newGeneric();
411
                Team team = Team.NewTitledInstance(secondPart, null);
412
                sensu.setAuthorship(team);
413
                misappliedNameTaxon.setSec(sensu);
414
            }else if (secondPart.matches(auctRegExStr)){
415
                secondPart = secondPart.replace("p. p.", "p.p.");
416
                misappliedNameTaxon.setAppendedPhrase(secondPart);
417
            }else{
418
                logger.warn(line + "Misapplied second part not recognized: " + secondPart);
419
            }
420
            //TODO
421
            Reference relRef = null;
422
            state.getCurrentTaxon().addMisappliedName(misappliedNameTaxon, relRef, null);
423
        }else if (nomInvalMatcher.matches()){
424
            String firstPart = nomInvalMatcher.group(1);
425
            String afterInval = nomInvalMatcher.group(2);
426
            if (StringUtils.isNotBlank(afterInval)){
427
                logger.warn(state.getCurrentLine() + ": After inval to be implemented: " + afterInval);
428
            }
429
            BotanicalName name = (BotanicalName)nameParser.parseSimpleName(firstPart, state.getConfig().getNomenclaturalCode(), Rank.SPECIES());
430
            name.addSource(makeOriginalSource(state));
431
            NomenclaturalStatus status = NomenclaturalStatus.NewInstance( NomenclaturalStatusType.INVALID());
432
            name.addStatus(status);
433
            Synonym syn = state.getCurrentTaxon().addSynonymName(name, SynonymType.SYNONYM_OF());
434
            syn.addSource(makeOriginalSource(state));
435
        }else if (sphalmMatcher.matches()){
436
            String firstPart = sphalmMatcher.group(1);
437
            String sphalmPart = synonymStr.replace(firstPart, "").replace("“","").replace("”","").trim();
438
            BotanicalName name = (BotanicalName)nameParser.parseSimpleName(firstPart, state.getConfig().getNomenclaturalCode(), Rank.SPECIES());
439
//            NomenclaturalStatus status = NomenclaturalStatus.NewInstance( NomenclaturalStatusType.INVALID());
440
//            name.addStatus(status);
441
            name.addSource(makeOriginalSource(state));
442
            Synonym syn = state.getCurrentTaxon().addSynonymName(name, SynonymType.SYNONYM_OF());
443
            syn.setAppendedPhrase(sphalmPart);
444
            syn.setSec(null);
445
            syn.addSource(makeOriginalSource(state));
446
        }else if (acceptedMatcher.matches()){
447
            String firstPart = acceptedMatcher.group(1);
448
            String homonymPart = acceptedMatcher.groupCount() < 2 ? null : acceptedMatcher.group(2);
449
            List<BotanicalName> list = handleHomotypicGroup(firstPart, state, (BotanicalName)state.getCurrentTaxon().getName(), false, homonyms, homonymPart, false);
450
            checkFirstSynonym(state, list, isFirstSynonym, synonymStr, false);
451
        }else if(heterotypicMatcher.matches()){
452
            String firstPart = heterotypicMatcher.group(1).trim();
453
            String secondPart = heterotypicMatcher.groupCount() < 3 ? null : heterotypicMatcher.group(3);
454
            String homonymPart = heterotypicMatcher.groupCount() < 4 ? null : heterotypicMatcher.group(4);
455
            boolean isDoubtful = firstPart.matches("^\\?\\s*.*");
456
            firstPart = replaceHomonIlleg(firstPart);
457
            boolean isHomonym = firstPart.matches(".*" + HOMONYM_MARKER);
458
            BotanicalName synName = makeName(state, firstPart);
459
            if (synName.isProtectedTitleCache()){
460
                logger.warn(line + "Heterotypic base synonym could not be parsed correctly: " + firstPart);
461
            }
462
            if (isHomonym){
463
                homonyms.add(synName);
464
            }
465
            Synonym syn = state.getCurrentTaxon().addHeterotypicSynonymName(synName);
466
            syn.setDoubtful(isDoubtful);
467
            syn.addSource(makeOriginalSource(state));
468
            List<BotanicalName> list = handleHomotypicGroup(secondPart, state, synName, true, homonyms, homonymPart, isDoubtful);
469
            checkFirstSynonym(state, list, isFirstSynonym, synonymStr, true);
470

    
471
        }else if (isSpecialHeterotypic(synonymStr)){
472
            BotanicalName synName = makeName(state, synonymStr);
473
            if (synName.isProtectedTitleCache()){
474
                logger.warn(line + "Special heterotypic synonym could not be parsed correctly:" + synonymStr);
475
            }
476
            Synonym syn = state.getCurrentTaxon().addHeterotypicSynonymName(synName);
477
            syn.addSource(makeOriginalSource(state));
478
        }else{
479
            logger.warn(line + "Synonym entry does not match: " + synonymStr);
480
        }
481
    }
482

    
483
    /**
484
     * @param state
485
     * @param list
486
     * @param isFirstSynonym
487
     * @param synonymStr
488
     * @param b
489
     */
490
    private void checkFirstSynonym(CubaImportState state, List<BotanicalName> list, boolean isFirstSynonym, String synonymStr, boolean isHeterotypicMatcher) {
491
        if (!isFirstSynonym){
492
            return;
493
        }
494
        String line = state.getCurrentLine() + ": ";
495
        BotanicalName currentName = isHeterotypicMatcher? (BotanicalName)state.getCurrentTaxon().getName(): list.get(0);
496
        boolean currentHasBasionym = currentName.getBasionymAuthorship() != null;
497
        BotanicalName firstSynonym = isHeterotypicMatcher ? list.get(0): list.get(1);
498
//        if (list.size() <= 1){
499
//            logger.error(line + "homotypic list size is 1 but shouldn't");
500
//            return;
501
//        }
502
        if (isHeterotypicMatcher && currentHasBasionym){
503
            logger.error(line + "Current taxon (" + currentName.getTitleCache() + ") has basionym author but has no homotypic basionym , but : " + synonymStr);
504
        }else if (isHeterotypicMatcher){
505
            //first synonym must not have a basionym author
506
            if (firstSynonym.getBasionymAuthorship() != null){
507
                logger.error(line + "Current taxon (" + currentName.getTitleCache() + ") has no basionym but first synonym requires basionym : " + synonymStr);
508
            }
509
        }else{  //isAcceptedMatcher
510
            if (currentHasBasionym){
511
                if (! matchAuthor(currentName.getBasionymAuthorship(), firstSynonym.getCombinationAuthorship())){
512
                    logger.info(line + "Current basionym author and first synonym combination author do not match: " + currentName.getTitleCache() + "<->" + firstSynonym.getTitleCache());
513
                }
514
            }else{
515
                if (! matchAuthor(currentName.getCombinationAuthorship(), firstSynonym.getBasionymAuthorship())){
516
                    logger.info(line + "Current combination author and first synonym basionym author do not match: " + currentName.getTitleCache() + "<->" + firstSynonym.getTitleCache());
517
                }
518
            }
519
        }
520

    
521
    }
522

    
523

    
524
    /**
525
     * @param synonymStr
526
     * @return
527
     */
528
    private boolean isSpecialHeterotypic(String synonymStr) {
529
        if (synonymStr == null){
530
            return false;
531
        }else if (synonymStr.equals("Rhynchospora prenleloupiana (‘prenteloupiana’) Boeckeler")){
532
            return true;
533
        }else if (synonymStr.equals("Psidium longipes var. orbiculare (O.Berg) McVaugh")){
534
            return true;
535
        }
536
        return false;
537
    }
538

    
539

    
540
    /**
541
     * @param areaKey
542
     * @param record
543
     * @param state
544
     * @param taxon
545
     */
546
    private void makeSingleProvinceDistribution(String areaKey,
547
            HashMap<String, String> record,
548
            CubaImportState state) {
549
        try {
550
            UUID areaUuid = state.getTransformer().getNamedAreaUuid(areaKey);
551
            if (areaUuid == null){
552
                logger.warn("Area not recognized: " + areaKey);
553
                return;
554
            }
555
            if (record.get(areaKey)==null){
556
                return; //no status defined
557
            }
558

    
559
            NamedArea area = getNamedArea(state, areaUuid, null, null, null, null, null);
560
            if (area == null){
561
                logger.warn(state.getCurrentLine() + ": Area not recognized: " + area);
562
            }
563
            TaxonDescription desc = getTaxonDescription(state.getCurrentTaxon(), false, true);
564
            PresenceAbsenceTerm status =  makeProvinceStatus(areaKey, record, state);
565
            if (status == null){
566
                logger.warn(state.getCurrentLine() + ": Province distribution status could not be defined: " + record.get(areaKey));
567
            }
568
            Distribution distribution = Distribution.NewInstance(area, status);
569
            desc.addElement(distribution);
570
            distribution.addSource(makeDescriptionSource(state));
571
        } catch (UndefinedTransformerMethodException e) {
572
            e.printStackTrace();
573
        }
574

    
575
    }
576

    
577

    
578
    /**
579
     * @param synonymStr
580
     * @param state
581
     * @param homonyms
582
     * @param homonymPart
583
     * @param isDoubtful
584
     * @param taxon
585
     * @param homotypicalGroup
586
     */
587
    private List<BotanicalName> handleHomotypicGroup(String homotypicStrOrig,
588
            CubaImportState state,
589
            BotanicalName homotypicName,
590
            boolean isHeterotypic,
591
            List<BotanicalName> homonyms,
592
            String homonymPart,
593
            boolean isDoubtful) {
594

    
595
        List<BotanicalName> homotypicNameList = new ArrayList<>();
596
        homotypicNameList.add(homotypicName);
597

    
598
        String homotypicStr = homotypicStrOrig;
599
        if (homotypicStr == null){
600
            return homotypicNameList;
601
        }else if (homotypicStr.startsWith("(") && homotypicStr.endsWith("")){
602
            homotypicStr = homotypicStr.substring(1, homotypicStr.length() - 1);
603
        }
604

    
605
        HomotypicalGroup homotypicGroup = homotypicName.getHomotypicalGroup();
606
        String[] splits = homotypicStr.split("\\s*,\\s*");
607
        for (String split : splits){
608
            split = replaceHomonIlleg(split);
609
            boolean isHomonym = split.matches(".*" + HOMONYM_MARKER);
610
            BotanicalName newName = makeName(state, split);
611
            newName.setHomotypicalGroup(homotypicGroup);  //not really necessary as this is later set anyway
612
            if (newName.isProtectedTitleCache()){
613
                logger.warn(state.getCurrentLine() + ": homotypic name part could not be parsed: " + split);
614
            }
615
            if (isHomonym){
616
                homonyms.add(newName);
617
            }
618
            if (isHeterotypic){
619
                Synonym syn = state.getCurrentTaxon().addHeterotypicSynonymName(newName, null, null, homotypicGroup);
620
                syn.setDoubtful(isDoubtful);
621
                syn.addSource(makeOriginalSource(state));
622
//                newName.addBasionym(homotypicName);
623
            }else{
624
                state.getCurrentTaxon().addHomotypicSynonymName(newName);
625
            }
626
            handleBasionym(state, homotypicNameList, homonyms, newName);
627
            homotypicNameList.add(newName);
628
        }
629
        makeHomonyms(homonyms, homonymPart, state, homotypicGroup);
630
        return homotypicNameList;
631
    }
632

    
633

    
634
    /**
635
     * @param split
636
     * @return
637
     */
638
    private String replaceHomonIlleg(String split) {
639
        String result = split.trim().replace("homon. illeg.", "nom. illeg. homon.").trim();
640
        return result;
641
    }
642

    
643

    
644
    /**
645
     * @param homonyms
646
     * @param homonymPart
647
     * @param state
648
     * @param currentBasionym
649
     */
650
    private void makeHomonyms(List<BotanicalName> homonyms, String homonymPartOrig, CubaImportState state,
651
            HomotypicalGroup homotypicGroup) {
652
        String line = state.getCurrentLine() + ": ";
653
        String homonymPart = homonymPartOrig == null ? "" : homonymPartOrig.trim();
654
        if (homonyms.isEmpty() && homonymPart.equals("")){
655
            return;
656
        }else if (homonymPart.equals("")){
657
            logger.warn(line + "SynonymPart has homonyms but homonymPart is empty");
658
            return;
659
        }
660
        homonymPart = homonymPart.substring(1, homonymPart.length() - 1);
661
        String[] splits = homonymPart.split("\\]\\s*\\[");
662
        if (splits.length != homonyms.size()){
663
            if(homonyms.size() == 0 && splits.length >= 1){
664
                handleSimpleBlockingNames(splits, state, homotypicGroup);
665
            }else{
666
                logger.warn(line + "Number of homonyms (" + homonyms.size() + ") and homonymParts ("+splits.length+") does not match");
667
            }
668
            return;
669
        }
670
        int i = 0;
671
        for (String split : splits){
672
            split = split.replaceAll("^non\\s+", "");
673
            BotanicalName newName = makeName(state, split);
674
//            BotanicalName newName = (BotanicalName)nameParser.parseReferencedName(split, state.getConfig().getNomenclaturalCode(), Rank.SPECIES());
675
            if (newName.isProtectedTitleCache()){
676
                logger.warn(state.getCurrentLine() + ": homonym name could not be parsed: " + split);
677
            }
678
            homonyms.get(i).addRelationshipToName(newName, NameRelationshipType.LATER_HOMONYM(), null);
679
            i++;
680
        }
681
    }
682

    
683
    /**
684
     * @param homonymPart
685
     * @param state
686
     * @param homotypicGroup
687
     */
688
    private void handleSimpleBlockingNames(String[] splitsi,
689
            CubaImportState state,
690
            HomotypicalGroup homotypicGroup) {
691
        List<BotanicalName> replacementNameCandidates = new ArrayList<>();
692
        for (String spliti : splitsi){
693

    
694
            String split = spliti.replaceAll("^non\\s+", "");
695
            BotanicalName newName = makeName(state, split);
696
            if (newName.isProtectedTitleCache()){
697
                logger.warn(state.getCurrentLine() + ": blocking name could not be parsed: " + split);
698
            }
699
            Set<BotanicalName> typifiedNames = (Set)homotypicGroup.getTypifiedNames();
700
            Set<BotanicalName> candidates = new HashSet<>();
701
            for (BotanicalName name : typifiedNames){
702
                if (name.getGenusOrUninomial() != null && name.getGenusOrUninomial().equals(newName.getGenusOrUninomial())){
703
                    if (name.getStatus().isEmpty() || ! name.getStatus().iterator().next().getType().equals(NomenclaturalStatusType.ILLEGITIMATE())){
704
                        candidates.add(name);
705
                    }
706
                }
707
            }
708
            if (candidates.size() == 1){
709
                BotanicalName blockedName = candidates.iterator().next();
710
                newName.addRelationshipToName(blockedName, NameRelationshipType.BLOCKING_NAME_FOR(), null);
711
                replacementNameCandidates.add(blockedName);
712
            }else{
713
                logger.warn(state.getCurrentLine() + ": Blocking name could not be handled. " + candidates.size() + " candidates.");
714
            }
715
        }
716
        makeReplacedSynonymIfPossible(state, homotypicGroup, replacementNameCandidates);
717
    }
718

    
719
    /**
720
     * @param homotypicGroup
721
     * @param replacementNameCandidates
722
     */
723
    private void makeReplacedSynonymIfPossible(CubaImportState state,
724
            HomotypicalGroup homotypicGroup,
725
            List<BotanicalName> replacementNameCandidates) {
726
        String line = state.getCurrentLine() +": ";
727
        List<BotanicalName> replacedCandidates = new ArrayList<>();
728
        for (TaxonNameBase<?, ?> typifiedName : homotypicGroup.getTypifiedNames()){
729
            BotanicalName candidate = (BotanicalName)typifiedName;
730
            if (candidate.getBasionymAuthorship() == null){
731
                if (candidate.getStatus().isEmpty()){
732
                    if (! replacementNameCandidates.contains(candidate)){
733
                        replacedCandidates.add(candidate);
734
                    }
735
                }
736
            }
737
        }
738
        if (replacedCandidates.size() == 1){
739
            BotanicalName replacedSynonym = replacedCandidates.iterator().next();
740
            for (BotanicalName replacementName : replacementNameCandidates){
741
                replacementName.addReplacedSynonym(replacedSynonym, null, null, null);
742
            }
743
        }else if (replacedCandidates.size() < 1){
744
            logger.warn(line + "No replaced synonym candidate found");
745
        }else{
746
            logger.warn(line + "More than 1 ("+replacedCandidates.size()+") replaced synonym candidates found");
747
        }
748
    }
749

    
750

    
751
    /**
752
     * @param homotypicGroup
753
     * @param newName
754
     */
755
    private void handleBasionym(CubaImportState state, List<BotanicalName> homotypicNameList,
756
            List<BotanicalName> homonyms, BotanicalName newName) {
757
        for (BotanicalName existingName : homotypicNameList){
758
            if (existingName != newName){  //should not happen anymore, as new name is added later
759
                boolean onlyIfNotYetExists = true;
760
                createBasionymRelationIfPossible(state, existingName, newName, homonyms.contains(newName), onlyIfNotYetExists);
761
            }
762
        }
763
    }
764

    
765
    /**
766
     * @param state
767
     * @param name1
768
     * @param name2
769
     * @return
770
     */
771
    private void createBasionymRelationIfPossible(CubaImportState state, BotanicalName name1, BotanicalName name2,
772
            boolean name2isHomonym, boolean onlyIfNotYetExists) {
773
        BotanicalName basionymName = name1;
774
        BotanicalName newCombination = name2;
775
        //exactly one name must have a basionym author
776
        if (name1.getBasionymAuthorship() == null && name2.getBasionymAuthorship() == null
777
                || name1.getBasionymAuthorship() != null && name2.getBasionymAuthorship() != null){
778
            return;
779
        }
780

    
781
        //switch order if necessary
782
        if (! name2isHomonym && basionymName.getBasionymAuthorship() != null && newCombination.getBasionymAuthorship() == null){
783
            basionymName = name2;
784
            newCombination = name1;
785
        }
786
        if (matchAuthor(basionymName.getCombinationAuthorship(), newCombination.getBasionymAuthorship())
787
                && matchLastNamePart(basionymName, newCombination)){
788
            newCombination.addBasionym(basionymName);
789
        }else{
790
            if ( (newCombination.getBasionyms().isEmpty() || ! onlyIfNotYetExists)
791
                    && isLegitimate(basionymName)
792
                    && ! name2isHomonym){
793
                logger.info(state.getCurrentLine() + ": Names are potential basionyms but either author or name part do not match: " + basionymName.getTitleCache() + " <-> " + newCombination.getTitleCache());
794
            }
795
        }
796
    }
797

    
798
    /**
799
     * @param basionymName
800
     * @return
801
     */
802
    private boolean isLegitimate(BotanicalName basionymName) {
803
        for (NomenclaturalStatus nomStatus : basionymName.getStatus()){
804
            if (nomStatus.getType()!= null && nomStatus.getType().isIllegitimateType()){
805
                    return false;
806
            }
807
        }
808
        for (NameRelationship nameRel : basionymName.getNameRelations()){
809
            if (nameRel.getType()!= null && nameRel.getType().isIllegitimateType()){
810
                    return false;
811
            }
812
        }
813
        return true;
814
    }
815

    
816

    
817
    /**
818
     * @param basionymName
819
     * @param newCombination
820
     * @return
821
     */
822
    private boolean matchLastNamePart(BotanicalName name1, BotanicalName name2) {
823
        String lastNamePart1 = name1.getLastNamePart();
824
        String lastNamePart2 = name2.getLastNamePart();
825
        if (lastNamePart1 != null && lastNamePart2 != null){
826
            lastNamePart1 = normalizeBasionymNamePart(lastNamePart1);
827
            lastNamePart2 = normalizeBasionymNamePart(lastNamePart2);
828
            return (lastNamePart1.equals(lastNamePart2));
829
        }else{
830
            return false;
831
        }
832
    }
833

    
834
    /**
835
     * @param lastNamePart1
836
     * @return
837
     */
838
    private String normalizeBasionymNamePart(String lastNamePart) {
839
        String namePart = lastNamePart.toLowerCase()
840
                .replaceAll("(um|us|a|is|e|os|on|or)$", "")
841
                .replaceAll("er$", "r")    //e.g. ruber <-> rubra
842
                .replaceAll("ese$", "s");  //e.g.  cayanensis <-> cayanenese
843
                //TODO tampensis / tampense
844
        return namePart;
845
    }
846

    
847

    
848
    /**
849
     * @param combinationAuthorship
850
     * @param basi
851
     * @return
852
     */
853
    private boolean matchAuthor(TeamOrPersonBase<?> author1, TeamOrPersonBase<?> author2) {
854
        if (author1 == null || author2 == null){
855
            return false;
856
        }else {
857
            return author1.getNomenclaturalTitle().equals(author2.getNomenclaturalTitle());
858
        }
859
    }
860

    
861

    
862
    /**
863
     * @param record
864
     * @param state
865
     * @param taxon
866
     */
867
    private void makeNotes(HashMap<String, String> record, CubaImportState state) {
868
        String notesStr = getValue(record, "(Notas)");
869
        if (notesStr == null){
870
            return;
871
        }else{
872
            Annotation annotation = Annotation.NewDefaultLanguageInstance(notesStr);
873
            //TODO
874
            annotation.setAnnotationType(AnnotationType.TECHNICAL());
875
            state.getCurrentTaxon().addAnnotation(annotation);
876
        }
877
    }
878

    
879

    
880
    /**
881
     * @param record
882
     * @param state
883
     * @param familyTaxon
884
     * @return
885
     */
886
    private Taxon makeTaxon(HashMap<String, String> record, CubaImportState state, TaxonNode familyNode, boolean isSynonym) {
887
        String taxonStrOrig = getValue(record, "Taxón");
888
        if (taxonStrOrig == null){
889
            return isSynonym ? state.getCurrentTaxon() : null;
890
        }
891

    
892
        boolean isAbsent = false;
893
        String taxonStr = taxonStrOrig;
894
        if (taxonStrOrig.startsWith("[") && taxonStrOrig.endsWith("]")){
895
            taxonStr = taxonStr.substring(1, taxonStr.length() - 1);
896
            isAbsent = true;
897
        }
898

    
899
        boolean isAuct = false;
900
        if (taxonStr.endsWith("auct.")){
901
            isAuct = true;
902
            taxonStr.replace("auct.", "").trim();
903
        }
904
        state.setTaxonIsAbsent(isAbsent);
905
        BotanicalName botanicalName = makeName(state, taxonStr);
906
        Reference sec = getSecReference(state);
907
        Taxon taxon = Taxon.NewInstance(botanicalName, sec);
908
        if (isAuct){
909
            taxon.setAppendedPhrase("auct.");
910
        }
911

    
912
        TaxonNode higherNode;
913
        if (botanicalName.isProtectedTitleCache()){
914
            logger.warn(state.getCurrentLine() + ": Taxon could not be parsed: " + taxonStrOrig);
915
            higherNode = familyNode;
916
        }else{
917
            String genusStr = botanicalName.getGenusOrUninomial();
918
            Taxon genus = state.getHigherTaxon(genusStr);
919
            if (genus != null){
920
                higherNode = genus.getTaxonNodes().iterator().next();
921
            }else{
922
                BotanicalName name = TaxonNameFactory.NewBotanicalInstance(Rank.GENUS());
923
                name.addSource(makeOriginalSource(state));
924
                name.setGenusOrUninomial(genusStr);
925
                genus = Taxon.NewInstance(name, sec);
926
                genus.addSource(makeOriginalSource(state));
927
                higherNode = familyNode.addChildTaxon(genus, null, null);
928
                state.putHigherTaxon(genusStr, genus);
929
            }
930
        }
931
        taxon.addSource(makeOriginalSource(state));
932

    
933
        TaxonNode newNode = higherNode.addChildTaxon(taxon, null, null);
934
        if(isAbsent){
935
            botanicalName.setTitleCache(taxonStrOrig, true);
936
            newNode.setExcluded(true);
937
        }
938

    
939
        return taxon;
940
    }
941

    
942
    private final String orthVarRegExStr = "[A-Z][a-z]+\\s[a-z]+\\s(\\(‘([a-z]){3,}’\\))\\s(\\([A-Z][a-z]+\\.?\\)\\s)?[A-Z][a-zó]+\\.?";
943
    private final Pattern orthVarRegEx = Pattern.compile(orthVarRegExStr);
944
    /**
945
     * @param taxonStr
946
     * @return
947
     */
948
    private BotanicalName makeName(CubaImportState state, String nameStrOrig) {
949
        //normalize
950
        String nameStr = normalizeStatus(nameStrOrig);
951
        //orthVar
952
        Matcher orthVarMatcher = orthVarRegEx.matcher(nameStr);
953
        String orthVar = null;
954
        if (orthVarMatcher.matches()) {
955
            orthVar = orthVarMatcher.group(1);
956
            nameStr = nameStr.replace(" " + orthVar, "").trim().replaceAll("\\s{2,}", " ");
957
            orthVar = orthVar.substring(2, orthVar.length() - 2);
958
        }
959

    
960
        boolean isNomInval = false;
961
        if (nameStr.endsWith("nom. inval.")){
962
            isNomInval = true;
963
            nameStr = nameStr.replace("nom. inval.", "").trim();
964
        }
965

    
966
        BotanicalName result = (BotanicalName)nameParser.parseReferencedName(nameStr, nc, Rank.SPECIES());
967
        result.addSource(makeOriginalSource(state));
968
        if (isNomInval){
969
            result.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.INVALID()));
970
        }
971
        if (orthVar != null){
972
            BotanicalName orthVarName = (BotanicalName)result.clone();
973
            orthVarName.addSource(makeOriginalSource(state));
974
            //TODO
975
            Reference citation = null;
976
            orthVarName.addRelationshipToName(result, NameRelationshipType.ORTHOGRAPHIC_VARIANT(), citation, null, null);
977
            orthVarName.setSpecificEpithet(orthVar);
978
        }
979
        normalizeAuthors(result);
980
        return result;
981

    
982
    }
983

    
984
    /**
985
     * @param result
986
     */
987
    private void normalizeAuthors(BotanicalName result) {
988
        result.setCombinationAuthorship(normalizeAuthor(result.getCombinationAuthorship()));
989
        result.setExCombinationAuthorship(normalizeAuthor(result.getExCombinationAuthorship()));
990
        result.setExBasionymAuthorship(normalizeAuthor(result.getExBasionymAuthorship()));
991
        result.setBasionymAuthorship(normalizeAuthor(result.getBasionymAuthorship()));
992

    
993
    }
994

    
995

    
996
    /**
997
     * @param combinationAuthorship
998
     * @return
999
     */
1000
    private TeamOrPersonBase<?> normalizeAuthor(TeamOrPersonBase<?> author) {
1001
        if (author == null){
1002
            return null;
1003
        }
1004
        TeamOrPersonBase<?> result;
1005
        if (author.isInstanceOf(Person.class)){
1006
            result = normalizePerson(CdmBase.deproxy(author, Person.class));
1007
        }else{
1008
            Team team = CdmBase.deproxy(author, Team.class);
1009
            List<Person> list = team.getTeamMembers();
1010
            for(int i = 0; i < list.size(); i++){
1011
                Person person = list.get(i);
1012
                Person tmpMember = normalizePerson(person);
1013
                list.set(i, tmpMember);
1014
            }
1015
            return team;
1016
        }
1017
        return result;
1018
    }
1019

    
1020

    
1021
    /**
1022
     * @param deproxy
1023
     * @return
1024
     */
1025
    private Person normalizePerson(Person person) {
1026
        String title = person.getNomenclaturalTitle();
1027
        title = title.replaceAll("(?<=[a-zA-Z])\\.(?=[a-zA-Z])", ". ");
1028
        person.setNomenclaturalTitle(title);
1029
        boolean isFilius = title.endsWith(" f.");
1030
        if (isFilius){
1031
            title.replace(" f.", "");
1032
        }
1033

    
1034
        String[] splits = title.split("\\s+");
1035
        int nNotFirstName = isFilius ? 2 : 1;
1036
        person.setLastname(splits[splits.length - nNotFirstName] + (isFilius? " f." : ""));
1037
        person.setFirstname(CdmUtils.concat(" ", Arrays.copyOfRange(splits, 0, splits.length-nNotFirstName)));
1038
        return person;
1039
    }
1040

    
1041

    
1042
    /**
1043
     * @param state
1044
     * @return
1045
     */
1046
    private Reference getSecReference(CubaImportState state) {
1047
        Reference result = state.getSecReference();
1048
        if (result == null){
1049
            result = ReferenceFactory.newDatabase();
1050
            result.setTitle("Flora of Cuba");
1051
            state.setSecReference(result);
1052
        }
1053
        return result;
1054
    }
1055

    
1056

    
1057
    private static final String[] nomStatusStrings = new String[]{"nom. cons.", "ined.", "nom. illeg.",
1058
            "nom. rej.","nom. cons. prop.","nom. altern.","nom. confus.","nom. dub.", "nom. nud."};
1059
    /**
1060
     * @param taxonStr
1061
     * @return
1062
     */
1063
    private String normalizeStatus(String nameStr) {
1064
        if (nameStr == null){
1065
            return null;
1066
        }
1067
        String result = nameStr.replaceAll(HOMONYM_MARKER, "").trim();
1068
        for (String nomStatusStr : nomStatusStrings){
1069
            nomStatusStr = " " + nomStatusStr;
1070
            if (result.endsWith(nomStatusStr)){
1071
                result = result.replace(nomStatusStr, "," + nomStatusStr);
1072
            }
1073
        }
1074
        result = result.replaceAll(DOUBTFUL_MARKER, "").trim();
1075
        result = result.replace("[taxon]", "[infraspec.]");
1076
        return result;
1077

    
1078

    
1079
    }
1080

    
1081

    
1082
    /**
1083
     * @param record
1084
     * @param state
1085
     * @return
1086
     */
1087
    private TaxonNode getFamilyTaxon(HashMap<String, String> record, CubaImportState state) {
1088
        String familyStr = getValue(record, "Fam. default");
1089
        if (familyStr == null){
1090
            return null;
1091
        }
1092
        familyStr = familyStr.trim();
1093
        String alternativeFamilyStr = null;
1094
        if (familyStr.contains("/")){
1095
            String[] splits = familyStr.split("/");
1096
            if (splits.length > 2){
1097
                logger.warn(state.getCurrentLine() +": " + "More than 1 alternative name:" + familyStr);
1098
            }
1099
            familyStr = splits[0].trim();
1100
            alternativeFamilyStr = splits[1].trim();
1101
        }
1102

    
1103
        Taxon family = state.getHigherTaxon(familyStr);
1104
        TaxonNode familyNode;
1105
        if (family != null){
1106
            familyNode = family.getTaxonNodes().iterator().next();
1107
        }else{
1108
            BotanicalName name = makeFamilyName(state, familyStr);
1109
            Reference sec = getSecReference(state);
1110
            family = Taxon.NewInstance(name, sec);
1111
            ITaxonTreeNode rootNode = getClassification(state);
1112
            familyNode = rootNode.addChildTaxon(family, sec, null);
1113
            state.putHigherTaxon(familyStr, family);
1114

    
1115
        }
1116

    
1117
        if (isNotBlank(alternativeFamilyStr)){
1118
            NameRelationshipType type = NameRelationshipType.ALTERNATIVE_NAME();
1119
            BotanicalName alternativeName = makeFamilyName(state, alternativeFamilyStr);
1120
            BotanicalName familyName = (BotanicalName)family.getName();
1121
            boolean hasRelation = false;
1122
            for (NameRelationship nameRel : familyName.getRelationsToThisName()){
1123
                if (nameRel.getType().equals(type)){
1124
                    if (nameRel.getFromName().equals(alternativeName)){
1125
                        hasRelation = true;
1126
                    }
1127
                }
1128
            }
1129
            if (!hasRelation){
1130
                familyName.addRelationshipFromName(alternativeName, type, null);
1131
            }
1132

    
1133
        }
1134

    
1135
        return familyNode;
1136
    }
1137

    
1138

    
1139
    /**
1140
     * @param state
1141
     * @param taxon
1142
     */
1143
    private void validateTaxonIsAbsent(CubaImportState state, Taxon taxon) {
1144
        if (!state.isTaxonIsAbsent()){
1145
            return;
1146
        }
1147

    
1148
        for (DescriptionElementBase el : taxon.getDescriptions().iterator().next().getElements()){
1149
            if (el instanceof Distribution){
1150
                Distribution dist = (Distribution)el;
1151
                NamedArea area = dist.getArea();
1152
                if (isCubanArea(area)){
1153
                    PresenceAbsenceTerm status = dist.getStatus();
1154
                    if (status != null && !status.isAbsenceTerm()){
1155
                        if (!isDoubtfulTerm(status)){
1156
                            String name = taxon.getName().getTitleCache();
1157
                            logger.error(state.getCurrentLine() +": Taxon ("+name+")is absent'[]' but has presence distribution: " + status.getTitleCache());
1158
                            return;
1159
                        }
1160
                    }
1161
                }
1162
            }
1163
        }
1164
    }
1165

    
1166
    /**
1167
     * @param state
1168
     * @param taxon
1169
     */
1170
    private void validateEndemic(CubaImportState state, Taxon taxon) {
1171

    
1172
        boolean hasExternalPresence = false;
1173
        for (DescriptionElementBase el : taxon.getDescriptions().iterator().next().getElements()){
1174
            if (el instanceof Distribution){
1175
                Distribution dist = (Distribution)el;
1176
                NamedArea area = dist.getArea();
1177
                if (!isCubanArea(area)){
1178
                    PresenceAbsenceTerm status = dist.getStatus();
1179
                    if (status != null && !status.isAbsenceTerm()){
1180
                        if (!isDoubtfulTerm(status)){
1181
                            hasExternalPresence = true;
1182
                            if (state.isEndemic()){
1183
                                String name = taxon.getName().getTitleCache();
1184
                                logger.error(state.getCurrentLine() +": Taxon ("+name+")is endemic but has non-cuban distribution: " + area.getIdInVocabulary() + "-" + status.getIdInVocabulary());
1185
                                return;
1186
                            }
1187
                        }
1188
                    }
1189
                }
1190
            }
1191
        }
1192
        if (!state.isEndemic() && ! hasExternalPresence){
1193
            String name = taxon.getName().getTitleCache();
1194
            logger.error(state.getCurrentLine() +": Taxon ("+name+")is not endemic but has no non-cuban distribution" );
1195
        }
1196
    }
1197

    
1198

    
1199
    /**
1200
     * @param state
1201
     * @param taxon
1202
     * @param famStr
1203
     * @param famRef
1204
     * @return
1205
     */
1206
    private Taxon makeAlternativeFamilyTaxon(CubaImportState state, String famStr, Reference famRef) {
1207
        String key = famRef.getTitle() + ":"+ famStr;
1208
        Taxon family = state.getHigherTaxon(key);
1209
        if (family == null){
1210
            BotanicalName name = makeFamilyName(state, famStr);
1211
            family = Taxon.NewInstance(name, famRef);
1212
            state.putHigherTaxon(key, family);
1213
        }
1214

    
1215
        return family;
1216
    }
1217

    
1218

    
1219
    /**
1220
     * @param state
1221
     * @param famStr
1222
     * @return
1223
     */
1224
    private BotanicalName makeFamilyName(CubaImportState state, String famStr) {
1225
        BotanicalName name = state.getFamilyName(famStr);
1226
        if (name == null){
1227
            name = TaxonNameFactory.NewBotanicalInstance(Rank.FAMILY());
1228
            name.setGenusOrUninomial(famStr);
1229
            state.putFamilyName(famStr, name);
1230
            name.addSource(makeOriginalSource(state));
1231
        }
1232
        return name;
1233
    }
1234

    
1235

    
1236
    /**
1237
     * @param state
1238
     * @return
1239
     */
1240
    private TaxonNode getClassification(CubaImportState state) {
1241
        Classification classification = state.getClassification();
1242
        if (classification == null){
1243
            classification = getClassificationService().find(state.getConfig().getClassificationUuid());
1244
        }
1245
        TaxonNode rootNode = state.getRootNode();
1246
        if (rootNode == null){
1247
            rootNode = getTaxonNodeService().find(plantaeUuid);
1248
        }
1249
        if (rootNode == null){
1250
            Reference sec = getSecReference(state);
1251
            if (classification == null){
1252
                String classificationName = state.getConfig().getClassificationName();
1253
                //TODO
1254
                Language language = Language.DEFAULT();
1255
                classification = Classification.NewInstance(classificationName, sec, language);
1256
                state.setClassification(classification);
1257
                classification.setUuid(state.getConfig().getClassificationUuid());
1258
                classification.getRootNode().setUuid(rootUuid);
1259
            }
1260

    
1261
            BotanicalName plantaeName = TaxonNameFactory.NewBotanicalInstance(Rank.KINGDOM());
1262
            plantaeName.setGenusOrUninomial("Plantae");
1263
            Taxon plantae = Taxon.NewInstance(plantaeName, sec);
1264
            TaxonNode plantaeNode = classification.addChildTaxon(plantae, null, null);
1265
            plantaeNode.setUuid(plantaeUuid);
1266
            state.setRootNode(plantaeNode);
1267
            getClassificationService().save(classification);
1268

    
1269
            rootNode = plantaeNode;
1270
        }
1271
        return rootNode;
1272
    }
1273

    
1274

    
1275
    /**
1276
     * @param record
1277
     * @param originalKey
1278
     * @return
1279
     */
1280
    private String getValue(HashMap<String, String> record, String originalKey) {
1281
        String value = record.get(originalKey);
1282
        if (! StringUtils.isBlank(value)) {
1283
        	if (logger.isDebugEnabled()) { logger.debug(originalKey + ": " + value); }
1284
        	value = CdmUtils.removeDuplicateWhitespace(value.trim()).toString();
1285
        	return value;
1286
        }else{
1287
        	return null;
1288
        }
1289
    }
1290

    
1291

    
1292

    
1293
	/**
1294
	 *  Stores taxa records in DB
1295
	 */
1296
	@Override
1297
    protected void firstPass(CubaImportState state) {
1298
	    boolean isSynonymOnly = false;
1299

    
1300
        String line = state.getCurrentLine() + ": ";
1301
        HashMap<String, String> record = state.getOriginalRecord();
1302

    
1303
        Set<String> keys = record.keySet();
1304
        for (String key: keys) {
1305
            if (! expectedKeys.contains(key)){
1306
                logger.warn(line + "Unexpected Key: " + key);
1307
            }
1308
        }
1309

    
1310
        if (record.get("Fam. default") == null && keys.size() == 2 && record.get("Syn.") == null && record.get("Nat") != null && record.get("Adv") != null){
1311
            //second header line, don't handle
1312
            return;
1313
        }
1314

    
1315
        //Fam.
1316
        TaxonNode familyTaxon = getFamilyTaxon(record, state);
1317
        if (familyTaxon == null){
1318
            if (record.get("Taxón") != null){
1319
                logger.warn(line + "Family not recognized but taxon exists: " + record.get("Taxón"));
1320
                return;
1321
            }else if (record.get("Syn.") == null){
1322
                logger.warn(line + "Family not recognized but also no synonym exists");
1323
                return;
1324
            }else{
1325
                isSynonymOnly = true;
1326
            }
1327
        }
1328

    
1329
       //Taxón
1330
        Taxon taxon = makeTaxon(record, state, familyTaxon, isSynonymOnly);
1331
        if (taxon == null && ! isSynonymOnly){
1332
            logger.warn(line + "taxon could not be created and is null");
1333
            return;
1334
        }
1335
        state.setCurrentTaxon(taxon);
1336

    
1337
        //Fam. ALT
1338
        if (!isSynonymOnly){
1339
            makeAlternativeFamilies(record, state, familyTaxon, taxon);
1340
        }
1341

    
1342
        //(Notas)
1343
        makeNotes(record, state);
1344

    
1345
        //Syn.
1346
        makeSynonyms(record, state, !isSynonymOnly);
1347

    
1348
        //End, Ind, Ind? D, Nat N, Dud P, Adv A, Cult C
1349
        makeCubanDistribution(record, state);
1350

    
1351

    
1352
//        "CuW","PR PR*","Art","Hab(*)","May","Mat","IJ",
1353
//        "CuC","VC","Ci","SS","CA","Cam","LT",
1354
//        "CuE","Gr","Ho","SC","Gu",
1355
        makeProvincesDistribution(record, state);
1356

    
1357
//      "Esp","Ja","PR","Men","Bah","Cay",
1358
//      "AmN","AmC","AmS","VM"});
1359
        makeOtherAreasDistribution(record, state);
1360

    
1361
        validateTaxonIsAbsent(state, taxon);
1362
        if (!isSynonymOnly){
1363
            validateEndemic(state, taxon);
1364
        }
1365

    
1366
        state.setHighestStatusForTaxon(null);
1367

    
1368
		return;
1369
    }
1370

    
1371

    
1372
    /**
1373
     * @param state
1374
     * @return
1375
     */
1376
    private IdentifiableSource makeOriginalSource(CubaImportState state) {
1377
        return IdentifiableSource.NewDataImportInstance("line: " + state.getCurrentLine(), null, state.getConfig().getSourceReference());
1378
    }
1379
    /**
1380
     * @param state
1381
     * @return
1382
     */
1383
    private DescriptionElementSource makeDescriptionSource(CubaImportState state) {
1384
        return DescriptionElementSource.NewDataImportInstance("line: " + state.getCurrentLine(), null, state.getConfig().getSourceReference());
1385
    }
1386

    
1387
    private static Set<UUID> doubtfulStatus = new HashSet<>();
1388

    
1389
    /**
1390
     * @param status
1391
     * @return
1392
     */
1393
    private boolean isDoubtfulTerm(PresenceAbsenceTerm status) {
1394
        if (doubtfulStatus.isEmpty()){
1395
            doubtfulStatus.add(CubaTransformer.nonNativeDoubtfullyNaturalisedUuid);
1396
            doubtfulStatus.add(CubaTransformer.doubtfulIndigenousDoubtfulUuid);
1397
            doubtfulStatus.add(CubaTransformer.endemicDoubtfullyPresentUuid);
1398
            doubtfulStatus.add(CubaTransformer.naturalisedDoubtfullyPresentUuid);
1399
            doubtfulStatus.add(CubaTransformer.nonNativeDoubtfullyPresentUuid);
1400
            doubtfulStatus.add(CubaTransformer.occasionallyCultivatedUuid);
1401
            doubtfulStatus.add(CubaTransformer.rareCasualUuid);
1402
            doubtfulStatus.add(PresenceAbsenceTerm.NATIVE_PRESENCE_QUESTIONABLE().getUuid());
1403
            doubtfulStatus.add(PresenceAbsenceTerm.CULTIVATED_PRESENCE_QUESTIONABLE().getUuid());
1404
        }
1405
        boolean isDoubtful = doubtfulStatus.contains(status.getUuid());
1406
        return isDoubtful;
1407
    }
1408

    
1409

    
1410
    /**
1411
     * @param area
1412
     * @return
1413
     */
1414
    private boolean isCubanArea(NamedArea area) {
1415
        if (area.getUuid().equals(CubaTransformer.uuidCuba)){
1416
            return true;
1417
        }else if (area.getPartOf()!= null){
1418
            return isCubanArea(area.getPartOf());
1419
        }else{
1420
            return false;
1421
        }
1422
    }
1423

    
1424

    
1425
    /**
1426
     * @param record
1427
     * @param state
1428
     * @param familyTaxon
1429
     * @param taxon
1430
     */
1431
    private void makeAlternativeFamilies(HashMap<String, String> record,
1432
            CubaImportState state,
1433
            TaxonNode familyTaxon,
1434
            Taxon taxon) {
1435

    
1436
        String famFRC = record.get("Fam. FRC");
1437
        String famAS = record.get("Fam. A&S");
1438
        String famFC = record.get("Fam. FC");
1439

    
1440
        Reference refFRC = makeReference(state, CubaTransformer.uuidRefFRC);
1441
        Reference refAS = makeReference(state, CubaTransformer.uuidRefAS);
1442
        Reference refFC = makeReference(state, CubaTransformer.uuidRefFC);
1443

    
1444
        makeSingleAlternativeFamily(state, taxon, famFRC, refFRC);
1445
        makeSingleAlternativeFamily(state, taxon, famAS, refAS);
1446
        makeSingleAlternativeFamily(state, taxon, famFC, refFC);
1447
    }
1448

    
1449

    
1450
    /**
1451
     * @param state
1452
     * @param uuidreffrc
1453
     * @return
1454
     */
1455
    private Reference makeReference(CubaImportState state, UUID uuidRef) {
1456
        Reference ref = state.getReference(uuidRef);
1457
        if (ref == null){
1458
            ref = getReferenceService().find(uuidRef);
1459
            state.putReference(uuidRef, ref);
1460
        }
1461
        return ref;
1462
    }
1463

    
1464

    
1465
    /**
1466
     * @param state
1467
     * @param taxon
1468
     * @param famString
1469
     * @param famRef
1470
     */
1471
    private void makeSingleAlternativeFamily(CubaImportState state, Taxon taxon, String famStr, Reference famRef) {
1472
        if (isBlank(famStr)){
1473
            famStr = "-";
1474
//            return;
1475
        }
1476

    
1477
        TaxonDescription desc = getTaxonDescription(taxon, false, true);
1478

    
1479
        UUID altFamUuid1;
1480
        UUID altFamUuid2;
1481
        try {
1482
            altFamUuid1 = state.getTransformer().getFeatureUuid("Alt.Fam.");
1483
            altFamUuid2 = state.getTransformer().getFeatureUuid("Alt.Fam.2");
1484
        } catch (UndefinedTransformerMethodException e) {
1485
            throw new RuntimeException(e);
1486
        }
1487

    
1488

    
1489
        Taxon famTaxon = makeAlternativeFamilyTaxon(state, famStr, famRef);
1490

    
1491

    
1492
        //TextData
1493
        Feature feature1 = getFeature(state, altFamUuid1, "Families in other Floras (Text)", "Families in other Floras (Text)", "Other floras", null);
1494
        feature1.addRepresentation(Representation.NewInstance("Familias en otras Floras", "Familias en otras Floras", null, Language.SPANISH_CASTILIAN()));
1495
//        TextData textData = TextData.NewInstance(feature1, famStr, Language.DEFAULT(), null);
1496
        TextData textData = TextData.NewInstance(feature1, null, Language.DEFAULT(), null);
1497
        textData.addSource(OriginalSourceType.PrimaryTaxonomicSource, null,null, famRef, null, famTaxon.getName(),null);
1498
        desc.addElement(textData);
1499

    
1500

    
1501

    
1502
        //TaxonInteraction
1503
        Feature feature2 = getFeature(state, altFamUuid2, "Families in other Floras", "Families in other Floras", "Other floras(2)", null);
1504
        feature2.setSupportsTaxonInteraction(true);
1505
        feature2.addRepresentation(Representation.NewInstance("Familias en otras Floras", "Familias en otras Floras", null, Language.SPANISH_CASTILIAN()));
1506
        TaxonInteraction taxInteract = TaxonInteraction.NewInstance(feature2);
1507
        textData.putText(Language.SPANISH_CASTILIAN(), "Familias en otras Floras");
1508
        taxInteract.setTaxon2(famTaxon);
1509
        taxInteract.addSource(OriginalSourceType.PrimaryTaxonomicSource, null,null, famRef, null);
1510
        desc.addElement(taxInteract);
1511

    
1512
        //Concept Relation
1513
        famTaxon.addTaxonRelation(taxon, TaxonRelationshipType.INCLUDES(), taxon.getSec(), null);
1514

    
1515
    }
1516

    
1517

    
1518

    
1519

    
1520

    
1521
    /**
1522
     * @param record
1523
     * @param state
1524
     * @param taxon
1525
     */
1526
    // "CuW","PR PR*","Art","Hab(*)","May","Mat","IJ",
1527
//  "CuC","VC","Ci","SS","CA","Cam","LT",
1528
//  "CuE","Gr","Ho","SC","Gu",
1529
    private void makeProvincesDistribution(HashMap<String, String> record, CubaImportState state) {
1530
        List<String> areaKeys = Arrays.asList(new String[]{
1531
                "CuW","PR PR*","Art","Hab(*)","May","Mat","IJ",
1532
                "CuC","VC","Ci","SS","CA","Cam","LT",
1533
                "CuE","Gr","Ho","SC","Gu",
1534
                });
1535
        for (String areaKey : areaKeys){
1536
            state.setCubanProvince(true);
1537
            makeSingleProvinceDistribution(areaKey, record, state);
1538
        }
1539
    }
1540

    
1541
    private void makeOtherAreasDistribution(HashMap<String, String> record, CubaImportState state) {
1542
        List<String> areaKeys = Arrays.asList(new String[]{
1543
                "Esp","Ja","PR","Men","Bah","Cay",
1544
                "AmN","AmC","AmS","VM"});
1545
        for (String areaKey : areaKeys){
1546
            state.setCubanProvince(false);
1547
            makeSingleProvinceDistribution(areaKey, record, state);
1548
        }
1549
    }
1550

    
1551

    
1552

    
1553

    
1554
    /**
1555
     * @param areaKey
1556
     * @param record
1557
     * @param state
1558
     * @param highestStatus
1559
     * @return
1560
     * @throws UndefinedTransformerMethodException
1561
     */
1562
    private PresenceAbsenceTerm makeProvinceStatus(String areaKey,
1563
            HashMap<String, String> record,
1564
            CubaImportState state) throws UndefinedTransformerMethodException {
1565

    
1566
        String statusStr = record.get(areaKey);
1567
        if (statusStr == null){
1568
            return null;
1569
        }else{
1570
            statusStr = statusStr.trim();
1571
        }
1572
        PresenceAbsenceTerm status = state.getTransformer().getPresenceTermByKey(statusStr);
1573
        if (status == null){
1574
//            PresenceAbsenceTerm highestStatus = state.getHighestStatusForTaxon();
1575
            if (state.isCubanProvince() && isMinus(statusStr)){
1576
//                getAbsenceTermForStatus(state, highestStatus);
1577
                //we now handle cuban provinces same as external regions
1578
                status = state.getTransformer().getPresenceTermByKey("--");
1579
            }else if (! state.isCubanProvince() && isMinus(statusStr)){
1580
                status = state.getTransformer().getPresenceTermByKey("--");
1581
            }else{
1582
//                logger.warn("Unhandled status str for provinces / external regions: " + statusStr);
1583
                UUID statusUuid = state.getTransformer().getPresenceTermUuid(statusStr);
1584
                if (statusUuid == null){
1585
                    logger.error(state.getCurrentLine() + ": Undefined status str for provinces / external regions. No UUID given: '" + statusStr + "'");
1586
                }else{
1587
                    status = getPresenceTerm(state, statusUuid, statusStr, statusStr, statusStr, false);
1588
                }
1589
            }
1590
        }
1591

    
1592
        return status;
1593
    }
1594

    
1595

    
1596
    /**
1597
     * @param highestStatus
1598
     * @throws UndefinedTransformerMethodException
1599
     */
1600
    private PresenceAbsenceTerm getAbsenceTermForStatus(CubaImportState state, PresenceAbsenceTerm highestStatus) throws UndefinedTransformerMethodException {
1601
        if (highestStatus == null){
1602
            logger.warn(state.getCurrentLine() + ": Highest status not defined");
1603
            return null;
1604
        }
1605
        PresenceAbsenceTerm result = null;
1606
        if (highestStatus.equals(getStatus(state, "E"))){
1607
            result = getStatus(state, "-E");
1608
        }else if (highestStatus.getUuid().equals(state.getTransformer().getPresenceTermUuid("Ind.")) || highestStatus.equals(PresenceAbsenceTerm.NATIVE())){
1609
            result = getStatus(state, "-Ind.");
1610
        }else if (highestStatus.equals(getStatus(state, "Ind.?"))){
1611
            result = getStatus(state, "-Ind.?");  //TODO
1612
        }else if (highestStatus.equals(getStatus(state, "N"))){
1613
            result = getStatus(state, "-N");
1614
        }else if (highestStatus.equals(getStatus(state, "P"))){
1615
            result = getStatus(state, "-P");
1616
        }else if (highestStatus.equals(getStatus(state, "A"))){
1617
            result = getStatus(state, "-A");
1618
        }else if (highestStatus.equals(getStatus(state, "C"))){
1619
            result = getStatus(state, "-C");
1620
        }
1621
        logger.warn(state.getCurrentLine() + ": Absent province status could not be defined for highest status " + highestStatus.getTitleCache());
1622
        return result;
1623
    }
1624

    
1625

    
1626
    /**
1627
     * @param string
1628
     * @return
1629
     * @throws UndefinedTransformerMethodException
1630
     */
1631
    private PresenceAbsenceTerm getStatus(CubaImportState state, String key) throws UndefinedTransformerMethodException {
1632
        PresenceAbsenceTerm status = state.getTransformer().getPresenceTermByKey(key);
1633
        if (status == null){
1634
            UUID statusUuid = state.getTransformer().getPresenceTermUuid(key);
1635
            status = getPresenceTerm(state, statusUuid, null, null, null, false);
1636
        }
1637
        return status;
1638
    }
1639

    
1640

    
1641
    /**
1642
	 *  Stores parent-child, synonym and common name relationships
1643
	 */
1644
	@Override
1645
    protected void secondPass(CubaImportState state) {
1646
//		CyprusRow cyprusRow = state.getCyprusRow();
1647
		return;
1648
	}
1649

    
1650

    
1651
    @Override
1652
    protected boolean isIgnore(CubaImportState state) {
1653
        return ! state.getConfig().isDoTaxa();
1654
    }
1655

    
1656
    @Override
1657
    protected boolean doCheck(CubaImportState state) {
1658
        logger.warn("DoCheck not yet implemented for CubaExcelImport");
1659
        return true;
1660
    }
1661

    
1662
}
(1-1/5)