Project

General

Profile

Download (67 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.ExcelImportBase;
29
import eu.etaxonomy.cdm.io.excel.common.ExcelRowBase;
30
import eu.etaxonomy.cdm.model.agent.Person;
31
import eu.etaxonomy.cdm.model.agent.Team;
32
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
33
import eu.etaxonomy.cdm.model.common.Annotation;
34
import eu.etaxonomy.cdm.model.common.AnnotationType;
35
import eu.etaxonomy.cdm.model.common.CdmBase;
36
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
37
import eu.etaxonomy.cdm.model.common.Language;
38
import eu.etaxonomy.cdm.model.common.OriginalSourceType;
39
import eu.etaxonomy.cdm.model.common.Representation;
40
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
41
import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
42
import eu.etaxonomy.cdm.model.description.Distribution;
43
import eu.etaxonomy.cdm.model.description.Feature;
44
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
45
import eu.etaxonomy.cdm.model.description.TaxonDescription;
46
import eu.etaxonomy.cdm.model.description.TaxonInteraction;
47
import eu.etaxonomy.cdm.model.description.TextData;
48
import eu.etaxonomy.cdm.model.location.NamedArea;
49
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
50
import eu.etaxonomy.cdm.model.name.IBotanicalName;
51
import eu.etaxonomy.cdm.model.name.NameRelationship;
52
import eu.etaxonomy.cdm.model.name.NameRelationshipType;
53
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
54
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
55
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
56
import eu.etaxonomy.cdm.model.name.Rank;
57
import eu.etaxonomy.cdm.model.name.TaxonName;
58
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
59
import eu.etaxonomy.cdm.model.reference.Reference;
60
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
61
import eu.etaxonomy.cdm.model.taxon.Classification;
62
import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
63
import eu.etaxonomy.cdm.model.taxon.Synonym;
64
import eu.etaxonomy.cdm.model.taxon.SynonymType;
65
import eu.etaxonomy.cdm.model.taxon.Taxon;
66
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
67
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
68
import eu.etaxonomy.cdm.strategy.homotypicgroup.BasionymRelationCreator;
69
import eu.etaxonomy.cdm.strategy.parser.INonViralNameParser;
70
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
71

    
72
/**
73
 * @author a.mueller
74
 * @created 05.01.2016
75
 */
76

    
77
@Component
78
public class CubaExcelImport
79
        extends ExcelImportBase<CubaImportState, CubaImportConfigurator, ExcelRowBase> {
80
    private static final long serialVersionUID = -747486709409732371L;
81
    private static final Logger logger = Logger.getLogger(CubaExcelImport.class);
82

    
83
    private static final String HOMONYM_MARKER = "\\s+homon.?$";
84
    private static final String DOUBTFUL_MARKER = "^\\?\\s?";
85

    
86

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

    
90
    private static INonViralNameParser<?> nameParser = NonViralNameParserImpl.NewInstance();
91
    private static NomenclaturalCode nc = NomenclaturalCode.ICNAFP;
92

    
93
    private  static List<String> expectedKeys= Arrays.asList(new String[]{
94
            "Fam. default","Fam. FRC","Fam. A&S","Fam. FC",
95
            "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"});
96

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

    
103

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

    
124

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

    
134
        String line = state.getCurrentLine() + ": ";
135
        List<PresenceAbsenceTerm> result = new ArrayList<>();
136

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

    
145
        state.setEndemic(false);
146

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

    
285

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

    
297
    }
298

    
299

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

    
308

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

    
317

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

    
335

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

    
348

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

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

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

    
370

    
371
        if (synonymStr == null){
372
            //TODO test that this is not a synonym only line
373
            return;
374
        }
375

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

    
381

    
382
        synonymStr = synonymStr.trim();
383
        synonymStr = synonymStr.replace("[taxon]", "[infraspec.]");
384

    
385
//        String heterotypicRegExStr = "([^\\(]{5,}(\\(.+\\))?[^\\)\\(]{2,})(\\((.{6,})\\))?";
386
//        String heterotypicRegExStr = "([^\\(]{5,})(\\((.{6,})\\))?";
387

    
388
//        Pattern heterotypicRegEx = Pattern.compile(heterotypicRegExStr + homonymRegExStr);
389

    
390

    
391
        Matcher missapliedMatcher = missapliedRegEx.matcher(synonymStr);
392
        Matcher nomInvalMatcher = nomInvalRegEx.matcher(synonymStr);
393
        Matcher acceptedMatcher = acceptedRegEx.matcher(synonymStr);
394
        Matcher heterotypicMatcher = heterotypicRegEx.matcher(synonymStr);
395
        Matcher sphalmMatcher = sphalmRegEx.matcher(synonymStr);
396

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

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

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

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

    
524
    }
525

    
526

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

    
542

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

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

    
578
    }
579

    
580

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

    
598
        List<IBotanicalName> homotypicNameList = new ArrayList<>();
599
        homotypicNameList.add(homotypicName);
