Project

General

Profile

Download (39.8 KB) Statistics
| Branch: | Tag: | 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.excel.taxa;
11

    
12
import java.net.MalformedURLException;
13
import java.net.URI;
14
import java.net.URISyntaxException;
15
import java.util.Arrays;
16
import java.util.HashMap;
17
import java.util.HashSet;
18
import java.util.List;
19
import java.util.Map;
20
import java.util.Set;
21
import java.util.UUID;
22

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

    
27
import eu.etaxonomy.cdm.common.CdmUtils;
28
import eu.etaxonomy.cdm.io.common.TdwgAreaProvider;
29
import eu.etaxonomy.cdm.io.excel.common.ExcelRowBase.SourceDataHolder;
30
import eu.etaxonomy.cdm.io.tcsrdf.TcsRdfTransformer;
31
import eu.etaxonomy.cdm.model.agent.Team;
32
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
33
import eu.etaxonomy.cdm.model.common.CdmBase;
34
import eu.etaxonomy.cdm.model.common.DefinedTerm;
35
import eu.etaxonomy.cdm.model.common.Extension;
36
import eu.etaxonomy.cdm.model.common.ExtensionType;
37
import eu.etaxonomy.cdm.model.common.Identifier;
38
import eu.etaxonomy.cdm.model.common.Language;
39
import eu.etaxonomy.cdm.model.common.OriginalSourceType;
40
import eu.etaxonomy.cdm.model.description.CommonTaxonName;
41
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
42
import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
43
import eu.etaxonomy.cdm.model.description.Distribution;
44
import eu.etaxonomy.cdm.model.description.Feature;
45
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
46
import eu.etaxonomy.cdm.model.description.TaxonDescription;
47
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
48
import eu.etaxonomy.cdm.model.description.TextData;
49
import eu.etaxonomy.cdm.model.location.NamedArea;
50
import eu.etaxonomy.cdm.model.media.Media;
51
import eu.etaxonomy.cdm.model.name.INonViralName;
52
import eu.etaxonomy.cdm.model.name.NameRelationshipType;
53
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
54
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
55
import eu.etaxonomy.cdm.model.name.Rank;
56
import eu.etaxonomy.cdm.model.name.TaxonName;
57
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
58
import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
59
import eu.etaxonomy.cdm.model.reference.Reference;
60
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
61
import eu.etaxonomy.cdm.model.reference.ReferenceType;
62
import eu.etaxonomy.cdm.model.taxon.Classification;
63
import eu.etaxonomy.cdm.model.taxon.Synonym;
64
import eu.etaxonomy.cdm.model.taxon.SynonymType;
65
import eu.etaxonomy.cdm.model.taxon.Taxon;
66
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
67
import eu.etaxonomy.cdm.persistence.dto.MergeResult;
68
import eu.etaxonomy.cdm.strategy.exceptions.StringNotParsableException;
69
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
70
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
71
import eu.etaxonomy.cdm.strategy.parser.TimePeriodParser;
72

    
73
/**
74
 * @author a.babadshanjan
75
 * @since 08.01.2009
76
 */
