Unifiy name and taxon creation
[cdmlib-apps.git] / app-import / src / main / java / eu / etaxonomy / cdm / io / algaterra / AlgaTerraSpecimenImportBase.java
index ece745c9240dea7af0a5a15d091a3da60f00f6cb..bbcbf79bbb627c4373ab9ab36bb2448ba762b9e6 100644 (file)
@@ -13,6 +13,8 @@ import java.net.URI;
 import java.sql.Date;\r
 import java.sql.ResultSet;\r
 import java.sql.SQLException;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
 import java.util.Set;\r
 import java.util.UUID;\r
 \r
@@ -24,19 +26,31 @@ import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;
 import eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportBase;\r
 import eu.etaxonomy.cdm.io.common.ResultSetPartitioner;\r
 import eu.etaxonomy.cdm.io.common.Source;\r
+import eu.etaxonomy.cdm.io.common.TdwgAreaProvider;\r
 import eu.etaxonomy.cdm.model.agent.Team;\r
+import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;\r
+import eu.etaxonomy.cdm.model.common.Annotation;\r
+import eu.etaxonomy.cdm.model.common.AnnotationType;\r
+import eu.etaxonomy.cdm.model.common.DefinedTerm;\r
+import eu.etaxonomy.cdm.model.common.Language;\r
 import eu.etaxonomy.cdm.model.common.OrderedTermVocabulary;\r
+import eu.etaxonomy.cdm.model.common.TermType;\r
+import eu.etaxonomy.cdm.model.common.TermVocabulary;\r
 import eu.etaxonomy.cdm.model.common.TimePeriod;\r
 import eu.etaxonomy.cdm.model.description.DescriptionBase;\r
 import eu.etaxonomy.cdm.model.description.Feature;\r
 import eu.etaxonomy.cdm.model.description.SpecimenDescription;\r
 import eu.etaxonomy.cdm.model.description.State;\r
+import eu.etaxonomy.cdm.model.description.TaxonDescription;\r
+import eu.etaxonomy.cdm.model.location.Country;\r
 import eu.etaxonomy.cdm.model.location.NamedArea;\r
+import eu.etaxonomy.cdm.model.location.NamedAreaType;\r
 import eu.etaxonomy.cdm.model.location.Point;\r
 import eu.etaxonomy.cdm.model.location.ReferenceSystem;\r
-import eu.etaxonomy.cdm.model.location.TdwgArea;\r
-import eu.etaxonomy.cdm.model.location.WaterbodyOrCountry;\r
 import eu.etaxonomy.cdm.model.occurrence.Collection;\r