600

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

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

    
636

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

    
646

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

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

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

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

    
753

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

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

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

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

    
820

    
821
    /**
822
     * @param combinationAuthorship
823
     * @param basi
824
     * @return
825
     */
826
    private boolean matchAuthor(TeamOrPersonBase<?> author1, TeamOrPersonBase<?> author2) {
827
        if (author1 == null || author2 == null){
828
            return false;
829
        }else {
830
            return author1.getNomenclaturalTitle().equals(author2.getNomenclaturalTitle());
831
        }
832
    }
833

    
834

    
835
    /**
836
     * @param record
837
     * @param state
838
     * @param taxon
839
     */
840
    private void makeNotes(HashMap<String, String> record, CubaImportState state) {
841
        String notesStr = getValue(record, "(Notas)");
842
        if (notesStr == null){
843
            return;
844
        }else{
845
            Annotation annotation = Annotation.NewDefaultLanguageInstance(notesStr);
846
            //TODO
847
            annotation.setAnnotationType(AnnotationType.TECHNICAL());
848
            state.getCurrentTaxon().addAnnotation(annotation);
849
        }
850
    }
851

    
852

    
853
    /**
854
     * @param record
855
     * @param state
856
     * @param familyTaxon
857
     * @return
858
     */
859
    private Taxon makeTaxon(HashMap<String, String> record, CubaImportState state, TaxonNode familyNode, boolean isSynonym) {
860
        String taxonStrOrig = getValue(record, "Taxón");
861
        if (taxonStrOrig == null){
862
            return isSynonym ? state.getCurrentTaxon() : null;
863
        }
864

    
865
        boolean isAbsent = false;
866
        String taxonStr = taxonStrOrig;
867
        if (taxonStrOrig.startsWith("[") && taxonStrOrig.endsWith("]")){
868
            taxonStr = taxonStr.substring(1, taxonStr.length() - 1);
869
            isAbsent = true;
870
        }
871

    
872
        boolean isAuct = false;
873
        if (taxonStr.endsWith("auct.")){
874
            isAuct = true;
875
            taxonStr.replace("auct.", "").trim();
876
        }
877
        state.setTaxonIsAbsent(isAbsent);
878
        IBotanicalName botanicalName = makeName(state, taxonStr);
879
        Reference sec = getSecReference(state);
880
        Taxon taxon = Taxon.NewInstance(botanicalName, sec);
881
        if (isAuct){
882
            taxon.setAppendedPhrase("auct.");
883
        }
884

    
885
        TaxonNode higherNode;
886
        if (botanicalName.isProtectedTitleCache()){
887
            logger.warn(state.getCurrentLine() + ": Taxon could not be parsed: " + taxonStrOrig);
888
            higherNode = familyNode;
889
        }else{
890
            String genusStr = botanicalName.getGenusOrUninomial();
891
            Taxon genus = state.getHigherTaxon(genusStr);
892
            if (genus != null){
893
                higherNode = genus.getTaxonNodes().iterator().next();
894
            }else{
895
                IBotanicalName name = TaxonNameFactory.NewBotanicalInstance(Rank.GENUS());
896
                name.addSource(makeOriginalSource(state));
897
                name.setGenusOrUninomial(genusStr);
898
                genus = Taxon.NewInstance(name, sec);
899
                genus.addSource(makeOriginalSource(state));
900
                higherNode = familyNode.addChildTaxon(genus, null, null);
901
                state.putHigherTaxon(genusStr, genus);
902
            }
903
        }
904
        taxon.addSource(makeOriginalSource(state));
905

    
906
        TaxonNode newNode = higherNode.addChildTaxon(taxon, null, null);
907
        if(isAbsent){
908
            botanicalName.setTitleCache(taxonStrOrig, true);
909
            newNode.setExcluded(true);
910
        }
911

    
912
        return taxon;
913
    }
914

    
915
    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ó]+\\.?";
916
    private final Pattern orthVarRegEx = Pattern.compile(orthVarRegExStr);
917
    /**
918
     * @param taxonStr
919
     * @return
920
     */
921
    private IBotanicalName makeName(CubaImportState state, String nameStrOrig) {
922
        //normalize
923
        String nameStr = normalizeStatus(nameStrOrig);
924
        //orthVar
925
        Matcher orthVarMatcher = orthVarRegEx.matcher(nameStr);
926
        String orthVar = null;
927
        if (orthVarMatcher.matches()) {
928
            orthVar = orthVarMatcher.group(1);
929
            nameStr = nameStr.replace(" " + orthVar, "").trim().replaceAll("\\s{2,}", " ");
930
            orthVar = orthVar.substring(2, orthVar.length() - 2);
931
        }
932

    
933
        boolean isNomInval = false;
934
        if (nameStr.endsWith("nom. inval.")){
935
            isNomInval = true;
936
            nameStr = nameStr.replace("nom. inval.", "").trim();
937
        }
938

    
939
        TaxonName result = (TaxonName)nameParser.parseReferencedName(nameStr, nc, Rank.SPECIES());
940
        result.addSource(makeOriginalSource(state));
941
        if (isNomInval){
942
            result.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.INVALID()));