77

    
78
@Component
79
public class NormalExplicitImport extends TaxonExcelImportBase {
80
    private static final long serialVersionUID = 3642423349766191160L;
81

    
82
    private static final Logger logger = Logger.getLogger(NormalExplicitImport.class);
83

    
84
	public static Set<String> validMarkers = new HashSet<String>(Arrays.asList(new String[]{"", "valid", "accepted", "a", "v", "t", "!"}));
85
	public static Set<String> synonymMarkers = new HashSet<String>(Arrays.asList(new String[]{"**","invalid", "synonym", "s", "i"}));
86
	public static Set<String> nameStatusMarkers = new HashSet<String>(Arrays.asList(new String[]{"illegitimate", "nom. rej.", "nom. cons."}));
87
	public static final UUID uuidRefExtension = UUID.fromString("a46533df-7a78-448f-9b80-36d087fbdf2a");
88

    
89
    private static final Object NOM_ILLEG = "illegitimate";
90
    private static final Object NOM_REJ = "nom. rej.";
91
    private static final Object NOM_CONS = "nom. cons.";
92

    
93

    
94
	/* (non-Javadoc)
95
	 * @see eu.etaxonomy.cdm.io.excel.common.ExcelTaxonOrSpecimenImportBase#analyzeSingleValue(eu.etaxonomy.cdm.io.excel.common.ExcelTaxonOrSpecimenImportBase.KeyValue, eu.etaxonomy.cdm.io.excel.common.ExcelImportState)
96
	 */
97
	@Override
98
	protected void analyzeSingleValue(KeyValue keyValue, TaxonExcelImportState state) {
99

    
100
		NormalExplicitRow normalExplicitRow = (NormalExplicitRow)state.getCurrentRow();
101
		String key = keyValue.key;
102
		String value = keyValue.value;
103
		Integer index = keyValue.index;
104
		if (((NormalExplicitImportConfigurator)state.getConfig()).getParentUUID() != null){
105
            normalExplicitRow.setParentId("0");
106
		}
107
//  Infraspecific rank  Infraspecific epithet   Authorship  Taxonomic status in TPL Nomenclatural status from original data source  Confidence level    Source  Source id   IPNI id Publication Collation   Page    Date    Accepted ID
108

    
109
		key = key.replace(" ","");
110
		if (key.equalsIgnoreCase(ID_COLUMN)) {
111
			//String ivalue = floatString2IntValue(value);
112
			normalExplicitRow.setId(value);
113

    
114
		} else if(key.equalsIgnoreCase(PARENT_ID_COLUMN) ) {
115
			//int ivalue = floatString2IntValue(value);
116
			normalExplicitRow.setParentId(value);
117

    
118
		} else if(key.equalsIgnoreCase(RANK_COLUMN)) {
119
			normalExplicitRow.setRank(value);
120

    
121
		} else if(key.trim().equalsIgnoreCase(SCIENTIFIC_NAME_COLUMN) || key.trim().equalsIgnoreCase(FULLNAME_COLUMN)) {
122
			normalExplicitRow.setScientificName(value);
123

    
124
		} else if(key.equalsIgnoreCase(AUTHOR_COLUMN)|| key.equalsIgnoreCase(AUTHORS_COLUMN) || key.equals(AUTHORSHIP_COLUMN)) {
125
			normalExplicitRow.setAuthor(value);
126
		}else if(key.equalsIgnoreCase(PUBLISHING_AUTHOR_COLUMN)) {
127
            normalExplicitRow.setPublishingAuthor(value);
128
		}else if(key.equalsIgnoreCase(BASIONYM_AUTHOR_COLUMN)) {
129
            normalExplicitRow.setBasionymAuthor(value);
130

    
131
		}else if(key.equalsIgnoreCase(BASIONYM_COLUMN)) {
132
            normalExplicitRow.setBasionym(value);
133
		}else if(key.trim().equalsIgnoreCase(NOMENCLATURAL_SYNONYM_COLUMN)) {
134
            normalExplicitRow.setSynonym(value);
135
		} else if(key.equalsIgnoreCase(REFERENCE_COLUMN) || key.equalsIgnoreCase(PUBLICATION_COLUMN)) {
136
			normalExplicitRow.setReference(value);
137

    
138
		} else if(key.equalsIgnoreCase(COLLATION_COLUMN)) {
139
            normalExplicitRow.setCollation(value);
140

    
141
        }else if(key.equalsIgnoreCase(PAGE_COLUMN)) {
142
            normalExplicitRow.setPage(value);
143

    
144
        }else if(key.equalsIgnoreCase(NAMESTATUS_COLUMN) || key.trim().startsWith(NOMENCLATURAL_STATUS_COLUMN)) {
145
			normalExplicitRow.setNameStatus(value);
146

    
147
		} else if(key.equalsIgnoreCase(VERNACULAR_NAME_COLUMN)) {
148
			normalExplicitRow.setCommonName(value);
149

    
150
		} else if(key.equalsIgnoreCase(LANGUAGE_COLUMN)) {
151
			normalExplicitRow.setLanguage(value);
152

    
153
		} else if(key.equalsIgnoreCase(TDWG_COLUMN) ) {
154
			//TODO replace still necessary?
155
			value = value.replace(".0", "");
156
			normalExplicitRow.putDistribution(index, value);
157

    
158
		} else if(key.equalsIgnoreCase(PROTOLOGUE_COLUMN)) {
159
			normalExplicitRow.putProtologue(index, value);
160

    
161
		} else if(key.equalsIgnoreCase(IMAGE_COLUMN)) {
162
			normalExplicitRow.putImage(index, value);
163

    
164
		} else if(key.equalsIgnoreCase(DATE_COLUMN) || key.equalsIgnoreCase(YEAR_COLUMN)|| key.equalsIgnoreCase(PUBLICATION_YEAR_COLUMN)) {
165
            normalExplicitRow.setDate(value);
166

    
167
        } else if(key.equalsIgnoreCase(FAMILY_COLUMN)) {
168
            normalExplicitRow.setFamily(value);
169
        } else if(key.equalsIgnoreCase(INFRA_FAMILY_COLUMN)) {
170
            normalExplicitRow.setInfraFamily(value);
171
        }else if(key.equalsIgnoreCase(GENUS_COLUMN)) {
172
            normalExplicitRow.setGenus(value);
173
        }else if(key.trim().equalsIgnoreCase(INFRA_GENUS_COLUMN.trim())) {
174
            normalExplicitRow.setInfraGenus(value);
175
        }else if(key.equalsIgnoreCase(SPECIES_COLUMN)) {
176
            normalExplicitRow.setSpecies(value);
177
        }else if(key.equalsIgnoreCase(INFRA_SPECIES_COLUMN) || key.equalsIgnoreCase(INFRA_SPECIES_EPITHET_COLUMN)) {
178
            normalExplicitRow.setInfraSpecies(value);
179
        }else if(key.equalsIgnoreCase(INFRA_SPECIES_RANK_COLUMN)) {
180
            normalExplicitRow.setInfraSpecies_Rank(value);
181
        } else if (key.equalsIgnoreCase(VERSION_COLUMN)){
182
            normalExplicitRow.setVersion(value);
183
        }else if (key.equalsIgnoreCase(ACCEPTED_ID_COLUMN)){
184
            normalExplicitRow.setAccepted_id(value);
185
        }else if (key.equalsIgnoreCase(TAXONOMIC_STATUS)){
186
            normalExplicitRow.setTaxonomicStatus(value);
187
        }else if (key.equalsIgnoreCase(IPNI_ID_COLUMN)){
188
            normalExplicitRow.setIpni_id(value);
189
        }else if (key.equalsIgnoreCase(SOURCE_COLUMN)){
190
            normalExplicitRow.setSource(value);
191
        } else if (key.equalsIgnoreCase(SOURCE_ID_COLUMN)){
192
            normalExplicitRow.setSource_Id(value);
193
        }
194

    
195

    
196

    
197

    
198
        else if(key.equalsIgnoreCase("!")) {
199
            //! = Legitimate, * = Illegitimate, ** = Invalid, *** = nom. rej., !! = nom. cons.
200
            if (value.equals("!")){
201
                normalExplicitRow.setNameStatus("accepted");
202
            } else if (value.equals("*")){
203
                normalExplicitRow.setNameStatus("illegitimate");
204
            } else if (value.equals("**")){
205
                normalExplicitRow.setNameStatus("invalid");
206
            } else if (value.equals("***")){
207
                normalExplicitRow.setNameStatus("nom. rej.");
208
            } else if (value.equals("!!")){
209
                normalExplicitRow.setNameStatus("nom. cons.");
210
            } else{
211
                normalExplicitRow.setNameStatus("accepted");
212
            }
213
        }else if(key.equalsIgnoreCase("Nomenclatural status from original data source")) {
214

    
215
            if (value.equals("Illegitimate")){
216
                normalExplicitRow.setNameStatus("illegitimate");
217
            } else if (value.equals("Invalid")){
218
                normalExplicitRow.setNameStatus("invalid");
219
            } else{
220
                normalExplicitRow.setNameStatus("accepted");
221
            }
222
        }else {
223
			if (analyzeFeatures(state, keyValue)){
224

    
225
			}else{
226
				String message = "Unexpected column header " + key;
227
				fireWarningEvent(message, state, 10);
228
				state.setUnsuccessfull();
229
				//logger.error(message);
230
			}
231
		}
232
		return;
233
	}
234

    
235

    
236
	/**
237
	 *  Create base taxa and add all information attached to it's name.
238
	 */
239
	@Override
240
    protected void firstPass(TaxonExcelImportState state) {
241

    
242
//		if (1==1){
243
//			return;
244
//		}
245
//		System.out.println("FP:" + state.getCurrentLine());
246
		Rank rank = null;
247
		NormalExplicitRow taxonDataHolder = (NormalExplicitRow)state.getCurrentRow();
248

    
249
		String rankStr = taxonDataHolder.getRank();
250
		String taxonNameStr = taxonDataHolder.getScientificName();
251
		String authorStr = taxonDataHolder.getAuthor();
252
		String publishingAuthor= taxonDataHolder.getPublishingAuthor();
253
		String basionymAuthor = taxonDataHolder.getBasionymAuthor();
254

    
255
		String referenceStr = taxonDataHolder.getReference();
256
		String nameStatus = taxonDataHolder.getNameStatus();
257
		String familyNameStr = taxonDataHolder.getFamily();
258
		String infraFamilyNameStr = taxonDataHolder.getInfraFamily();
259
		String genusNameStr = taxonDataHolder.getGenus();
260
		String infraGenusNameStr = taxonDataHolder.getInfraGenus();
261
		String speciesNameStr = taxonDataHolder.getSpecies();
262
		String infraSpeciesNameStr = taxonDataHolder.getInfraSpecies();
263

    
264
		String version = taxonDataHolder.getVersion();
265

    
266
		String ipni_id = taxonDataHolder.getIpni_id();
267
		String source = taxonDataHolder.getSource();
268
		String source_id = taxonDataHolder.getSource_Id();
269
		String taxonomicStatus = taxonDataHolder.getTaxonomicStatus();
270

    
271

    
272
		String dateStr = taxonDataHolder.getDate();
273
		String id = taxonDataHolder.getId();
274
		UUID cdmUuid = taxonDataHolder.getCdmUuid();
275

    
276
		TaxonBase<?> taxonBase = null;
277
		if (cdmUuid != null){
278
			taxonBase = getTaxonService().find(cdmUuid);
279
		}else{
280
			if (rankStr == null || StringUtils.isBlank(rankStr)){
281
			    if (taxonDataHolder.getInfraSpecies() != null){
282
			        if (taxonDataHolder.getInfraSpecies_Rank() !=  null || !StringUtils.isBlank(taxonDataHolder.getInfraSpecies_Rank()) ){
283
			            try {
284
                            rank = Rank.getRankByNameOrIdInVoc(taxonDataHolder.getInfraSpecies_Rank());
285
                        } catch (UnknownCdmTypeException e) {
286
                            // TODO Auto-generated catch block
287
                            e.printStackTrace();
288
                        }
289
		            }else {
290
		                rank = Rank.INFRASPECIES();
291
		            }
292
		        } else if (taxonDataHolder.getSpecies()!= null){
293
		            rank = Rank.SPECIES();
294
		        } else if (taxonDataHolder.getInfraGenus() != null){
295
		            rank = Rank.INFRAGENUS();
296
		        } else if (taxonDataHolder.getGenus() != null){
297
                    rank = Rank.GENUS();
298
		        }
299

    
300
		    } else{
301
				// Rank
302
				try {
303
				    if (!StringUtils.isBlank(rankStr)) {
304
                        rank = Rank.getRankByNameOrIdInVoc(rankStr);
305
                        }
306
				} catch (UnknownCdmTypeException ex) {
307
					try {
308
						rank = Rank.getRankByEnglishName(rankStr, state.getConfig().getNomenclaturalCode(), false);
309
					} catch (UnknownCdmTypeException e) {
310
					    try {
311
	                           rank = TcsRdfTransformer.rankString2Rank(rankStr);
312
	                       } catch (UnknownCdmTypeException e1) {
313
	                            // TODO Auto-generated catch block
314
	                            e1.printStackTrace();
315
	                       }
316

    
317
					}
318
				}
319
		    }
320
			if (StringUtils.isBlank(taxonNameStr )){
321

    
322
			    if (taxonDataHolder.getGenus() != null){
323
			        taxonNameStr = taxonDataHolder.getGenus();
324
			        if (taxonDataHolder.getSpecies() != null){
325
			            taxonNameStr += " " + taxonDataHolder.getSpecies();
326
			        }
327
			        if (taxonDataHolder.getInfraSpecies_Rank() != null){
328
                        taxonNameStr += " " + taxonDataHolder.getInfraSpecies_Rank();
329
                    }
330
			        if (taxonDataHolder.getInfraSpecies() != null){
331
                        taxonNameStr += " " + taxonDataHolder.getInfraSpecies();
332
                    }
333
			    }
334
			}
335
			if (StringUtils.isBlank(taxonNameStr )){
336
			    return;
337
			}
338
			 //taxon
339
            taxonBase = createTaxon(state, rank, taxonNameStr, authorStr, publishingAuthor, basionymAuthor, referenceStr, dateStr, nameStatus, taxonomicStatus);
340
		}
341

    
342
		if (taxonBase == null){
343
			String message = "Taxon is already in DB. Record will not be handled";
344
			fireWarningEvent(message, "Record: " + state.getCurrentLine(), 6);
345
			logger.warn(message);
346
			//state.setUnsuccessfull();
347
			return;
348
		}
349

    
350
		//protologue
351
		for (String protologue : taxonDataHolder.getProtologues()){
352
			TextData textData = TextData.NewInstance(Feature.PROTOLOGUE());
353
			this.getNameDescription(taxonBase.getName(), state).addElement(textData);
354
			URI uri;
355
			try {
356
				uri = new URI(protologue);
357
				textData.addMedia(Media.NewInstance(uri, null, null, null));
358

    
359
			} catch (URISyntaxException e) {
360
				String warning = "URISyntaxException when trying to convert to URI: " + protologue;
361
				logger.error(warning);
362
				state.setUnsuccessfull();
363
			}
364
		}
365

    
366
		if (ipni_id != null){
367
		    taxonBase.getName().addIdentifier(Identifier.NewInstance(ipni_id, DefinedTerm.IDENTIFIER_NAME_IPNI()));
368
		}
369

    
370
		if (source != null){
371
		    Reference sourceRef = state.getReference(source);
372
		    if (sourceRef == null){
373
		        sourceRef = ReferenceFactory.newGeneric();
374
		        sourceRef.setTitleCache(source, true);
375
		        state.putReference(source, sourceRef);
376
		    }
377
		    taxonBase.addSource(OriginalSourceType.PrimaryTaxonomicSource, source_id,"Taxon" ,sourceRef, null);
378
		}
379

    
380
		//state.putTaxon(id, taxonBase);
381
		taxonBase = getTaxonService().save(taxonBase);
382
		taxonDataHolder.setCdmUuid(taxonBase.getUuid());
383
		if (id == "0"){
384
		    state.putTaxon(taxonNameStr, taxonBase);
385
		}else{
386
		    state.putTaxon(id, taxonBase);
387
		}
388
		return;
389
    }
390

    
391

    
392

    
393
	/**
394
	 *  Stores parent-child, synonym and common name relationships.
395
	 *  Adds all taxon related descriptive information (this is not done in the first pass
396
	 *  because the information may also be attached to a synonym).
397
	 */
398
	@Override
399
    protected void secondPass(TaxonExcelImportState state) {
400
		if (logger.isDebugEnabled()){logger.debug(state.getCurrentLine());}
401
		try {
402
			NormalExplicitRow taxonDataHolder = (NormalExplicitRow)state.getCurrentRow();
403
			String taxonNameStr = taxonDataHolder.getScientificName();
404
			String nameStatus = taxonDataHolder.getNameStatus();
405
			String commonNameStr = taxonDataHolder.getCommonName();
406

    
407
			String synonymNameStr = taxonDataHolder.getSynonym();
408
			String basionymNameStr = taxonDataHolder.getBasionym();
409
			String accepted_idStr = taxonDataHolder.getAccepted_id();
410

    
411
			String parentId = taxonDataHolder.getParentId();
412
			String childId = taxonDataHolder.getId();
413
			UUID cdmUuid = taxonDataHolder.getCdmUuid();
414
			Taxon acceptedTaxon = null;
415
			TaxonName nameUsedInSource = null;
416
			TaxonBase<?> taxonBase = null;
417
			Taxon parentTaxon = null;
418

    
419
			if (cdmUuid != null){
420
				taxonBase = getTaxonService().find(cdmUuid);
421
				if (taxonBase != null ){
422
                    acceptedTaxon = getAcceptedTaxon(taxonBase);
423
                    nameUsedInSource = taxonBase.getName();
424
				}
425
			} else{
426
			    taxonBase = state.getTaxonBase(childId);
427
			    if (accepted_idStr != null){
428
			        acceptedTaxon = (Taxon) state.getTaxonBase(accepted_idStr);
429
			    }
430

    
431
    			 if (parentId == "0" && state.getParent() == null){
432
                     parentTaxon =(Taxon) getTaxonService().load(((NormalExplicitImportConfigurator)state.getConfig()).getParentUUID());
433
                     state.setParent(parentTaxon);
434
                 }else if (parentId != "0"){
435
                    parentTaxon = CdmBase.deproxy(state.getTaxonBase(parentId), Taxon.class);
436
                 } else if (state.getParent() != null){
437
                     parentTaxon = state.getParent();
438
                 }
439
    			if (taxonBase != null ){
440
    			    if (acceptedTaxon == null){
441
    			        acceptedTaxon = getAcceptedTaxon(taxonBase);
442
    			    }
443
    				if (synonymNameStr != null){
444
    				    Synonym syn = createSynonym(state,taxonBase,synonymNameStr);
445
    				    acceptedTaxon.addSynonym(syn, SynonymType.HETEROTYPIC_SYNONYM_OF());
446
    				}
447
    				if (basionymNameStr != null){
448
    				    Synonym syn = createSynonym(state,taxonBase,basionymNameStr);
449
                        acceptedTaxon.addSynonym(syn, SynonymType.HOMOTYPIC_SYNONYM_OF());
450
                        syn.getName().addRelationshipToName(acceptedTaxon.getName(), NameRelationshipType.BASIONYM(), null);
451
    				}
452
    				nameUsedInSource = taxonBase.getName();
453

    
454
    			    //TODO error handling for class cast
455

    
456

    
457
    				nameUsedInSource = taxonBase.getName();
458
    				nameStatus = CdmUtils.Nz(nameStatus).trim().toLowerCase();
459
    				if (validMarkers.contains(nameStatus)  && accepted_idStr == null){
460
    						Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);
461
    						acceptedTaxon = taxon;
462
    						// Add the parent relationship
463
    						//if (state.getCurrentRow().getParentId() != 0) {
464
    						MergeResult result = null;
465
    							if (parentTaxon != null) {
466
    								//Taxon taxon = (Taxon)state.getTaxonBase(childId);
467

    
468
    							//	Reference sourceRef = state.getConfig().getSourceReference();
469
    								String microCitation = null;
470
    								Taxon childTaxon = taxon;
471
    								makeParent(state, parentTaxon, childTaxon, null, microCitation);
472
    								getTaxonService().saveOrUpdate(childTaxon);
473
    								state.putTaxon(parentId, parentTaxon);
474
    							} else {
475
    								String message = "Taxonomic parent not found for " + taxonNameStr;
476
    								logger.warn(message);
477
    								fireWarningEvent(message, state, 6);
478
    								//state.setUnsuccessfull();
479
    							}
480
    //						}else{
481
    //							//do nothing (parent == 0) no parent exists
482
    //						}
483
    					}else if (synonymMarkers.contains(nameStatus) || accepted_idStr != null){
484
    						//add synonym relationship
485
    					    if (accepted_idStr == null){
486
    					        acceptedTaxon = parentTaxon;
487
    					    }
488
    						try {
489
    							Synonym synonym = CdmBase.deproxy(taxonBase,Synonym.class);
490
    							if (acceptedTaxon == null){
491
    								String message = "Accepted/valid taxon could not be found. Please check referential integrity.";
492
    								fireWarningEvent(message, state, 8);
493
    							}else{
494
    							   acceptedTaxon.addSynonym(synonym, SynonymType.SYNONYM_OF());
495
							       getTaxonService().saveOrUpdate(acceptedTaxon);
496

    
497
    							}
498
    						} catch (Exception e) {
499
    							String message = "Unhandled exception (%s) occurred during synonym import/update";
500
    							message = String.format(message, e.getMessage());
501
    							fireWarningEvent(message, state, 10);
502
    							state.setUnsuccessfull();
503
    						}
504

    
505
    					}else{
506
    					    if (parentTaxon != null) {
507
                                Taxon taxon = (Taxon)state.getTaxonBase(childId);
508

    
509
                               // Reference sourceRef = state.getConfig().getSourceReference();
510
                                String microCitation = null;
511
                                Taxon childTaxon = taxon;
512
                                makeParent(state, parentTaxon, childTaxon, null, microCitation);
513
                                getTaxonService().saveOrUpdate(parentTaxon);
514
                                state.putTaxon(parentId, parentTaxon);
515
                            } else {
516
                                String message = "Taxonomic parent not found for " + taxonNameStr;
517
                                logger.warn(message);
518
                                fireWarningEvent(message, state, 6);
519
                                //state.setUnsuccessfull();
520
                            }
521
    					}
522

    
523

    
524
    			}
525
    			if (StringUtils.isBlank(taxonNameStr) && acceptedTaxon == null) {
526
                    acceptedTaxon = parentTaxon;
527
                    nameUsedInSource = null;
528
                }
529
			}
530
			if (acceptedTaxon == null && (StringUtils.isNotBlank(commonNameStr) ||taxonDataHolder.getFeatures().size() > 0 )){
531
				String message = "Accepted taxon could not be found. Can't add additional data (common names, descriptive data, ...) to taxon";
532
				fireWarningEvent(message, state, 6);
533
			}else{
534
				//common names
535
				if (StringUtils.isNotBlank(commonNameStr)){			// add common name to taxon
536
					handleCommonName(state, taxonNameStr, commonNameStr, acceptedTaxon);
537
				}
538

    
539

    
540
				//media
541
				for (String imageUrl : taxonDataHolder.getImages()){
542
					TaxonDescription td = acceptedTaxon.getImageGallery(true);
543
					DescriptionElementBase mediaHolder;
544
					if (td.getElements().size() != 0){
545
						mediaHolder = td.getElements().iterator().next();
546
					}else{
547
						mediaHolder = TextData.NewInstance(Feature.IMAGE());
548
						td.addElement(mediaHolder);
549
					}
550
					try {
551
						Media media = getImageMedia(imageUrl, READ_MEDIA_DATA);
552
						mediaHolder.addMedia(media);
553
					} catch (MalformedURLException e) {
554
						logger.warn("Can't add media: " + e.getMessage());
555
						state.setUnsuccessfull();
556
					}
557
				}
558

    
559
				//tdwg label
560
				for (String tdwg : taxonDataHolder.getDistributions()){
561
					TaxonDescription td = this.getTaxonDescription(acceptedTaxon, state.getConfig().getSourceReference() ,false, true);
562
					NamedArea area = TdwgAreaProvider.getAreaByTdwgAbbreviation(tdwg);
563
					if (area == null){
564
						area = TdwgAreaProvider.getAreaByTdwgLabel(tdwg);
565
					}
566
					if (area != null){
567
						Distribution distribution = Distribution.NewInstance(area, PresenceAbsenceTerm.PRESENT());
568
						td.addElement(distribution);
569
					}else{
570
						String message = "TDWG area could not be recognized: " + tdwg;
571
						logger.warn(message);
572
						state.setUnsuccessfull();
573
					}
574
				}
575

    
576
				//features
577
				handleFeatures(state, taxonDataHolder, acceptedTaxon, nameUsedInSource);
578
			}
579
		} catch (Exception e) {
580
			e.printStackTrace();
581
		}
582
		return;
583
	}
