Project

General

Profile

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

    
10
package eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns;
11

    
12
import java.sql.ResultSet;
13
import java.sql.SQLException;
14
import java.util.ArrayList;
15
import java.util.HashMap;
16
import java.util.HashSet;
17
import java.util.List;
18
import java.util.Map;
19
import java.util.Set;
20
import java.util.UUID;
21
import java.util.regex.Matcher;
22
import java.util.regex.Pattern;
23

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

    
28
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;
29
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeNotSupportedException;
30
import eu.etaxonomy.cdm.common.CdmUtils;
31
import eu.etaxonomy.cdm.io.common.IOValidator;
32
import eu.etaxonomy.cdm.io.common.mapping.DbImportAnnotationMapper;
33
import eu.etaxonomy.cdm.io.common.mapping.DbImportExtensionMapper;
34
import eu.etaxonomy.cdm.io.common.mapping.DbImportMapping;
35
import eu.etaxonomy.cdm.io.common.mapping.DbImportMethodMapper;
36
import eu.etaxonomy.cdm.io.common.mapping.DbImportObjectCreationMapper;
37
import eu.etaxonomy.cdm.io.common.mapping.DbNotYetImplementedMapper;
38
import eu.etaxonomy.cdm.io.common.mapping.IMappingImport;
39
import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
40
import eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns.validation.CentralAfricaFernsTaxonImportValidator;
41
import eu.etaxonomy.cdm.model.agent.Team;
42
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
43
import eu.etaxonomy.cdm.model.common.AnnotationType;
44
import eu.etaxonomy.cdm.model.common.CdmBase;
45
import eu.etaxonomy.cdm.model.common.ExtensionType;
46
import eu.etaxonomy.cdm.model.common.TimePeriod;
47
import eu.etaxonomy.cdm.model.name.BotanicalName;
48
import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
49
import eu.etaxonomy.cdm.model.name.NameTypeDesignationStatus;
50
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
51
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
52
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
53
import eu.etaxonomy.cdm.model.name.NonViralName;
54
import eu.etaxonomy.cdm.model.name.Rank;
55
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
56
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignationStatus;
57
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
58
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
59
import eu.etaxonomy.cdm.model.occurrence.Collection;
60
import eu.etaxonomy.cdm.model.occurrence.DerivedUnitBase;
61
import eu.etaxonomy.cdm.model.occurrence.Specimen;
62
import eu.etaxonomy.cdm.model.reference.Reference;
63
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
64
import eu.etaxonomy.cdm.model.taxon.Synonym;
65
import eu.etaxonomy.cdm.model.taxon.Taxon;
66
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
67
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
68

    
69

    
70
/**
71
 * @author a.mueller
72
 * @created 20.02.2010
73
 * @version 1.0
74
 */