943
        }
944
        if (orthVar != null){
945
            TaxonName orthVarName = (TaxonName)result.clone();
946
            orthVarName.addSource(makeOriginalSource(state));
947
            //TODO
948
            Reference citation = null;
949
            orthVarName.addRelationshipToName(result, NameRelationshipType.ORTHOGRAPHIC_VARIANT(), citation, null, null);
950
            orthVarName.setSpecificEpithet(orthVar);
951
        }
952
        normalizeAuthors(result);
953
        return result;
954

    
955
    }
956

    
957
    /**
958
     * @param result
959
     */
960
    private void normalizeAuthors(IBotanicalName result) {
961
        result.setCombinationAuthorship(normalizeAuthor(result.getCombinationAuthorship()));
962
        result.setExCombinationAuthorship(normalizeAuthor(result.getExCombinationAuthorship()));
963
        result.setExBasionymAuthorship(normalizeAuthor(result.getExBasionymAuthorship()));
964
        result.setBasionymAuthorship(normalizeAuthor(result.getBasionymAuthorship()));
965

    
966
    }
967

    
968

    
969
    /**
970
     * @param combinationAuthorship
971
     * @return
972
     */
973
    private TeamOrPersonBase<?> normalizeAuthor(TeamOrPersonBase<?> author) {
974
        if (author == null){
975
            return null;
976
        }
977
        TeamOrPersonBase<?> result;
978
        if (author.isInstanceOf(Person.class)){
979
            result = normalizePerson(CdmBase.deproxy(author, Person.class));
980
        }else{
981
            Team team = CdmBase.deproxy(author, Team.class);
982
            List<Person> list = team.getTeamMembers();
983
            for(int i = 0; i < list.size(); i++){
984
                Person person = list.get(i);
985
                Person tmpMember = normalizePerson(person);
986
                list.set(i, tmpMember);
987
            }
988
            return team;
989
        }
990
        return result;
991
    }
992

    
993

    
994
    /**
995
     * @param deproxy
996
     * @return
997
     */
998
    private Person normalizePerson(Person person) {
999
        String title = person.getNomenclaturalTitle();
1000
        title = title.replaceAll("(?<=[a-zA-Z])\\.(?=[a-zA-Z])", ". ");
1001
        person.setNomenclaturalTitle(title);
1002
        boolean isFilius = title.endsWith(" f.");
1003
        if (isFilius){
1004
            title.replace(" f.", "");
1005
        }
1006

    
1007
        String[] splits = title.split("\\s+");
1008
        int nNotFirstName = isFilius ? 2 : 1;
1009
        person.setLastname(splits[splits.length - nNotFirstName] + (isFilius? " f." : ""));
1010
        person.setFirstname(CdmUtils.concat(" ", Arrays.copyOfRange(splits, 0, splits.length-nNotFirstName)));
1011
        return person;
1012
    }
1013

    
1014

    
1015
    /**
1016
     * @param state
1017
     * @return
1018
     */
1019
    private Reference getSecReference(CubaImportState state) {
1020
        Reference result = state.getSecReference();
1021
        if (result == null){
1022
            result = ReferenceFactory.newDatabase();
1023
            result.setTitle("Flora of Cuba");
1024
            state.setSecReference(result);
1025
        }
1026
        return result;
1027
    }
1028

    
1029

    
1030
    private static final String[] nomStatusStrings = new String[]{"nom. cons.", "ined.", "nom. illeg.",
1031
            "nom. rej.","nom. cons. prop.","nom. altern.","nom. confus.","nom. dub.", "nom. nud."};
1032
    /**
1033
     * @param taxonStr
1034
     * @return
1035
     */
1036
    private String normalizeStatus(String nameStr) {
1037
        if (nameStr == null){
1038
            return null;
1039
        }
1040
        String result = nameStr.replaceAll(HOMONYM_MARKER, "").trim();
1041
        for (String nomStatusStr : nomStatusStrings){
1042
            nomStatusStr = " " + nomStatusStr;
1043
            if (result.endsWith(nomStatusStr)){
1044
                result = result.replace(nomStatusStr, "," + nomStatusStr);
1045
            }
1046
        }
1047
        result = result.replaceAll(DOUBTFUL_MARKER, "").trim();
1048
        result = result.replace("[taxon]", "[infraspec.]");
1049
        return result;
1050

    
1051

    
1052
    }
1053

    
1054

    
1055
    /**
1056
     * @param record
1057
     * @param state
1058
     * @return
1059
     */