584

    
585

    
586
	/**
587
     * @param state
588
     * @param taxonBase
589
     * @param synonymNameStr
590
     */
591
    private Synonym createSynonym(TaxonExcelImportState state, TaxonBase<?> taxonBase, String synonymNameStr) {
592
        NomenclaturalCode nc = state.getConfig().getNomenclaturalCode();
593
        TaxonName name = null;
594
        if (nc.isKindOf(NomenclaturalCode.ICZN)){
595
            name = TaxonNameFactory.NewZoologicalInstance(taxonBase.getName().getRank());
596
        }else if (nc.isKindOf(NomenclaturalCode.ICNAFP)){
597
            name = TaxonNameFactory.NewBotanicalInstance(taxonBase.getName().getRank());
598
        } else{
599
            name = TaxonNameFactory.NewNonViralInstance(taxonBase.getName().getRank());
600
        }
601
        name.setTitleCache(synonymNameStr, true);
602
        if (name != null){
603
            return Synonym.NewInstance(name, null);
604
        }
605
        logger.debug("The nomenclatural code is not supported.");
606
        return null;
607
    }
608

    
609

    
610
    /**
611
	 * @param state
612
	 * @param taxonDataHolder
613
	 * @param acceptedTaxon
614
	 */
615
	private void handleFeatures(TaxonExcelImportState state, NormalExplicitRow taxonDataHolder, Taxon acceptedTaxon, TaxonName nameUsedInSource) {
616
		//feature
617
		for (UUID featureUuid : taxonDataHolder.getFeatures()){
618
			Feature feature = getFeature(state, featureUuid);
619
			List<String> textList = taxonDataHolder.getFeatureTexts(featureUuid);
620
			List<String> languageList = taxonDataHolder.getFeatureLanguages(featureUuid);
621

    
622
			for (int i = 0; i < textList.size(); i++){
623
				String featureText = textList.get(i);
624
				String featureLanguage = languageList == null ? null :languageList.get(i);
625
				Language language = getFeatureLanguage(featureLanguage, state);
626
				//TODO
627
				TaxonDescription td = this.getTaxonDescription(acceptedTaxon, state.getConfig().getSourceReference() ,false, true);
628
				TextData textData = TextData.NewInstance(feature);
629
				textData.putText(language, featureText);
630
				td.addElement(textData);
631

    
632
				SourceDataHolder sourceDataHolder = taxonDataHolder.getFeatureTextReferences(featureUuid, i);
633
				List<Map<SourceType, String>> sourceList = sourceDataHolder.getSources();
634
				for (Map<SourceType, String> sourceMap : sourceList){
635

    
636
					//ref
637
					Reference ref = ReferenceFactory.newGeneric();
638
					boolean refExists = false; //in case none of the ref fields exists, the ref should not be added
639
					for (SourceType type : sourceMap.keySet()){
640
						String value = sourceMap.get(type);
641
						if (type.equals(SourceType.Author)){
642
							TeamOrPersonBase<?> author = getAuthorAccordingToConfig(value, state);
643
							ref.setAuthorship(author);
644
						}else if (type.equals(SourceType.Title)) {
645
							ref.setTitle(value);
646
						}else if (type.equals(SourceType.Year)) {
647
							ref.setDatePublished(TimePeriodParser.parseString(value));
648
						}else if (type.equals(SourceType.RefExtension)) {
649
							ExtensionType extensionType = getExtensionType(state, uuidRefExtension, "RefExtension", "Reference Extension", "RefExt.");
650
							Extension extension = Extension.NewInstance(ref, value, extensionType);
651
						}
652
						refExists = true;
653
					}
654
					DescriptionElementSource source = DescriptionElementSource.NewInstance(OriginalSourceType.PrimaryTaxonomicSource);
655
					if (refExists){
656
						ref = getReferenceAccordingToConfig(ref, state);
657
						source.setCitation(ref);
658
						source.setNameUsedInSource(nameUsedInSource);
659
					}
660
					textData.addSource(source);
661
				}
662
			}
663
		}
664
	}