75
@Component
76
public class CentralAfricaFernsTaxonImport  extends CentralAfricaFernsImportBase<TaxonBase> implements IMappingImport<TaxonBase, CentralAfricaFernsImportState>{
77
	private static final Logger logger = Logger.getLogger(CentralAfricaFernsTaxonImport.class);
78
	
79
	public static final UUID TNS_EXT_UUID = UUID.fromString("41cb0450-ac84-4d73-905e-9c7773c23b05");
80
	
81
	
82
	private DbImportMapping mapping;
83
	
84
	//second path is not used anymore, there is now an ErmsTaxonRelationImport class instead
85
	private boolean isSecondPath = false;
86
	
87
	private static final String pluralString = "taxa";
88
	private static final String dbTableName = "[African pteridophytes]";
89
	private static final Class cdmTargetClass = TaxonBase.class;
90

    
91
	public CentralAfricaFernsTaxonImport(){
92
		super(pluralString, dbTableName, cdmTargetClass);
93
	}
94
	
95
	
96

    
97
	/* (non-Javadoc)
98
	 * @see eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns.CentralAfricaFernsImportBase#getIdQuery()
99
	 */
100
	@Override
101
	protected String getIdQuery() {
102
		String strQuery = " SELECT [Taxon number] FROM " + dbTableName ;
103
		return strQuery;
104
	}
105

    
106

    
107
	/* (non-Javadoc)
108
	 * @see eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns.CentralAfricaFernsImportBase#getMapping()
109
	 */
110
	protected DbImportMapping getMapping() {
111
		if (mapping == null){
112
			mapping = new DbImportMapping();
113
			
114
			mapping.addMapper(DbImportObjectCreationMapper.NewInstance(this, "Taxon number", TAXON_NAMESPACE)); //id + tu_status
115

    
116
			mapping.addMapper(DbImportMethodMapper.NewInstance(this, "mapTypes", ResultSet.class, CentralAfricaFernsImportState.class));
117
			mapping.addMapper(DbImportAnnotationMapper.NewInstance("Notes", AnnotationType.EDITORIAL()));
118

    
119
			mapping.addMapper(DbImportMethodMapper.NewInstance(this, "mapReferences", ResultSet.class, CentralAfricaFernsImportState.class));
120
			mapping.addMapper(DbImportMethodMapper.NewInstance(this, "mapNomRemarks", ResultSet.class, CentralAfricaFernsImportState.class));
121
			
122
			mapping.addMapper(DbImportExtensionMapper.NewInstance("Illustrations - non-original", CentralAfricaFernsTransformer.uuidIllustrationsNonOriginal, "Illustrations - non-original", "Illustrations - non-original", null));
123

    
124
//			mapping.addMapper(DbImportTextDataCreationMapper.NewInstance("Illustrations - non-original", objectToCreateNamespace, dbTaxonFkAttribute, this.TAXON_NAMESPACE, "Illustrations - non-original", Language.ENGLISH(), Feature, null);
125
//			mapping.addMapper(DbImportTextDataCreationMapper.NewInstance(dbIdAttribute, objectToCreateNamespace, dbTaxonFkAttribute, taxonNamespace, dbTextAttribute, Language.ENGLISH(), Feature.ECOLOGY(), null));
126

    
127
			//not yet implemented or ignore
128
			mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Types XXX", "Method Mapper does not work yet. Needs implementation for all 5 types. FIXMEs in implementation"));
129

    
130
			mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Basionym of", "Needs better understanding"));
131
			mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Synonym of", "Needs better understanding. Strange values like "));
132
			
133
			
134
			mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Chromosome number" , "Wrong data. Seems to be 'reference full'"));
135
			
136
			mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Book Publisher & Place" , "How to access the reference via String mapper?"));
137
			
138
			mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Reprint no" , "What's this?"));
139
			mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Date verified" , "Needed?"));
140
			
141
			
142
//			
143
//			UUID credibilityUuid = ErmsTransformer.uuidCredibility;
144
//			mapping.addMapper(DbImportExtensionMapper.NewInstance("tu_credibility", credibilityUuid, "credibility", "credibility", "credibility")); //Werte: null, unknown, marked for deletion
145
//			
146
			//ignore
147
//			mapping.addMapper(DbIgnoreMapper.NewInstance("cache_citation", "citation cache not needed in PESI"));
148
			
149
			//not yet implemented or ignore
150
//			mapping.addMapper(DbNotYetImplementedMapper.NewInstance("tu_hidden", "Needs DbImportMarkerMapper implemented"));
151
			
152
		}
153
		return mapping;
154
	}
155

    
156
	/* (non-Javadoc)
157
	 * @see eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportBase#getRecordQuery(eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportConfigurator)
158
	 */
159
	@Override
160
	protected String getRecordQuery(CentralAfricaFernsImportConfigurator config) {
161
		String strSelect = " SELECT * ";
162
		String strFrom = " FROM [African pteridophytes] as ap";
163
		String strWhere = " WHERE ( ap.[taxon number] IN (" + ID_LIST_TOKEN + ") )";
164
		String strOrderBy = " ORDER BY [Taxon number]";
165
		String strRecordQuery = strSelect + strFrom + strWhere + strOrderBy;
166
		return strRecordQuery;
167
	}
168

    
169

    
170
	/* (non-Javadoc)
171
	 * @see eu.etaxonomy.cdm.io.berlinModel.in.IPartitionedIO#getRelatedObjectsForPartition(java.sql.ResultSet)
172
	 */
173
	public Map<Object, Map<String, ? extends CdmBase>> getRelatedObjectsForPartition(ResultSet rs) {
174
		String nameSpace;
175
		Class cdmClass;
176
		Set<String> idSet;
177
		Map<Object, Map<String, ? extends CdmBase>> result = new HashMap<Object, Map<String, ? extends CdmBase>>();
178
		
179
		try{
180
				Set<String> nameIdSet = new HashSet<String>();
181
				Set<String> referenceIdSet = new HashSet<String>();
182
				while (rs.next()){
183
	//				handleForeignKey(rs, nameIdSet, "PTNameFk");
184
	//				handleForeignKey(rs, referenceIdSet, "PTRefFk");
185
				}
186

    
187
			//reference map
188
//			nameSpace = "Reference";
189
//			cdmClass = Reference.class;
190
//			Map<String, Person> referenceMap = (Map<String, Person>)getCommonService().getSourcedObjectsByIdInSource(Person.class, teamIdSet, nameSpace);
191
//			result.put(Reference.class, referenceMap);
192

    
193
		} catch (SQLException e) {
194
			throw new RuntimeException(e);
195
		}
196
		return result;
197
	}
198
	
199
	private TaxonBase mapTypes(ResultSet rs, CentralAfricaFernsImportState state) throws SQLException{
200
		TaxonBase<?> taxonBase = state.getRelatedObject(state.CURRENT_OBJECT_NAMESPACE, state.CURRENT_OBJECT_ID, TaxonBase.class);
201
		TaxonNameBase name = taxonBase.getName();
202
		for (int i = 1; i <= 5; i++){
203
			String[] typeInfo = new String[3];
204
			typeInfo = getTypeInfo(rs, i);
205
			if (StringUtils.isBlank(typeInfo[0]) && StringUtils.isBlank(typeInfo[1]) && StringUtils.isBlank(typeInfo[2])){
206
				continue;
207
			}
208
			makeSingleType(state, name, typeInfo[0], typeInfo[1], typeInfo[2]);
209
		}
210
		return taxonBase;
211
	}
212
	
213
	
214
	private String[] getTypeInfo(ResultSet rs, int i) throws SQLException {
215
		String[] typeInfo = new String[3];
216
		String number;
217
		if (i == 1){
218
			number = "";
219
		}else{
220
			number = String.valueOf(i);
221
		}
222
		typeInfo[0] = rs.getString("Type" + number);
223
		typeInfo[1] = rs.getString("Type collector and number" + number);
224
		typeInfo[2] = rs.getString("Type location" + number);
225
		
226
		return typeInfo;
227
	}
228

    
229

    
230

    
231
	private void makeSingleType(CentralAfricaFernsImportState state, TaxonNameBase name, String typeString, String typeCollectorString, String typeLocationString) {
232
		if (name.getRank().isHigher(Rank.SPECIES())){
233
			//TODO move to TaxonRelationImport
234
			handleNameType(state, name, typeString, typeCollectorString, typeLocationString);
235
		}else{
236
			handleSpecimenType(state, name, typeString, typeCollectorString, typeLocationString);
237
		}
238
	}
239

    
240

    
241

    
242
	private void handleSpecimenType(CentralAfricaFernsImportState state, TaxonNameBase name, String typeString, String typeCollectorString, String typeLocationString) {
243
		List<SpecimenTypeDesignation> designations = new ArrayList<SpecimenTypeDesignation>();
244
		typeLocationString = CdmUtils.Nz(typeLocationString);
245
		if (typeLocationString.equalsIgnoreCase("not located")){
246
			
247
		}else{
248
			String[] splits = typeLocationString.split(";");
249
			for (String split : splits){
250
				List<SpecimenTypeDesignation> splitDesignations = handleTypeLocationPart(state, typeString, typeCollectorString, split);
251
				designations.addAll(splitDesignations);
252
			}
253
		}
254
		if (designations.size() == 0){
255
			logger.error(state.getTaxonNumber() + " - No designations defined. TypeString: " + CdmUtils.Nz(typeString) + ", CollectorString: " + typeCollectorString);
256
		}
257
		//type and collector
258
		DerivedUnitFacade lastFacade = null;
259
		for (SpecimenTypeDesignation designation: designations){
260
			name.addTypeDesignation(designation, false);
261
			if (typeString != null && (typeString.contains("Not designated.")|| typeString.contains("No type designated."))){
262
				designation.setNotDesignated(true);
263
			}
264

    
265
			DerivedUnitBase specimen = designation.getTypeSpecimen();
266

    
267
			if (lastFacade != null){
268
				lastFacade.addDuplicate(specimen);
269
			}else{
270

    
271
				try {
272
					lastFacade = DerivedUnitFacade.NewInstance(specimen);
273
				} catch (DerivedUnitFacadeNotSupportedException e) {
274
					throw new RuntimeException(e);
275
				}
276
				
277
				//TODO not so nice
278
				lastFacade.setLocality(typeString);
279
				makeTypeCollectorInfo(lastFacade, typeCollectorString);
280
				
281
			}
282
		}
283
			
284
	}
285

    
286

    
287

    
288
	private List<SpecimenTypeDesignation> handleTypeLocationPart(CentralAfricaFernsImportState state, 
289
				String typeString, String typeCollectorString, String typeLocationPart) {
290
		List<SpecimenTypeDesignation> result = new ArrayList<SpecimenTypeDesignation>();
291
		String[] splits = typeLocationPart.split(","); 
292
		//see also SpecimenTypeParser
293
		String typeTypePattern = "(holo.|lecto.|iso.|isolecto.|syn.|isosyn.|neo.|isoneo.)";
294
		String collectionPattern = "^[A-Z]+(\\-[A-Z]+)?";
295
		String numberPattern = "([0-9]+([\\-\\s\\.\\/][0-9]+)?)?";
296
		String addInfoPattern = "[!\\+\\?]?";
297
		String typeCollectionPattern = collectionPattern + "\\s?" + numberPattern + addInfoPattern;
298
		SpecimenTypeDesignation lastDesignation = null;
299
		
300
		for (String split: splits){
301
			split = split.trim();
302
			if (StringUtils.isBlank(split)){
303
				continue;
304
			}else if(split.trim().startsWith("designated by")){
305
				split = handleDesignatedBy(lastDesignation, split);
306
			}else if (split.trim().matches(typeTypePattern)){
307
				makeSpecimentTypeStatus(lastDesignation, split);
308
			}else if(split.matches(typeCollectionPattern)){
309
				
310
				lastDesignation = makeSpecimenTypeCollection(lastDesignation, split, collectionPattern, numberPattern, addInfoPattern);
311
			}else if(split.equalsIgnoreCase("not located")){
312
				lastDesignation = makeCachedSpecimenDesignation(split);
313
			}else{
314
				logger.error(state.getTaxonNumber() + " - Unknown type location part: " +  split);
315
				if (lastDesignation == null){
316
					lastDesignation = makeCachedSpecimenDesignation(split);
317
				}
318
			}
319
			if (lastDesignation != null && ! result.contains(lastDesignation)){
320
				result.add(lastDesignation);
321
			}else if (lastDesignation == null){
322
				logger.warn("Last Designation is null");
323
			}
324
		}
325
		
326
		return result;
327
	}
328

    
329

    
330

    
331
	/**
332
	 * @param split
333
	 * @return
334
	 */
335
	private SpecimenTypeDesignation makeCachedSpecimenDesignation(String split) {
336
		SpecimenTypeDesignation lastDesignation;
337
		lastDesignation = SpecimenTypeDesignation.NewInstance();
338
		Specimen specimen = Specimen.NewInstance();
339
		specimen.setTitleCache(split, true);
340
		lastDesignation.setTypeSpecimen(specimen);
341
		return lastDesignation;
342
	}
343

    
344

    
345

    
346
	private SpecimenTypeDesignation makeSpecimenTypeCollection(SpecimenTypeDesignation designation, String collectionString, String strCollectionPattern, String strNumberPattern, String strAddInfoPattern) {
347
		SpecimenTypeDesignation result = SpecimenTypeDesignation.NewInstance();
348
		Specimen specimen = Specimen.NewInstance();
349
		result.setTypeSpecimen(specimen);
350
		
351
		//collection
352
		Pattern collectionPattern = Pattern.compile(strCollectionPattern);
353
		Matcher matcher = collectionPattern.matcher(collectionString);
354
		if (! matcher.find()){
355
			throw new RuntimeException("collectionString doesn't match: " + collectionString);
356
		}
357
		String strCollection = matcher.group();
358
		Collection collection = getCollection(strCollection);
359
		specimen.setCollection(collection);
360
		collectionString = collectionString.substring(strCollection.length()).trim();
361
		
362
		
363
		//collection number
364
		Pattern numberPattern = Pattern.compile(strNumberPattern);
365
		matcher = numberPattern.matcher(collectionString);
366
		if (matcher.find()){
367
			String strNumber = matcher.group();
368
			collectionString = collectionString.substring(strNumber.length()).trim();
369
			if (StringUtils.isNotBlank(strNumber)){
370
				specimen.setCatalogNumber(strNumber);
371
			}
372
		}else{
373
			//throw new RuntimeException("numberString doesn't match: " + collectionString);
374
		}
375
		
376
		//additional info
377
		Pattern addInfoPattern = Pattern.compile(strAddInfoPattern);
378
		matcher = addInfoPattern.matcher(collectionString);
379
		if (matcher.find()){
380
			String strAddInfo = matcher.group();
381
			collectionString = collectionString.substring(strAddInfo.length()).trim();
382
			if (StringUtils.isBlank(strAddInfo)){
383
				//do nothing
384
			}else if (strAddInfo.equals("!")){
385
				//TODO add seen by author
386
			}else if (strAddInfo.equals("?")){
387
				//TODO add doubtful
388
			}else if (strAddInfo.equals("+")){
389
				//TODO add +
390
			}
391
		}else{
392
			//throw new RuntimeException("addInfoString doesn't match: " + collectionString);
393
		}
394
		if (StringUtils.isNotBlank(collectionString)){
395
			logger.error("Collection string is not empty: " + collectionString );
396
		}
397
		return result;
398
	}
399

    
400

    
401

    
402
	private Collection getCollection(String strCollection) {
403
		//TODO use BCI and deduplication
404
		Collection result = Collection.NewInstance();
405
		return result;
406
	}
407

    
408

    
409

    
410
	private void makeSpecimentTypeStatus(SpecimenTypeDesignation designation, String type) {
411
		SpecimenTypeDesignationStatus status; 
412
		if (type.equalsIgnoreCase("iso.")){
413
			status = SpecimenTypeDesignationStatus.ISOTYPE();
414
		}else if (type.equalsIgnoreCase("isolecto.")){
415
			status = SpecimenTypeDesignationStatus.ISOLECTOTYPE();
416
		}else if (type.equalsIgnoreCase("syn.")){
417
			status = SpecimenTypeDesignationStatus.SYNTYPE();
418
		}else if (type.equalsIgnoreCase("holo.")){
419
			status = SpecimenTypeDesignationStatus.HOLOTYPE();
420
		}else if (type.equalsIgnoreCase("lecto.")){
421
			status = SpecimenTypeDesignationStatus.LECTOTYPE();
422
		}else if (type.equalsIgnoreCase("isosyn.")){
423
			status = SpecimenTypeDesignationStatus.ISOSYNTYPE();
424
		}else if (type.equalsIgnoreCase("neo.")){
425
			status = SpecimenTypeDesignationStatus.NEOTYPE();
426
		}else if (type.equalsIgnoreCase("isoneo.")){
427
			status = SpecimenTypeDesignationStatus.ISONEOTYPE();
428
		}else{
429
			logger.error("Type Status not supported: " + type);
430
			throw new RuntimeException("Type Status not supported: " + type);
431
		}
432
		if (designation == null){
433
			logger.error("Designation is null");
434
		}else{
435
			designation.setTypeStatus(status);
436
		}
437
	}
438

    
439

    
440

    
441
	private void handleNameType(CentralAfricaFernsImportState state, TaxonNameBase name, String typeString, String typeCollectorString, String typeLocation) {
442
		String originalString = typeString; //just for testing
443
		if (StringUtils.isNotBlank(typeCollectorString)){
444
			logger.error(state.getTaxonNumber() + " - Type collector string for name type is not empty: " + typeCollectorString);
445
		}
446
		if (StringUtils.isNotBlank(typeLocation)){
447
			logger.error(state.getTaxonNumber() + " - Type location string for name type is not empty: " + typeLocation);
448
		}
449
		NameTypeDesignation nameTypeDesignation = NameTypeDesignation.NewInstance();
450
		NameTypeDesignationStatus status = null;
451
		if (StringUtils.isBlank(typeString)){
452
			logger.warn(state.getTaxonNumber() + " - TypeString is empty");
453
		}
454
		if (typeString.startsWith("None designated.")){
455
			nameTypeDesignation.setNotDesignated(true);
456
			typeString = typeString.replaceFirst("None designated\\.", "").trim();
457
		}
458
		if (typeString.contains("Lectotype: ")|| typeString.contains(", lecto." )){
459
			status = NameTypeDesignationStatus.LECTOTYPE();
460
			typeString = typeString.replace("Lectotype: ", "");
461
			typeString = typeString.replace(", lecto.", "");
462
			typeString = handleDesignatedBy(nameTypeDesignation, typeString);
463
		}else{
464
			typeString = handleDesignatedBy(nameTypeDesignation, typeString);
465
		}
466
		
467
//		String strSecondNamePattern = "([^\\(]*|\\(.*\\))+;.+"; //never ending story
468
		String strSecondNamePattern = ".+;.+";
469
		String firstName;
470
		String secondName = null;
471
		if (typeString.matches(strSecondNamePattern)){
472
			String[] split = typeString.split(";");
473
			firstName = split[0].trim();
474
			secondName = split[1].trim();
475
			if (split.length > 2){
476
				logger.warn(state.getTaxonNumber() + " - There are more than 2 name types: " + typeString);
477
			}
478
		}else{
479
			firstName = typeString;
480
		}
481
		if (StringUtils.isNotBlank(firstName)){
482
			BotanicalName[] nameTypeNames = getNameTypeName(firstName);
483
			BotanicalName nameTypeName = nameTypeNames[0];
484
			BotanicalName nameTypeAcceptedName = nameTypeNames[1];
485
			nameTypeDesignation.setTypeName(nameTypeName);
486
			if (nameTypeName.isProtectedTitleCache()){
487
				logger.error(state.getTaxonNumber() + " - Name type could not be parsed: " + nameTypeName.getTitleCache());
488
			}
489
			if (! nameTypeName.getRank().equals(Rank.SPECIES())){
490
				logger.warn(state.getTaxonNumber() + " - Name type is not of rank species: " + nameTypeName.getTitleCache());
491
			}
492
		}
493
		if (StringUtils.isNotBlank(secondName)){
494
			TaxonNameBase secondNameType = handleSecondNameTypeName(secondName);
495
			if (secondNameType.isProtectedTitleCache()){
496
				logger.error(state.getTaxonNumber() + " - Second name type could not be parsed: " + secondNameType.getTitleCache());
497
			}
498
			if (! secondNameType.getRank().equals(Rank.SPECIES())){
499
				logger.error(state.getTaxonNumber() + " - Second name type is not of rank species: " + secondNameType.getTitleCache());
500
			}
501

    
502
		}
503
		nameTypeDesignation.setTypeStatus(status);
504
		name.addTypeDesignation(nameTypeDesignation, false);
505
		
506
	}
507

    
508

    
509

    
510
	private TaxonNameBase handleSecondNameTypeName(String strName) {
511
		//TODO needs feedbacke from Thomas
512
		logger.info("Not yet implemented");
513
		if (strName.endsWith(",")){
514
			strName = strName.substring(0, strName.length() -1);
515
		}
516
		BotanicalName result = (BotanicalName)NonViralNameParserImpl.NewInstance().parseFullName(strName, NomenclaturalCode.ICBN, Rank.SPECIES());
517
		return result;
518
	}
519

    
520

    
521

    
522
	private BotanicalName[] getNameTypeName(String strName) {
523
		//TODO implement get existing names 
524
		logger.info("Not yet fully implemented");
525
		
526
		BotanicalName[] result = new BotanicalName[2];
527
		if (strName.endsWith(",")){
528
			strName = strName.substring(0, strName.length() -1);
529
		}
530
		String acceptedName;
531
		String acceptedNamePattern = "\\(.*\\)\\.?$";
532
		if (strName.matches(".*" + acceptedNamePattern)){
533
			int accStart = strName.lastIndexOf("(");
534
			String notAcceptedName = strName.substring(0, accStart -1 );
535
			acceptedName = strName.substring(accStart + 1, strName.length() - 1);
536
			if (acceptedName.endsWith(")")){
537
				acceptedName = acceptedName.substring(0, acceptedName.length()-1);
538
			}
539
			acceptedName = acceptedName.replaceFirst("=", "").trim();
540
			result[1] = (BotanicalName)NonViralNameParserImpl.NewInstance().parseFullName(acceptedName, NomenclaturalCode.ICBN, null);
541
			strName = notAcceptedName;
542
		}
543
		
544
		result[0] = (BotanicalName)NonViralNameParserImpl.NewInstance().parseFullName(strName, NomenclaturalCode.ICBN, Rank.SPECIES());
545
		return result;
546
	}
547

    
548

    
549

    
550
	private String handleDesignatedBy(TypeDesignationBase typeDesignation, String typeString) {
551
		String[] splitDesignated = typeString.split(", designated by ");
552
		if (splitDesignated.length > 1){
553
			Reference designationCitation = getDesignationCitation(typeDesignation, splitDesignated[1]);
554
			typeDesignation.setCitation(designationCitation);
555
			if (splitDesignated.length > 2){
556
				throw new IllegalStateException("More than one designation is not expected");
557
			}
558
		}
559
		return splitDesignated[0].trim();
560
	}
561

    
562

    
563

    
564
	private Reference getDesignationCitation(TypeDesignationBase typeDesignation, String citationString) {
565
		// TODO try to find an existing Reference
566
		Reference result = ReferenceFactory.newGeneric();
567
		String strBracketPattern = "\\((10 Oct. )?\\d{4}:\\s?(\\d{1,3}(--\\d{1,3})?|[XLVI]{1,7}|\\.{1,8})\\)\\.?";
568

    
569
		String strStandardPattern = ".*" + strBracketPattern;
570
//		strStandardPattern = ".*";
571
		if (Pattern.matches(strStandardPattern, citationString)){
572
			parseStandardPattern(typeDesignation, result, citationString, strBracketPattern);
573
		}else{
574
			logger.error("Can't parse designation citation: " + citationString);
575
			result.setTitleCache(citationString);
576
		}
577
		return result;
578
	}
579

    
580

    
581

    
582
	private void parseStandardPattern(TypeDesignationBase typeDesignation, Reference result, String citationString, String bracketPattern) {
583
		String authorPart = citationString.split(bracketPattern)[0];
584
		String bracket = citationString.substring(authorPart.length()+1, citationString.length()-1).trim();
585
		authorPart = authorPart.trim();
586
		if (bracket.endsWith(")")){
587
			bracket = bracket.substring(0, bracket.length()-1);
588
		}
589
		Team team = Team.NewTitledInstance(authorPart, authorPart);
590
		result.setAuthorTeam(team);
591
		String[] bracketSplit = bracket.split(":");
592
		TimePeriod datePublished = TimePeriod.parseString(bracketSplit[0].trim());
593
		result.setDatePublished(datePublished);
594
		String citationMicroReference = bracketSplit[1].trim();
595
		citationMicroReference = citationMicroReference.replace("--", "-");
596
		typeDesignation.setCitationMicroReference(citationMicroReference);
597
	}
598

    
599

    
600

    
601
	private void makeTypeCollectorInfo(DerivedUnitFacade specimen, String collectorAndNumberString) {
602
		if (StringUtils.isBlank(collectorAndNumberString)){
603
			return;
604
		}
605
		String reNumber = "(s\\.n\\.|\\d.*)";
606
		Pattern reNumberPattern = Pattern.compile(reNumber);
607
		Matcher matcher = reNumberPattern.matcher(collectorAndNumberString);
608
		
609
		if ( matcher.find()){
610
			int numberStart = matcher.start();
611
			String number = collectorAndNumberString.substring(numberStart).trim();
612
			if (numberStart > 0){
613
				numberStart = numberStart -1;
614
			}
615
			String collectorString = collectorAndNumberString.substring(0, numberStart).trim();
616
			specimen.setFieldNumber(number);
617
			TeamOrPersonBase team = getTeam(collectorString);
618
			specimen.setCollector(team);
619
			
620
		}else{
621
			logger.warn("collector string did not match number pattern: " + collectorAndNumberString);
622
			
623
		}
624
	}
625

    
626

    
627
	private TeamOrPersonBase getTeam(String teamString) {
628
		//TODO check existing team
629
		TeamOrPersonBase result = Team.NewTitledInstance(teamString, teamString);
630
		return result;
631
	}
632

    
633

    
634

    
635
	/**
636
	 * for internal use only, used by MethodMapper
637
	 */
638
	private TaxonBase mapReferences(ResultSet rs, CentralAfricaFernsImportState state) throws SQLException{
639
		String taxonNumber = state.getTaxonNumber();
640
		String referenceFullString = rs.getString("Reference full");
641
		String referenceAbbreviatedString = rs.getString("Reference - abbreviated");
642
		String volume = rs.getString("Book / Journal volume");
643
		String pages = rs.getString("Book / Journal pages");
644
		String illustrations = rs.getString("Illustration/s");
645
		
646
		String fascicle = rs.getString("Book / Journal fascicle");
647
		String part = rs.getString("Book / Journal part");
648
		String paperTitle = rs.getString("Book / Paper title");
649
		
650
		String datePublishedString = rs.getString("Date published");
651
		String referenceString = referenceFullString;
652
		if (StringUtils.isBlank(referenceString)){
653
			referenceString = referenceAbbreviatedString;
654
		}
655
		
656
		TaxonBase<?> taxonBase = state.getRelatedObject(state.CURRENT_OBJECT_NAMESPACE, state.CURRENT_OBJECT_ID, TaxonBase.class);
657
		if (StringUtils.isNotBlank(referenceString) || StringUtils.isNotBlank(volume) || 
658
					StringUtils.isNotBlank(pages) || StringUtils.isNotBlank(illustrations) || 
659
					StringUtils.isNotBlank(datePublishedString) || StringUtils.isNotBlank(paperTitle)){
660
			NonViralName name = CdmBase.deproxy(taxonBase.getName(), NonViralName.class);
661
			Reference reference = ReferenceFactory.newGeneric();
662
			reference.setAuthorTeam((TeamOrPersonBase)name.getCombinationAuthorTeam());
663
			reference.setTitle(referenceString);
664
			reference.setVolume(volume);
665
			reference.setEdition(part);
666
			Reference inrefernce = null;
667
			//TODO parser
668
			TimePeriod datePublished = TimePeriod.parseString(datePublishedString);
669
			reference.setDatePublished(datePublished);
670
			if (StringUtils.isNotBlank(paperTitle)){
671
				Reference innerReference = ReferenceFactory.newGeneric();
672
				innerReference.setDatePublished(datePublished);
673
				name.setNomenclaturalReference(innerReference);
674
				innerReference.setInReference(reference);
675
				reference = innerReference;
676
			}else{
677
				name.setNomenclaturalReference(reference);
678
			}
679
			
680
			//details
681
			String details = CdmUtils.concat(", ", pages, illustrations);
682
			details = StringUtils.isBlank(details) ? null : details.trim();
683
			name.setNomenclaturalMicroReference(details);
684
			try {
685
				UUID uuidFascicle = state.getTransformer().getExtensionTypeUuid("fascicle");
686
				ExtensionType extensionType = getExtensionType(state, uuidFascicle, "Fascicle", "Fascicle", null);
687
				reference.addExtension(fascicle, extensionType);
688
			} catch (UndefinedTransformerMethodException e) {
689
				e.printStackTrace();
690
			}
691
			
692
		}else{
693
			logger.warn(taxonNumber + " - Taxon has no reference");
694
		}
695
		return taxonBase;
696
	}
697

    
698
	/**
699
	 * for internal use only, used by MethodMapper
700
	 * @throws Exception 
701
	 */
702
	private TaxonBase mapNomRemarks(ResultSet rs, CentralAfricaFernsImportState state) throws Exception{
703
		try {
704
			String taxonNumber = state.getTaxonNumber();
705
			String nomRemarksString = rs.getString("Nom  remarks");
706
			String taxonStatus = rs.getString("Current/Synonym");
707
			
708
			TaxonBase<?> taxonBase = state.getRelatedObject(state.CURRENT_OBJECT_NAMESPACE, state.CURRENT_OBJECT_ID, TaxonBase.class);
709
			if (StringUtils.isNotBlank(nomRemarksString)){
710
				NonViralName name = CdmBase.deproxy(taxonBase.getName(), NonViralName.class);
711
				parseNomRemark(state, name, nomRemarksString.trim(),taxonStatus, taxonNumber);
712
			}
713
			return taxonBase;
714
		} catch (Exception e) {
715
			throw e;
716
		}
717
	}
718

    
719
	
720
	private void parseNomRemark(CentralAfricaFernsImportState state, NonViralName name, String nomRemarksString, String taxonStatus, String taxonNumber) {
721
		
722
		if (nomRemarksString.equalsIgnoreCase("comb. illeg.")){
723
			name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.COMBINATION_ILLEGITIMATE()));
724
			return;
725
//		}else if (nomRemarksString.startsWith("comb. inval.")){
726
//			//TODO
727
//			nomRemarksString = nomRemarksString.replace("comb. inval.", "");
728
//		}else if (nomRemarksString.equals("comb. nov.")){
729
//			name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.COMBINATION_NOVUM);
730
		}else if (nomRemarksString.equals("nom. ambig.")){
731
			name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.AMBIGUOUS()));