1060
    private TaxonNode getFamilyTaxon(HashMap<String, String> record, CubaImportState state) {
1061
        String familyStr = getValue(record, "Fam. default");
1062
        if (familyStr == null){
1063
            return null;
1064
        }
1065
        familyStr = familyStr.trim();
1066
        String alternativeFamilyStr = null;
1067
        if (familyStr.contains("/")){
1068
            String[] splits = familyStr.split("/");
1069
            if (splits.length > 2){
1070
                logger.warn(state.getCurrentLine() +": " + "More than 1 alternative name:" + familyStr);
1071
            }
1072
            familyStr = splits[0].trim();
1073
            alternativeFamilyStr = splits[1].trim();
1074
        }
1075

    
1076
        Taxon family = state.getHigherTaxon(familyStr);
1077
        TaxonNode familyNode;
1078
        if (family != null){
1079
            familyNode = family.getTaxonNodes().iterator().next();
1080
        }else{
1081
            TaxonName name = (TaxonName)makeFamilyName(state, familyStr);
1082
            Reference sec = getSecReference(state);
1083
            family = Taxon.NewInstance(name, sec);
1084
            ITaxonTreeNode rootNode = getClassification(state);
1085
            familyNode = rootNode.addChildTaxon(family, sec, null);
1086
            state.putHigherTaxon(familyStr, family);
1087

    
1088
        }
1089

    
1090
        if (isNotBlank(alternativeFamilyStr)){
1091
            NameRelationshipType type = NameRelationshipType.ALTERNATIVE_NAME();
1092
            TaxonName alternativeName = (TaxonName)makeFamilyName(state, alternativeFamilyStr);
1093
            IBotanicalName familyName = family.getName();
1094
            boolean hasRelation = false;
1095
            for (NameRelationship nameRel : familyName.getRelationsToThisName()){
1096
                if (nameRel.getType().equals(type)){
1097
                    if (nameRel.getFromName().equals(alternativeName)){
1098
                        hasRelation = true;
1099
                    }
1100
                }
1101
            }
1102
            if (!hasRelation){
1103
                familyName.addRelationshipFromName(alternativeName, type, null);
1104
            }
1105

    
1106
        }
1107

    
1108
        return familyNode;
1109
    }
1110

    
1111

    
1112
    /**
1113
     * @param state
1114
     * @param taxon
1115
     */
1116
    private void validateTaxonIsAbsent(CubaImportState state, Taxon taxon) {
1117
        if (!state.isTaxonIsAbsent()){
1118
            return;
1119
        }
1120

    
1121
        for (DescriptionElementBase el : taxon.getDescriptions().iterator().next().getElements()){
1122
            if (el instanceof Distribution){
1123
                Distribution dist = (Distribution)el;
1124
                NamedArea area = dist.getArea();
1125
                if (isCubanArea(area)){
1126
                    PresenceAbsenceTerm status = dist.getStatus();
1127
                    if (status != null && !status.isAbsenceTerm()){
1128
                        if (!isDoubtfulTerm(status)){
1129
                            String name = taxon.getName().getTitleCache();
1130
                            logger.error(state.getCurrentLine() +": Taxon ("+name+")is absent'[]' but has presence distribution: " + status.getTitleCache());
1131
                            return;
1132
                        }
1133
                    }
1134
                }
1135
            }
1136
        }
1137
    }
1138

    
1139
    /**
1140
     * @param state
1141
     * @param taxon
1142
     */
1143
    private void validateEndemic(CubaImportState state, Taxon taxon) {
1144

    
1145
        boolean hasExternalPresence = false;
1146
        for (DescriptionElementBase el : taxon.getDescriptions().iterator().next().getElements()){
1147
            if (el instanceof Distribution){
1148
                Distribution dist = (Distribution)el;
1149
                NamedArea area = dist.getArea();
1150
                if (!isCubanArea(area)){
1151
                    PresenceAbsenceTerm status = dist.getStatus();
1152
                    if (status != null && !status.isAbsenceTerm()){
1153
                        if (!isDoubtfulTerm(status)){
1154
                            hasExternalPresence = true;
1155
                            if (state.isEndemic()){
1156
                                String name = taxon.getName().getTitleCache();
1157
                                logger.error(state.getCurrentLine() +": Taxon ("+name+")is endemic but has non-cuban distribution: " + area.getIdInVocabulary() + "-" + status.getIdInVocabulary());
1158
                                return;
1159
                            }
1160
                        }
1161
                    }
1162
                }
1163
            }
1164
        }
1165
        if (!state.isEndemic() && ! hasExternalPresence){
1166
            String name = taxon.getName().getTitleCache();
1167
            logger.error(state.getCurrentLine() +": Taxon ("+name+")is not endemic but has no non-cuban distribution" );
1168
        }
1169
    }
1170

    
1171

    
1172
    /**
1173
     * @param state
1174
     * @param taxon
1175
     * @param famStr
1176
     * @param famRef
1177
     * @return
1178
     */