665

    
666
	private final Map<String, UUID> referenceMapping = new HashMap<String, UUID>();
667
	private final Map<UUID, Reference> referenceStore = new HashMap<UUID, Reference>();
668

    
669
	private Reference getReferenceAccordingToConfig(Reference value, TaxonExcelImportState state) {
670
		Reference result = null;
671
		String titleCache = value.getTitleCache();
672
		UUID referenceUuid = referenceMapping.get(titleCache);
673
		if (referenceUuid != null){
674
			result = referenceStore.get(referenceUuid);
675
		}
676
		if (result == null){
677
			result = value;
678
			referenceStore.put(result.getUuid(), result);
679
		}
680
		if (referenceUuid == null){
681
			referenceMapping.put(titleCache, result.getUuid());
682
		}
683
		return result;
684
	}
685

    
686

    
687
	private final Map<String, UUID> authorMapping = new HashMap<String, UUID>();
688
	private final Map<UUID, TeamOrPersonBase> authorStore = new HashMap<UUID, TeamOrPersonBase>();
689

    
690
	private TeamOrPersonBase<?> getAuthorAccordingToConfig(String value, TaxonExcelImportState state) {
691
		TeamOrPersonBase<?> result = null;
692
		UUID authorUuid = authorMapping.get(value);
693
		if (authorUuid != null){
694
			result = authorStore.get(authorUuid);
695
		}
696
		if (result == null){
697
			//TODO parsing
698
			TeamOrPersonBase<?> author = Team.NewInstance();
699
			author.setTitleCache(value, true);
700
			result = author;
701
			authorStore.put(result.getUuid(), result);
702
		}
703
		if (authorUuid == null){
704
			authorMapping.put(value, result.getUuid());
705
		}
706
		return result;
707
	}