732
			return;
733
		}else if (nomRemarksString.matches("nom\\. cons(erv)?\\.")){
734
			name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.CONSERVED()));
735
			return;
736
		}else if (nomRemarksString.matches("nom\\. illeg(it)?\\.")){
737
			name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.ILLEGITIMATE()));
738
			return;
739
		}else if (nomRemarksString.matches("nom\\. inval(id)?\\.")){
740
			name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.INVALID()));
741
			return;
742
		}else if (nomRemarksString.matches("nom\\. nov\\.")){
743
			name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.NOVUM()));
744
			return;
745
		}else if (nomRemarksString.matches("nom\\. nud\\.")){
746
			name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.NUDUM()));
747
			return;
748
		}else if (nomRemarksString.matches("nom\\. superfl\\.")){
749
			name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.SUPERFLUOUS()));
750
			return;
751
		}else if (nomRemarksString.matches("p(\\.|ro\\s)?p(\\.|arte)")){
752
			//pro parte is handled in taxon relationship import
753
			if (! taxonStatus.equals("s")){
754
				logger.warn(" - " +  taxonNumber + " Pro parte synonym is not of type synonym");
755
			}
756
			return;
757
		}else if (nomRemarksString.matches("as '.*'")){
758
			String nameAsString = nomRemarksString.substring(4, nomRemarksString.length()-1);
759
			//TODO discuss make it a name relationship
760
			UUID uuidPublishedAs = CentralAfricaFernsTransformer.uuidNamePublishedAs;
761
			ExtensionType extensionType = getExtensionType(state, uuidPublishedAs, "Name published as", "Name published as", "as");
762
			name.addExtension(nameAsString, extensionType);
763
			return;
764
		}