1179
    private Taxon makeAlternativeFamilyTaxon(CubaImportState state, String famStr, Reference famRef) {
1180
        String key = famRef.getTitle() + ":"+ famStr;
1181
        Taxon family = state.getHigherTaxon(key);
1182
        if (family == null){
1183
            IBotanicalName name = makeFamilyName(state, famStr);
1184
            family = Taxon.NewInstance(name, famRef);
1185
            state.putHigherTaxon(key, family);
1186
        }
1187

    
1188
        return family;
1189
    }
1190

    
1191

    
1192
    /**
1193
     * @param state
1194
     * @param famStr
1195
     * @return
1196
     */
1197
    private IBotanicalName makeFamilyName(CubaImportState state, String famStr) {
1198
        IBotanicalName name = state.getFamilyName(famStr);
1199
        if (name == null){
1200
            name = TaxonNameFactory.NewBotanicalInstance(Rank.FAMILY());
1201
            name.setGenusOrUninomial(famStr);
1202
            state.putFamilyName(famStr, name);
1203
            name.addSource(makeOriginalSource(state));
1204
        }
1205
        return name;
1206
    }
1207

    
1208

    
1209
    /**
1210
     * @param state
1211
     * @return
1212
     */
1213
    private TaxonNode getClassification(CubaImportState state) {
1214
        Classification classification = state.getClassification();
1215
        if (classification == null){
1216
            classification = getClassificationService().find(state.getConfig().getClassificationUuid());
1217
        }
1218
        TaxonNode rootNode = state.getRootNode();
1219
        if (rootNode == null){
1220
            rootNode = getTaxonNodeService().find(plantaeUuid);
1221
        }
1222
        if (rootNode == null){
1223
            Reference sec = getSecReference(state);
1224
            if (classification == null){
1225
                String classificationName = state.getConfig().getClassificationName();
1226
                //TODO
1227
                Language language = Language.DEFAULT();
1228
                classification = Classification.NewInstance(classificationName, sec, language);
1229
                state.setClassification(classification);
1230
                classification.setUuid(state.getConfig().getClassificationUuid());
1231
                classification.getRootNode().setUuid(rootUuid);
1232
            }
1233

    
1234
            IBotanicalName plantaeName = TaxonNameFactory.NewBotanicalInstance(Rank.KINGDOM());
1235
            plantaeName.setGenusOrUninomial("Plantae");
1236
            Taxon plantae = Taxon.NewInstance(plantaeName, sec);
1237
            TaxonNode plantaeNode = classification.addChildTaxon(plantae, null, null);
1238
            plantaeNode.setUuid(plantaeUuid);
1239
            state.setRootNode(plantaeNode);
1240
            getClassificationService().save(classification);
1241

    
1242
            rootNode = plantaeNode;
1243
        }
1244
        return rootNode;
1245
    }
1246

    
1247

    
1248
    /**
1249
     * @param record
1250
     * @param originalKey
1251
     * @return
1252
     */
1253
    private String getValue(HashMap<String, String> record, String originalKey) {
1254
        String value = record.get(originalKey);
1255
        if (! StringUtils.isBlank(value)) {
1256
        	if (logger.isDebugEnabled()) { logger.debug(originalKey + ": " + value); }
1257
        	value = CdmUtils.removeDuplicateWhitespace(value.trim()).toString();
1258
        	return value;
1259
        }else{
1260
        	return null;
1261
        }
1262
    }
1263

    
1264

    
1265

    
1266
	/**
1267
	 *  Stores taxa records in DB
1268
	 */
1269
	@Override
1270
    protected void firstPass(CubaImportState state) {
1271
	    boolean isSynonymOnly = false;
1272

    
1273
        String line = state.getCurrentLine() + ": ";
1274
        HashMap<String, String> record = state.getOriginalRecord();
1275

    
1276
        Set<String> keys = record.keySet();
1277
        for (String key: keys) {
1278
            if (! expectedKeys.contains(key)){
1279
                logger.warn(line + "Unexpected Key: " + key);
1280
            }
1281
        }
1282

    
1283
        if (record.get("Fam. default") == null && keys.size() == 2 && record.get("Syn.") == null && record.get("Nat") != null && record.get("Adv") != null){
1284
            //second header line, don't handle
1285
            return;
1286
        }
1287

    
1288
        //Fam.
1289
        TaxonNode familyTaxon = getFamilyTaxon(record, state);
1290
        if (familyTaxon == null){
1291
            if (record.get("Taxón") != null){
1292
                logger.warn(line + "Family not recognized but taxon exists: " + record.get("Taxón"));
1293
                return;
1294
            }else if (record.get("Syn.") == null){
1295
                logger.warn(line + "Family not recognized but also no synonym exists");
1296
                return;
1297
            }else{
1298
                isSynonymOnly = true;
1299
            }
1300
        }
1301

    
1302
       //Taxón
1303
        Taxon taxon = makeTaxon(record, state, familyTaxon, isSynonymOnly);
1304
        if (taxon == null && ! isSynonymOnly){
1305
            logger.warn(line + "taxon could not be created and is null");
1306
            return;
1307
        }
1308
        state.setCurrentTaxon(taxon);
1309

    
1310
        //Fam. ALT
1311
        if (!isSynonymOnly){
1312
            makeAlternativeFamilies(record, state, familyTaxon, taxon);
1313
        }
1314

    
1315
        //(Notas)
1316
        makeNotes(record, state);
1317

    
1318
        //Syn.
1319
        makeSynonyms(record, state, !isSynonymOnly);
1320

    
1321
        //End, Ind, Ind? D, Nat N, Dud P, Adv A, Cult C
1322
        makeCubanDistribution(record, state);
1323

    
1324

    
1325
//        "CuW","PR PR*","Art","Hab(*)","May","Mat","IJ",
1326
//        "CuC","VC","Ci","SS","CA","Cam","LT",
1327
//        "CuE","Gr","Ho","SC","Gu",
1328
        makeProvincesDistribution(record, state);
1329

    
1330
//      "Esp","Ja","PR","Men","Bah","Cay",
1331
//      "AmN","AmC","AmS","VM"});
1332
        makeOtherAreasDistribution(record, state);
1333

    
1334
        validateTaxonIsAbsent(state, taxon);
1335
        if (!isSynonymOnly){
1336
            validateEndemic(state, taxon);
1337
        }
1338

    
1339
        state.setHighestStatusForTaxon(null);
1340

    
1341
		return;
1342
    }
