Project

General

Profile

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

    
12
import java.util.HashMap;
13
import java.util.Map;
14
import java.util.UUID;
15

    
16
import org.apache.log4j.Logger;
17
import org.joda.time.Partial;
18
import org.springframework.stereotype.Component;
19

    
20
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;
21
import eu.etaxonomy.cdm.common.CdmUtils;
22
import eu.etaxonomy.cdm.io.common.utils.ImportDeduplicationHelper;
23
import eu.etaxonomy.cdm.model.agent.AgentBase;
24
import eu.etaxonomy.cdm.model.agent.Institution;
25
import eu.etaxonomy.cdm.model.agent.Person;
26
import eu.etaxonomy.cdm.model.agent.Team;
27
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
28
import eu.etaxonomy.cdm.model.common.CdmBase;
29
import eu.etaxonomy.cdm.model.common.DefinedTerm;
30
import eu.etaxonomy.cdm.model.common.ExtensionType;
31
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
32
import eu.etaxonomy.cdm.model.common.Language;
33
import eu.etaxonomy.cdm.model.common.TimePeriod;
34
import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
35
import eu.etaxonomy.cdm.model.description.TaxonDescription;
36
import eu.etaxonomy.cdm.model.location.Country;
37
import eu.etaxonomy.cdm.model.location.NamedArea;
38
import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
39
import eu.etaxonomy.cdm.model.location.NamedAreaType;
40
import eu.etaxonomy.cdm.model.location.Point;
41
import eu.etaxonomy.cdm.model.location.ReferenceSystem;
42
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
43
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignationStatus;
44
import eu.etaxonomy.cdm.model.name.TaxonName;
45
import eu.etaxonomy.cdm.model.occurrence.Collection;
46
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
47
import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent;
48
import eu.etaxonomy.cdm.model.reference.Reference;
49
import eu.etaxonomy.cdm.model.taxon.Synonym;
50
import eu.etaxonomy.cdm.model.taxon.Taxon;
51
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
52
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
53
import eu.etaxonomy.cdm.strategy.parser.DeterminationModifierParser;
54
import eu.etaxonomy.cdm.strategy.parser.SpecimenTypeParser;
55
import eu.etaxonomy.cdm.strategy.parser.TimePeriodParser;
56

    
57
/**
58
 * @author a.mueller
59
 * @date 21.04.2017
60
 *
61
 */