708

    
709

    
710
	private final Map<String, UUID> languageMapping = new HashMap<String, UUID>();
711

    
712
	private Language getFeatureLanguage(String featureLanguage, TaxonExcelImportState state) {
713
		if (StringUtils.isBlank(featureLanguage)){
714
			return null;
715
		}
716
		UUID languageUuid = languageMapping.get(featureLanguage);
717
		if (languageUuid == null){
718
			Language result = getTermService().getLanguageByIso(featureLanguage);
719
			languageUuid = result.getUuid();
720
			languageMapping.put(featureLanguage, languageUuid);
721
		}
722
		Language result = getLanguage(state, languageUuid, null, null, null);
723
		return result;
724
	}
725

    
726

    
727
	/**
728
	 * @param state
729
	 * @param taxonNameStr
730
	 * @param commonNameStr
731
	 * @param parentId
732
	 */
733
	private void handleCommonName(TaxonExcelImportState state,
734
			String taxonNameStr, String commonNameStr, Taxon acceptedTaxon) {
735
		Language language = getTermService().getLanguageByIso(((NormalExplicitRow)state.getCurrentRow()).getLanguage());
736
		if (language == null && CdmUtils.isNotEmpty(((NormalExplicitRow)state.getCurrentRow()).getLanguage())  ){
737
			String error ="Language is null but shouldn't";
738
			logger.error(error);
739
			throw new IllegalArgumentException(error);
740
		}
741
		CommonTaxonName commonTaxonName = CommonTaxonName.NewInstance(commonNameStr, language);
742
		try {
743
			TaxonDescription taxonDescription = getTaxonDescription(acceptedTaxon, false, true);
744
			taxonDescription.addElement(commonTaxonName);
745
			logger.info("Common name " + commonNameStr + " added to " + acceptedTaxon.getTitleCache());
746
		} catch (ClassCastException ex) {
747
			logger.error(taxonNameStr + " is not a taxon instance.");
748
		}
749
	}