1343

    
1344

    
1345
    /**
1346
     * @param state
1347
     * @return
1348
     */
1349
    private IdentifiableSource makeOriginalSource(CubaImportState state) {
1350
        return IdentifiableSource.NewDataImportInstance("line: " + state.getCurrentLine(), null, state.getConfig().getSourceReference());
1351
    }
1352
    /**
1353
     * @param state
1354
     * @return
1355
     */
1356
    private DescriptionElementSource makeDescriptionSource(CubaImportState state) {
1357
        return DescriptionElementSource.NewDataImportInstance("line: " + state.getCurrentLine(), null, state.getConfig().getSourceReference());
1358
    }
1359

    
1360
    private static Set<UUID> doubtfulStatus = new HashSet<>();
1361

    
1362
    /**
1363
     * @param status
1364
     * @return
1365
     */
1366
    private boolean isDoubtfulTerm(PresenceAbsenceTerm status) {
1367
        if (doubtfulStatus.isEmpty()){
1368
            doubtfulStatus.add(CubaTransformer.nonNativeDoubtfullyNaturalisedUuid);
1369
            doubtfulStatus.add(CubaTransformer.doubtfulIndigenousDoubtfulUuid);
1370
            doubtfulStatus.add(CubaTransformer.endemicDoubtfullyPresentUuid);
1371
            doubtfulStatus.add(CubaTransformer.naturalisedDoubtfullyPresentUuid);
1372
            doubtfulStatus.add(CubaTransformer.nonNativeDoubtfullyPresentUuid);
1373
            doubtfulStatus.add(CubaTransformer.occasionallyCultivatedUuid);
1374
            doubtfulStatus.add(CubaTransformer.rareCasualUuid);
1375
            doubtfulStatus.add(PresenceAbsenceTerm.NATIVE_PRESENCE_QUESTIONABLE().getUuid());
1376
            doubtfulStatus.add(PresenceAbsenceTerm.CULTIVATED_PRESENCE_QUESTIONABLE().getUuid());
1377
        }
1378
        boolean isDoubtful = doubtfulStatus.contains(status.getUuid());
1379
        return isDoubtful;
1380
    }
1381

    
1382

    
1383
    /**
1384
     * @param area
1385
     * @return
1386
     */
1387
    private boolean isCubanArea(NamedArea area) {
1388
        if (area.getUuid().equals(CubaTransformer.uuidCuba)){
1389
            return true;
1390
        }else if (area.getPartOf()!= null){
1391
            return isCubanArea(area.getPartOf());
1392
        }else{
1393
            return false;
1394
        }
1395
    }
1396

    
1397

    
1398
    /**
1399
     * @param record
1400
     * @param state
1401
     * @param familyTaxon
1402
     * @param taxon
1403
     */
1404
    private void makeAlternativeFamilies(HashMap<String, String> record,
1405
            CubaImportState state,
1406
            TaxonNode familyTaxon,
1407
            Taxon taxon) {
1408

    
1409
        String famFRC = record.get("Fam. FRC");
1410
        String famAS = record.get("Fam. A&S");
1411
        String famFC = record.get("Fam. FC");
1412

    
1413
        Reference refFRC = makeReference(state, CubaTransformer.uuidRefFRC);
1414
        Reference refAS = makeReference(state, CubaTransformer.uuidRefAS);
1415
        Reference refFC = makeReference(state, CubaTransformer.uuidRefFC);
1416

    
1417
        makeSingleAlternativeFamily(state, taxon, famFRC, refFRC);
1418
        makeSingleAlternativeFamily(state, taxon, famAS, refAS);
1419
        makeSingleAlternativeFamily(state, taxon, famFC, refFC);
1420
    }
