Project

General

Profile

Download (67.1 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.description.DescriptionElementBase;
39
import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
40
import eu.etaxonomy.cdm.model.description.Distribution;
41
import eu.etaxonomy.cdm.model.description.Feature;
42
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
43
import eu.etaxonomy.cdm.model.description.TaxonDescription;
44
import eu.etaxonomy.cdm.model.description.TaxonInteraction;
45
import eu.etaxonomy.cdm.model.description.TextData;
46
import eu.etaxonomy.cdm.model.location.NamedArea;
47
import eu.etaxonomy.cdm.model.name.BotanicalName;
48
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
49
import eu.etaxonomy.cdm.model.name.NameRelationship;
50
import eu.etaxonomy.cdm.model.name.NameRelationshipType;
51
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
52
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
53
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
54
import eu.etaxonomy.cdm.model.name.Rank;
55
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
56
import eu.etaxonomy.cdm.model.reference.Reference;
57
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
58
import eu.etaxonomy.cdm.model.taxon.Classification;
59
import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
60
import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;
61
import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
62
import eu.etaxonomy.cdm.model.taxon.Taxon;
63
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
64
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
65
import eu.etaxonomy.cdm.strategy.parser.INonViralNameParser;
66
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
67

    
68
/**
69
 * @author a.mueller
70
 * @created 05.01.2016
71
 */
72

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

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

    
81

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

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

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

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

    
98

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

    
119

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

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

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

    
140
        state.setEndemic(false);
141

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

    
280

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

    
292
    }
293

    
294

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

    
303

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

    
312

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

    
330

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

    
343

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

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

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

    
365

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

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

    
376

    
377
        synonymStr = synonymStr.trim();
378
        synonymStr = synonymStr.replace("[taxon]", "[infraspec.]");
379

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

    
383
//        Pattern heterotypicRegEx = Pattern.compile(heterotypicRegExStr + homonymRegExStr);
384

    
385

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

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

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

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

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

    
519
    }
520

    
521

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

    
537

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

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

    
573
    }
574

    
575

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

    
593
        List<BotanicalName> homotypicNameList = new ArrayList<>();
594
        homotypicNameList.add(homotypicName);
595

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

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

    
631

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

    
641

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

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

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

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

    
748

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

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

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

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

    
814

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

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

    
845

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

    
859

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

    
877

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

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

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

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

    
929
        higherNode.addChildTaxon(taxon, null, null);
930
        taxon.addSource(makeOriginalSource(state));
931

    
932
        return taxon;
933
    }
934

    
935
    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ó]+\\.?";
936
    private final Pattern orthVarRegEx = Pattern.compile(orthVarRegExStr);
937
    /**
938
     * @param taxonStr
939
     * @return
940
     */
941
    private BotanicalName makeName(CubaImportState state, String nameStrOrig) {
942
        //normalize
943
        String nameStr = normalizeStatus(nameStrOrig);
944
        //orthVar
945
        Matcher orthVarMatcher = orthVarRegEx.matcher(nameStr);
946
        String orthVar = null;
947
        if (orthVarMatcher.matches()) {
948
            orthVar = orthVarMatcher.group(1);
949
            nameStr = nameStr.replace(" " + orthVar, "").trim().replaceAll("\\s{2,}", " ");
950
            orthVar = orthVar.substring(2, orthVar.length() - 2);
951
        }
952

    
953
        boolean isNomInval = false;
954
        if (nameStr.endsWith("nom. inval.")){
955
            isNomInval = true;
956
            nameStr = nameStr.replace("nom. inval.", "").trim();
957
        }
958

    
959
        BotanicalName result = (BotanicalName)nameParser.parseReferencedName(nameStr, nc, Rank.SPECIES());
960
        result.addSource(makeOriginalSource(state));
961
        if (isNomInval){
962
            result.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.INVALID()));
963
        }