750

    
751

    
752
	/**
753
	 * @param state
754
	 * @param rank
755
	 * @param taxonNameStr
756
	 * @param authorStr
757
	 * @param nameStatus
758
	 * @param nameStatus2
759
	 * @return
760
	 */
761
	private TaxonBase createTaxon(TaxonExcelImportState state, Rank rank,
762
	        String familyNameStr, String infraFamilyNameStr, String genusNameStr, String infraGenusNameStr, String speciesNameStr, String infraSpeciesNameStr, String authorStr, String publishingAuthorStr, String basionymAuthorStr,String reference, String date, String nameStatus, String taxonomicStatus) {
763
		// Create the taxon name object depending on the setting of the nomenclatural code
764
		// in the configurator (botanical code, zoological code, etc.)
765

    
766
		NomenclaturalCode nc = getConfigurator().getNomenclaturalCode();
767

    
768
		TaxonBase taxonBase;
769
		String nameCache = null;
770
		if (rank == null){
771
		    System.err.println("bla");
772
		}
773
		if (rank.isGenus()){
774
		    nameCache =genusNameStr;
775
		} else if (rank.isInfraGeneric()){
776
		    nameCache =CdmUtils.concat(" " +rank.getIdInVocabulary() + " ",genusNameStr,infraGenusNameStr);
777

    
778
        } else if (rank.isSpecies()){
779
            nameCache = CdmUtils.concat(" ", genusNameStr,speciesNameStr);
780
        } else if (rank.isInfraSpecific()){
781
            nameCache = CdmUtils.concat(" " +rank.getIdInVocabulary() + " ",genusNameStr,infraGenusNameStr);
782
        }
783
		if (! synonymMarkers.contains(nameStatus)  && state.getConfig().isReuseExistingTaxaWhenPossible()){
784
			taxonBase = getTaxonService().findBestMatchingTaxon(nameCache);
785
		}else{
786
			taxonBase = getTaxonService().findBestMatchingSynonym(nameCache);
787
			if (taxonBase != null){
788
				logger.info("Matching taxon/synonym found for " + nameCache);
789
			}
790
		}
791
		if (taxonBase != null){
792
			logger.info("Matching taxon/synonym found for " + nameCache);
793
			return null;
794
		}else {
795
			taxonBase = createTaxon(state, rank, nameCache, authorStr, publishingAuthorStr, basionymAuthorStr, reference, date, nameStatus, taxonomicStatus, nc);
796
		}
797
		return taxonBase;
798
	}