62
@Component
63
public class BogotaSpecimenImport<CONFIG extends BogotaSpecimenImportConfigurator>
64
        extends SimpleExcelSpecimenImport<CONFIG> {
65

    
66
    private static final long serialVersionUID = -884838817884874228L;
67
    private static final Logger logger = Logger.getLogger(BogotaSpecimenImport.class);
68

    
69
    private static final String COL_TAXON_UUID = "Platform Name ID = cdmID";
70
    private static final String COL_VOUCHER_ID = "Voucher ID";
71

    
72
    private static final String COL_FAMILY = "Family";
73
    private static final String COL_GENUS = "Genus";
74
    private static final String COL_SPECIFIC_EPI = "Specific Epithet";
75
    private static final String COL_BASIONYM_AUTHOR = "Author in parenthesis";
76
    private static final String COL_AUTHOR = "Author";
77
    private static final String COL_IDENTIFIER = "Identifier";
78
    private static final String COL_IDENTIFICATION_DATE = "Identification date";
79
    private static final String COL_IDENTIFICATION_QUALIFIER = "Qualifier";
80
    private static final String COL_TYPUS = "Type";
81
    private static final String COL_IDENTIFICATION_HISTORY = "Identification history";
82
    private static final String COL_COLLECTOR_VERBATIM = "Verbatim Collectors  (Originalfeld JBB)";
83
    private static final String COL_COLLECTOR_LASTNAME = "Primary Collector Last Name  (Originalfeld JBB)";
84
    private static final String COL_COLLECTOR_FIRSTNAME = "Primary Collector First Name Initial (Originalfeld JBB)";
85
    private static final String COL_COLLECTOR_MIDDLENAME = "Primary Collector Middle Name Initial (Originalfeld JBB)";
86
    private static final String COL_COLLECTOR_TYPE = "Primary collector type (Originalfeld JBB)";
87
    private static final String COL_COLLECTOR_NUMBER = "Collector's No";
88
    private static final String COL_COLLECTORS = "Collectors";
89
    private static final String COL_COLLECTION_DATE_FROM = "Collection Date from";
90
    private static final String COL_COLLECTION_DATE_TO = "Collection Date to";
91
    private static final String COL_ALTITUDE_FROM = "Altitude Value from";
92
    private static final String COL_ALTITUDE_TO = "Altitude Value to";
93
    private static final String COL_ALTITUDE_UNIT = "Altitude Unit";
94
    private static final String COL_LOCALITY = "Locality";
95
    private static final String COL_LOCALITY_ID = "LocalityID";
96
    private static final String COL_LATITUDE = "Latitude";
97
    private static final String COL_LONGITUDE = "Longitude";
98
    private static final String COL_ERROR_DISTANCE = "Error distance in m";
99
    private static final String COL_COUNTRY = "Country";
100
    private static final String COL_STATE_AREA = "State/Province/Greater Area";
101
    private static final String COL_GEO_METHOD = "Geocode Method";
102
    private static final String COL_HABITUS = "Habitus";
103
    private static final String COL_COLLECTION = "[Series] Voucher location";
104

    
105
    private static final UUID uuidAnonymous = UUID.fromString("2303f043-6e92-4afa-9082-7719e78a1c8a");
106
    private static final UUID uuidBogota = UUID.fromString("95b6cb03-8452-4439-98bd-8c1aa3c1da4e");
107
    private static final UUID uuidDefaultGeocodMethod = UUID.fromString("0983e680-b0ca-4e46-8df7-0f1d757a2e01");
108
    private static final UUID uuidExtTypeIdentificationHistory = UUID.fromString("7cee5c29-e16b-4e6f-ad57-bf7044259375");
109
    private static final UUID uuidDetQualVelAff = UUID.fromString("511a0c23-2646-4035-b570-36bdc2eb5557");
110

    
111
//    @SuppressWarnings("unchecked")
112
    private ImportDeduplicationHelper<SimpleExcelSpecimenImportState<?>> deduplicationHelper;
113
//           = (ImportDeduplicationHelper<SimpleExcelSpecimenImportState<?>>)ImportDeduplicationHelper.NewStandaloneInstance();
114

    
115

    
116
    @Override
117
    protected String getWorksheetName() {
118
        return "To be imported";
119
    }
120

    
121
//    private boolean isFirst = true;
122
//    private TransactionStatus tx = null;
123

    
124
    /**
125
     * {@inheritDoc}
126
     */
127
    @Override
128
    protected void firstPass(SimpleExcelSpecimenImportState<CONFIG> state) {
129
//        if (isFirst){
130
//            tx = this.startTransaction();
131
//            isFirst = false;
132
//        }
133

    
134
        HashMap<String, String> record = state.getOriginalRecord();
135

    
136
        String voucherId = getValue(record, COL_VOUCHER_ID);
137
        if (!isInInterval(state)){
138
            return;
139
        }
140
        String line = state.getCurrentLine() + " (id:"+ voucherId+"): ";
141
        if (state.getCurrentLine() % 100 == 0){System.out.println(line);}
142
        try {
143

    
144
            //species
145
            TaxonBase<?> taxonBase = getOrCreateTaxon(state, line, record, voucherId);
146

    
147
            if (taxonBase != null){
148
                Taxon taxon = getTaxon(taxonBase);
149

    
150
                TaxonDescription taxonDescription = getTaxonDescription(state, line, taxon);
151

    
152
                DerivedUnit specimen = makeSpecimen(state, line, record, voucherId, taxonBase);
153

    
154
                IndividualsAssociation indAssoc = IndividualsAssociation.NewInstance(specimen);
155
                indAssoc.addImportSource(voucherId, COL_VOUCHER_ID, getSourceCitation(state), null);
156
                taxonDescription.addElement(indAssoc);
157

    
158
            }
159
        } catch (Exception e) {
160
            state.getResult().addError("An unexpected exception appeared in record", e, null, line);
161
            e.printStackTrace();
162
        }
163

    
164
    }
165

    
166

    
167
    /**
168
     * @param state
169
     * @return
170
     */
171
    private boolean isInInterval(SimpleExcelSpecimenImportState<CONFIG> state) {
172
        Integer min = state.getConfig().getMinLineNumber();
173
        Integer max = state.getConfig().getMaxLineNumber();
174
        Integer current = state.getCurrentLine();
175
        if (current < min || current > max){
176
            return false;
177
        }else{
178
            return true;
179
        }
180
    }
181

    
182

    
183
    /**
184
     * @param state
185
     * @param line
186
     * @param taxon
187
     * @return
188
     */
189
    private TaxonDescription getTaxonDescription(SimpleExcelSpecimenImportState<CONFIG> state, String line,
190
            Taxon taxon) {
191
        Reference ref = getSourceCitation(state);
192
        TaxonDescription desc = this.getTaxonDescription(taxon, ref, ! IMAGE_GALLERY, CREATE);
193
        return desc;
194
    }
195

    
196

    
197
    /**
198
     * @param state
199
     * @param line
200
     * @param record
201
     * @param voucherId
202
     * @return
203
     */
204
    private DerivedUnit makeSpecimen(SimpleExcelSpecimenImportState<CONFIG> state, String line,
205
            HashMap<String, String> record, String voucherId, TaxonBase<?> taxonBase) {
206

    
207
        DerivedUnitFacade facade = DerivedUnitFacade.NewPreservedSpecimenInstance();
208
        facade.setAccessionNumber(voucherId);
209
        makeDetermination(facade.innerDerivedUnit(), state, line, record, taxonBase.getName());
210
        makeTypus(facade.innerDerivedUnit(), state, line, record, taxonBase.getName());
211
        makeCollectorFields(facade, state, line, record);
212
        makeLocationFields(facade, state, line, record);
213
        makeHabitus(facade, state, line, record);
214
        makeCollection(facade, state, line, record);
215
        DerivedUnit specimen = facade.innerDerivedUnit();
216
        specimen.addSource(makeOriginalSource(state));
217
        return specimen;
218
    }
219

    
220

    
221
    /**
222
     * @param innerDerivedUnit
223
     * @param state
224
     * @param line
225
     * @param record
226
     * @param name
227
     */
228
    private void makeTypus(DerivedUnit specimen, SimpleExcelSpecimenImportState<CONFIG> state, String line,
229
            HashMap<String, String> record, TaxonName name) {
230
        String typus = record.get(COL_TYPUS);
231
        if (typus != null){
232
            SpecimenTypeDesignationStatus status;
233
            try {
234
                status = SpecimenTypeParser.parseSpecimenTypeStatus(typus);
235
                SpecimenTypeDesignation designation = SpecimenTypeDesignation.NewInstance();
236
                designation.setTypeStatus(status);
237
                name.addSpecimenTypeDesignation(specimen, status, null, null, null, false, false);
238
            } catch (UnknownCdmTypeException e) {
239
                state.getResult().addWarning("Type designation could not be parsed", null, line);
240
            }
241
        }
242
    }
243

    
244

    
245
    /**
246
     * @param facade
247
     * @param state
248
     * @param line
249
     * @param record
250
     */
251
    private void makeCollection(DerivedUnitFacade facade, SimpleExcelSpecimenImportState<CONFIG> state,
252
            String line, HashMap<String, String> record) {
253
        String strCollection = record.get(COL_COLLECTION);
254
        String collectionFormat = ".*\\([A-Z]{2,4}\\)";
255
        if (!strCollection.matches(collectionFormat)){
256
            String message = "Voucher location format does not match the expected format. Voucher '(" + strCollection + ")' location not added.";
257
            state.getResult().addError(message, null, line);
258
            return;
259
        }
260
        String[] splits = strCollection.split("\\(");
261
        String collectionName = splits[0];
262
        String collectionCode = splits[1].replace(")", "");
263
        Collection collection = Collection.NewInstance();
264
        collection.setName(collectionName);
265
        collection.setCode(collectionCode);
266
        collection = getDeduplicationHelper(state).getExistingCollection(state, collection);
267
        facade.setCollection(collection);
268
    }
269

    
270

    
271
    /**
272
     * @param state
273
     * @return
274
     */
275
    private ImportDeduplicationHelper<SimpleExcelSpecimenImportState<?>> getDeduplicationHelper(SimpleExcelSpecimenImportState<CONFIG> state) {
276
        if (deduplicationHelper == null){
277
            deduplicationHelper = ImportDeduplicationHelper.NewInstance(this, state);
278
        }
279
        return deduplicationHelper;
280
    }
281

    
282

    
283
    /**
284
     * @param facade
285
     * @param state
286
     * @param line
287
     * @param record
288
     */
289
    private void makeHabitus(DerivedUnitFacade facade, SimpleExcelSpecimenImportState<CONFIG> state, String line,
290
            HashMap<String, String> record) {
291
        String habitus = record.get(COL_HABITUS);
292
        if (habitus != null){
293
            facade.setPlantDescription(habitus);
294
        }
295
    }
296

    
297

    
298
    /**
299
     * @param facade
300
     * @param state
301
     * @param line
302
     * @param record
303
     * @param voucherId
304
     */
305
    private void makeLocationFields(DerivedUnitFacade facade, SimpleExcelSpecimenImportState<CONFIG> state, String line,
306
            HashMap<String, String> record) {
307
        //Altitude
308
        String strAltitudeFrom = record.get(COL_ALTITUDE_FROM);
309
        String strAltitudeTo = record.get(COL_ALTITUDE_TO);
310
        Integer intAltitudeFrom = intFromString(state, strAltitudeFrom, line, COL_ALTITUDE_FROM);
311
        Integer intAltitudeTo = intFromString(state, strAltitudeTo, line, COL_ALTITUDE_TO);
312
        if (intAltitudeFrom != null){
313
            facade.setAbsoluteElevation(intAltitudeFrom);
314
            if (!intAltitudeFrom.equals(intAltitudeTo)){
315
                facade.setAbsoluteElevationMax(intAltitudeTo);
316
            }
317
            if (!record.get(COL_ALTITUDE_UNIT).equals("m")){
318
                state.getResult().addWarning("Altitude unit is not m but " + record.get(COL_ALTITUDE_UNIT), "makeLocationFields", line);
319
            }
320
        }
321
        checkNoToIfNoFrom(strAltitudeFrom, strAltitudeTo, state, line, COL_ALTITUDE_TO);
322

    
323
        //locality
324
        String locality = record.get(COL_LOCALITY);
325
        if (locality != null){  //should always exist
326
            facade.setLocality(locality, Language.SPANISH_CASTILIAN());
327
        }
328

    
329
        //Lat + Long
330
        String strLatitude = record.get(COL_LATITUDE);
331
        String strLongitude = record.get(COL_LONGITUDE);
332
        String strError = record.get(COL_ERROR_DISTANCE);
333
        Double dblLatitude = doubleFromString(state, strLatitude, line, COL_LATITUDE);
334
        Double dblLongitude = doubleFromString(state, strLongitude, line, COL_LONGITUDE);
335
        Integer intError = intFromString(state, strError, line, COL_ERROR_DISTANCE);
336
        ReferenceSystem referenceSystem = makeReferenceSystem(state, record, line);
337

    
338
        if (dblLatitude != null || dblLongitude != null || intError != null){ //should always exist
339
            Point exactLocation = Point.NewInstance(dblLongitude, dblLatitude, referenceSystem, intError);
340
            facade.setExactLocation(exactLocation);
341
        }
342

    
343
        //Country
344
        String strCountry = record.get(COL_COUNTRY);
345
        if (strCountry != null){
346
            if (strCountry.equals("Colombia")){
347
                Country colombia = Country.COLOMBIAREPUBLICOF();
348
                colombia.setLabel("Colombia");
349
                getTermService().saveOrUpdate(colombia);
350
                facade.setCountry(colombia);
351
            }else{
352
                state.getResult().addWarning("Country was not Colombia as expected but " +  strCountry,
353
                        "makeLocationFields", line);
354
            }
355
        }
356

    
357
        //State
358
        String strStateArea = record.get(COL_STATE_AREA);
359
        if (strStateArea != null){
360
            if (strStateArea.replaceAll("\\s", "").equalsIgnoreCase("Bogotá,D.C.")){
361
                NamedArea bogota = makeBogota(state, line);
362
                facade.addCollectingArea(bogota);
363
            }else{
364
                state.getResult().addWarning(COL_STATE_AREA + " was not 'Bogotá,  D.C.' as expected but " +  strCountry,
365
                        "makeLocationFields", line);
366
            }
367
        }
368
    }
369

    
370

    
371
    /**
372
     * @param strAltitudeFrom
373
     * @param strAltitudeTo
374
     * @param state
375
     * @param line
376
     * @param colAltitudeTo
377
     */
378
    private void checkNoToIfNoFrom(String strFrom, String strTo,
379
            SimpleExcelSpecimenImportState<CONFIG> state,
380
            String line, String toAttributeName) {
381
        if (isNotBlank(strTo) && isBlank(strFrom)){
382
            String message = "A min-max attribute has a max value (%s) but no min value. This is invalid."
383
                    + " The max value attribute name is %s.";
384
            message = String.format(message, strTo, toAttributeName);
385
            state.getResult().addWarning(message, null, line);
386
        }
387
    }
388

    
389
    private ReferenceSystem defaultGeocodeMethod;
390

    
391
    /**
392
     * @param state
393
     * @param record
394
     * @param line
395
     * @return
396
     */
397
    private ReferenceSystem makeReferenceSystem(SimpleExcelSpecimenImportState<CONFIG> state,
398
            Map<String, String> record, String line) {
399
        String defaultStrRefSys = "Wieczorek, J., Guo, Q., & Hijmans, R. (2004). The point-radius method for georeferencing locality descriptions and calculating associated uncertainty. International journal of geographical information science, 18(8), 745-767.; Escobar D, Díaz SR, Jojoa LM, Rudas E, Albarracín RD, Ramírez C, Gómez JY, López CR, Saavedra J (2015). Georreferenciación de localidades: Una guía de referencia para colecciones biológicas. Instituto de Investigación de Recursos Biológicos Alexander von Humboldt – Instituto de Ciencias Naturales, Universidad Nacional de Colombia. Bogotá D.C., Colombia. 95 p.";
400
        String strRefSys = record.get(COL_GEO_METHOD);
401
        if (strRefSys == null){
402
            return null;
403
        }else if (!strRefSys.equals(defaultStrRefSys)){
404
            state.getResult().addError("The expected Geocode Method is not the expected default method. Geocode Method was not added.", null, line);
405
            return null;
406
        }else if (defaultGeocodeMethod != null){
407
            return defaultGeocodeMethod;
408
        }else{
409
            String label = "Point radius method";
410
            String description = defaultStrRefSys;
411
            String labelAbbrev = "PRM";
412
            defaultGeocodeMethod = getReferenceSystem(state, uuidDefaultGeocodMethod,
413
                    label, description, labelAbbrev, null);
414
            return defaultGeocodeMethod;
415
        }
416
    }
417

    
418
    private NamedArea bogota;
419
    /**
420
     * @param state
421
     * @param line
422
     * @return
423
     */
424
    private NamedArea makeBogota(SimpleExcelSpecimenImportState<CONFIG> state, String line) {
425
        if (bogota != null){
426
            return bogota;
427
        }else{
428
            String label = "Bogotá, D.C.";
429
            NamedAreaType areaType = NamedAreaType.ADMINISTRATION_AREA();
430
            NamedAreaLevel level = NamedAreaLevel.STATE();
431
            bogota = getNamedArea(state, uuidBogota, label, label, null, areaType,
432
                    level, null, null, null);
433
            return bogota;
434
        }
435
    }
436

    
437

    
438
    /**
439
     * @param facade
440
     * @param state
441
     * @param line
442
     * @param record
443
     */
444
    private void makeCollectorFields(DerivedUnitFacade facade, SimpleExcelSpecimenImportState<CONFIG> state, String line,
445
            HashMap<String, String> record) {
446

    
447
        //collector number
448
        facade.setFieldNumber(record.get(COL_COLLECTOR_NUMBER));
449

    
450
        //gathering date
451
        String dateFrom = unknownToNull((record.get(COL_COLLECTION_DATE_FROM)));
452
        String dateTo = unknownToNull(record.get(COL_COLLECTION_DATE_TO));
453
        checkNoToIfNoFrom(dateFrom, dateTo, state, line, COL_COLLECTION_DATE_TO);
454
        try {
455
            if (dateFrom != null && dateFrom.equals(dateTo)){
456
                dateTo = null;
457
            }
458
            TimePeriod gatheringPeriod = TimePeriodParser.parseEnglishDate(dateFrom, dateTo);
459
            facade.setGatheringPeriod(gatheringPeriod);
460
        } catch (Exception e) {
461
            state.getResult().addError("Error creating gathering date", e, null, line);
462
        }
463

    
464
        //collector
465
        String collectorType = record.get(COL_COLLECTOR_TYPE);
466
        String collectors = record.get(COL_COLLECTORS);
467
        AgentBase<?> collector;
468
        if (collectorType.startsWith("Anonymous")){
469
            collector = getAnonymous();
470
        }else if (collectorType.equals("Brother") || collectorType.equals("Person")){
471
            Person person = Person.NewInstance();
472
            if (collectorType.equals("Person")){
473
                person.setLastname(record.get(COL_COLLECTOR_LASTNAME));
474
                String initials = CdmUtils.concat("", record.get(COL_COLLECTOR_FIRSTNAME), record.get(COL_COLLECTOR_MIDDLENAME));
475
                initials = (initials == null)? null : initials.replaceAll("\\s", "");
476
                person.setInitials(initials);
477
                String full = person.getTitleCache();
478
                if (!full.equals(collectors)){
479
                    person.setTitleCache(collectors, true);
480
                    //TODO longterm, collector cache
481
                }
482
            }else{
483
                person.setTitleCache(collectors, true);
484
                person.setPrefix("Hno.");
485
                person.setFirstname(collectors.replace("Hno.", "").trim());
486
            }
487
            collector = person;
488
        }else if (collectorType.equals("Group")){
489
            collector = Team.NewTitledInstance(collectors, collectors);
490
        }else if (collectorType.equals("Institution")){
491
            collector = Institution.NewNamedInstance(collectors);
492
        }else{
493
            String message = "Collector type " + collectorType + " not yet supported by import. Collector not added.";
494
            state.getResult().addError(message, null, line);
495
            collector = null;
496
        }
497
        collector = getDeduplicationHelper(state).getExistingAgent(state, collector);
498
        facade.setCollector(collector);
499
    }
500

    
501

    
502
    /**
503
     * @param string
504
     * @return
505
     */
506
    private String unknownToNull(String string) {
507
        if (string == null || string.equalsIgnoreCase("unknown")){
508
            return null;
509
        }else{
510
            return string;
511
        }
512
    }
513

    
514
    private Person anonymous;
515
    private Person getAnonymous() {
516
        if (anonymous != null){
517
            return anonymous;
518
        }
519
        anonymous = CdmBase.deproxy(getAgentService().find(uuidAnonymous), Person.class);
520
        if (anonymous == null){
521
            anonymous = Person.NewTitledInstance("Anon.");
522
            anonymous.setUuid(uuidAnonymous);
523
            getAgentService().save(anonymous);
524
        }
525
        return anonymous;
526
    }
527

    
528

    
529
    /**
530
     * @param facade
531
     * @param state
532
     * @param line
533
     * @param record
534
     * @param taxonBase
535
     */
536
    private void makeDetermination(DerivedUnit specimen, SimpleExcelSpecimenImportState<CONFIG> state, String line,
537
            HashMap<String, String> record, TaxonName taxonName) {
538

    
539
        DeterminationEvent determination;
540
        determination = DeterminationEvent.NewInstance(taxonName, specimen);
541
        determination.setPreferredFlag(true);
542

    
543
        //determiner/identifier
544
        TeamOrPersonBase<?> determiner = makeDeterminer(state, record, line);
545
        determination.setDeterminer(determiner);
546

    
547
        //date
548
        TimePeriod date = makeIdentificationDate(state, record, line);
549
        determination.setTimeperiod(date);
550

    
551
        //qualifier
552
        DefinedTerm qualifier = makeDeterminationQualifier(state, record, line);
553
        determination.setModifier(qualifier);
554

    
555
        //history
556
        String history = record.get(COL_IDENTIFICATION_HISTORY);
557
        if (history != null){
558
            String label = "Identification History";
559
            String text = label;
560
            ExtensionType detHistoryType = getExtensionType(state, uuidExtTypeIdentificationHistory, label, text, null);
561
            specimen.addExtension(history, detHistoryType);
562
        }
563
    }
564

    
565

    
566
    /**
567
     * @param state
568
     * @param record
569
     * @param line
570
     * @return
571
     */
572
    private TeamOrPersonBase<?> makeDeterminer(SimpleExcelSpecimenImportState<CONFIG> state,
573
            HashMap<String, String> record, String line) {
574
        String identifier = record.get(COL_IDENTIFIER);
575
        if (identifier == null){
576
            return null;
577
        }else if (identifier.equals("Anon.")){
578
            return getAnonymous();
579
        }else{
580
            Person person = Person.NewInstance();
581
            person.setTitleCache(identifier, true);
582
//            String format = "([A-Z]\\.){1,3}" +
583
//                    NonViralNameParserImplRegExBase.capitalWord +
584
//                    "(-" + NonViralNameParserImplRegExBase.capitalWord;
585

    
586
            String[] splits = identifier.split("\\.");
587
            int length = splits.length;
588
            if (splits[length - 1].equals("")){
589
                splits[length - 2]= splits[length - 2]+".";
590
                length--;
591
            }
592
            if (splits[length - 1].startsWith("-")){
593
                splits[length - 2]= splits[length - 2]+"." + splits[length - 1];
594
                length--;
595
            }
596
            String lastName = splits[length - 1];
597
            String initials = null;
598
            for (int i= 0; i < length-1;i++){
599
                initials = CdmUtils.concat("", initials, splits[i]+".");
600
            }
601
            person.setLastname(lastName);
602
            person.setInitials(initials);
603
            TeamOrPersonBase<?> result = getDeduplicationHelper(state).getExistingAuthor(state, person);
604
            return result;
605
        }
606
    }
607

    
608

    
609
    /**
610
     * @param state
611
     * @param record
612
     * @param line
613
     * @return
614
     */
615
    private TimePeriod makeIdentificationDate(SimpleExcelSpecimenImportState<CONFIG> state,
616
            HashMap<String, String> record, String line) {
617
        String strDate = record.get(COL_IDENTIFICATION_DATE);
618
        if (strDate == null || strDate.equals("s.n.")){
619
            return null;
620
        }
621
        String[] splits = strDate.split("/");
622
        String strYear = splits[splits.length-1];
623
        String strMonth = splits.length < 2? null:splits[splits.length-2];
624
        String strDay = splits.length < 3? null:splits[splits.length-3];
625

    
626
        Integer year = intFromString(state, strYear, line, COL_IDENTIFICATION_DATE);
627
        Integer month = intFromString(state, strMonth, line, COL_IDENTIFICATION_DATE);
628
        Integer day = intFromString(state, strDay, line, COL_IDENTIFICATION_DATE);
629
        Partial start = TimePeriodParser.makePartialFromDateParts(year, month, day);
630
        return TimePeriod.NewInstance(start);
631
    }
632

    
633

    
634
    /**
635
     * @param state
636
     * @param record
637
     * @param line
638
     * @return
639
     */
640
    private DefinedTerm makeDeterminationQualifier(SimpleExcelSpecimenImportState<CONFIG> state,
641
            HashMap<String, String> record, String line) {
642
        String qualifier = record.get(COL_IDENTIFICATION_QUALIFIER);
643
        if (qualifier != null){
644
            try {
645
                return DeterminationModifierParser.parseDeterminationQualifier(qualifier);
646
            } catch (UnknownCdmTypeException e) {
647
                //TODO add to terms
648
                if (qualifier.equals("vel. aff.")){
649

    
650
                    DefinedTerm velAff = (DefinedTerm)getTermService().find(uuidDetQualVelAff);
651
                    if (velAff == null){
652
                        velAff = DefinedTerm.NewModifierInstance(qualifier, qualifier, qualifier);
653
                        velAff.setUuid(uuidDetQualVelAff);
654
                        getTermService().save(velAff);
655
                    }
656
                    return velAff;
657
                }
658
                state.getResult().addError("Determination qualifier could not be recognized: " + qualifier, null, line);
659
                return null;
660
            }
661
        }else{
662
            return null;
663
        }
664
    }
665

    
666

    
667
    /**
668
     * @param taxonBase
669
     * @return
670
     */
671
    private Taxon getTaxon(TaxonBase<?> taxonBase) {
672
        if (taxonBase.isInstanceOf(Synonym.class)){
673
            return CdmBase.deproxy(taxonBase, Synonym.class).getAcceptedTaxon();
674
        }else{
675
            return CdmBase.deproxy(taxonBase, Taxon.class);
676
        }
677
    }
678

    
679

    
680
    /**
681
     * @param state
682
     * @param line
683
     * @param record
684
     * @param noStr
685
     * @return
686
     */
687
    private TaxonBase<?> getOrCreateTaxon(SimpleExcelSpecimenImportState<CONFIG> state, String line,
688
            HashMap<String, String> record, String noStr) {
689

    
690
        String strUuidTaxon = record.get(COL_TAXON_UUID);
691
        if (strUuidTaxon != null){
692
            UUID uuidTaxon;
693
            try {
694
                uuidTaxon = UUID.fromString(strUuidTaxon);
695
            } catch (Exception e) {
696
                state.getResult().addError("Taxon uuid has incorrect format. Taxon could not be loaded. Data not imported.", null, line);
697
                return null;
698
            }
699
            TaxonBase<?> result = getTaxonService().find(uuidTaxon);
700
            if (result == null){
701
                state.getResult().addError("Taxon for uuid  "+strUuidTaxon+" could not be found in database. "
702
                        + "Taxon could not be loaded. Data not imported.", null, line);
703

    
704
            }
705
            return result;
706
        }else{
707
            TaxonName taxonName = null;
708
            Reference sec = null;
709
            Taxon result = Taxon.NewInstance(taxonName, sec);
710
            result.addSource(makeOriginalSource(state));
711
            //TODO export uuid
712

    
713
//            state.getResult().addInfo("Taxon");
714
            //TODO
715
            return null;
716
        }
717
    }
718

    
719

    
720
    @Override
721
    protected void secondPass(SimpleExcelSpecimenImportState<CONFIG> state) {
722
//        if (tx != null){
723
//            this.commitTransaction(tx);
724
//            tx = null;
725
//        }
726
    }
727

    
728
    @Override
729
    protected IdentifiableSource makeOriginalSource(SimpleExcelSpecimenImportState<CONFIG> state) {
730
        return IdentifiableSource.NewDataImportInstance(getValue(state.getOriginalRecord(), COL_VOUCHER_ID), COL_VOUCHER_ID, getSourceCitation(state));
731
    }
732

    
733
    /**
734
     * @param state
735
     * @return
736
     */
737
    protected Reference getSourceCitation(SimpleExcelSpecimenImportState<CONFIG> state) {
738
        Reference source = state.getConfig().getSourceReference();
739
        if (source.getId() == 0){
740
            Reference persisted = getReferenceService().find(source.getUuid());
741
            if (persisted == null){
742
                getReferenceService().saveOrUpdate(source);
743
            }else{
744
                state.getConfig().setSourceReference(persisted);
745
                source = persisted;
746
            }
747
        }
748
        return source;
749
    }
750
}
(3-3/6)