964
        if (orthVar != null){
965
            BotanicalName orthVarName = (BotanicalName)result.clone();
966
            orthVarName.addSource(makeOriginalSource(state));
967
            //TODO
968
            Reference<?> citation = null;
969
            orthVarName.addRelationshipToName(result, NameRelationshipType.ORTHOGRAPHIC_VARIANT(), citation, null, null);
970
            orthVarName.setSpecificEpithet(orthVar);
971
        }
972
        normalizeAuthors(result);
973
        return result;
974

    
975
    }
976

    
977
    /**
978
     * @param result
979
     */
980
    private void normalizeAuthors(BotanicalName result) {
981
        result.setCombinationAuthorship(normalizeAuthor(result.getCombinationAuthorship()));
982
        result.setExCombinationAuthorship(normalizeAuthor(result.getExCombinationAuthorship()));
983
        result.setExBasionymAuthorship(normalizeAuthor(result.getExBasionymAuthorship()));
984
        result.setBasionymAuthorship(normalizeAuthor(result.getBasionymAuthorship()));
985

    
986
    }
987

    
988

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

    
1013

    
1014
    /**
1015
     * @param deproxy
1016
     * @return
1017
     */
1018
    private Person normalizePerson(Person person) {
1019
        String title = person.getNomenclaturalTitle();
1020
        title = title.replaceAll("(?<=[a-zA-Z])\\.(?=[a-zA-Z])", ". ");
1021
        person.setNomenclaturalTitle(title);
1022
        boolean isFilius = title.endsWith(" f.");
1023
        if (isFilius){
1024
            title.replace(" f.", "");
1025
        }
1026

    
1027
        String[] splits = title.split("\\s+");
1028
        int nNotFirstName = isFilius ? 2 : 1;
1029
        person.setLastname(splits[splits.length - nNotFirstName] + (isFilius? " f." : ""));
1030
        person.setFirstname(CdmUtils.concat(" ", Arrays.copyOfRange(splits, 0, splits.length-nNotFirstName)));
1031
        return person;
1032
    }
1033

    
1034

    
1035
    /**
1036
     * @param state
1037
     * @return
1038
     */
1039
    private Reference<?> getSecReference(CubaImportState state) {
1040
        Reference<?> result = state.getSecReference();
1041
        if (result == null){
1042
            result = ReferenceFactory.newDatabase();
1043
            result.setTitle("Flora of Cuba");
1044
            state.setSecReference(result);
1045
        }
1046
        return result;
1047
    }
1048

    
1049

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

    
1071

    
1072
    }
1073

    
1074

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

    
1096
        Taxon family = state.getHigherTaxon(familyStr);
1097
        TaxonNode familyNode;
1098
        if (family != null){
1099
            familyNode = family.getTaxonNodes().iterator().next();
1100
        }else{
1101
            BotanicalName name = makeFamilyName(state, familyStr);
1102
            Reference<?> sec = getSecReference(state);
1103
            family = Taxon.NewInstance(name, sec);
1104
            ITaxonTreeNode rootNode = getClassification(state);
1105
            familyNode = rootNode.addChildTaxon(family, sec, null);
1106
            state.putHigherTaxon(familyStr, family);
1107

    
1108
        }
1109

    
1110
        if (isNotBlank(alternativeFamilyStr)){
1111
            NameRelationshipType type = NameRelationshipType.ALTERNATIVE_NAME();
1112
            BotanicalName alternativeName = makeFamilyName(state, alternativeFamilyStr);
1113
            BotanicalName familyName = (BotanicalName)family.getName();
1114
            boolean hasRelation = false;
1115
            for (NameRelationship nameRel : familyName.getRelationsToThisName()){
1116
                if (nameRel.getType().equals(type)){
1117
                    if (nameRel.getFromName().equals(alternativeName)){
1118
                        hasRelation = true;
1119
                    }
1120
                }
1121
            }
1122
            if (!hasRelation){
1123
                familyName.addRelationshipFromName(alternativeName, type, null);
1124
            }
1125

    
1126
        }
1127

    
1128
        return familyNode;
1129
    }
1130

    
1131

    
1132
    /**
1133
     * @param state
1134
     * @param taxon
1135
     */