799

    
800
	/**
801
     * @param state
802
     * @param rank
803
     * @param taxonNameStr
804
     * @param authorStr
805
     * @param nameStatus
806
     * @param nameStatus2
807
     * @return
808
     */
809
    private TaxonBase createTaxon(TaxonExcelImportState state, Rank rank,
810
            String taxonNameStr, String authorStr, String publishingAuthorStr, String basionymAuthorStr,String reference, String date, String nameStatus, String taxonomicStatus) {
811
        // Create the taxon name object depending on the setting of the nomenclatural code
812
        // in the configurator (botanical code, zoological code, etc.)
813
        if (StringUtils.isBlank(taxonNameStr)){
814
            return null;
815
        }
816
        NomenclaturalCode nc = getConfigurator().getNomenclaturalCode();
817

    
818
        TaxonBase taxonBase = null;
819

    
820
        String titleCache = CdmUtils.concat(" ", taxonNameStr, authorStr);
821
        if (! synonymMarkers.contains(nameStatus)  && state.getConfig().isReuseExistingTaxaWhenPossible()){
822
            titleCache = CdmUtils.concat(" ", taxonNameStr, authorStr);
823
            taxonBase = getTaxonService().findBestMatchingTaxon(titleCache);
824
        }else if ( state.getConfig().isReuseExistingTaxaWhenPossible()){
825
            taxonBase = getTaxonService().findBestMatchingSynonym(titleCache);
826
            if (taxonBase != null){
827
                logger.info("Matching taxon/synonym found for " + titleCache);
828
            }
829
        }
830
        if (taxonBase != null && taxonBase.getName().getTitleCache().equals(CdmUtils.concat(" ", taxonNameStr, authorStr))){
831
            logger.info("Matching taxon/synonym found for " + titleCache + " - "+taxonBase.getTitleCache());
832
            return null;
833
        }else {
834
            taxonBase = createTaxon(state, rank, taxonNameStr, authorStr, publishingAuthorStr, basionymAuthorStr, reference, date, nameStatus, taxonomicStatus, nc);
835
        }
836
        return taxonBase;
837
    }
838

    
839

    
840

    
841
	/**
842
	 * @param state
843
	 * @param rank
844
	 * @param taxonNameStr
845
	 * @param authorStr
846
	 * @param nameStatus
847
	 * @param nameStatus2
848
	 * @param nc
849
	 * @return
850
	 */