765

    
766
		
767
		if (StringUtils.isNotBlank(nomRemarksString)){
768
			ExtensionType extensionType = getExtensionType(state, CentralAfricaFernsTransformer.uuidNomenclaturalRemarks, "Nomenclatural remarks", "Nomenclatural remarks", null);
769
			name.addExtension(nomRemarksString, extensionType);
770
		}
771
		
772
		
773
		
774
		
775
	}
776

    
777

    
778

    
779
	/* (non-Javadoc)
780
	 * @see eu.etaxonomy.cdm.io.common.mapping.IMappingImport#createObject(java.sql.ResultSet)
781
	 */
782
	public TaxonBase createObject(ResultSet rs, CentralAfricaFernsImportState state) throws SQLException {
783
		BotanicalName taxonName = BotanicalName.NewInstance(null);
784
		Reference sec = state.getConfig().getSourceReference();
785
		
786
		String taxonNumber = rs.getString("Taxon number");
787
		state.setTaxonNumber(taxonNumber);
788
		
789
		String orderName = rs.getString("Order name");
790
		String subOrderName = rs.getString("Suborder name");
791
		String familyName = rs.getString("Family name");
792
		String subFamilyName = rs.getString("Subfamily name");
793
		String tribusName = rs.getString("Tribus name");
794
		String subTribusName = rs.getString("Subtribus name");
795
		String sectionName = rs.getString("Section name");
796
		String genusName = rs.getString("Genus name");
797
		String subGenusName = rs.getString("Subgenus name");
798
		String seriesName = rs.getString("Series name");
799
		String specificEpihet = rs.getString("Specific epihet");
800
		String subspeciesName = rs.getString("Subspecies name");
801
		String varietyName = rs.getString("Variety name");
802
		String subFormaName = rs.getString("Subforma");
803
		String subVariety = rs.getString("Subvariery");
804
		String formaName = rs.getString("Forma name");
805
		String subsectionName = rs.getString("Subsection name");
806
		
807
		String status = rs.getString("Current/Synonym");
808
		
809
		TaxonBase taxon = makeTaxon(taxonName, sec, taxonNumber, status);
810
		
811
//			Integer parent3Rank = rs.getInt("parent3rank");
812
		
813
		//rank and epithets
814
		Rank lowestRank = setLowestUninomial(taxonName, orderName,  subOrderName, familyName, subFamilyName, tribusName, subTribusName,genusName);
815
		lowestRank = setLowestInfraGeneric(taxonName, lowestRank, subGenusName, sectionName, subsectionName, seriesName);
816
		if (StringUtils.isNotBlank(specificEpihet)){
817
			taxonName.setSpecificEpithet(specificEpihet);
818
			lowestRank = Rank.SPECIES();
819
		}
820
		lowestRank = setLowestInfraSpecific(taxonName, lowestRank, subspeciesName,  varietyName, subVariety, formaName,subFormaName);
821
		
822
		taxonName.setRank(lowestRank);
823
		state.setCurrentRank(taxonName.getRank());
824
		setAuthor(taxonName, rs, taxonNumber, false);
825
		
826
		//add original source for taxon name (taxon original source is added in mapper
827
//		Reference citation = state.getConfig().getSourceReference();
828
//		addOriginalSource(taxonName, taxonNumber, TAXON_NAMESPACE, citation);
829
		return taxon;
830
		
831
	}