1421

    
1422

    
1423
    /**
1424
     * @param state
1425
     * @param uuidreffrc
1426
     * @return
1427
     */
1428
    private Reference makeReference(CubaImportState state, UUID uuidRef) {
1429
        Reference ref = state.getReference(uuidRef);
1430
        if (ref == null){
1431
            ref = getReferenceService().find(uuidRef);
1432
            state.putReference(uuidRef, ref);
1433
        }
1434
        return ref;
1435
    }
1436

    
1437

    
1438
    /**
1439
     * @param state
1440
     * @param taxon
1441
     * @param famString
1442
     * @param famRef
1443
     */
1444
    private void makeSingleAlternativeFamily(CubaImportState state, Taxon taxon, String famStr, Reference famRef) {
1445
        if (isBlank(famStr)){
1446
            famStr = "-";
1447
//            return;
1448
        }
1449

    
1450
        TaxonDescription desc = getTaxonDescription(taxon, false, true);
1451

    
1452
        UUID altFamUuid1;
1453
        UUID altFamUuid2;
1454
        try {
1455
            altFamUuid1 = state.getTransformer().getFeatureUuid("Alt.Fam.");
1456
            altFamUuid2 = state.getTransformer().getFeatureUuid("Alt.Fam.2");
1457
        } catch (UndefinedTransformerMethodException e) {
1458
            throw new RuntimeException(e);
1459
        }
1460

    
1461

    
1462
        Taxon famTaxon = makeAlternativeFamilyTaxon(state, famStr, famRef);
1463

    
1464

    
1465
        //TextData
1466
        Feature feature1 = getFeature(state, altFamUuid1, "Families in other Floras (Text)", "Families in other Floras (Text)", "Other floras", null);
1467
        feature1.addRepresentation(Representation.NewInstance("Familias en otras Floras", "Familias en otras Floras", null, Language.SPANISH_CASTILIAN()));
1468
//        TextData textData = TextData.NewInstance(feature1, famStr, Language.DEFAULT(), null);
1469
        TextData textData = TextData.NewInstance(feature1, null, Language.DEFAULT(), null);
1470
        textData.addSource(OriginalSourceType.PrimaryTaxonomicSource, null,null, famRef, null, famTaxon.getName(),null);
1471
        desc.addElement(textData);
1472

    
1473

    
1474

    
1475
        //TaxonInteraction
1476
        Feature feature2 = getFeature(state, altFamUuid2, "Families in other Floras", "Families in other Floras", "Other floras(2)", null);
1477
        feature2.setSupportsTaxonInteraction(true);
1478
        feature2.addRepresentation(Representation.NewInstance("Familias en otras Floras", "Familias en otras Floras", null, Language.SPANISH_CASTILIAN()));
1479
        TaxonInteraction taxInteract = TaxonInteraction.NewInstance(feature2);
1480
        textData.putText(Language.SPANISH_CASTILIAN(), "Familias en otras Floras");
1481
        taxInteract.setTaxon2(famTaxon);
1482
        taxInteract.addSource(OriginalSourceType.PrimaryTaxonomicSource, null,null, famRef, null);
1483
        desc.addElement(taxInteract);
1484

    
1485
        //Concept Relation
1486
        famTaxon.addTaxonRelation(taxon, TaxonRelationshipType.INCLUDES(), taxon.getSec(), null);
1487

    
1488
    }
1489

    
1490

    
1491

    
1492

    
1493

    
1494
    /**
1495
     * @param record
1496
     * @param state
1497
     * @param taxon
1498
     */
1499
    // "CuW","PR PR*","Art","Hab(*)","May","Mat","IJ",
1500
//  "CuC","VC","Ci","SS","CA","Cam","LT",
1501
//  "CuE","Gr","Ho","SC","Gu",
1502
    private void makeProvincesDistribution(HashMap<String, String> record, CubaImportState state) {
1503
        List<String> areaKeys = Arrays.asList(new String[]{
1504
                "CuW","PR PR*","Art","Hab(*)","May","Mat","IJ",
1505
                "CuC","VC","Ci","SS","CA","Cam","LT",
1506
                "CuE","Gr","Ho","SC","Gu",
1507
                });
1508
        for (String areaKey : areaKeys){
1509
            state.setCubanProvince(true);
1510
            makeSingleProvinceDistribution(areaKey, record, state);
1511
        }
1512
    }
1513

    
1514
    private void makeOtherAreasDistribution(HashMap<String, String> record, CubaImportState state) {
1515
        List<String> areaKeys = Arrays.asList(new String[]{
1516
                "Esp","Ja","PR","Men","Bah","Cay",
1517
                "AmN","AmC","AmS","VM"});
1518
        for (String areaKey : areaKeys){
1519
            state.setCubanProvince(false);
1520
            makeSingleProvinceDistribution(areaKey, record, state);
1521
        }
1522
    }