851
	private TaxonBase<?> createTaxon(TaxonExcelImportState state, Rank rank, String taxonNameStr,
852
			String authorStr, String publishingAutorStr, String basionymAuthor, String reference, String date, String nameStatus, String taxonomicStatus, NomenclaturalCode nc) {
853
		TaxonBase<?> taxonBase;
854
		INonViralName taxonName = null;
855
		if (nc == NomenclaturalCode.ICVCN){
856
			logger.warn("ICVCN not yet supported");
857

    
858
		}else{
859
		    //String taxonNameStr = titleCache.substring(0, titleCache.indexOf(authorStr));
860
			taxonName = nc.getNewTaxonNameInstance(rank);
861
			NonViralNameParserImpl parser = NonViralNameParserImpl.NewInstance();
862
			taxonName = parser.parseFullName(taxonNameStr, nc, rank);
863

    
864
			if (! taxonName.getNameCache().equals(taxonNameStr)){
865
				taxonName.setNameCache(taxonNameStr, true);
866
			}
867

    
868
			// Create the author
869
			if (StringUtils.isNotBlank(authorStr)) {
870
				try {
871
					parser.parseAuthors(taxonName, authorStr);
872
				} catch (StringNotParsableException e) {
873
					taxonName.setAuthorshipCache(authorStr);
874
 				}
875
			}
876
			if (StringUtils.isNotBlank(reference)) {
877
			    String pub = CdmUtils.concat(" ", reference, ((NormalExplicitRow)state.getCurrentRow()).getCollation());
878
			    String[] split = pub.split(":");
879
			    pub = split[0];
880

    
881
			    INomenclaturalReference ref = state.getReference(pub);
882
			    if (ref == null){
883
			        ref = parser.parseReferenceTitle(pub, date, true);
884
			        state.putReference(pub, (Reference) ref);
885
			    }
886
			    if (split.length > 1){
887
                    String detail = split[split.length-1];
888
                    taxonName.setNomenclaturalMicroReference(detail.trim());
889

    
890
                }
891

    
892
             //   ref.setAbbrevTitle(pub);
893

    
894

    
895
			    if (ref.getAuthorship() == null){
896
			        ref.setAuthorship(taxonName.getCombinationAuthorship());
897
			    }
898

    
899
			    if (ref.getAbbrevTitle() == null && !ref.isOfType(ReferenceType.Article)) {
900
                    ref.setAbbrevTitle(reference);
901
                    ref.setProtectedAbbrevTitleCache(false);
902
                }
903

    
904
                ref.setProtectedTitleCache(false);
905
                taxonName.setNomenclaturalReference(ref);
906
			  //  taxonName.setNomenclaturalMicroReference(state.getCurrentRow().getCollation());
907
			}
908
		}
909

    
910
		//Create the taxon
911
		//Reference sec = state.getConfig().getSourceReference();
912
		// Create the status
913
		nameStatus = CdmUtils.Nz(nameStatus).trim().toLowerCase();
914
		taxonomicStatus = CdmUtils.Nz(taxonomicStatus).trim().toLowerCase();
915
		if (synonymMarkers.contains(nameStatus) || synonymMarkers.contains(taxonomicStatus)){
916
            taxonBase = Synonym.NewInstance(taxonName, null);
917
        }else if (validMarkers.contains(nameStatus)){
918
			taxonBase = Taxon.NewInstance(taxonName, null);
919
		}else  {
920
			Taxon taxon = Taxon.NewInstance(taxonName, null);
921
			if (nameStatusMarkers.contains(nameStatus)){
922
			    if (nameStatus.equals(NOM_ILLEG)){
923
			        taxonName.addStatus(NomenclaturalStatusType.ILLEGITIMATE(), null, null);
924
			    } else if (nameStatus.equals(NOM_REJ)){
925
			        taxonName.addStatus(NomenclaturalStatusType.REJECTED(), null, null);
926
			    } else if (nameStatus.equals(NOM_CONS)){
927
                    taxonName.addStatus(NomenclaturalStatusType.CONSERVED(), null, null);
928
                }
929
			}else{
930
			    taxon.setTaxonStatusUnknown(true);
931
			}
932
			taxonBase = taxon;
933
		}
934
		taxonBase.getName().addSource(OriginalSourceType.Import, null,"TaxonName" ,state.getConfig().getSourceReference(), null);
935

    
936
		taxonBase.addSource(OriginalSourceType.Import, null,"TaxonName" ,state.getConfig().getSourceReference(), null);
937

    
938
		return taxonBase;
939
	}
940

    
941
	/**
942
	 * @param taxon
943
	 * @return
944
	 */
945
	//TODO implementation must be improved when matching of taxon names with existing names is implemented
946
	//=> the assumption that the only description is the description added by this import
947
	//is wrong then
948
	private TaxonNameDescription getNameDescription(TaxonName name, TaxonExcelImportState state) {
949
		Set<TaxonNameDescription> descriptions = name.getDescriptions();
950
		if (descriptions.size()>1){
951
			throw new IllegalStateException("Implementation does not yet support names with multiple descriptions");
952
		}else if (descriptions.size()==1){
953
			return descriptions.iterator().next();
954
		}else{
955
		    TaxonNameDescription desc = TaxonNameDescription.NewInstance(name);
956
		    desc.addSource(OriginalSourceType.Import, null, "NameDescription", state.getConfig().getSourceReference(), null);
957
			return desc;
958
		}
959
	}
960

    
961
	private void makeParent(TaxonExcelImportState state, Taxon parentTaxon, Taxon childTaxon, Reference citation, String microCitation){
962
		Reference sec = state.getConfig().getSourceReference();
963

    
964
//		Reference sec = parentTaxon.getSec();
965
		Classification tree = state.getClassification();
966
		if (tree == null){
967
			//tree = makeTree(state, sec);
968
		    if (state.getConfig().getClassificationUuid() != null){
969
		        tree = getClassificationService().load(state.getConfig().getClassificationUuid());
970
		        state.setClassification(tree);
971
		    }
972
		    if (tree == null){
973
		        tree = makeTree(state, sec);
974
		        getClassificationService().save(tree);
975
		        state.setClassification(tree);
976
		    }
977
		}
978
		//if (sec.equals(childTaxon.getSec())){
979
		    boolean success =  (null !=  tree.addParentChild(parentTaxon, childTaxon, citation, microCitation));
980
			if (success == false){
981
				state.setUnsuccessfull();
982
			}
983
//		}else{
984
//			logger.warn("No relationship added for child " + childTaxon.getTitleCache());
985
//		}
986
		return;
987
	}
988

    
989

    
990
	/* (non-Javadoc)
991
	 * @see eu.etaxonomy.cdm.io.excel.common.ExcelTaxonOrSpecimenImportBase#createDataHolderRow()
992
	 */
993
	@Override
994
	protected NormalExplicitRow createDataHolderRow() {
995
		return new NormalExplicitRow();
996
	}
997

    
998

    
999

    
1000
	/* (non-Javadoc)
1001
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
1002
	 */
1003
	@Override
1004
	protected boolean doCheck(TaxonExcelImportState state) {
1005
		logger.warn("DoCheck not yet implemented for NormalExplicitImport");
1006
		return true;
1007
	}
1008

    
1009
	/* (non-Javadoc)
1010
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
1011
	 */
1012
	@Override
1013
	protected boolean isIgnore(TaxonExcelImportState state) {
1014
		return false;
1015
	}
1016

    
1017

    
1018

    
1019
}
(2-2/8)