+import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;\r
+import eu.etaxonomy.cdm.model.reference.Reference;\r
+import eu.etaxonomy.cdm.model.taxon.Taxon;\r
 \r
 /**\r
  * @author a.mueller\r
@@ -45,27 +59,29 @@ import eu.etaxonomy.cdm.model.occurrence.Collection;
 public abstract class AlgaTerraSpecimenImportBase extends BerlinModelImportBase{\r
        private static final Logger logger = Logger.getLogger(AlgaTerraSpecimenImportBase.class);\r
 \r
-       public static final String ECO_FACT_FIELD_OBSERVATION_NAMESPACE = "EcoFact";\r
-       public static final String ECO_FACT_DERIVED_UNIT_NAMESPACE = "EcoFact";\r
+       public static final String ECO_FACT_FIELD_OBSERVATION_NAMESPACE = "EcoFact_FieldObservation";\r
+       public static final String ECO_FACT_DERIVED_UNIT_NAMESPACE = "EcoFact_DerivedUnit";\r
        public static final String TYPE_SPECIMEN_FIELD_OBSERVATION_NAMESPACE = "TypeSpecimen_FieldObservation";\r
        public static final String TYPE_SPECIMEN_DERIVED_UNIT_NAMESPACE = "TypeSpecimen_DerivedUnit";\r
+       public static final String FACT_ECOLOGY_NAMESPACE = "Fact (Ecology)";\r
+       \r
        \r
        public static final String TERMS_NAMESPACE = "ALGA_TERRA_TERMS";\r
        \r
        //TODO move to transformrer\r
        final static UUID uuidMarkerAlkalinity = UUID.fromString("e52d0ea2-0c1f-4d95-ae6d-e21ab317c594");  \r
        final static UUID uuidRefSystemGps = UUID.fromString("c23e4928-c137-4e4a-b6ab-b430da3d0b94");  \r
-       final static UUID uuidFeatureSpecimenCommunity = UUID.fromString("3ff5b1ab-3999-4b5a-b8f7-01fd2f6c12c7");\r
-       final static UUID uuidFeatureAdditionalData = UUID.fromString("0ac82ab8-2c2b-4953-98eb-a9f718eb9c57");\r
-       final static UUID uuidFeatureHabitatExplanation = UUID.fromString("6fe32295-61a3-44fc-9fcf-a85790ea888f");\r
+       public final static UUID uuidFeatureSpecimenCommunity = UUID.fromString("3ff5b1ab-3999-4b5a-b8f7-01fd2f6c12c7");\r
+       public final static UUID uuidFeatureAdditionalData = UUID.fromString("0ac82ab8-2c2b-4953-98eb-a9f718eb9c57");\r
+       public final static UUID uuidFeatureHabitatExplanation = UUID.fromString("6fe32295-61a3-44fc-9fcf-a85790ea888f");\r
        \r
        final static UUID uuidVocAlgaTerraClimate = UUID.fromString("b0a677c6-8bb6-43f4-b1b8-fc377a10feb5");\r
        final static UUID uuidVocAlgaTerraHabitat = UUID.fromString("06f30114-e19c-4e7d-a8e5-5488c41fcbc5");\r
        final static UUID uuidVocAlgaTerraLifeForm = UUID.fromString("3c0b194e-809c-4b42-9498-6ff034066ed7");\r
        \r
-       final static UUID uuidFeatureAlgaTerraClimate = UUID.fromString("8754674c-9ab9-4f28-95f1-91eeee2314ee");\r
-       final static UUID uuidFeatureAlgaTerraHabitat = UUID.fromString("7def3fc2-cdc5-4739-8e13-62edbd053415");\r
-       final static UUID uuidFeatureAlgaTerraLifeForm = UUID.fromString("9b657901-1b0d-4a2a-8d21-dd8c1413e2e6");\r
+       public final static UUID uuidFeatureAlgaTerraClimate = UUID.fromString("8754674c-9ab9-4f28-95f1-91eeee2314ee");\r
+       public final static UUID uuidFeatureAlgaTerraHabitat = UUID.fromString("7def3fc2-cdc5-4739-8e13-62edbd053415");\r
+       public final static UUID uuidFeatureAlgaTerraLifeForm = UUID.fromString("9b657901-1b0d-4a2a-8d21-dd8c1413e2e6");\r
        \r
        final static UUID uuidVocParameter = UUID.fromString("45888b40-5bbb-4293-aa1e-02479796cd7c");\r
        final static UUID uuidStatMeasureSingleValue = UUID.fromString("eb4c3d98-4d4b-4c37-8eb4-17315ce79920");\r
@@ -92,10 +108,10 @@ public abstract class AlgaTerraSpecimenImportBase extends BerlinModelImportBase{
                        TransactionStatus txStatus = this.startTransaction();\r
                \r
                        boolean isOrdered = true;\r
-                       OrderedTermVocabulary<State> climateVoc = (OrderedTermVocabulary)getVocabulary(uuidVocAlgaTerraClimate, "Climate", "Climate", abbrevLabel, uri, isOrdered, null);\r
-                       OrderedTermVocabulary<State> habitatVoc = (OrderedTermVocabulary)getVocabulary(uuidVocAlgaTerraHabitat, "Habitat", "Habitat", abbrevLabel, uri, isOrdered, null);\r
-                       OrderedTermVocabulary<State> lifeformVoc = (OrderedTermVocabulary)getVocabulary(uuidVocAlgaTerraLifeForm, "Lifeform", "Lifeform", abbrevLabel, uri, isOrdered, null);\r
-                       \r
+                       State tmp = State.NewInstance();\r
+                       OrderedTermVocabulary<State> climateVoc = (OrderedTermVocabulary<State>)getVocabulary(TermType.State, uuidVocAlgaTerraClimate, "Climate", "Climate", abbrevLabel, uri, isOrdered, tmp);\r
+                       OrderedTermVocabulary<State> habitatVoc = (OrderedTermVocabulary<State>)getVocabulary(TermType.State, uuidVocAlgaTerraHabitat, "Habitat", "Habitat", abbrevLabel, uri, isOrdered, tmp);\r
+                       OrderedTermVocabulary<State> lifeformVoc = (OrderedTermVocabulary<State>)getVocabulary(TermType.State, uuidVocAlgaTerraLifeForm, "Lifeform", "Lifeform", abbrevLabel, uri, isOrdered, tmp);\r
                        \r
                        Feature feature = getFeature(state, uuidFeatureAlgaTerraClimate, "Climate","Climate", null, null);\r
                        feature.setSupportsCategoricalData(true);\r
@@ -144,19 +160,75 @@ public abstract class AlgaTerraSpecimenImportBase extends BerlinModelImportBase{
                                addOriginalSource(stateTerm, id.toString(), "EcoLifeForm", state.getTransactionalSourceReference());\r
                                getTermService().saveOrUpdate(stateTerm);\r
                        }\r
+               \r
+                       //material category\r
+                       TermVocabulary<DefinedTerm> materialCategoryVoc = getVocabulary(TermType.KindOfUnit, AlgaTerraImportTransformer.uuidKindOfUnitVoc, "Alga Terra Material Category", "Alga Terra Material Category", abbrevLabel, uri, false, DefinedTerm.NewKindOfUnitInstance(null, null, null));\r
+                       getVocabularyService().save(materialCategoryVoc);\r
+                       \r
+                       String materialSql = "SELECT * FROM MaterialCategory WHERE MaterialCategoryId <> 16 ";\r
+                       rs = source.getResultSet(materialSql);\r
+                       while (rs.next()){\r
+                               Integer id = rs.getInt("MaterialCategoryId");\r
+                               String category = rs.getString("MaterialCategory");\r
+                               String description = rs.getString("Description");\r
+                               UUID uuid = UUID.randomUUID();\r
+                               \r
+                               DefinedTerm kindOfUnit = DefinedTerm.NewKindOfUnitInstance(description, category, null);\r
+                               kindOfUnit.setUuid(uuid);\r
+                               addOriginalSource(kindOfUnit, id.toString(), "MaterialCategory", state.getTransactionalSourceReference());\r
+                               materialCategoryVoc.addTerm(kindOfUnit);\r
+                               getTermService().saveOrUpdate(kindOfUnit);\r
+                               materialCategoryMapping.put(id, uuid);\r
+                       }\r
+                       \r
+                       //areas\r
+                       OrderedTermVocabulary<NamedArea> informalAreasVoc = (OrderedTermVocabulary<NamedArea>)getVocabulary(TermType.NamedArea, AlgaTerraImportTransformer.uuidNamedAreaVocAlgaTerraInformalAreas, "AlgaTerra Specific Areas", "AlgaTerra Specific Areas", abbrevLabel, uri, true, NamedArea.NewInstance());\r
+                       getVocabularyService().save(informalAreasVoc);\r
+                       \r
+                       String areaSql = "SELECT * FROM TDWGGazetteer WHERE subL4 = 1 ";\r
+                       rs = source.getResultSet(areaSql);\r
+                       while (rs.next()){\r
+                               String l1Code = rs.getString("L1Code");\r
+                               String l2Code = rs.getString("L2Code");\r
+                               String l3Code = rs.getString("L3Code");\r
+                               String l4Code = rs.getString("L4Code");\r
+                               String gazetteer = rs.getString("Gazetteer");\r
+                               Integer id = rs.getInt("ID");\r
+                               String notes = rs.getString("Notes");\r
+                               //TODO stable uuids\r
+//                             UUID uuid = UUID.fromString(rs.getString("UUID"));\r
+                               UUID uuid = UUID.randomUUID();\r
+                               subL4Mapping.put(id, uuid);\r
+                               \r
+                               String tdwgCode =  (l4Code != null) ? l4Code : (l3Code != null) ? l3Code : (l2Code != null) ? l2Code : l1Code;\r
+                               \r
+                               NamedArea tdwgArea = TdwgAreaProvider.getAreaByTdwgAbbreviation(tdwgCode);\r
+                               NamedArea newArea  = getNamedArea(state, uuid ,gazetteer, gazetteer, null, null, null, informalAreasVoc, TermMatchMode.UUID_ONLY, null);\r
+                               if (isNotBlank(notes)){\r
+                                       newArea.addAnnotation(Annotation.NewInstance(notes, AnnotationType.EDITORIAL(), Language.DEFAULT()));\r
+                               }\r
+                               \r
+                               addOriginalSource(newArea, id.toString(), "TDWGGazetteer", state.getTransactionalSourceReference());\r
+                               getTermService().saveOrUpdate(newArea);\r
+                               newArea.setPartOf(tdwgArea);\r
+                               informalAreasVoc.addTerm(newArea);\r
+                       }\r
                        \r
                        this.commitTransaction(txStatus);\r
                        \r
                        state.setSpecimenVocabulariesCreated(true);\r
-               }\r
-               \r
+               }       \r
        }\r
        \r
+       //tmp\r
+       static Map<Integer, UUID> subL4Mapping = new HashMap<Integer, UUID>();\r
+       static Map<Integer, UUID> materialCategoryMapping = new HashMap<Integer, UUID>();\r
+       \r
        protected String getLocalityString(){\r
                return "Locality";\r
        }\r
        \r
-       protected void handleSingleSpecimen(ResultSet rs, DerivedUnitFacade facade, AlgaTerraImportState state, ResultSetPartitioner partitioner) throws SQLException {\r
+       protected void handleFieldObservationSpecimen(ResultSet rs, DerivedUnitFacade facade, AlgaTerraImportState state, ResultSetPartitioner partitioner) throws SQLException {\r
                //FIXME missing fields #3084, #3085, #3080\r
                try {\r
                        \r
@@ -168,7 +240,7 @@ public abstract class AlgaTerraSpecimenImportBase extends BerlinModelImportBase{
                        String geoCodeMethod = rs.getString("GeoCodeMethod");\r
                        \r
                        Integer altitude = nullSafeInt(rs, "Altitude");\r
-                       Integer lowerAltitude = nullSafeInt(rs,"AltitudeLowerValue");\r
+                       Integer lowerAltitude = nullSafeInt(rs, "AltitudeLowerValue");\r
                        String altitudeUnit = rs.getString("AltitudeUnit");\r
                        Double depth = nullSafeDouble(rs, "Depth");\r
                        Double depthLow = nullSafeDouble(rs, "DepthLow");\r
@@ -177,9 +249,6 @@ public abstract class AlgaTerraSpecimenImportBase extends BerlinModelImportBase{
                        Date collectionDateStart = rs.getDate("CollectionDate");\r
                        Date collectionDateEnd = rs.getDate("CollectionDateEnd");\r
                        \r
-                       Integer collectionFk = nullSafeInt(rs,"CollectionFk");\r
-                       \r
-                       \r
                        //location\r
                        facade.setLocality(locality);\r
                                \r
@@ -198,22 +267,15 @@ public abstract class AlgaTerraSpecimenImportBase extends BerlinModelImportBase{
                                if (lowerAltitude == null){\r
                                        facade.setAbsoluteElevation(altitude);\r
                                }else{\r
-                                       if (! facade.isEvenDistance(lowerAltitude, altitude)){\r
-                                               //FIXME there is a ticket for this\r
-                                               altitude = altitude + 1;\r
-                                               logger.info("Current implementation of altitude does not allow uneven distances");\r
-                                       }\r
                                        facade.setAbsoluteElevationRange(lowerAltitude,altitude);\r
                                }\r
                        }\r
                        if ( depth != null){\r
-                               //FIXME needs model change to accept double #3072\r
-                               Integer intDepth = depth.intValue();\r
                                if (depthLow == null){\r
-                                       facade.setDistanceToWaterSurface(intDepth);\r
+                                       facade.setDistanceToWaterSurface(depth);\r
                                }else{\r
-                                       //FIXME range not yet in model #3074\r
-                                       facade.setDistanceToWaterSurface(intDepth);\r
+                                       //TODO which direction is correct?\r
+                                       facade.setDistanceToWaterSurfaceRange(depth, depthLow);\r
                                }\r
                        }\r
                        \r
@@ -225,66 +287,102 @@ public abstract class AlgaTerraSpecimenImportBase extends BerlinModelImportBase{
                        \r
                        //areas\r
                        makeAreas(state, rs, facade);\r
-                       \r
-                       //collection\r
-                       if (collectionFk != null){\r
-                               Collection subCollection = state.getRelatedObject(AlgaTerraCollectionImport.NAMESPACE_SUBCOLLECTION, String.valueOf(collectionFk), Collection.class);\r
-                               if (subCollection != null){\r
-                                       facade.setCollection(subCollection);\r
-                               }else{\r
-                                       Collection collection = state.getRelatedObject(AlgaTerraCollectionImport.NAMESPACE_COLLECTION, String.valueOf(collectionFk), Collection.class);\r
-                                       facade.setCollection(collection);\r
-                               }\r
-                       }\r
-                       \r
+\r
                        //notes\r
-                       //TODO is this an annotation on field observation or on the derived unit?\r
+                       //=> not required according to Henning\r
                        \r
-                       //TODO id, created for fact +  ecoFact\r
-                       //      this.doIdCreatedUpdatedNotes(state, descriptionElement, rs, id, namespace);\r
+                       //id, created, updated, notes\r
                        if (unitId != null){\r
-                               this.doIdCreatedUpdatedNotes(state, facade.innerDerivedUnit(), rs, unitId, getDerivedUnitNameSpace());\r
+                               this.doIdCreatedUpdatedNotes(state, facade.innerFieldUnit(), rs, unitId, getFieldObservationNameSpace());\r
                        }else{\r
-                               logger.warn("Specimen has no unitId: " +  facade.innerDerivedUnit() + ": " + getDerivedUnitNameSpace());\r
+                               logger.warn("FieldObservation has no unitId: " +  facade.innerFieldUnit() + ": " + getFieldObservationNameSpace());\r
                        }\r
-                       \r
-                       \r
                } catch (Exception e) {\r
                        throw new RuntimeException(e);\r
                }\r
        \r
        }\r
        \r
+       protected void handleFirstDerivedSpecimen(ResultSet rs, DerivedUnitFacade facade, AlgaTerraImportState state, ResultSetPartitioner partitioner) throws SQLException {\r
+               Integer unitId = nullSafeInt(rs, "unitId");\r
+               Integer collectionFk = nullSafeInt(rs,"CollectionFk");\r
+               String label = rs.getString("Label"); \r
+               \r
+               //collection\r
+               if (collectionFk != null){\r
+                       Collection subCollection = state.getRelatedObject(AlgaTerraCollectionImport.NAMESPACE_SUBCOLLECTION, String.valueOf(collectionFk), Collection.class);\r
+                       if (subCollection != null){\r
+                               facade.setCollection(subCollection);\r
+                       }else{\r
+                               Collection collection = state.getRelatedObject(AlgaTerraCollectionImport.NAMESPACE_COLLECTION, String.valueOf(collectionFk), Collection.class);\r
+                               if (collection == null){\r
+                                       logger.warn("Collection for collectionFK " + collectionFk + " can not be found.");\r
+                               }\r
+                               facade.setCollection(collection);\r
+                       }\r
+               }\r
+               \r
+               //Label\r
+               if (isNotBlank(label)){\r
+                       //TODO implement label #4218, #3090, #3084\r
+                       logger.warn("Label not yet implemented for specimen, #4218, #3090, #3084");\r
+               }\r
+               \r
+               //TODO id, created for fact +  ecoFact\r
+               //      this.doIdCreatedUpdatedNotes(state, descriptionElement, rs, id, namespace);\r
+               if (unitId != null){\r
+                       this.doIdCreatedUpdatedNotes(state, facade.innerDerivedUnit(), rs, unitId, getDerivedUnitNameSpace());\r
+               }else{\r
+                       logger.warn("Specimen has no unitId: " +  facade.innerDerivedUnit() + ": " + getDerivedUnitNameSpace());\r
+               }\r
+       }\r
+               \r
+       \r
+       \r
        protected abstract String getDerivedUnitNameSpace();\r
+       \r
+       protected abstract String getFieldObservationNameSpace();\r
+       \r
 \r
        protected DescriptionBase getFieldObservationDescription(DerivedUnitFacade facade) {\r
-               Set<DescriptionBase> descriptions = facade.innerFieldObservation().getDescriptions();\r
+               Set<DescriptionBase> descriptions = facade.innerFieldUnit().getDescriptions();\r
                for (DescriptionBase desc : descriptions){\r
                        if (desc.isImageGallery() == false){\r
                                return desc;\r
                        }\r
                }\r
-               SpecimenDescription specDesc = SpecimenDescription.NewInstance(facade.innerFieldObservation());\r
+               SpecimenDescription specDesc = SpecimenDescription.NewInstance(facade.innerFieldUnit());\r
                descriptions.add(specDesc);\r
                return specDesc;\r
        }\r
        \r
 \r
        private void makeAreas(AlgaTerraImportState state, ResultSet rs, DerivedUnitFacade facade) throws SQLException {\r
-               Object gazetteerId = rs.getObject("GazetteerId");\r
+               Integer gazetteerId = nullSafeInt(rs, "GazetteerId");\r
                if (gazetteerId != null){\r
                        //TDWG\r
                        NamedArea tdwgArea;\r
                        String tdwg4 = rs.getString("L4Code");\r
                        if (isNotBlank(tdwg4)){\r
-                               tdwgArea = TdwgArea.getAreaByTdwgAbbreviation(tdwg4);\r
+                               tdwgArea = TdwgAreaProvider.getAreaByTdwgAbbreviation(tdwg4);\r
                        }else{\r
                                String tdwg3 = rs.getString("L3Code");\r
                                if (isNotBlank(tdwg3)){\r
-                                       tdwgArea = TdwgArea.getAreaByTdwgAbbreviation(tdwg3);\r
+                                       tdwgArea = TdwgAreaProvider.getAreaByTdwgAbbreviation(tdwg3);\r
                                }else{\r
-                                       Integer tdwg2 = rs.getInt("L2Code");                            \r
-                                       tdwgArea = TdwgArea.getAreaByTdwgAbbreviation(String.valueOf(tdwg2));\r
+                                       Number tdwg2D = nullSafeDouble(rs, "L2Code"); \r
+                                       if (tdwg2D != null){\r
+                                               Integer tdwg2 = tdwg2D.intValue();\r
+                                               tdwgArea = TdwgAreaProvider.getAreaByTdwgAbbreviation(String.valueOf(tdwg2));\r
+                                       }else{\r
+                                               Number tdwg1D = nullSafeDouble(rs, "L1Code");                                   \r
+                                               if (tdwg1D != null){\r
+                                                       Integer tdwg1 = tdwg1D.intValue();\r
+                                                       tdwgArea = TdwgAreaProvider.getAreaByTdwgAbbreviation(String.valueOf(tdwg1));\r
+                                               }else{\r
+                                                       tdwgArea = null;\r
+                                               }\r
+                                       }\r
                                }\r
                        }\r
                        if (tdwgArea == null){\r
@@ -294,16 +392,36 @@ public abstract class AlgaTerraSpecimenImportBase extends BerlinModelImportBase{
                        }\r
                        \r
                        //Countries\r
-                       WaterbodyOrCountry country = null;\r
+                       Country country = null;\r
                        String isoCountry = rs.getString("ISOCountry");\r
                        String countryStr = rs.getString("Country");\r
                        if (isNotBlank(isoCountry)){\r
-                               country = WaterbodyOrCountry.getWaterbodyOrCountryByIso3166A2(isoCountry);\r
+                               country = Country.getCountryByIso3166A2(isoCountry);\r
                        }else if (isNotBlank(countryStr)){\r
                                logger.warn("Country exists but no ISO code");\r
+                       }else{\r
+                               \r
+                       }\r
+                       \r
+                       NamedArea subL4Area = null;\r
+                       Boolean subL4 = nullSafeBoolean(rs, "subL4");\r
+                       if (subL4 != null && subL4.booleanValue() == true){\r
+                               subL4Area = makeSubL4Area(state, gazetteerId);\r
+                               if (subL4Area != null){\r
+                                       facade.addCollectingArea(subL4Area);\r
+                               }else{\r
+                                       logger.warn("SubL4 area not found for gazetteerId: " + gazetteerId);\r
+                               }\r
                        }\r
-                       if (country == null){\r
-                               logger.warn("Country does not exist for GazetteerID " + gazetteerId);\r
+                       \r
+                       if (country == null ){\r
+                               if (! gazetteerId.equals(40)){//special handling for Borneo, TDWG area is enough here as it matches exactly\r
+                                       if (subL4Area == null ){\r
+                                               logger.warn("Country does not exist and SubL4 could not be found for GazetteerID " + gazetteerId);\r
+                                       }else {  \r
+                                               logger.info("Country could not be defined but subL4 area was added");\r
+                                       }\r
+                               }\r
                        }else{\r
                                facade.setCountry(country);\r
                        }\r
@@ -311,11 +429,17 @@ public abstract class AlgaTerraSpecimenImportBase extends BerlinModelImportBase{
                }\r
            \r
                //Waterbody\r
-               WaterbodyOrCountry waterbody = null;\r
+               NamedArea waterbody = null;\r
                String waterbodyStr = rs.getString("WaterBody");\r
                if (isNotBlank(waterbodyStr)){\r
                        if (waterbodyStr.equals("Atlantic Ocean")){\r
-                               waterbody = WaterbodyOrCountry.ATLANTICOCEAN();\r
+                               waterbody = NamedArea.ATLANTICOCEAN();\r
+                       }else if (waterbodyStr.equals("Pacific Ocean")){\r
+                               waterbody = NamedArea.PACIFICOCEAN();\r
+                       }else if (waterbodyStr.equals("Indian Ocean")){\r
+                               waterbody = NamedArea.INDIANOCEAN();\r
+                       }else if (waterbodyStr.equals("Arctic Ocean")){\r
+                               waterbody = NamedArea.ARCTICOCEAN();\r
                        }else{\r
                                logger.warn("Waterbody not recognized: " + waterbody);\r
                        }\r
@@ -330,8 +454,82 @@ public abstract class AlgaTerraSpecimenImportBase extends BerlinModelImportBase{
        }\r
 \r
 \r
-       \r
+       private NamedArea makeSubL4Area(AlgaTerraImportState state, Integer gazetteerId) {\r
+               UUID uuid = subL4Mapping.get(gazetteerId);\r
+               NamedArea area = (NamedArea)getTermService().find(uuid);\r
+               if (area == null){\r
+                       logger.warn("SubL4 area could not be found in repository");\r
+               }\r
+               return area;\r
+       }\r
 \r
+       private boolean handleMissingCountry(AlgaTerraImportState state, DerivedUnitFacade facade, Integer gazetteerId) {\r
+               NamedArea area = null;\r
+               if (gazetteerId != null){\r
+                       if (gazetteerId.equals(42)){\r
+                               area = getNamedArea(state, AlgaTerraImportTransformer.uuidNamedAreaBorneo, null, null, null, null, null);\r
+                       }else if (gazetteerId.equals(1684)){\r
+                               area = getNamedArea(state, AlgaTerraImportTransformer.uuidNamedAreaPatagonia, null, null, null, null, null);\r
+                       }else if (gazetteerId.equals(2167)){\r
+                               area = getNamedArea(state, AlgaTerraImportTransformer.uuidNamedAreaTierraDelFuego, null, null, null, null, null);\r
+                       }\r
+               }\r
+               if (area != null){\r
+                       facade.addCollectingArea(area);\r
+                       return true;\r
+               }\r
+               return false;\r
+               \r
+       }\r
+\r
+       protected SpecimenOrObservationType makeDerivedUnitType(String recordBasis) {\r
+               SpecimenOrObservationType result = null;\r
+               if (StringUtils.isBlank(recordBasis)){\r
+                       result = SpecimenOrObservationType.DerivedUnit;\r
+               } else if (recordBasis.equalsIgnoreCase("FossileSpecimen")){\r
+                       result = SpecimenOrObservationType.Fossil;\r
+               }else if (recordBasis.equalsIgnoreCase("HumanObservation")){\r
+                       result = SpecimenOrObservationType.HumanObservation;\r
+               }else if (recordBasis.equalsIgnoreCase("Literature")){\r
+                       //FIXME\r
+                       logger.warn("Literature record basis not yet supported");\r
+                       result = SpecimenOrObservationType.DerivedUnit;\r
+               }else if (recordBasis.equalsIgnoreCase("LivingSpecimen")){\r
+                       result = SpecimenOrObservationType.LivingSpecimen;\r
+               }else if (recordBasis.equalsIgnoreCase("MachineObservation")){\r
+                       result = SpecimenOrObservationType.MachineObservation;\r
+               }else if (recordBasis.equalsIgnoreCase("Observation")){\r
+                       result = SpecimenOrObservationType.Observation;\r
+               }else if (recordBasis.equalsIgnoreCase("LivingCulture")){\r
+                       //FIXME\r
+                       logger.warn("LivingCulture record basis not yet supported");\r
+                       result = SpecimenOrObservationType.DerivedUnit;\r
+               }else if (recordBasis.equalsIgnoreCase("PreservedSpecimen")){\r
+                       result = SpecimenOrObservationType.PreservedSpecimen;\r
+               }\r
+               return result;\r
+       }\r
+\r
+\r
+       protected Feature makeFeature(SpecimenOrObservationType type, AlgaTerraImportState state) {\r
+               if (type.equals(SpecimenOrObservationType.DerivedUnit)){\r
+                       return Feature.INDIVIDUALS_ASSOCIATION();\r
+               }else if (type.isFeatureObservation()){\r
+                       return Feature.OBSERVATION();\r
+               }else if (type.isPreservedSpecimen()){\r
+                       return Feature.SPECIMEN();\r
+               }else if (type.equals(SpecimenOrObservationType.LivingSpecimen)){\r
+                       UUID uuid = AlgaTerraImportTransformer.uuidFeatureLivingSpecimen;\r
+                       Feature feature = getFeature(state, uuid, "Living Specimen", "Living Specimen", null, Feature.SPECIMEN().getVocabulary());\r
+                       if (feature == null){\r
+                               logger.warn("Living Specimen Feature could not be created");\r
+                       }\r
+                       return feature;\r
+               }\r
+               logger.warn("No feature defined for derived unit type: " + type);\r
+               return null;\r
+       }\r
+       \r
        private ReferenceSystem makeRefrenceSystem(String geoCodeMethod, AlgaTerraImportState state) {\r
                if (StringUtils.isBlank(geoCodeMethod)){\r
                        return null;\r
@@ -341,8 +539,7 @@ public abstract class AlgaTerraSpecimenImportBase extends BerlinModelImportBase{
                }else if(geoCodeMethod.startsWith("Google")){\r
                        return ReferenceSystem.GOOGLE_EARTH();\r
                }else if(geoCodeMethod.startsWith("Map")){\r
-                       logger.warn("Reference system " +  geoCodeMethod +  " not yet supported.");\r
-                       return null;\r
+                       return ReferenceSystem.MAP();\r
                }else if(geoCodeMethod.startsWith("WikiProjekt Georeferenzierung") || geoCodeMethod.startsWith("http://toolserver.org/~geohack/geohack.php") ){\r
                        return ReferenceSystem.WGS84();\r
                }else {\r
@@ -355,10 +552,42 @@ public abstract class AlgaTerraSpecimenImportBase extends BerlinModelImportBase{
        \r
 \r
        private void handleCollectorTeam(AlgaTerraImportState state, DerivedUnitFacade facade, ResultSet rs) throws SQLException {\r
-               // FIXME parsen\r
                String collector = rs.getString("Collector");\r
-               Team team = Team.NewTitledInstance(collector, collector);\r
-               facade.setCollector(team);\r
+               TeamOrPersonBase<?> author = getAuthor(collector);\r
+               facade.setCollector(author);\r
+       }\r
+\r
+       /**\r
+        * @param facade\r
+        * @param collector\r
+        */\r
+       protected TeamOrPersonBase<?> getAuthor(String author) {\r
+               // FIXME TODO parsen und deduplizieren\r
+               Team team = Team.NewTitledInstance(author, author);\r
+               return team;\r
+       }\r
+       \r
+\r
+       /**\r
+        * Use same TaxonDescription if two records belong to the same taxon \r
+        * @param state \r
+        * @param newTaxonId\r
+        * @param oldTaxonId\r
+        * @param oldDescription\r
+        * @param taxonMap\r
+        * @return\r
+        */\r
+       protected TaxonDescription getTaxonDescription(AlgaTerraImportState state, Taxon taxon, Reference<?> sourceSec){\r
+               TaxonDescription result = null;\r
+               Set<TaxonDescription> descriptionSet= taxon.getDescriptions();\r
+               if (descriptionSet.size() > 0) {\r
+                       result = descriptionSet.iterator().next(); \r
+               }else{\r
+                       result = TaxonDescription.NewInstance();\r
+                       result.setTitleCache(sourceSec.getTitleCache(), true);\r
+                       taxon.addDescription(result);\r
+               }\r
+               return result;\r
        }\r
 \r
        \r