1523

    
1524

    
1525

    
1526

    
1527
    /**
1528
     * @param areaKey
1529
     * @param record
1530
     * @param state
1531
     * @param highestStatus
1532
     * @return
1533
     * @throws UndefinedTransformerMethodException
1534
     */
1535
    private PresenceAbsenceTerm makeProvinceStatus(String areaKey,
1536
            HashMap<String, String> record,
1537
            CubaImportState state) throws UndefinedTransformerMethodException {
1538

    
1539
        String statusStr = record.get(areaKey);
1540
        if (statusStr == null){
1541
            return null;
1542
        }else{
1543
            statusStr = statusStr.trim();
1544
        }
1545
        PresenceAbsenceTerm status = state.getTransformer().getPresenceTermByKey(statusStr);
1546
        if (status == null){
1547
//            PresenceAbsenceTerm highestStatus = state.getHighestStatusForTaxon();
1548
            if (state.isCubanProvince() && isMinus(statusStr)){
1549
//                getAbsenceTermForStatus(state, highestStatus);
1550
                //we now handle cuban provinces same as external regions
1551
                status = state.getTransformer().getPresenceTermByKey("--");
1552
            }else if (! state.isCubanProvince() && isMinus(statusStr)){
1553
                status = state.getTransformer().getPresenceTermByKey("--");
1554
            }else{
1555
//                logger.warn("Unhandled status str for provinces / external regions: " + statusStr);
1556
                UUID statusUuid = state.getTransformer().getPresenceTermUuid(statusStr);
1557
                if (statusUuid == null){
1558
                    logger.error(state.getCurrentLine() + ": Undefined status str for provinces / external regions. No UUID given: '" + statusStr + "'");
1559
                }else{
1560
                    status = getPresenceTerm(state, statusUuid, statusStr, statusStr, statusStr, false);
1561
                }
1562
            }
1563
        }
1564

    
1565
        return status;
1566
    }
1567

    
1568

    
1569
    /**
1570
     * @param highestStatus
1571
     * @throws UndefinedTransformerMethodException
1572
     */
1573
    private PresenceAbsenceTerm getAbsenceTermForStatus(CubaImportState state, PresenceAbsenceTerm highestStatus) throws UndefinedTransformerMethodException {
1574
        if (highestStatus == null){
1575
            logger.warn(state.getCurrentLine() + ": Highest status not defined");
1576
            return null;
1577
        }
1578
        PresenceAbsenceTerm result = null;
1579
        if (highestStatus.equals(getStatus(state, "E"))){
1580
            result = getStatus(state, "-E");
1581
        }else if (highestStatus.getUuid().equals(state.getTransformer().getPresenceTermUuid("Ind.")) || highestStatus.equals(PresenceAbsenceTerm.NATIVE())){
1582
            result = getStatus(state, "-Ind.");
1583
        }else if (highestStatus.equals(getStatus(state, "Ind.?"))){
1584
            result = getStatus(state, "-Ind.?");  //TODO
1585
        }else if (highestStatus.equals(getStatus(state, "N"))){
1586
            result = getStatus(state, "-N");
1587
        }else if (highestStatus.equals(getStatus(state, "P"))){
1588
            result = getStatus(state, "-P");
1589
        }else if (highestStatus.equals(getStatus(state, "A"))){
1590
            result = getStatus(state, "-A");
1591
        }else if (highestStatus.equals(getStatus(state, "C"))){
1592
            result = getStatus(state, "-C");
1593
        }
1594
        logger.warn(state.getCurrentLine() + ": Absent province status could not be defined for highest status " + highestStatus.getTitleCache());
1595
        return result;
1596
    }
1597

    
1598

    
1599
    /**
1600
     * @param string
1601
     * @return
1602
     * @throws UndefinedTransformerMethodException
1603
     */
1604
    private PresenceAbsenceTerm getStatus(CubaImportState state, String key) throws UndefinedTransformerMethodException {
1605
        PresenceAbsenceTerm status = state.getTransformer().getPresenceTermByKey(key);
1606
        if (status == null){
1607
            UUID statusUuid = state.getTransformer().getPresenceTermUuid(key);
1608
            status = getPresenceTerm(state, statusUuid, null, null, null, false);
1609
        }
1610
        return status;
1611
    }
1612

    
1613

    
1614
    /**
1615
	 *  Stores parent-child, synonym and common name relationships
1616
	 */
1617
	@Override
1618
    protected void secondPass(CubaImportState state) {
1619
//		CyprusRow cyprusRow = state.getCyprusRow();
1620
		return;
1621
	}
1622

    
1623

    
1624
    @Override
1625
    protected boolean isIgnore(CubaImportState state) {
1626
        return ! state.getConfig().isDoTaxa();
1627
    }
1628

    
1629
    @Override
1630
    protected boolean doCheck(CubaImportState state) {
1631
        logger.warn("DoCheck not yet implemented for CubaExcelImport");
1632
        return true;
1633
    }
1634

    
1635
}
(1-1/5)