832

    
833

    
834

    
835
	/**
836
	 * Creates the taxon object depending on name, sec and status
837
	 * @param taxonName
838
	 * @param sec
839
	 * @param taxonNumber
840
	 * @param status
841
	 * @return
842
	 */
843
	private TaxonBase makeTaxon(BotanicalName taxonName, Reference sec, String taxonNumber, String status) {
844
		TaxonBase taxon;
845
		if ("c".equalsIgnoreCase(status)|| "incertus".equalsIgnoreCase(status) ){
846
			taxon = Taxon.NewInstance(taxonName, sec);
847
			if ("incertus".equalsIgnoreCase(status)){
848
				taxon.setDoubtful(true);
849
			}
850
		}else if ("s".equalsIgnoreCase(status)){
851
			taxon = Synonym.NewInstance(taxonName, sec);
852
		}else{
853
			logger.warn(taxonNumber + ": Status not given for taxon " );
854
			taxon = Taxon.NewUnknownStatusInstance(taxonName, sec);
855
		}
856
		return taxon;
857
	}
858

    
859

    
860
	private Rank setLowestInfraSpecific(BotanicalName taxonName, Rank lowestRank, String subspeciesName, String varietyName,
861
			String subVariety, String formaName, String subFormaName) {
862
		if (StringUtils.isNotBlank(subFormaName)){
863
			taxonName.setInfraSpecificEpithet(subFormaName);
864
			return Rank.SUBFORM();
865
		}else if (StringUtils.isNotBlank(formaName)){
866
			taxonName.setInfraSpecificEpithet(formaName);
867
			return Rank.FORM();
868
		}else if (StringUtils.isNotBlank(subVariety)){
869
			taxonName.setInfraSpecificEpithet(subVariety);
870
			return Rank.SUBVARIETY();
871
		}else if (StringUtils.isNotBlank(varietyName)){
872
			taxonName.setInfraSpecificEpithet(varietyName);
873
			return Rank.VARIETY();
874
		}else if (StringUtils.isNotBlank(subspeciesName)){
875
			taxonName.setInfraSpecificEpithet(subspeciesName);
876
			return Rank.SUBSPECIES();
877
		}else{
878
			return lowestRank;
879
		}
880
	}
