Project

General

Profile

Download (37.6 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.IBotanicalName;
48
import eu.etaxonomy.cdm.model.name.INonViralName;
49
import eu.etaxonomy.cdm.model.name.ITaxonNameBase;
50
import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
51
import eu.etaxonomy.cdm.model.name.NameTypeDesignationStatus;
52
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
53
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
54
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
55
import eu.etaxonomy.cdm.model.name.Rank;
56
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
57
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignationStatus;
58
import eu.etaxonomy.cdm.model.name.TaxonName;
59
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
60
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
61
import eu.etaxonomy.cdm.model.occurrence.Collection;
62
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
63
import eu.etaxonomy.cdm.model.reference.Reference;
64
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
65
import eu.etaxonomy.cdm.model.taxon.Synonym;
66
import eu.etaxonomy.cdm.model.taxon.Taxon;
67
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
68
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
69
import eu.etaxonomy.cdm.strategy.parser.TimePeriodParser;
70

    
71
/**
72
 * @author a.mueller
73
 * @since 20.02.2010
74
 */
75
@Component
76
public class CentralAfricaFernsTaxonImport  extends CentralAfricaFernsImportBase<TaxonBase> implements IMappingImport<TaxonBase, CentralAfricaFernsImportState>{
77

    
78
    private static final long serialVersionUID = 2109721344787099118L;
79
    private static final Logger logger = Logger.getLogger(CentralAfricaFernsTaxonImport.class);
80

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

    
83
	private DbImportMapping<?,?> mapping;
84

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

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

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

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

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

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

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

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

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

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

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

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

    
126

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

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

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

    
134

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

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

    
145
		}
146
		return mapping;
147
	}
148

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

    
162

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

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

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

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

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

    
204

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

    
217
		return typeInfo;
218
	}
219

    
220

    
221

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

    
231

    
232

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

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

    
256
			DerivedUnit specimen = designation.getTypeSpecimen();
257

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

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

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

    
272
			}
273
		}
274

    
275
	}
276

    
277

    
278

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

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

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

    
317
		return result;
318
	}
319

    
320

    
321

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

    
335

    
336

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

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

    
353

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

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

    
391

    
392

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

    
399

    
400

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

    
430

    
431

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

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

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

    
497
	}
498

    
499

    
500

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

    
511

    
512

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

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

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

    
539

    
540

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

    
553

    
554

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

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

    
571

    
572

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

    
590

    
591

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

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

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

    
614
		}
615
	}
616

    
617

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

    
624

    
625

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

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

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

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

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

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

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

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

    
710

    
711
	private void parseNomRemark(CentralAfricaFernsImportState state, INonViralName name, String nomRemarksString, String taxonStatus, String taxonNumber) {
712

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

    
757

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

    
763

    
764

    
765

    
766
	}
767

    
768

    
769

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

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

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

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

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

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

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

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

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

    
823
	}
824

    
825

    
826

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

    
851

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

    
874

    
875

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

    
894

    
895

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

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

    
925

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

    
935

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

    
944

    
945

    
946
}
(5-5/7)