Project

General

Profile

Download (29.4 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.occurrence.FieldUnit;
49
import eu.etaxonomy.cdm.model.reference.Reference;
50
import eu.etaxonomy.cdm.model.taxon.Synonym;
51
import eu.etaxonomy.cdm.model.taxon.Taxon;
52
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
53
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
54
import eu.etaxonomy.cdm.strategy.parser.DeterminationModifierParser;
55
import eu.etaxonomy.cdm.strategy.parser.SpecimenTypeParser;
56
import eu.etaxonomy.cdm.strategy.parser.TimePeriodParser;
57

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

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

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

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

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

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

    
116

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

    
122
    /**
123
     * {@inheritDoc}
124
     */
125
    @Override
126
    protected void firstPass(SimpleExcelSpecimenImportState<CONFIG> state) {
127

    
128
        HashMap<String, String> record = state.getOriginalRecord();
129

    
130
        String voucherId = getValue(record, COL_VOUCHER_ID);
131
        if (!isInInterval(state)){
132
            return;
133
        }
134
        String line = state.getCurrentLine() + " (id:"+ voucherId+"): ";
135
        if (state.getCurrentLine() % 100 == 0){System.out.println(line);}
136
        try {
137

    
138
            //species
139
            TaxonBase<?> taxonBase = getOrCreateTaxon(state, line, record, voucherId);
140

    
141
            if (taxonBase != null){
142
                Taxon taxon = getTaxon(taxonBase);
143

    
144
                TaxonDescription taxonDescription = getTaxonDescription(state, line, taxon);
145

    
146
                DerivedUnit specimen = makeSpecimen(state, line, record, voucherId, taxonBase);
147

    
148
                IndividualsAssociation indAssoc = IndividualsAssociation.NewInstance(specimen);
149
                indAssoc.addImportSource(voucherId, COL_VOUCHER_ID, getSourceCitation(state), null);
150
                taxonDescription.addElement(indAssoc);
151

    
152
            }
153
        } catch (Exception e) {
154
            state.getResult().addError("An unexpected exception appeared in record", e, null, line);
155
            e.printStackTrace();
156
        }
157

    
158
    }
159

    
160

    
161
    /**
162
     * @param state
163
     * @return
164
     */
165
    private boolean isInInterval(SimpleExcelSpecimenImportState<CONFIG> state) {
166
        Integer min = state.getConfig().getMinLineNumber();
167
        Integer max = state.getConfig().getMaxLineNumber();
168
        Integer current = state.getCurrentLine();
169
        if (current < min || current > max){
170
            return false;
171
        }else{
172
            return true;
173
        }
174
    }
175

    
176

    
177
    /**
178
     * @param state
179
     * @param line
180
     * @param taxon
181
     * @return
182
     */
183
    private TaxonDescription getTaxonDescription(SimpleExcelSpecimenImportState<CONFIG> state, String line,
184
            Taxon taxon) {
185
        Reference ref = getSourceCitation(state);
186
        TaxonDescription desc = this.getTaxonDescription(taxon, ref, ! IMAGE_GALLERY, ! CREATE);
187
        if (desc == null){
188
            //TODO move title creation into base method
189
            desc = this.getTaxonDescription(taxon, ref, ! IMAGE_GALLERY, CREATE);
190
            desc.setTitleCache("Specimen Excel import for " +  taxon.getName().getTitleCache(), true);
191
        }
192
        return desc;
193
    }
194

    
195

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

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

    
221

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

    
245

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

    
271

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

    
283

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

    
298

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

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

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

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

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

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

    
371

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

    
390
    private ReferenceSystem defaultGeocodeMethod;
391

    
392
    /**
393
     * @param state
394
     * @param record
395
     * @param line
396
     * @return
397
     */
398
    private ReferenceSystem makeReferenceSystem(SimpleExcelSpecimenImportState<CONFIG> state,
399
            Map<String, String> record, String line) {
400
        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.";
401
        String strRefSys = record.get(COL_GEO_METHOD);
402
        if (strRefSys == null){
403
            return null;
404
        }else if (!strRefSys.equals(defaultStrRefSys)){
405
            state.getResult().addError("The expected Geocode Method is not the expected default method. Geocode Method was not added.", null, line);
406
            return null;
407
        }else if (defaultGeocodeMethod != null){
408
            return defaultGeocodeMethod;
409
        }else{
410
            String label = "Point radius method";
411
            String description = defaultStrRefSys;
412
            String labelAbbrev = "PRM";
413
            defaultGeocodeMethod = getReferenceSystem(state, uuidDefaultGeocodMethod,
414
                    label, description, labelAbbrev, null);
415
            return defaultGeocodeMethod;
416
        }
417
    }
418

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

    
438

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

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

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

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

    
502

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

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

    
529

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

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

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

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

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

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

    
566

    
567
    /**
568
     * @param state
569
     * @param record
570
     * @param line
571
     * @return
572
     */
573
    private TeamOrPersonBase<?> makeDeterminer(SimpleExcelSpecimenImportState<CONFIG> state,
574
            HashMap<String, String> record, String line) {
575
        String identifier = record.get(COL_IDENTIFIER);
576
        if (identifier == null){
577
            return null;
578
        }else if (identifier.equals("Anon.")){
579
            return getAnonymous();
580
        }else{
581
            Person person = Person.NewInstance();
582
            person.setTitleCache(identifier, true);
583

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

    
606

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

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

    
631

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

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

    
664

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

    
677

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

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

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

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

    
717
    @Override
718
    protected IdentifiableSource makeOriginalSource(SimpleExcelSpecimenImportState<CONFIG> state) {
719
        return IdentifiableSource.NewDataImportInstance(getValue(state.getOriginalRecord(), COL_VOUCHER_ID), COL_VOUCHER_ID, getSourceCitation(state));
720
    }
721

    
722
    /**
723
     * @param state
724
     * @return
725
     */
726
    protected Reference getSourceCitation(SimpleExcelSpecimenImportState<CONFIG> state) {
727
        Reference source = state.getConfig().getSourceReference();
728
        if (source.getId() == 0){
729
            Reference persisted = getReferenceService().find(source.getUuid());
730
            if (persisted == null){
731
                getReferenceService().saveOrUpdate(source);
732
            }else{
733
                state.getConfig().setSourceReference(persisted);
734
                source = persisted;
735
            }
736
        }
737
        return source;
738
    }
739
}
(3-3/6)