881

    
882

    
883

    
884
	private Rank setLowestInfraGeneric(BotanicalName taxonName, Rank lowestRank, String subGenusName, String sectionName, String subSectionName, String seriesName) {
885
		if (StringUtils.isNotBlank(seriesName)){
886
			taxonName.setInfraGenericEpithet(seriesName);
887
			return Rank.SERIES();
888
		}else if (StringUtils.isNotBlank(subSectionName)){
889
			taxonName.setInfraGenericEpithet(subSectionName);
890
			return Rank.SUBSECTION_BOTANY();
891
		}else if (StringUtils.isNotBlank(sectionName)){
892
			taxonName.setInfraGenericEpithet(sectionName);
893
			return Rank.SECTION_BOTANY();
894
		}else if (StringUtils.isNotBlank(subGenusName)){
895
			taxonName.setInfraGenericEpithet(subGenusName);
896
			return Rank.SUBGENUS();
897
		}else{
898
			return lowestRank;
899
		}
900
	}
901

    
902

    
903

    
904
	private Rank setLowestUninomial(BotanicalName taxonName, String orderName, String subOrderName, String familyName, String subFamilyName,
905
			String tribusName, String subTribusName, String genusName) {
906
		
907
		if (StringUtils.isNotBlank(genusName)){
908
			taxonName.setGenusOrUninomial(genusName);
909
			return Rank.GENUS();
910
		}else if (StringUtils.isNotBlank(subTribusName)){
911
			taxonName.setGenusOrUninomial(subTribusName);
912
			return Rank.SUBTRIBE();
913
		}else if (StringUtils.isNotBlank(tribusName)){
914
			taxonName.setGenusOrUninomial(tribusName);
915
			return Rank.TRIBE();
916
		}else if (StringUtils.isNotBlank(subFamilyName)){
917
			taxonName.setGenusOrUninomial(subFamilyName);
918
			return Rank.SUBFAMILY();
919
		}else if (StringUtils.isNotBlank(familyName)){
920
			taxonName.setGenusOrUninomial(familyName);
921
			return Rank.FAMILY();
922
		}else if (StringUtils.isNotBlank(subOrderName)){
923
			taxonName.setGenusOrUninomial(subOrderName);
924
			return Rank.SUBORDER();
925
		}else if (StringUtils.isNotBlank(orderName)){
926
			taxonName.setGenusOrUninomial(orderName);
927
			return Rank.ORDER();
928
		}else{
929
			return null;
930
		}
931
	}
932
	
933

    
934
	/* (non-Javadoc)
935
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
936
	 */
937
	@Override
938
	protected boolean doCheck(CentralAfricaFernsImportState state){
939
		IOValidator<CentralAfricaFernsImportState> validator = new CentralAfricaFernsTaxonImportValidator();
940
		return validator.validate(state);
941
	}
942
	
943
	
944
	/* (non-Javadoc)
945
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
946
	 */
947
	@Override
948
	protected boolean isIgnore(CentralAfricaFernsImportState state){
949
		return ! state.getConfig().isDoTaxa();
950
	}
951

    
952

    
953

    
954
}
(5-5/7)