Project

General

Profile

Download (37.4 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.DerivedUnit;
61
import eu.etaxonomy.cdm.model.reference.Reference;
62
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
63
import eu.etaxonomy.cdm.model.taxon.Synonym;
64
import eu.etaxonomy.cdm.model.taxon.Taxon;
65
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
66
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
67
import eu.etaxonomy.cdm.strategy.parser.TimePeriodParser;
68

    
69

    
70
/**
71
 * @author a.mueller
72
 * @created 20.02.2010
73
 */
74
@Component
75
public class CentralAfricaFernsTaxonImport  extends CentralAfricaFernsImportBase<TaxonBase> implements IMappingImport<TaxonBase, CentralAfricaFernsImportState>{
76
	private static final Logger logger = Logger.getLogger(CentralAfricaFernsTaxonImport.class);
77

    
78
	public static final UUID TNS_EXT_UUID = UUID.fromString("41cb0450-ac84-4d73-905e-9c7773c23b05");
79

    
80

    
81
	private DbImportMapping<?,?> mapping;
82

    
83
	//second path is not used anymore, there is now an ErmsTaxonRelationImport class instead
84
//	private boolean isSecondPath = false;
85

    
86
	private static final String pluralString = "taxa";
87
	private static final String dbTableName = "[African pteridophytes]";
88
	private static final Class<?> cdmTargetClass = TaxonBase.class;
89

    
90
	public CentralAfricaFernsTaxonImport(){
91
		super(pluralString, dbTableName, cdmTargetClass);
92
	}
93

    
94

    
95
	@Override
96
    protected String getIdQuery() {
97
		String strQuery = " SELECT [Taxon number] FROM " + dbTableName ;
98
		return strQuery;
99
	}
100

    
101
	@Override
102
	protected DbImportMapping<?,?> getMapping() {
103
		if (mapping == null){
104
			mapping = new DbImportMapping();
105

    
106
			mapping.addMapper(DbImportObjectCreationMapper.NewInstance(this, "Taxon number", TAXON_NAMESPACE)); //id + tu_status
107

    
108
			mapping.addMapper(DbImportMethodMapper.NewInstance(this, "mapTypes", ResultSet.class, CentralAfricaFernsImportState.class));
109
			mapping.addMapper(DbImportAnnotationMapper.NewInstance("Notes", AnnotationType.EDITORIAL()));
110

    
111
			mapping.addMapper(DbImportMethodMapper.NewInstance(this, "mapReferences", ResultSet.class, CentralAfricaFernsImportState.class));
112
			mapping.addMapper(DbImportMethodMapper.NewInstance(this, "mapNomRemarks", ResultSet.class, CentralAfricaFernsImportState.class));
113

    
114
			mapping.addMapper(DbImportExtensionMapper.NewInstance("Illustrations - non-original", CentralAfricaFernsTransformer.uuidIllustrationsNonOriginal, "Illustrations - non-original", "Illustrations - non-original", null));
115

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

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

    
122
			mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Basionym of", "Needs better understanding"));
123
			mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Synonym of", "Needs better understanding. Strange values like "));
124

    
125

    
126
			mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Chromosome number" , "Wrong data. Seems to be 'reference full'"));
127

    
128
			mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Book Publisher & Place" , "How to access the reference via String mapper?"));
129

    
130
			mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Reprint no" , "What's this?"));
131
			mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Date verified" , "Needed?"));
132

    
133

    
134
//
135
//			UUID credibilityUuid = ErmsTransformer.uuidCredibility;
136
//			mapping.addMapper(DbImportExtensionMapper.NewInstance("tu_credibility", credibilityUuid, "credibility", "credibility", "credibility")); //Werte: null, unknown, marked for deletion
137
//
138
			//ignore
139
//			mapping.addMapper(DbIgnoreMapper.NewInstance("cache_citation", "citation cache not needed in PESI"));
140

    
141
			//not yet implemented or ignore
142
//			mapping.addMapper(DbNotYetImplementedMapper.NewInstance("tu_hidden", "Needs DbImportMarkerMapper implemented"));
143

    
144
		}
145
		return mapping;
146
	}
147

    
148
	/* (non-Javadoc)
149
	 * @see eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportBase#getRecordQuery(eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportConfigurator)
150
	 */
151
	@Override
152
	protected String getRecordQuery(CentralAfricaFernsImportConfigurator config) {
153
		String strSelect = " SELECT * ";
154
		String strFrom = " FROM [African pteridophytes] as ap";
155
		String strWhere = " WHERE ( ap.[taxon number] IN (" + ID_LIST_TOKEN + ") )";
156
		String strOrderBy = " ORDER BY [Taxon number]";
157
		String strRecordQuery = strSelect + strFrom + strWhere + strOrderBy;
158
		return strRecordQuery;
159
	}
160

    
161

    
162
	@Override
163
	public Map<Object, Map<String, ? extends CdmBase>> getRelatedObjectsForPartition(ResultSet rs, CentralAfricaFernsImportState state) {
164
//		String nameSpace;
165
//		Class<?> cdmClass;
166
//		Set<String> idSet;
167
		Map<Object, Map<String, ? extends CdmBase>> result = new HashMap<Object, Map<String, ? extends CdmBase>>();
168

    
169
		try{
170
				Set<String> nameIdSet = new HashSet<String>();
171
				Set<String> referenceIdSet = new HashSet<String>();
172
				while (rs.next()){
173
	//				handleForeignKey(rs, nameIdSet, "PTNameFk");
174
	//				handleForeignKey(rs, referenceIdSet, "PTRefFk");
175
				}
176

    
177
			//reference map
178
//			nameSpace = "Reference";
179
//			cdmClass = Reference.class;
180
//			Map<String, Person> referenceMap = (Map<String, Person>)getCommonService().getSourcedObjectsByIdInSource(Person.class, teamIdSet, nameSpace);
181
//			result.put(Reference.class, referenceMap);
182

    
183
		} catch (SQLException e) {
184
			throw new RuntimeException(e);
185
		}
186
		return result;
187
	}
188

    
189
	private TaxonBase mapTypes(ResultSet rs, CentralAfricaFernsImportState state) throws SQLException{
190
		TaxonBase<?> taxonBase = state.getRelatedObject(state.CURRENT_OBJECT_NAMESPACE, state.CURRENT_OBJECT_ID, TaxonBase.class);
191
		TaxonNameBase name = taxonBase.getName();
192
		for (int i = 1; i <= 5; i++){
193
			String[] typeInfo = new String[3];
194
			typeInfo = getTypeInfo(rs, i);
195
			if (StringUtils.isBlank(typeInfo[0]) && StringUtils.isBlank(typeInfo[1]) && StringUtils.isBlank(typeInfo[2])){
196
				continue;
197
			}
198
			makeSingleType(state, name, typeInfo[0], typeInfo[1], typeInfo[2]);
199
		}
200
		return taxonBase;
201
	}
202

    
203

    
204
	private String[] getTypeInfo(ResultSet rs, int i) throws SQLException {
205
		String[] typeInfo = new String[3];
206
		String number;
207
		if (i == 1){
208
			number = "";
209
		}else{
210
			number = String.valueOf(i);
211
		}
212
		typeInfo[0] = rs.getString("Type" + number);
213
		typeInfo[1] = rs.getString("Type collector and number" + number);
214
		typeInfo[2] = rs.getString("Type location" + number);
215

    
216
		return typeInfo;
217
	}
218

    
219

    
220

    
221
	private void makeSingleType(CentralAfricaFernsImportState state, TaxonNameBase name, String typeString, String typeCollectorString, String typeLocationString) {
222
		if (name.getRank().isHigher(Rank.SPECIES())){
223
			//TODO move to TaxonRelationImport
224
			handleNameType(state, name, typeString, typeCollectorString, typeLocationString);
225
		}else{
226
			handleSpecimenType(state, name, typeString, typeCollectorString, typeLocationString);
227
		}
228
	}
229

    
230

    
231

    
232
	private void handleSpecimenType(CentralAfricaFernsImportState state, TaxonNameBase name, String typeString, String typeCollectorString, String typeLocationString) {
233
		List<SpecimenTypeDesignation> designations = new ArrayList<SpecimenTypeDesignation>();
234
		typeLocationString = CdmUtils.Nz(typeLocationString);
235
		if (typeLocationString.equalsIgnoreCase("not located")){
236

    
237
		}else{
238
			String[] splits = typeLocationString.split(";");
239
			for (String split : splits){
240
				List<SpecimenTypeDesignation> splitDesignations = handleTypeLocationPart(state, typeString, typeCollectorString, split);
241
				designations.addAll(splitDesignations);
242
			}
243
		}
244
		if (designations.size() == 0){
245
			logger.error(state.getTaxonNumber() + " - No designations defined. TypeString: " + CdmUtils.Nz(typeString) + ", CollectorString: " + typeCollectorString);
246
		}
247
		//type and collector
248
		DerivedUnitFacade lastFacade = null;
249
		for (SpecimenTypeDesignation designation: designations){
250
			name.addTypeDesignation(designation, false);
251
			if (typeString != null && (typeString.contains("Not designated.")|| typeString.contains("No type designated."))){
252
				designation.setNotDesignated(true);
253
			}
254

    
255
			DerivedUnit specimen = designation.getTypeSpecimen();
256

    
257
			if (lastFacade != null){
258
				lastFacade.addDuplicate(specimen);
259
			}else{
260

    
261
				try {
262
					lastFacade = DerivedUnitFacade.NewInstance(specimen);
263
				} catch (DerivedUnitFacadeNotSupportedException e) {
264
					throw new RuntimeException(e);
265
				}
266

    
267
				//TODO not so nice
268
				lastFacade.setLocality(typeString);
269
				makeTypeCollectorInfo(lastFacade, typeCollectorString);
270

    
271
			}
272
		}
273

    
274
	}
275

    
276

    
277

    
278
	private List<SpecimenTypeDesignation> handleTypeLocationPart(CentralAfricaFernsImportState state,
279
				String typeString, String typeCollectorString, String typeLocationPart) {
280
		List<SpecimenTypeDesignation> result = new ArrayList<SpecimenTypeDesignation>();
281
		String[] splits = typeLocationPart.split(",");
282
		//see also SpecimenTypeParser
283
		String typeTypePattern = "(holo.|lecto.|iso.|isolecto.|syn.|isosyn.|neo.|isoneo.)";
284
		String collectionPattern = "^[A-Z]+(\\-[A-Z]+)?";
285
		String numberPattern = "([0-9]+([\\-\\s\\.\\/][0-9]+)?)?";
286
		String addInfoPattern = "[!\\+\\?]?";
287
		String typeCollectionPattern = collectionPattern + "\\s?" + numberPattern + addInfoPattern;
288
		SpecimenTypeDesignation lastDesignation = null;
289

    
290
		for (String split: splits){
291
			split = split.trim();
292
			if (StringUtils.isBlank(split)){
293
				continue;
294
			}else if(split.trim().startsWith("designated by")){
295
				split = handleDesignatedBy(lastDesignation, split);
296
			}else if (split.trim().matches(typeTypePattern)){
297
				makeSpecimentTypeStatus(lastDesignation, split);
298
			}else if(split.matches(typeCollectionPattern)){
299

    
300
				lastDesignation = makeSpecimenTypeCollection(lastDesignation, split, collectionPattern, numberPattern, addInfoPattern);
301
			}else if(split.equalsIgnoreCase("not located")){
302
				lastDesignation = makeCachedSpecimenDesignation(split);
303
			}else{
304
				logger.error(state.getTaxonNumber() + " - Unknown type location part: " +  split);
305
				if (lastDesignation == null){
306
					lastDesignation = makeCachedSpecimenDesignation(split);
307
				}
308
			}
309
			if (lastDesignation != null && ! result.contains(lastDesignation)){
310
				result.add(lastDesignation);
311
			}else if (lastDesignation == null){
312
				logger.warn("Last Designation is null");
313
			}
314
		}
315

    
316
		return result;
317
	}
318

    
319

    
320

    
321
	/**
322
	 * @param split
323
	 * @return
324
	 */
325
	private SpecimenTypeDesignation makeCachedSpecimenDesignation(String split) {
326
		SpecimenTypeDesignation lastDesignation;
327
		lastDesignation = SpecimenTypeDesignation.NewInstance();
328
		DerivedUnit specimen = DerivedUnit.NewPreservedSpecimenInstance();
329
		specimen.setTitleCache(split, true);
330
		lastDesignation.setTypeSpecimen(specimen);
331
		return lastDesignation;
332
	}
333

    
334

    
335

    
336
	private SpecimenTypeDesignation makeSpecimenTypeCollection(SpecimenTypeDesignation designation, String collectionString, String strCollectionPattern, String strNumberPattern, String strAddInfoPattern) {
337
		SpecimenTypeDesignation result = SpecimenTypeDesignation.NewInstance();
338
		DerivedUnit specimen = DerivedUnit.NewPreservedSpecimenInstance();
339
		result.setTypeSpecimen(specimen);
340

    
341
		//collection
342
		Pattern collectionPattern = Pattern.compile(strCollectionPattern);
343
		Matcher matcher = collectionPattern.matcher(collectionString);
344
		if (! matcher.find()){
345
			throw new RuntimeException("collectionString doesn't match: " + collectionString);
346
		}
347
		String strCollection = matcher.group();
348
		Collection collection = getCollection(strCollection);
349
		specimen.setCollection(collection);
350
		collectionString = collectionString.substring(strCollection.length()).trim();
351

    
352

    
353
		//collection number
354
		Pattern numberPattern = Pattern.compile(strNumberPattern);
355
		matcher = numberPattern.matcher(collectionString);
356
		if (matcher.find()){
357
			String strNumber = matcher.group();
358
			collectionString = collectionString.substring(strNumber.length()).trim();
359
			if (StringUtils.isNotBlank(strNumber)){
360
				specimen.setCatalogNumber(strNumber);
361
			}
362
		}else{
363
			//throw new RuntimeException("numberString doesn't match: " + collectionString);
364
		}
365

    
366
		//additional info
367
		Pattern addInfoPattern = Pattern.compile(strAddInfoPattern);
368
		matcher = addInfoPattern.matcher(collectionString);
369
		if (matcher.find()){
370
			String strAddInfo = matcher.group();
371
			collectionString = collectionString.substring(strAddInfo.length()).trim();
372
			if (StringUtils.isBlank(strAddInfo)){
373
				//do nothing
374
			}else if (strAddInfo.equals("!")){
375
				//TODO add seen by author
376
			}else if (strAddInfo.equals("?")){
377
				//TODO add doubtful
378
			}else if (strAddInfo.equals("+")){
379
				//TODO add +
380
			}
381
		}else{
382
			//throw new RuntimeException("addInfoString doesn't match: " + collectionString);
383
		}
384
		if (StringUtils.isNotBlank(collectionString)){
385
			logger.error("Collection string is not empty: " + collectionString );
386
		}
387
		return result;
388
	}
389

    
390

    
391

    
392
	private Collection getCollection(String strCollection) {
393
		//TODO use BCI and deduplication
394
		Collection result = Collection.NewInstance();
395
		return result;
396
	}
397

    
398

    
399

    
400
	private void makeSpecimentTypeStatus(SpecimenTypeDesignation designation, String type) {
401
		SpecimenTypeDesignationStatus status;
402
		if (type.equalsIgnoreCase("iso.")){
403
			status = SpecimenTypeDesignationStatus.ISOTYPE();
404
		}else if (type.equalsIgnoreCase("isolecto.")){
405
			status = SpecimenTypeDesignationStatus.ISOLECTOTYPE();
406
		}else if (type.equalsIgnoreCase("syn.")){
407
			status = SpecimenTypeDesignationStatus.SYNTYPE();
408
		}else if (type.equalsIgnoreCase("holo.")){
409
			status = SpecimenTypeDesignationStatus.HOLOTYPE();
410
		}else if (type.equalsIgnoreCase("lecto.")){
411
			status = SpecimenTypeDesignationStatus.LECTOTYPE();
412
		}else if (type.equalsIgnoreCase("isosyn.")){
413
			status = SpecimenTypeDesignationStatus.ISOSYNTYPE();
414
		}else if (type.equalsIgnoreCase("neo.")){
415
			status = SpecimenTypeDesignationStatus.NEOTYPE();
416
		}else if (type.equalsIgnoreCase("isoneo.")){
417
			status = SpecimenTypeDesignationStatus.ISONEOTYPE();
418
		}else{
419
			logger.error("Type Status not supported: " + type);
420
			throw new RuntimeException("Type Status not supported: " + type);
421
		}
422
		if (designation == null){
423
			logger.error("Designation is null");
424
		}else{
425
			designation.setTypeStatus(status);
426
		}
427
	}
428

    
429

    
430

    
431
	private void handleNameType(CentralAfricaFernsImportState state, TaxonNameBase name, String typeString, String typeCollectorString, String typeLocation) {
432
		String originalString = typeString; //just for testing
433
		if (StringUtils.isNotBlank(typeCollectorString)){
434
			logger.error(state.getTaxonNumber() + " - Type collector string for name type is not empty: " + typeCollectorString);
435
		}
436
		if (StringUtils.isNotBlank(typeLocation)){
437
			logger.error(state.getTaxonNumber() + " - Type location string for name type is not empty: " + typeLocation);
438
		}
439
		NameTypeDesignation nameTypeDesignation = NameTypeDesignation.NewInstance();
440
		NameTypeDesignationStatus status = null;
441
		if (StringUtils.isBlank(typeString)){
442
			logger.warn(state.getTaxonNumber() + " - TypeString is empty");
443
		}
444
		if (typeString.startsWith("None designated.")){
445
			nameTypeDesignation.setNotDesignated(true);
446
			typeString = typeString.replaceFirst("None designated\\.", "").trim();
447
		}
448
		if (typeString.contains("Lectotype: ")|| typeString.contains(", lecto." )){
449
			status = NameTypeDesignationStatus.LECTOTYPE();
450
			typeString = typeString.replace("Lectotype: ", "");
451
			typeString = typeString.replace(", lecto.", "");
452
			typeString = handleDesignatedBy(nameTypeDesignation, typeString);
453
		}else{
454
			typeString = handleDesignatedBy(nameTypeDesignation, typeString);
455
		}
456

    
457
//		String strSecondNamePattern = "([^\\(]*|\\(.*\\))+;.+"; //never ending story
458
		String strSecondNamePattern = ".+;.+";
459
		String firstName;
460
		String secondName = null;
461
		if (typeString.matches(strSecondNamePattern)){
462
			String[] split = typeString.split(";");
463
			firstName = split[0].trim();
464
			secondName = split[1].trim();
465
			if (split.length > 2){
466
				logger.warn(state.getTaxonNumber() + " - There are more than 2 name types: " + typeString);
467
			}
468
		}else{
469
			firstName = typeString;
470
		}
471
		if (StringUtils.isNotBlank(firstName)){
472
			BotanicalName[] nameTypeNames = getNameTypeName(firstName);
473
			BotanicalName nameTypeName = nameTypeNames[0];
474
			BotanicalName nameTypeAcceptedName = nameTypeNames[1];
475
			nameTypeDesignation.setTypeName(nameTypeName);
476
			if (nameTypeName.isProtectedTitleCache()){
477
				logger.error(state.getTaxonNumber() + " - Name type could not be parsed: " + nameTypeName.getTitleCache());
478
			}
479
			if (! nameTypeName.getRank().equals(Rank.SPECIES())){
480
				logger.warn(state.getTaxonNumber() + " - Name type is not of rank species: " + nameTypeName.getTitleCache());
481
			}
482
		}
483
		if (StringUtils.isNotBlank(secondName)){
484
			TaxonNameBase secondNameType = handleSecondNameTypeName(secondName);
485
			if (secondNameType.isProtectedTitleCache()){
486
				logger.error(state.getTaxonNumber() + " - Second name type could not be parsed: " + secondNameType.getTitleCache());
487
			}
488
			if (! secondNameType.getRank().equals(Rank.SPECIES())){
489
				logger.error(state.getTaxonNumber() + " - Second name type is not of rank species: " + secondNameType.getTitleCache());
490
			}
491

    
492
		}
493
		nameTypeDesignation.setTypeStatus(status);
494
		name.addTypeDesignation(nameTypeDesignation, false);
495

    
496
	}
497

    
498

    
499

    
500
	private TaxonNameBase handleSecondNameTypeName(String strName) {
501
		//TODO needs feedbacke from Thomas
502
		logger.info("Not yet implemented");
503
		if (strName.endsWith(",")){
504
			strName = strName.substring(0, strName.length() -1);
505
		}
506
		BotanicalName result = (BotanicalName)NonViralNameParserImpl.NewInstance().parseFullName(strName, NomenclaturalCode.ICNAFP, Rank.SPECIES());
507
		return result;
508
	}
509

    
510

    
511

    
512
	private BotanicalName[] getNameTypeName(String strName) {
513
		//TODO implement get existing names
514
		logger.info("Not yet fully implemented");
515

    
516
		BotanicalName[] result = new BotanicalName[2];
517
		if (strName.endsWith(",")){
518
			strName = strName.substring(0, strName.length() -1);
519
		}
520
		String acceptedName;
521
		String acceptedNamePattern = "\\(.*\\)\\.?$";
522
		if (strName.matches(".*" + acceptedNamePattern)){
523
			int accStart = strName.lastIndexOf("(");
524
			String notAcceptedName = strName.substring(0, accStart -1 );
525
			acceptedName = strName.substring(accStart + 1, strName.length() - 1);
526
			if (acceptedName.endsWith(")")){
527
				acceptedName = acceptedName.substring(0, acceptedName.length()-1);
528
			}
529
			acceptedName = acceptedName.replaceFirst("=", "").trim();
530
			result[1] = (BotanicalName)NonViralNameParserImpl.NewInstance().parseFullName(acceptedName, NomenclaturalCode.ICNAFP, null);
531
			strName = notAcceptedName;
532
		}
533

    
534
		result[0] = (BotanicalName)NonViralNameParserImpl.NewInstance().parseFullName(strName, NomenclaturalCode.ICNAFP, Rank.SPECIES());
535
		return result;
536
	}
537

    
538

    
539

    
540
	private String handleDesignatedBy(TypeDesignationBase<?> typeDesignation, String typeString) {
541
		String[] splitDesignated = typeString.split(", designated by ");
542
		if (splitDesignated.length > 1){
543
			Reference designationCitation = getDesignationCitation(typeDesignation, splitDesignated[1]);
544
			typeDesignation.setCitation(designationCitation);
545
			if (splitDesignated.length > 2){
546
				throw new IllegalStateException("More than one designation is not expected");
547
			}
548
		}
549
		return splitDesignated[0].trim();
550
	}
551

    
552

    
553

    
554
	private Reference getDesignationCitation(TypeDesignationBase<?> typeDesignation, String citationString) {
555
		// TODO try to find an existing Reference
556
		Reference result = ReferenceFactory.newGeneric();
557
		String strBracketPattern = "\\((10 Oct. )?\\d{4}:\\s?(\\d{1,3}(--\\d{1,3})?|[XLVI]{1,7}|\\.{1,8})\\)\\.?";
558

    
559
		String strStandardPattern = ".*" + strBracketPattern;
560
//		strStandardPattern = ".*";
561
		if (Pattern.matches(strStandardPattern, citationString)){
562
			parseStandardPattern(typeDesignation, result, citationString, strBracketPattern);
563
		}else{
564
			logger.error("Can't parse designation citation: " + citationString);
565
			result.setTitleCache(citationString);
566
		}
567
		return result;
568
	}
569

    
570

    
571

    
572
	private void parseStandardPattern(TypeDesignationBase typeDesignation, Reference result, String citationString, String bracketPattern) {
573
		String authorPart = citationString.split(bracketPattern)[0];
574
		String bracket = citationString.substring(authorPart.length()+1, citationString.length()-1).trim();
575
		authorPart = authorPart.trim();
576
		if (bracket.endsWith(")")){
577
			bracket = bracket.substring(0, bracket.length()-1);
578
		}
579
		Team team = Team.NewTitledInstance(authorPart, authorPart);
580
		result.setAuthorship(team);
581
		String[] bracketSplit = bracket.split(":");
582
		TimePeriod datePublished = TimePeriodParser.parseString(bracketSplit[0].trim());
583
		result.setDatePublished(datePublished);
584
		String citationMicroReference = bracketSplit[1].trim();
585
		citationMicroReference = citationMicroReference.replace("--", "-");
586
		typeDesignation.setCitationMicroReference(citationMicroReference);
587
	}
588

    
589

    
590

    
591
	private void makeTypeCollectorInfo(DerivedUnitFacade specimen, String collectorAndNumberString) {
592
		if (StringUtils.isBlank(collectorAndNumberString)){
593
			return;
594
		}
595
		String reNumber = "(s\\.n\\.|\\d.*)";
596
		Pattern reNumberPattern = Pattern.compile(reNumber);
597
		Matcher matcher = reNumberPattern.matcher(collectorAndNumberString);
598

    
599
		if ( matcher.find()){
600
			int numberStart = matcher.start();
601
			String number = collectorAndNumberString.substring(numberStart).trim();
602
			if (numberStart > 0){
603
				numberStart = numberStart -1;
604
			}
605
			String collectorString = collectorAndNumberString.substring(0, numberStart).trim();
606
			specimen.setFieldNumber(number);
607
			TeamOrPersonBase team = getTeam(collectorString);
608
			specimen.setCollector(team);
609

    
610
		}else{
611
			logger.warn("collector string did not match number pattern: " + collectorAndNumberString);
612

    
613
		}
614
	}
615

    
616

    
617
	private TeamOrPersonBase getTeam(String teamString) {
618
		//TODO check existing team
619
		TeamOrPersonBase result = Team.NewTitledInstance(teamString, teamString);
620
		return result;
621
	}
622

    
623

    
624

    
625
	/**
626
	 * for internal use only, used by MethodMapper
627
	 */
628
	private TaxonBase mapReferences(ResultSet rs, CentralAfricaFernsImportState state) throws SQLException{
629
		String taxonNumber = state.getTaxonNumber();
630
		String referenceFullString = rs.getString("Reference full");
631
		String referenceAbbreviatedString = rs.getString("Reference - abbreviated");
632
		String volume = rs.getString("Book / Journal volume");
633
		String pages = rs.getString("Book / Journal pages");
634
		String illustrations = rs.getString("Illustration/s");
635

    
636
		String fascicle = rs.getString("Book / Journal fascicle");
637
		String part = rs.getString("Book / Journal part");
638
		String paperTitle = rs.getString("Book / Paper title");
639

    
640
		String datePublishedString = rs.getString("Date published");
641
		String referenceString = referenceFullString;
642
		if (StringUtils.isBlank(referenceString)){
643
			referenceString = referenceAbbreviatedString;
644
		}
645

    
646
		TaxonBase<?> taxonBase = state.getRelatedObject(state.CURRENT_OBJECT_NAMESPACE, state.CURRENT_OBJECT_ID, TaxonBase.class);
647
		if (StringUtils.isNotBlank(referenceString) || StringUtils.isNotBlank(volume) ||
648
					StringUtils.isNotBlank(pages) || StringUtils.isNotBlank(illustrations) ||
649
					StringUtils.isNotBlank(datePublishedString) || StringUtils.isNotBlank(paperTitle)){
650
			NonViralName<?> name = CdmBase.deproxy(taxonBase.getName(), NonViralName.class);
651
			Reference reference = ReferenceFactory.newGeneric();
652
			reference.setAuthorship(name.getCombinationAuthorship());
653
			reference.setTitle(referenceString);
654
			reference.setVolume(volume);
655
			reference.setEdition(part);
656
			Reference inrefernce = null;
657
			//TODO parser
658
			TimePeriod datePublished = TimePeriodParser.parseString(datePublishedString);
659
			reference.setDatePublished(datePublished);
660
			if (StringUtils.isNotBlank(paperTitle)){
661
				Reference innerReference = ReferenceFactory.newGeneric();
662
				innerReference.setDatePublished(datePublished);
663
				name.setNomenclaturalReference(innerReference);
664
				innerReference.setInReference(reference);
665
				reference = innerReference;
666
			}else{
667
				name.setNomenclaturalReference(reference);
668
			}
669

    
670
			//details
671
			String details = CdmUtils.concat(", ", pages, illustrations);
672
			details = StringUtils.isBlank(details) ? null : details.trim();
673
			name.setNomenclaturalMicroReference(details);
674
			try {
675
				UUID uuidFascicle = state.getTransformer().getExtensionTypeUuid("fascicle");
676
				ExtensionType extensionType = getExtensionType(state, uuidFascicle, "Fascicle", "Fascicle", null);
677
				reference.addExtension(fascicle, extensionType);
678
			} catch (UndefinedTransformerMethodException e) {
679
				e.printStackTrace();
680
			}
681

    
682
		}else{
683
			logger.warn(taxonNumber + " - Taxon has no reference");
684
		}
685
		return taxonBase;
686
	}
687

    
688
	/**
689
	 * for internal use only, used by MethodMapper
690
	 * @throws Exception
691
	 */
692
	private TaxonBase mapNomRemarks(ResultSet rs, CentralAfricaFernsImportState state) throws Exception{
693
		try {
694
			String taxonNumber = state.getTaxonNumber();
695
			String nomRemarksString = rs.getString("Nom  remarks");
696
			String taxonStatus = rs.getString("Current/Synonym");
697

    
698
			TaxonBase<?> taxonBase = state.getRelatedObject(state.CURRENT_OBJECT_NAMESPACE, state.CURRENT_OBJECT_ID, TaxonBase.class);
699
			if (StringUtils.isNotBlank(nomRemarksString)){
700
				NonViralName name = CdmBase.deproxy(taxonBase.getName(), NonViralName.class);
701
				parseNomRemark(state, name, nomRemarksString.trim(),taxonStatus, taxonNumber);
702
			}
703
			return taxonBase;
704
		} catch (Exception e) {
705
			throw e;
706
		}
707
	}
708

    
709

    
710
	private void parseNomRemark(CentralAfricaFernsImportState state, NonViralName name, String nomRemarksString, String taxonStatus, String taxonNumber) {
711

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

    
756

    
757
		if (StringUtils.isNotBlank(nomRemarksString)){
758
			ExtensionType extensionType = getExtensionType(state, CentralAfricaFernsTransformer.uuidNomenclaturalRemarks, "Nomenclatural remarks", "Nomenclatural remarks", null);
759
			name.addExtension(nomRemarksString, extensionType);
760
		}
761

    
762

    
763

    
764

    
765
	}
766

    
767

    
768

    
769
	/* (non-Javadoc)
770
	 * @see eu.etaxonomy.cdm.io.common.mapping.IMappingImport#createObject(java.sql.ResultSet)
771
	 */
772
	@Override
773
    public TaxonBase createObject(ResultSet rs, CentralAfricaFernsImportState state) throws SQLException {
774
		BotanicalName taxonName = BotanicalName.NewInstance(null);
775
		Reference sec = state.getConfig().getSourceReference();
776

    
777
		String taxonNumber = rs.getString("Taxon number");
778
		state.setTaxonNumber(taxonNumber);
779

    
780
		String orderName = rs.getString("Order name");
781
		String subOrderName = rs.getString("Suborder name");
782
		String familyName = rs.getString("Family name");
783
		String subFamilyName = rs.getString("Subfamily name");
784
		String tribusName = rs.getString("Tribus name");
785
		String subTribusName = rs.getString("Subtribus name");
786
		String sectionName = rs.getString("Section name");
787
		String genusName = rs.getString("Genus name");
788
		String subGenusName = rs.getString("Subgenus name");
789
		String seriesName = rs.getString("Series name");
790
		String specificEpihet = rs.getString("Specific epihet");
791
		String subspeciesName = rs.getString("Subspecies name");
792
		String varietyName = rs.getString("Variety name");
793
		String subFormaName = rs.getString("Subforma");
794
		String subVariety = rs.getString("Subvariery");
795
		String formaName = rs.getString("Forma name");
796
		String subsectionName = rs.getString("Subsection name");
797

    
798
		String status = rs.getString("Current/Synonym");
799

    
800
		TaxonBase taxon = makeTaxon(taxonName, sec, taxonNumber, status);
801

    
802
//			Integer parent3Rank = rs.getInt("parent3rank");
803

    
804
		//rank and epithets
805
		Rank lowestRank = setLowestUninomial(taxonName, orderName,  subOrderName, familyName, subFamilyName, tribusName, subTribusName,genusName);
806
		lowestRank = setLowestInfraGeneric(taxonName, lowestRank, subGenusName, sectionName, subsectionName, seriesName);
807
		if (StringUtils.isNotBlank(specificEpihet)){
808
			taxonName.setSpecificEpithet(specificEpihet);
809
			lowestRank = Rank.SPECIES();
810
		}
811
		lowestRank = setLowestInfraSpecific(taxonName, lowestRank, subspeciesName,  varietyName, subVariety, formaName,subFormaName);
812

    
813
		taxonName.setRank(lowestRank);
814
		state.setCurrentRank(taxonName.getRank());
815
		setAuthor(taxonName, rs, taxonNumber, false);
816

    
817
		//add original source for taxon name (taxon original source is added in mapper
818
//		Reference citation = state.getConfig().getSourceReference();
819
//		addOriginalSource(taxonName, taxonNumber, TAXON_NAMESPACE, citation);
820
		return taxon;
821

    
822
	}
823

    
824

    
825

    
826
	/**
827
	 * Creates the taxon object depending on name, sec and status
828
	 * @param taxonName
829
	 * @param sec
830
	 * @param taxonNumber
831
	 * @param status
832
	 * @return
833
	 */
834
	private TaxonBase makeTaxon(BotanicalName taxonName, Reference sec, String taxonNumber, String status) {
835
		TaxonBase taxon;
836
		if ("c".equalsIgnoreCase(status)|| "incertus".equalsIgnoreCase(status) ){
837
			taxon = Taxon.NewInstance(taxonName, sec);
838
			if ("incertus".equalsIgnoreCase(status)){
839
				taxon.setDoubtful(true);
840
			}
841
		}else if ("s".equalsIgnoreCase(status)){
842
			taxon = Synonym.NewInstance(taxonName, sec);
843
		}else{
844
			logger.warn(taxonNumber + ": Status not given for taxon " );
845
			taxon = Taxon.NewUnknownStatusInstance(taxonName, sec);
846
		}
847
		return taxon;
848
	}
849

    
850

    
851
	private Rank setLowestInfraSpecific(BotanicalName taxonName, Rank lowestRank, String subspeciesName, String varietyName,
852
			String subVariety, String formaName, String subFormaName) {
853
		if (StringUtils.isNotBlank(subFormaName)){
854
			taxonName.setInfraSpecificEpithet(subFormaName);
855
			return Rank.SUBFORM();
856
		}else if (StringUtils.isNotBlank(formaName)){
857
			taxonName.setInfraSpecificEpithet(formaName);
858
			return Rank.FORM();
859
		}else if (StringUtils.isNotBlank(subVariety)){
860
			taxonName.setInfraSpecificEpithet(subVariety);
861
			return Rank.SUBVARIETY();
862
		}else if (StringUtils.isNotBlank(varietyName)){
863
			taxonName.setInfraSpecificEpithet(varietyName);
864
			return Rank.VARIETY();
865
		}else if (StringUtils.isNotBlank(subspeciesName)){
866
			taxonName.setInfraSpecificEpithet(subspeciesName);
867
			return Rank.SUBSPECIES();
868
		}else{
869
			return lowestRank;
870
		}
871
	}
872

    
873

    
874

    
875
	private Rank setLowestInfraGeneric(BotanicalName taxonName, Rank lowestRank, String subGenusName, String sectionName, String subSectionName, String seriesName) {
876
		if (StringUtils.isNotBlank(seriesName)){
877
			taxonName.setInfraGenericEpithet(seriesName);
878
			return Rank.SERIES();
879
		}else if (StringUtils.isNotBlank(subSectionName)){
880
			taxonName.setInfraGenericEpithet(subSectionName);
881
			return Rank.SUBSECTION_BOTANY();
882
		}else if (StringUtils.isNotBlank(sectionName)){
883
			taxonName.setInfraGenericEpithet(sectionName);
884
			return Rank.SECTION_BOTANY();
885
		}else if (StringUtils.isNotBlank(subGenusName)){
886
			taxonName.setInfraGenericEpithet(subGenusName);
887
			return Rank.SUBGENUS();
888
		}else{
889
			return lowestRank;
890
		}
891
	}
892

    
893

    
894

    
895
	private Rank setLowestUninomial(BotanicalName taxonName, String orderName, String subOrderName, String familyName, String subFamilyName,
896
			String tribusName, String subTribusName, String genusName) {
897

    
898
		if (StringUtils.isNotBlank(genusName)){
899
			taxonName.setGenusOrUninomial(genusName);
900
			return Rank.GENUS();
901
		}else if (StringUtils.isNotBlank(subTribusName)){
902
			taxonName.setGenusOrUninomial(subTribusName);
903
			return Rank.SUBTRIBE();
904
		}else if (StringUtils.isNotBlank(tribusName)){
905
			taxonName.setGenusOrUninomial(tribusName);
906
			return Rank.TRIBE();
907
		}else if (StringUtils.isNotBlank(subFamilyName)){
908
			taxonName.setGenusOrUninomial(subFamilyName);
909
			return Rank.SUBFAMILY();
910
		}else if (StringUtils.isNotBlank(familyName)){
911
			taxonName.setGenusOrUninomial(familyName);
912
			return Rank.FAMILY();
913
		}else if (StringUtils.isNotBlank(subOrderName)){
914
			taxonName.setGenusOrUninomial(subOrderName);
915
			return Rank.SUBORDER();
916
		}else if (StringUtils.isNotBlank(orderName)){
917
			taxonName.setGenusOrUninomial(orderName);
918
			return Rank.ORDER();
919
		}else{
920
			return null;
921
		}
922
	}
923

    
924

    
925
	/* (non-Javadoc)
926
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
927
	 */
928
	@Override
929
	protected boolean doCheck(CentralAfricaFernsImportState state){
930
		IOValidator<CentralAfricaFernsImportState> validator = new CentralAfricaFernsTaxonImportValidator();
931
		return validator.validate(state);
932
	}
933

    
934

    
935
	/* (non-Javadoc)
936
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
937
	 */
938
	@Override
939
	protected boolean isIgnore(CentralAfricaFernsImportState state){
940
		return ! state.getConfig().isDoTaxa();
941
	}
942

    
943

    
944

    
945
}
(5-5/7)