1136
    private void validateTaxonIsAbsent(CubaImportState state, Taxon taxon) {
1137
        if (!state.isTaxonIsAbsent()){
1138
            return;
1139
        }
1140

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

    
1159
    /**
1160
     * @param state
1161
     * @param taxon
1162
     */
1163
    private void validateEndemic(CubaImportState state, Taxon taxon) {
1164

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

    
1191

    
1192
    /**
1193
     * @param state
1194
     * @param taxon
1195
     * @param famStr
1196
     * @param famRef
1197
     * @return
1198
     */
1199
    private Taxon makeAlternativeFamilyTaxon(CubaImportState state, String famStr, Reference<?> famRef) {
1200
        String key = famRef.getTitle() + ":"+ famStr;
1201
        Taxon family = state.getHigherTaxon(key);
1202
        if (family == null){
1203
            BotanicalName name = makeFamilyName(state, famStr);
1204
            family = Taxon.NewInstance(name, famRef);
1205
            state.putHigherTaxon(key, family);
1206
        }
1207

    
1208
        return family;
1209
    }
1210

    
1211

    
1212
    /**
1213
     * @param state
1214
     * @param famStr
1215
     * @return
1216
     */
1217
    private BotanicalName makeFamilyName(CubaImportState state, String famStr) {
1218
        BotanicalName name = state.getFamilyName(famStr);
1219
        if (name == null){
1220
            name = BotanicalName.NewInstance(Rank.FAMILY());
1221
            name.setGenusOrUninomial(famStr);
1222
            state.putFamilyName(famStr, name);
1223
            name.addSource(makeOriginalSource(state));
1224
        }
1225
        return name;
1226
    }
1227

    
1228

    
1229
    /**
1230
     * @param state
1231
     * @return
1232
     */
1233
    private TaxonNode getClassification(CubaImportState state) {
1234
        Classification classification = state.getClassification();
1235
        if (classification == null){
1236
            classification = getClassificationService().find(state.getConfig().getClassificationUuid());
1237
        }
1238
        TaxonNode rootNode = state.getRootNode();
1239
        if (rootNode == null){
1240
            rootNode = getTaxonNodeService().find(plantaeUuid);
1241
        }
1242
        if (rootNode == null){
1243
            Reference<?> sec = getSecReference(state);
1244
            if (classification == null){
1245
                String classificationName = state.getConfig().getClassificationName();
1246
                //TODO
1247
                Language language = Language.DEFAULT();
1248
                classification = Classification.NewInstance(classificationName, sec, language);
1249
                state.setClassification(classification);
1250
                classification.setUuid(state.getConfig().getClassificationUuid());
1251
                classification.getRootNode().setUuid(rootUuid);
1252
            }
1253

    
1254
            BotanicalName plantaeName = BotanicalName.NewInstance(Rank.KINGDOM());
1255
            plantaeName.setGenusOrUninomial("Plantae");
1256
            Taxon plantae = Taxon.NewInstance(plantaeName, sec);
1257
            TaxonNode plantaeNode = classification.addChildTaxon(plantae, null, null);
1258
            plantaeNode.setUuid(plantaeUuid);
1259
            state.setRootNode(plantaeNode);
1260
            getClassificationService().save(classification);
1261

    
1262
            rootNode = plantaeNode;
1263
        }
1264
        return rootNode;
1265
    }
1266

    
1267

    
1268
    /**
1269
     * @param record
1270
     * @param originalKey
1271
     * @return
1272
     */
1273
    private String getValue(HashMap<String, String> record, String originalKey) {
1274
        String value = record.get(originalKey);
1275
        if (! StringUtils.isBlank(value)) {
1276
        	if (logger.isDebugEnabled()) { logger.debug(originalKey + ": " + value); }
1277
        	value = CdmUtils.removeDuplicateWhitespace(value.trim()).toString();
1278
        	return value;
1279
        }else{
1280
        	return null;
1281
        }
1282
    }
1283

    
1284

    
1285

    
1286
	/**
1287
	 *  Stores taxa records in DB
1288
	 */
1289
	@Override
1290
    protected void firstPass(CubaImportState state) {
1291
	    boolean isSynonymOnly = false;
1292

    
1293
        String line = state.getCurrentLine() + ": ";
1294
        HashMap<String, String> record = state.getOriginalRecord();
1295

    
1296
        Set<String> keys = record.keySet();
1297
        for (String key: keys) {
1298
            if (! expectedKeys.contains(key)){
1299
                logger.warn(line + "Unexpected Key: " + key);
1300
            }
1301
        }
1302

    
1303
        if (record.get("Fam. default") == null && keys.size() == 2 && record.get("Syn.") == null && record.get("Nat") != null && record.get("Adv") != null){
1304
            //second header line, don't handle
1305
            return;
1306
        }
1307

    
1308
        //Fam.
1309
        TaxonNode familyTaxon = getFamilyTaxon(record, state);
1310
        if (familyTaxon == null){
1311
            if (record.get("Taxón") != null){
1312
                logger.warn(line + "Family not recognized but taxon exists: " + record.get("Taxón"));
1313
                return;
1314
            }else if (record.get("Syn.") == null){
1315
                logger.warn(line + "Family not recognized but also no synonym exists");
1316
                return;
1317
            }else{
1318
                isSynonymOnly = true;
1319
            }
1320
        }
1321

    
1322
       //Taxón
1323
        Taxon taxon = makeTaxon(record, state, familyTaxon, isSynonymOnly);
1324
        if (taxon == null && ! isSynonymOnly){
1325
            logger.warn(line + "taxon could not be created and is null");
1326
            return;
1327
        }
1328
        state.setCurrentTaxon(taxon);
1329

    
1330
        //Fam. ALT
1331
        makeAlternativeFamilies(record, state, familyTaxon, taxon);
1332

    
1333
        //(Notas)
1334
        makeNotes(record, state);
1335

    
1336
        //Syn.
1337
        makeSynonyms(record, state, !isSynonymOnly);
1338

    
1339
        //End, Ind, Ind? D, Nat N, Dud P, Adv A, Cult C
1340
        makeCubanDistribution(record, state);
1341

    
1342

    
1343
//        "CuW","PR PR*","Art","Hab(*)","May","Mat","IJ",
1344
//        "CuC","VC","Ci","SS","CA","Cam","LT",
1345
//        "CuE","Gr","Ho","SC","Gu",
1346
        makeProvincesDistribution(record, state);
1347

    
1348
//      "Esp","Ja","PR","Men","Bah","Cay",
1349
//      "AmN","AmC","AmS","VM"});
1350
        makeOtherAreasDistribution(record, state);
1351

    
1352
        validateTaxonIsAbsent(state, taxon);
1353
        if (!isSynonymOnly){
1354
            validateEndemic(state, taxon);
1355
        }
1356

    
1357
        state.setHighestStatusForTaxon(null);
1358

    
1359
		return;
1360
    }
1361

    
1362

    
1363
    /**
1364
     * @param state
1365
     * @return
1366
     */
1367
    private IdentifiableSource makeOriginalSource(CubaImportState state) {
1368
        return IdentifiableSource.NewDataImportInstance("line: " + state.getCurrentLine(), null, state.getConfig().getSourceReference());
1369
    }
1370
    /**
1371
     * @param state
1372
     * @return
1373
     */
1374
    private DescriptionElementSource makeDescriptionSource(CubaImportState state) {
1375
        return DescriptionElementSource.NewDataImportInstance("line: " + state.getCurrentLine(), null, state.getConfig().getSourceReference());
1376
    }
1377

    
1378
    private static Set<UUID> doubtfulStatus = new HashSet<>();
1379

    
1380
    /**
1381
     * @param status
1382
     * @return
1383
     */
1384
    private boolean isDoubtfulTerm(PresenceAbsenceTerm status) {
1385
        if (doubtfulStatus.isEmpty()){
1386
            doubtfulStatus.add(CubaTransformer.nonNativeDoubtfullyNaturalisedUuid);
1387
            doubtfulStatus.add(CubaTransformer.doubtfulIndigenousDoubtfulUuid);
1388
            doubtfulStatus.add(CubaTransformer.endemicDoubtfullyPresentUuid);
1389
            doubtfulStatus.add(CubaTransformer.naturalisedDoubtfullyPresentUuid);
1390
            doubtfulStatus.add(CubaTransformer.nonNativeDoubtfullyPresentUuid);
1391
            doubtfulStatus.add(CubaTransformer.occasionallyCultivatedUuid);
1392
            doubtfulStatus.add(CubaTransformer.rareCasualUuid);
1393
            doubtfulStatus.add(PresenceAbsenceTerm.NATIVE_PRESENCE_QUESTIONABLE().getUuid());
1394
            doubtfulStatus.add(PresenceAbsenceTerm.CULTIVATED_PRESENCE_QUESTIONABLE().getUuid());
1395
        }
1396
        boolean isDoubtful = doubtfulStatus.contains(status.getUuid());
1397
        return isDoubtful;
1398
    }
1399

    
1400

    
1401
    /**
1402
     * @param area
1403
     * @return
1404
     */
1405
    private boolean isCubanArea(NamedArea area) {
1406
        if (area.getUuid().equals(CubaTransformer.uuidCuba)){
1407
            return true;
1408
        }else if (area.getPartOf()!= null){
1409
            return isCubanArea(area.getPartOf());
1410
        }else{
1411
            return false;
1412
        }
1413
    }
1414

    
1415

    
1416
    /**
1417
     * @param record
1418
     * @param state
1419
     * @param familyTaxon
1420
     * @param taxon
1421
     */
1422
    private void makeAlternativeFamilies(HashMap<String, String> record,
1423
            CubaImportState state,
1424
            TaxonNode familyTaxon,
1425
            Taxon taxon) {
1426

    
1427
        String famFRC = record.get("Fam. FRC");
1428
        String famAS = record.get("Fam. A&S");
1429
        String famFC = record.get("Fam. FC");
1430

    
1431
        Reference<?> refFRC = makeReference(state, CubaTransformer.uuidRefFRC);
1432
        Reference<?> refAS = makeReference(state, CubaTransformer.uuidRefAS);
1433
        Reference<?> refFC = makeReference(state, CubaTransformer.uuidRefFC);
1434

    
1435
        makeSingleAlternativeFamily(state, taxon, famFRC, refFRC);
1436
        makeSingleAlternativeFamily(state, taxon, famAS, refAS);
1437
        makeSingleAlternativeFamily(state, taxon, famFC, refFC);
1438
    }
1439

    
1440

    
1441
    /**
1442
     * @param state
1443
     * @param uuidreffrc
1444
     * @return
1445
     */
1446
    private Reference<?> makeReference(CubaImportState state, UUID uuidRef) {
1447
        Reference<?> ref = state.getReference(uuidRef);
1448
        if (ref == null){
1449
            ref = getReferenceService().find(uuidRef);
1450
            state.putReference(uuidRef, ref);
1451
        }
1452
        return ref;
1453
    }
1454

    
1455

    
1456
    /**
1457
     * @param state
1458
     * @param taxon
1459
     * @param famString
1460
     * @param famRef
1461
     */
1462
    private void makeSingleAlternativeFamily(CubaImportState state, Taxon taxon, String famStr, Reference<?> famRef) {
1463
        if (isBlank(famStr)){
1464
            return;
1465
        }
1466

    
1467
        TaxonDescription desc = getTaxonDescription(taxon, false, true);
1468

    
1469
        UUID altFamUuid1;
1470
        UUID altFamUuid2;
1471
        try {
1472
            altFamUuid1 = state.getTransformer().getFeatureUuid("Alt.Fam.");
1473
            altFamUuid2 = state.getTransformer().getFeatureUuid("Alt.Fam.2");
1474
        } catch (UndefinedTransformerMethodException e) {
1475
            throw new RuntimeException(e);
1476
        }
1477

    
1478

    
1479
        Taxon famTaxon = makeAlternativeFamilyTaxon(state, famStr, famRef);
1480

    
1481

    
1482
        //TextData
1483
        Feature feature1 = getFeature(state, altFamUuid1, "Family in other floras", "Family in other floras", "Other floras", null);
1484
//        TextData textData = TextData.NewInstance(feature1, famStr, Language.DEFAULT(), null);
1485
        TextData textData = TextData.NewInstance(feature1, null, Language.DEFAULT(), null);
1486
        textData.addSource(OriginalSourceType.PrimaryTaxonomicSource, null,null, famRef, null, famTaxon.getName(),null);
1487
        desc.addElement(textData);
1488

    
1489

    
1490

    
1491
        //TaxonInteraction
1492
        Feature feature2 = getFeature(state, altFamUuid2, "Family in other floras(2)", "Family in other floras(2)", "Other floras(2)", null);
1493
        feature2.setSupportsTaxonInteraction(true);
1494
        TaxonInteraction taxInteract = TaxonInteraction.NewInstance(feature2);
1495
        taxInteract.setTaxon2(famTaxon);
1496
        taxInteract.addSource(OriginalSourceType.PrimaryTaxonomicSource, null,null, famRef, null);
1497
        desc.addElement(taxInteract);
1498

    
1499
        //Concept Relation
1500
        famTaxon.addTaxonRelation(taxon, TaxonRelationshipType.INCLUDES(), taxon.getSec(), null);
1501

    
1502
    }
1503

    
1504

    
1505

    
1506

    
1507

    
1508
    /**
1509
     * @param record
1510
     * @param state
1511
     * @param taxon
1512
     */
1513
    // "CuW","PR PR*","Art","Hab(*)","May","Mat","IJ",
1514
//  "CuC","VC","Ci","SS","CA","Cam","LT",
1515
//  "CuE","Gr","Ho","SC","Gu",
1516
    private void makeProvincesDistribution(HashMap<String, String> record, CubaImportState state) {
1517
        List<String> areaKeys = Arrays.asList(new String[]{
1518
                "CuW","PR PR*","Art","Hab(*)","May","Mat","IJ",
1519
                "CuC","VC","Ci","SS","CA","Cam","LT",
1520
                "CuE","Gr","Ho","SC","Gu",
1521
                });
1522
        for (String areaKey : areaKeys){
1523
            state.setCubanProvince(true);
1524
            makeSingleProvinceDistribution(areaKey, record, state);
1525
        }
1526
    }
1527

    
1528
    private void makeOtherAreasDistribution(HashMap<String, String> record, CubaImportState state) {
1529
        List<String> areaKeys = Arrays.asList(new String[]{
1530
                "Esp","Ja","PR","Men","Bah","Cay",
1531
                "AmN","AmC","AmS","VM"});
1532
        for (String areaKey : areaKeys){
1533
            state.setCubanProvince(false);
1534
            makeSingleProvinceDistribution(areaKey, record, state);
1535
        }
1536
    }
1537

    
1538

    
1539

    
1540

    
1541
    /**
1542
     * @param areaKey
1543
     * @param record
1544
     * @param state
1545
     * @param highestStatus
1546
     * @return
1547
     * @throws UndefinedTransformerMethodException
1548
     */
1549
    private PresenceAbsenceTerm makeProvinceStatus(String areaKey,
1550
            HashMap<String, String> record,
1551
            CubaImportState state) throws UndefinedTransformerMethodException {
1552

    
1553
        String statusStr = record.get(areaKey);
1554
        if (statusStr == null){
1555
            return null;
1556
        }else{
1557
            statusStr = statusStr.trim();
1558
        }
1559
        PresenceAbsenceTerm status = state.getTransformer().getPresenceTermByKey(statusStr);
1560
        if (status == null){
1561
//            PresenceAbsenceTerm highestStatus = state.getHighestStatusForTaxon();
1562
            if (state.isCubanProvince() && isMinus(statusStr)){
1563
//                getAbsenceTermForStatus(state, highestStatus);
1564
                //we now handle cuban provinces same as external regions
1565
                status = state.getTransformer().getPresenceTermByKey("--");
1566
            }else if (! state.isCubanProvince() && isMinus(statusStr)){
1567
                status = state.getTransformer().getPresenceTermByKey("--");
1568
            }else{
1569
//                logger.warn("Unhandled status str for provinces / external regions: " + statusStr);
1570
                UUID statusUuid = state.getTransformer().getPresenceTermUuid(statusStr);
1571
                if (statusUuid == null){
1572
                    logger.error(state.getCurrentLine() + ": Undefined status str for provinces / external regions. No UUID given: '" + statusStr + "'");
1573
                }else{
1574
                    status = getPresenceTerm(state, statusUuid, statusStr, statusStr, statusStr, false);
1575
                }
1576
            }
1577
        }
1578

    
1579
        return status;
1580
    }
1581

    
1582

    
1583
    /**
1584
     * @param highestStatus
1585
     * @throws UndefinedTransformerMethodException
1586
     */
1587
    private PresenceAbsenceTerm getAbsenceTermForStatus(CubaImportState state, PresenceAbsenceTerm highestStatus) throws UndefinedTransformerMethodException {
1588
        if (highestStatus == null){
1589
            logger.warn(state.getCurrentLine() + ": Highest status not defined");
1590
            return null;
1591
        }
1592
        PresenceAbsenceTerm result = null;
1593
        if (highestStatus.equals(getStatus(state, "E"))){
1594
            result = getStatus(state, "-E");
1595
        }else if (highestStatus.getUuid().equals(state.getTransformer().getPresenceTermUuid("Ind.")) || highestStatus.equals(PresenceAbsenceTerm.NATIVE())){
1596
            result = getStatus(state, "-Ind.");
1597
        }else if (highestStatus.equals(getStatus(state, "Ind.?"))){
1598
            result = getStatus(state, "-Ind.?");  //TODO
1599
        }else if (highestStatus.equals(getStatus(state, "N"))){
1600
            result = getStatus(state, "-N");
1601
        }else if (highestStatus.equals(getStatus(state, "P"))){
1602
            result = getStatus(state, "-P");
1603
        }else if (highestStatus.equals(getStatus(state, "A"))){
1604
            result = getStatus(state, "-A");
1605
        }else if (highestStatus.equals(getStatus(state, "C"))){
1606
            result = getStatus(state, "-C");
1607
        }
1608
        logger.warn(state.getCurrentLine() + ": Absent province status could not be defined for highest status " + highestStatus.getTitleCache());
1609
        return result;
1610
    }
1611

    
1612

    
1613
    /**
1614
     * @param string
1615
     * @return
1616
     * @throws UndefinedTransformerMethodException
1617
     */
1618
    private PresenceAbsenceTerm getStatus(CubaImportState state, String key) throws UndefinedTransformerMethodException {
1619
        PresenceAbsenceTerm status = state.getTransformer().getPresenceTermByKey(key);
1620
        if (status == null){
1621
            UUID statusUuid = state.getTransformer().getPresenceTermUuid(key);
1622
            status = getPresenceTerm(state, statusUuid, null, null, null, false);
1623
        }
1624
        return status;
1625
    }
1626

    
1627

    
1628
    /**
1629
	 *  Stores parent-child, synonym and common name relationships
1630
	 */
1631
	@Override
1632
    protected void secondPass(CubaImportState state) {
1633
//		CyprusRow cyprusRow = state.getCyprusRow();
1634
		return;
1635
	}
1636

    
1637

    
1638
    @Override
1639
    protected boolean isIgnore(CubaImportState state) {
1640
        return ! state.getConfig().isDoTaxa();
1641
    }
1642

    
1643
    @Override
1644
    protected boolean doCheck(CubaImportState state) {
1645
        logger.warn("DoCheck not yet implemented for CubaExcelImport");
1646
        return true;
1647
    }
1648

    
1649
}
(1-1/5)